SEC-232: Add role hierarchy contribution.
This commit is contained in:
parent
1a4b32e50e
commit
2f03000b68
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
/**
|
||||
* Exception that is thrown because of a cycle in the role hierarchy definition
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*/
|
||||
public class CycleInRoleHierarchyException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -4970510612118296707L;
|
||||
|
||||
public CycleInRoleHierarchyException() {
|
||||
super("Exception thrown because of a cycle in the role hierarchy definition!");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
|
||||
/**
|
||||
* The simple interface of a role hierarchy.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*
|
||||
*/
|
||||
public interface RoleHierarchy {
|
||||
|
||||
/**
|
||||
* This method returns an array of all reachable authorities.<br>
|
||||
* Reachable authorities are the directly assigned authorities plus all
|
||||
* authorities that are (transitively) reachable from them in the role
|
||||
* hierarchy.<br>
|
||||
* Example:<br>
|
||||
* Role hierarchy: ROLE_A > ROLE_B and ROLE_B > ROLE_C.<br>
|
||||
* Directly assigned authority: ROLE_A.<br>
|
||||
* Reachable authorities: ROLE_A, ROLE_B, ROLE_C.
|
||||
*
|
||||
* @param authorities - Array of the directly assigned authorities.
|
||||
* @return Array of all reachable authorities given the assigned authorities.
|
||||
*/
|
||||
public GrantedAuthority[] getReachableGrantedAuthorities(GrantedAuthority[] authorities);
|
||||
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.acegisecurity.GrantedAuthorityImpl;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This class defines a role hierarchy for use with the UserDetailsServiceWrapper.
|
||||
* </p>
|
||||
* <p>
|
||||
* Here is an example configuration of a role hierarchy (hint: read the ">" sign as "includes"):
|
||||
<pre>
|
||||
<property name="hierarchy">
|
||||
<value>
|
||||
ROLE_A > ROLE_B
|
||||
ROLE_B > ROLE_AUTHENTICATED
|
||||
ROLE_AUTHENTICATED > ROLE_UNAUTHENTICATED
|
||||
</value>
|
||||
</property>
|
||||
</pre>
|
||||
</p>
|
||||
* <p>
|
||||
* Explanation of the above:<br>
|
||||
* In effect every user with ROLE_A also has ROLE_B, ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;<br>
|
||||
* every user with ROLE_B also has ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;<br>
|
||||
* every user with ROLE_AUTHENTICATED also has ROLE_UNAUTHENTICATED.
|
||||
* </p>
|
||||
* <p>
|
||||
* Hierarchical Roles will dramatically shorten your access rules (and also make the access rules much more elegant).
|
||||
* </p>
|
||||
* <p>
|
||||
* Consider this access rule for Acegi's RoleVoter (background: every user that is authenticated should be
|
||||
* able to log out):<br>
|
||||
* /logout.html=ROLE_A,ROLE_B,ROLE_AUTHENTICATED<br>
|
||||
* With hierarchical roles this can now be shortened to:<br>
|
||||
* /logout.html=ROLE_AUTHENTICATED<br>
|
||||
* In addition to shorter rules this will also make your access rules more readable and your intentions clearer.
|
||||
* </p>
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*
|
||||
*/
|
||||
public class RoleHierarchyImpl implements RoleHierarchy {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(RoleHierarchyImpl.class);
|
||||
|
||||
private String roleHierarchyStringRepresentation = null;
|
||||
|
||||
/**
|
||||
* rolesReachableInOneStepMap is a Map that under the key of a specific role name contains a set of all roles
|
||||
* reachable from this role in 1 step
|
||||
*/
|
||||
private Map rolesReachableInOneStepMap = null;
|
||||
|
||||
/**
|
||||
* rolesReachableInOneOrMoreStepsMap is a Map that under the key of a specific role name contains a set of all
|
||||
* roles reachable from this role in 1 or more steps
|
||||
*/
|
||||
private Map rolesReachableInOneOrMoreStepsMap = null;
|
||||
|
||||
/**
|
||||
* Set the role hierarchy and precalculate for every role the set of all reachable roles, i. e. all roles lower in
|
||||
* the hierarchy of every given role. Precalculation is done for performance reasons (reachable roles can then be
|
||||
* calculated in O(1) time).
|
||||
* During precalculation cycles in role hierarchy are detected and will cause a
|
||||
* <tt>CycleInRoleHierarchyException</tt> to be thrown.
|
||||
*
|
||||
* @param roleHierarchyStringRepresentation - String definition of the role hierarchy.
|
||||
*/
|
||||
public void setHierarchy(String roleHierarchyStringRepresentation) {
|
||||
this.roleHierarchyStringRepresentation = roleHierarchyStringRepresentation;
|
||||
|
||||
logger.debug("setHierarchy() - The following role hierarchy was set: " + roleHierarchyStringRepresentation);
|
||||
|
||||
buildRolesReachableInOneStepMap();
|
||||
buildRolesReachableInOneOrMoreStepsMap();
|
||||
}
|
||||
|
||||
public GrantedAuthority[] getReachableGrantedAuthorities(GrantedAuthority[] authorities) {
|
||||
if (authorities == null || authorities.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Set reachableRoles = new HashSet();
|
||||
|
||||
for (int i = 0; i < authorities.length; i++) {
|
||||
reachableRoles.add(authorities[i]);
|
||||
Set additionalReachableRoles = (Set) rolesReachableInOneOrMoreStepsMap.get(authorities[i]);
|
||||
if (additionalReachableRoles != null) {
|
||||
reachableRoles.addAll(additionalReachableRoles);
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("getReachableGrantedAuthorities() - From the roles " + ArrayUtils.toString(authorities)
|
||||
+ " one can reach " + reachableRoles + " in zero or more steps.");
|
||||
}
|
||||
|
||||
return (GrantedAuthority[]) reachableRoles.toArray(new GrantedAuthority[reachableRoles.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse input and build the map for the roles reachable in one step: the higher role will become a key that
|
||||
* references a set of the reachable lower roles.
|
||||
*/
|
||||
private void buildRolesReachableInOneStepMap() {
|
||||
String parsingRegex = "(\\s*(\\w+)\\s*\\>\\s*(\\w+))";
|
||||
Pattern pattern = Pattern.compile(parsingRegex);
|
||||
|
||||
Matcher roleHierarchyMatcher = pattern.matcher(roleHierarchyStringRepresentation);
|
||||
rolesReachableInOneStepMap = new HashMap();
|
||||
|
||||
while (roleHierarchyMatcher.find()) {
|
||||
GrantedAuthority higherRole = new GrantedAuthorityImpl(roleHierarchyMatcher.group(2));
|
||||
GrantedAuthority lowerRole = new GrantedAuthorityImpl(roleHierarchyMatcher.group(3));
|
||||
Set rolesReachableInOneStepSet = null;
|
||||
|
||||
if (!rolesReachableInOneStepMap.containsKey(higherRole)) {
|
||||
rolesReachableInOneStepSet = new HashSet();
|
||||
rolesReachableInOneStepMap.put(higherRole, rolesReachableInOneStepSet);
|
||||
} else {
|
||||
rolesReachableInOneStepSet = (Set) rolesReachableInOneStepMap.get(higherRole);
|
||||
}
|
||||
rolesReachableInOneStepSet.add(lowerRole);
|
||||
|
||||
logger.debug("buildRolesReachableInOneStepMap() - From role "
|
||||
+ higherRole + " one can reach role " + lowerRole + " in one step.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For every higher role from rolesReachableInOneStepMap store all roles that are reachable from it in the map of
|
||||
* roles reachable in one or more steps. (Or throw a CycleInRoleHierarchyException if a cycle in the role
|
||||
* hierarchy definition is detected)
|
||||
*/
|
||||
private void buildRolesReachableInOneOrMoreStepsMap() {
|
||||
rolesReachableInOneOrMoreStepsMap = new HashMap();
|
||||
// iterate over all higher roles from rolesReachableInOneStepMap
|
||||
Iterator roleIterator = rolesReachableInOneStepMap.keySet().iterator();
|
||||
|
||||
while (roleIterator.hasNext()) {
|
||||
GrantedAuthority role = (GrantedAuthority) roleIterator.next();
|
||||
Set rolesToVisitSet = new HashSet();
|
||||
|
||||
if (rolesReachableInOneStepMap.containsKey(role)) {
|
||||
rolesToVisitSet.addAll((Set) rolesReachableInOneStepMap.get(role));
|
||||
}
|
||||
|
||||
Set visitedRolesSet = new HashSet();
|
||||
|
||||
while (!rolesToVisitSet.isEmpty()) {
|
||||
// take a role from the rolesToVisit set
|
||||
GrantedAuthority aRole = (GrantedAuthority) rolesToVisitSet.iterator().next();
|
||||
rolesToVisitSet.remove(aRole);
|
||||
visitedRolesSet.add(aRole);
|
||||
if (rolesReachableInOneStepMap.containsKey(aRole)) {
|
||||
Set newReachableRoles = (Set) rolesReachableInOneStepMap.get(aRole);
|
||||
|
||||
if (CollectionUtils.containsAny(rolesToVisitSet, newReachableRoles)
|
||||
|| CollectionUtils.containsAny(visitedRolesSet, newReachableRoles)) {
|
||||
throw new CycleInRoleHierarchyException();
|
||||
} else {
|
||||
// no cycle
|
||||
rolesToVisitSet.addAll(newReachableRoles);
|
||||
}
|
||||
}
|
||||
}
|
||||
rolesReachableInOneOrMoreStepsMap.put(role, visitedRolesSet);
|
||||
|
||||
logger.debug("buildRolesReachableInOneOrMoreStepsMap() - From role "
|
||||
+ role + " one can reach " + visitedRolesSet + " in one or more steps.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import org.acegisecurity.userdetails.UserDetails;
|
||||
import org.acegisecurity.userdetails.UserDetailsService;
|
||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
/**
|
||||
* This class wraps Acegi's UserDetailsService in a way that its loadUserByUsername()
|
||||
* method returns wrapped UserDetails that return all hierachically reachable authorities
|
||||
* instead of only the directly assigned authorities.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*/
|
||||
public class UserDetailsServiceWrapper implements UserDetailsService {
|
||||
|
||||
private UserDetailsService userDetailsService = null;
|
||||
|
||||
private RoleHierarchy roleHierarchy = null;
|
||||
|
||||
public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
public void setUserDetailsService(UserDetailsService userDetailsService) {
|
||||
this.userDetailsService = userDetailsService;
|
||||
}
|
||||
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
// wrapped UserDetailsService might throw UsernameNotFoundException or DataAccessException which will then bubble up
|
||||
return new UserDetailsWrapper(userDetails, roleHierarchy);
|
||||
}
|
||||
|
||||
public UserDetailsService getWrappedUserDetailsService() {
|
||||
return userDetailsService;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.acegisecurity.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* This class wraps Acegi's UserDetails in a way that its getAuthorities()-Method is
|
||||
* delegated to RoleHierarchy.getReachableGrantedAuthorities. All other methods are
|
||||
* delegated to the UserDetails implementation.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*/
|
||||
public class UserDetailsWrapper implements UserDetails {
|
||||
|
||||
private static final long serialVersionUID = 1532428778390085311L;
|
||||
|
||||
private UserDetails userDetails = null;
|
||||
|
||||
private RoleHierarchy roleHierarchy = null;
|
||||
|
||||
public UserDetailsWrapper(UserDetails userDetails, RoleHierarchy roleHierarchy) {
|
||||
this.userDetails = userDetails;
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
public boolean isAccountNonExpired() {
|
||||
return userDetails.isAccountNonExpired();
|
||||
}
|
||||
|
||||
public boolean isAccountNonLocked() {
|
||||
return userDetails.isAccountNonLocked();
|
||||
}
|
||||
|
||||
public GrantedAuthority[] getAuthorities() {
|
||||
return roleHierarchy.getReachableGrantedAuthorities(userDetails.getAuthorities());
|
||||
}
|
||||
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return userDetails.isCredentialsNonExpired();
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return userDetails.isEnabled();
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return userDetails.getPassword();
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return userDetails.getUsername();
|
||||
}
|
||||
|
||||
public UserDetails getUnwrappedUserDetails() {
|
||||
return userDetails;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Test helper class for the hierarchical roles tests.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*/
|
||||
public abstract class HierarchicalRolesTestHelper {
|
||||
|
||||
public static boolean containTheSameGrantedAuthorities(GrantedAuthority[] authorities1, GrantedAuthority[] authorities2) {
|
||||
if (authorities1 == null && authorities2 == null) {
|
||||
return true;
|
||||
} else if (authorities1 == null || authorities2 == null) {
|
||||
return false;
|
||||
}
|
||||
List authoritiesList1 = new ArrayList();
|
||||
CollectionUtils.addAll(authoritiesList1, authorities1);
|
||||
List authoritiesList2 = new ArrayList();
|
||||
CollectionUtils.addAll(authoritiesList2, authorities2);
|
||||
return CollectionUtils.isEqualCollection(authoritiesList1, authoritiesList2);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.acegisecurity.GrantedAuthorityImpl;
|
||||
|
||||
/**
|
||||
* Tests for {@link RoleHierarchyImpl}.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*/
|
||||
public class RoleHierarchyImplTests extends TestCase {
|
||||
|
||||
public RoleHierarchyImplTests() {
|
||||
}
|
||||
|
||||
public RoleHierarchyImplTests(String testCaseName) {
|
||||
super(testCaseName);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestRunner.run(RoleHierarchyImplTests.class);
|
||||
}
|
||||
|
||||
public void testSimpleRoleHierarchy() {
|
||||
GrantedAuthority[] authorities0 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_0") };
|
||||
GrantedAuthority[] authorities1 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A") };
|
||||
GrantedAuthority[] authorities2 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_B") };
|
||||
|
||||
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
|
||||
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B");
|
||||
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities0), authorities0));
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities2));
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities2), authorities2));
|
||||
}
|
||||
|
||||
public void testTransitiveRoleHierarchies() {
|
||||
GrantedAuthority[] authorities1 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A") };
|
||||
GrantedAuthority[] authorities2 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_B"), new GrantedAuthorityImpl("ROLE_C") };
|
||||
GrantedAuthority[] authorities3 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_B"), new GrantedAuthorityImpl("ROLE_C"),
|
||||
new GrantedAuthorityImpl("ROLE_D") };
|
||||
|
||||
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
|
||||
|
||||
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C");
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities2));
|
||||
|
||||
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C\nROLE_C > ROLE_D");
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(roleHierarchyImpl.getReachableGrantedAuthorities(authorities1), authorities3));
|
||||
}
|
||||
|
||||
public void testCyclesInRoleHierarchy() {
|
||||
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
|
||||
|
||||
try {
|
||||
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_A");
|
||||
fail("Cycle in role hierarchy was not detected!");
|
||||
} catch (CycleInRoleHierarchyException e) {}
|
||||
|
||||
try {
|
||||
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_A");
|
||||
fail("Cycle in role hierarchy was not detected!");
|
||||
} catch (CycleInRoleHierarchyException e) {}
|
||||
|
||||
try {
|
||||
roleHierarchyImpl.setHierarchy("ROLE_A > ROLE_B\nROLE_B > ROLE_C\nROLE_C > ROLE_A");
|
||||
fail("Cycle in role hierarchy was not detected!");
|
||||
} catch (CycleInRoleHierarchyException e) {}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.acegisecurity.GrantedAuthorityImpl;
|
||||
|
||||
/**
|
||||
* Tests for {@link HierarchicalRolesTestHelper}.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*/
|
||||
public class TestHelperTests extends TestCase {
|
||||
|
||||
public TestHelperTests() {
|
||||
}
|
||||
|
||||
public TestHelperTests(String testCaseName) {
|
||||
super(testCaseName);
|
||||
}
|
||||
|
||||
public void testContainTheSameGrantedAuthorities() {
|
||||
GrantedAuthority[] authorities1 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_B") };
|
||||
GrantedAuthority[] authorities2 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_B"), new GrantedAuthorityImpl("ROLE_A") };
|
||||
GrantedAuthority[] authorities3 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_C") };
|
||||
GrantedAuthority[] authorities4 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A") };
|
||||
GrantedAuthority[] authorities5 = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_A") };
|
||||
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(null, null));
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities1));
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities2));
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities2, authorities1));
|
||||
|
||||
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(null, authorities1));
|
||||
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, null));
|
||||
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities3));
|
||||
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities3, authorities1));
|
||||
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities1, authorities4));
|
||||
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities4, authorities1));
|
||||
assertFalse(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(authorities4, authorities5));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.acegisecurity.GrantedAuthorityImpl;
|
||||
import org.acegisecurity.userdetails.User;
|
||||
import org.acegisecurity.userdetails.UserDetails;
|
||||
import org.acegisecurity.userdetails.UserDetailsService;
|
||||
import org.acegisecurity.userdetails.UsernameNotFoundException;
|
||||
import org.jmock.Mock;
|
||||
import org.jmock.MockObjectTestCase;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
|
||||
public class UserDetailsServiceWrapperTests extends MockObjectTestCase {
|
||||
|
||||
private UserDetailsService wrappedUserDetailsService = null;
|
||||
private UserDetailsServiceWrapper userDetailsServiceWrapper = null;
|
||||
|
||||
public UserDetailsServiceWrapperTests() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UserDetailsServiceWrapperTests(String testCaseName) {
|
||||
super(testCaseName);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestRunner.run(UserDetailsServiceWrapperTests.class);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
|
||||
roleHierarchy.setHierarchy("ROLE_A > ROLE_B");
|
||||
GrantedAuthority[] authorities = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A") };
|
||||
UserDetails user = new User("EXISTING_USER", "PASSWORD", true, true, true, true, authorities);
|
||||
Mock wrappedUserDetailsServiceMock = mock(UserDetailsService.class);
|
||||
wrappedUserDetailsServiceMock.stubs().method("loadUserByUsername").with(eq("EXISTING_USER")).will(returnValue(user));
|
||||
wrappedUserDetailsServiceMock.stubs().method("loadUserByUsername").with(eq("USERNAME_NOT_FOUND_EXCEPTION")).will(throwException(new UsernameNotFoundException("USERNAME_NOT_FOUND_EXCEPTION")));
|
||||
wrappedUserDetailsServiceMock.stubs().method("loadUserByUsername").with(eq("DATA_ACCESS_EXCEPTION")).will(throwException(new EmptyResultDataAccessException(1234)));
|
||||
wrappedUserDetailsService = (UserDetailsService) wrappedUserDetailsServiceMock.proxy();
|
||||
userDetailsServiceWrapper = new UserDetailsServiceWrapper();
|
||||
userDetailsServiceWrapper.setRoleHierarchy(roleHierarchy);
|
||||
userDetailsServiceWrapper.setUserDetailsService(wrappedUserDetailsService);
|
||||
}
|
||||
|
||||
public void testLoadUserByUsername() {
|
||||
GrantedAuthority[] authorities = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_B") };
|
||||
UserDetails expectedUserDetails = new User("EXISTING_USER", "PASSWORD", true, true, true, true, authorities);
|
||||
UserDetails userDetails = userDetailsServiceWrapper.loadUserByUsername("EXISTING_USER");
|
||||
assertEquals(expectedUserDetails.getPassword(), userDetails.getPassword());
|
||||
assertEquals(expectedUserDetails.getUsername(), userDetails.getUsername());
|
||||
assertEquals(expectedUserDetails.isAccountNonExpired(), userDetails.isAccountNonExpired());
|
||||
assertEquals(expectedUserDetails.isAccountNonLocked(), userDetails.isAccountNonLocked());
|
||||
assertEquals(expectedUserDetails.isCredentialsNonExpired(), expectedUserDetails.isCredentialsNonExpired());
|
||||
assertEquals(expectedUserDetails.isEnabled(), userDetails.isEnabled());
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(expectedUserDetails.getAuthorities(), userDetails.getAuthorities()));
|
||||
|
||||
try {
|
||||
userDetails = userDetailsServiceWrapper.loadUserByUsername("USERNAME_NOT_FOUND_EXCEPTION");
|
||||
fail("testLoadUserByUsername() - UsernameNotFoundException did not bubble up!");
|
||||
} catch (UsernameNotFoundException e) {}
|
||||
|
||||
try {
|
||||
userDetails = userDetailsServiceWrapper.loadUserByUsername("DATA_ACCESS_EXCEPTION");
|
||||
fail("testLoadUserByUsername() - DataAccessException did not bubble up!");
|
||||
} catch (DataAccessException e) {}
|
||||
}
|
||||
|
||||
public void testGetWrappedUserDetailsService() {
|
||||
assertTrue(userDetailsServiceWrapper.getWrappedUserDetailsService() == wrappedUserDetailsService);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package org.acegisecurity.userdetails.hierarchicalroles;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
import org.acegisecurity.GrantedAuthority;
|
||||
import org.acegisecurity.GrantedAuthorityImpl;
|
||||
import org.acegisecurity.userdetails.User;
|
||||
import org.acegisecurity.userdetails.UserDetails;
|
||||
|
||||
/**
|
||||
* Tests for {@link UserDetailsWrapper}.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*/
|
||||
public class UserDetailsWrapperTests extends TestCase {
|
||||
|
||||
private GrantedAuthority[] authorities = null;
|
||||
private UserDetails userDetails1 = null;
|
||||
private UserDetails userDetails2 = null;
|
||||
private UserDetailsWrapper userDetailsWrapper1 = null;
|
||||
private UserDetailsWrapper userDetailsWrapper2 = null;
|
||||
|
||||
public UserDetailsWrapperTests() {
|
||||
}
|
||||
|
||||
public UserDetailsWrapperTests(String testCaseName) {
|
||||
super(testCaseName);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
|
||||
roleHierarchy.setHierarchy("ROLE_A > ROLE_B");
|
||||
authorities = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A") };
|
||||
userDetails1 = new User("TestUser1", "TestPassword1", true, true, true, true, authorities);
|
||||
userDetails2 = new User("TestUser2", "TestPassword2", false, false, false, false, authorities);
|
||||
userDetailsWrapper1 = new UserDetailsWrapper(userDetails1, roleHierarchy);
|
||||
userDetailsWrapper2 = new UserDetailsWrapper(userDetails2, roleHierarchy);
|
||||
}
|
||||
|
||||
public void testIsAccountNonExpired() {
|
||||
assertEquals(userDetails1.isAccountNonExpired(), userDetailsWrapper1.isAccountNonExpired());
|
||||
assertEquals(userDetails2.isAccountNonExpired(), userDetailsWrapper2.isAccountNonExpired());
|
||||
}
|
||||
|
||||
public void testIsAccountNonLocked() {
|
||||
assertEquals(userDetails1.isAccountNonLocked(), userDetailsWrapper1.isAccountNonLocked());
|
||||
assertEquals(userDetails2.isAccountNonLocked(), userDetailsWrapper2.isAccountNonLocked());
|
||||
}
|
||||
|
||||
public void testGetAuthorities() {
|
||||
GrantedAuthority[] expectedAuthorities = new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_B") };
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(userDetailsWrapper1.getAuthorities(), expectedAuthorities));
|
||||
assertTrue(HierarchicalRolesTestHelper.containTheSameGrantedAuthorities(userDetailsWrapper2.getAuthorities(), expectedAuthorities));
|
||||
}
|
||||
|
||||
public void testIsCredentialsNonExpired() {
|
||||
assertEquals(userDetails1.isCredentialsNonExpired(), userDetailsWrapper1.isCredentialsNonExpired());
|
||||
assertEquals(userDetails2.isCredentialsNonExpired(), userDetailsWrapper2.isCredentialsNonExpired());
|
||||
}
|
||||
|
||||
public void testIsEnabled() {
|
||||
assertEquals(userDetails1.isEnabled(), userDetailsWrapper1.isEnabled());
|
||||
assertEquals(userDetails2.isEnabled(), userDetailsWrapper2.isEnabled());
|
||||
}
|
||||
|
||||
public void testGetPassword() {
|
||||
assertEquals(userDetails1.getPassword(), userDetailsWrapper1.getPassword());
|
||||
assertEquals(userDetails2.getPassword(), userDetailsWrapper2.getPassword());
|
||||
}
|
||||
|
||||
public void testGetUsername() {
|
||||
assertEquals(userDetails1.getUsername(), userDetailsWrapper1.getUsername());
|
||||
assertEquals(userDetails2.getUsername(), userDetailsWrapper2.getUsername());
|
||||
}
|
||||
|
||||
public void testGetUnwrappedUserDetails() {
|
||||
assertTrue(userDetailsWrapper1.getUnwrappedUserDetails() == userDetails1);
|
||||
assertTrue(userDetailsWrapper2.getUnwrappedUserDetails() == userDetails2);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue