diff --git a/core/src/main/java/org/springframework/security/authoritymapping/MapBasedAttributes2GrantedAuthoritiesMapper.java b/core/src/main/java/org/springframework/security/authoritymapping/MapBasedAttributes2GrantedAuthoritiesMapper.java new file mode 100755 index 0000000000..32188a1bf8 --- /dev/null +++ b/core/src/main/java/org/springframework/security/authoritymapping/MapBasedAttributes2GrantedAuthoritiesMapper.java @@ -0,0 +1,167 @@ +package org.springframework.security.authoritymapping; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.GrantedAuthorityImpl; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + + +/** + *
+ * This class implements the Attributes2GrantedAuthoritiesMapper and + * MappableAttributesRetriever interfaces based on the supplied Map. + * It supports both one-to-one and one-to-many mappings. The granted + * authorities to map to can be supplied either as a String or as a + * GrantedAuthority object. + *
+ * @author Ruud Senden + */ +public class MapBasedAttributes2GrantedAuthoritiesMapper implements Attributes2GrantedAuthoritiesMapper, MappableAttributesRetriever, InitializingBean { + private Map attributes2grantedAuthoritiesMap = null; + private String stringSeparator = ","; + private String[] mappableAttributes = null; + + /** + * Check whether all properties have been set to correct values, and do some preprocessing. + */ + public void afterPropertiesSet() { + Assert.notEmpty(attributes2grantedAuthoritiesMap,"A non-empty attributes2grantedAuthoritiesMap must be supplied"); + attributes2grantedAuthoritiesMap = preProcessMap(attributes2grantedAuthoritiesMap); + try { + mappableAttributes = (String[])attributes2grantedAuthoritiesMap.keySet().toArray(new String[]{}); + } catch ( ArrayStoreException ase ) { + throw new IllegalArgumentException("attributes2grantedAuthoritiesMap contains non-String objects as keys"); + } + } + + /** + * Preprocess the given map + * @param orgMap The map to process + * @return the processed Map + */ + private Map preProcessMap(Map orgMap) { + Map result = new HashMap(orgMap.size()); + Iterator it = orgMap.entrySet().iterator(); + while ( it.hasNext() ) { + Map.Entry entry = (Map.Entry)it.next(); + result.put(entry.getKey(),getGrantedAuthorityCollection(entry.getValue())); + } + return result; + } + + /** + * Convert the given value to a collection of Granted Authorities + * + * @param value + * The value to convert to a GrantedAuthority Collection + * @return Collection containing the GrantedAuthority Collection + */ + private Collection getGrantedAuthorityCollection(Object value) { + Collection result = new ArrayList(); + addGrantedAuthorityCollection(result,value); + return result; + } + + /** + * Convert the given value to a collection of Granted Authorities, + * adding the result to the given result collection. + * + * @param value + * The value to convert to a GrantedAuthority Collection + * @return Collection containing the GrantedAuthority Collection + */ + private void addGrantedAuthorityCollection(Collection result, Object value) { + if ( value != null ) { + if ( value instanceof Collection ) { + addGrantedAuthorityCollection(result,(Collection)value); + } else if ( value instanceof Object[] ) { + addGrantedAuthorityCollection(result,(Object[])value); + } else if ( value instanceof String ) { + addGrantedAuthorityCollection(result,(String)value); + } else if ( value instanceof GrantedAuthority ) { + result.add(value); + } else { + throw new IllegalArgumentException("Invalid object type: "+value.getClass().getName()); + } + } + } + + private void addGrantedAuthorityCollection(Collection result, Collection value) { + Iterator it = value.iterator(); + while ( it.hasNext() ) { + addGrantedAuthorityCollection(result,it.next()); + } + } + + private void addGrantedAuthorityCollection(Collection result, Object[] value) { + for ( int i = 0 ; i < value.length ; i++ ) { + addGrantedAuthorityCollection(result,value[i]); + } + } + + private void addGrantedAuthorityCollection(Collection result, String value) { + StringTokenizer st = new StringTokenizer(value,stringSeparator,false); + while ( st.hasMoreTokens() ) { + String nextToken = st.nextToken(); + if ( StringUtils.hasText(nextToken) ) { + result.add(new GrantedAuthorityImpl(nextToken)); + } + } + } + + /** + * Map the given array of attributes to Spring Security GrantedAuthorities. + */ + public GrantedAuthority[] getGrantedAuthorities(String[] attributes) { + List gaList = new ArrayList(); + for (int i = 0; i < attributes.length; i++) { + Collection c = (Collection)attributes2grantedAuthoritiesMap.get(attributes[i]); + if ( c != null ) { gaList.addAll(c); } + } + GrantedAuthority[] result = new GrantedAuthority[gaList.size()]; + result = (GrantedAuthority[])gaList.toArray(result); + return result; + } + + /** + * @return Returns the attributes2grantedAuthoritiesMap. + */ + public Map getAttributes2grantedAuthoritiesMap() { + return attributes2grantedAuthoritiesMap; + } + /** + * @param attributes2grantedAuthoritiesMap The attributes2grantedAuthoritiesMap to set. + */ + public void setAttributes2grantedAuthoritiesMap(Map attributes2grantedAuthoritiesMap) { + this.attributes2grantedAuthoritiesMap = attributes2grantedAuthoritiesMap; + } + + /** + * + * @see org.springframework.security.authoritymapping.MappableAttributesRetriever#getMappableAttributes() + */ + public String[] getMappableAttributes() { + return mappableAttributes; + } + /** + * @return Returns the stringSeparator. + */ + public String getStringSeparator() { + return stringSeparator; + } + /** + * @param stringSeparator The stringSeparator to set. + */ + public void setStringSeparator(String stringSeparator) { + this.stringSeparator = stringSeparator; + } +} diff --git a/core/src/test/java/org/springframework/security/authoritymapping/MapBasedAttributes2GrantedAuthoritiesMapperTest.java b/core/src/test/java/org/springframework/security/authoritymapping/MapBasedAttributes2GrantedAuthoritiesMapperTest.java new file mode 100755 index 0000000000..c2e5989cb1 --- /dev/null +++ b/core/src/test/java/org/springframework/security/authoritymapping/MapBasedAttributes2GrantedAuthoritiesMapperTest.java @@ -0,0 +1,232 @@ +package org.springframework.security.authoritymapping; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; + +import junit.framework.TestCase; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.springframework.security.GrantedAuthority; +import org.springframework.security.GrantedAuthorityImpl; + +/** + * + * @author Ruud Senden + */ +public class MapBasedAttributes2GrantedAuthoritiesMapperTest extends TestCase { + + protected void setUp() throws Exception { + // Set Log4j loglevel to debug to include all logstatements in tests + Logger.getRootLogger().setLevel(Level.DEBUG); + } + + public final void testAfterPropertiesSetNoMap() { + MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper(); + try { + mapper.afterPropertiesSet(); + fail("Expected exception not thrown"); + } catch (IllegalArgumentException expected) { + // Expected exception + } catch (Exception unexpected) { + fail("Unexpected exception: " + unexpected); + } + } + + public final void testAfterPropertiesSetEmptyMap() { + MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper(); + mapper.setAttributes2grantedAuthoritiesMap(new HashMap()); + try { + mapper.afterPropertiesSet(); + fail("Expected exception not thrown"); + } catch (IllegalArgumentException expected) { + // Expected exception + } catch (Exception unexpected) { + fail("Unexpected exception: " + unexpected); + } + } + + public final void testAfterPropertiesSetInvalidKeyTypeMap() { + MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper(); + HashMap m = new HashMap(); + m.put(new Object(),"ga1"); + mapper.setAttributes2grantedAuthoritiesMap(m); + try { + mapper.afterPropertiesSet(); + fail("Expected exception not thrown"); + } catch (IllegalArgumentException expected) { + // Expected exception + } catch (Exception unexpected) { + fail("Unexpected exception: " + unexpected); + } + } + + public final void testAfterPropertiesSetInvalidValueTypeMap1() { + MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper(); + HashMap m = new HashMap(); + m.put("role1",new Object()); + mapper.setAttributes2grantedAuthoritiesMap(m); + try { + mapper.afterPropertiesSet(); + fail("Expected exception not thrown"); + } catch (IllegalArgumentException expected) { + // Expected exception + } catch (Exception unexpected) { + fail("Unexpected exception: " + unexpected); + } + } + + public final void testAfterPropertiesSetInvalidValueTypeMap2() { + MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper(); + HashMap m = new HashMap(); + m.put("role1",new Object[]{new String[]{"ga1","ga2"}, new Object()}); + mapper.setAttributes2grantedAuthoritiesMap(m); + try { + mapper.afterPropertiesSet(); + fail("Expected exception not thrown"); + } catch (IllegalArgumentException expected) { + // Expected exception + } catch (Exception unexpected) { + fail("Unexpected exception: " + unexpected); + } + } + + public final void testAfterPropertiesSetValidMap() { + MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper(); + HashMap m = getValidAttributes2GrantedAuthoritiesMap(); + mapper.setAttributes2grantedAuthoritiesMap(m); + try { + mapper.afterPropertiesSet(); + } catch (Exception unexpected) { + fail("Unexpected exception: " + unexpected); + } + } + + public final void testMapping1() { + String[] roles = { "role1" }; + String[] expectedGas = { "ga1" }; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping2() { + String[] roles = { "role2" }; + String[] expectedGas = { "ga2" }; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping3() { + String[] roles = { "role3" }; + String[] expectedGas = { "ga3", "ga4" }; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping4() { + String[] roles = { "role4" }; + String[] expectedGas = { "ga5", "ga6" }; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping5() { + String[] roles = { "role5" }; + String[] expectedGas = { "ga7", "ga8", "ga9" }; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping6() { + String[] roles = { "role6" }; + String[] expectedGas = { "ga10", "ga11", "ga12" }; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping7() { + String[] roles = { "role7" }; + String[] expectedGas = { "ga13", "ga14" }; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping8() { + String[] roles = { "role8" }; + String[] expectedGas = { "ga13", "ga14" }; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping9() { + String[] roles = { "role9" }; + String[] expectedGas = {}; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping10() { + String[] roles = { "role10" }; + String[] expectedGas = {}; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMapping11() { + String[] roles = { "role11" }; + String[] expectedGas = {}; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testNonExistingMapping() { + String[] roles = { "nonExisting" }; + String[] expectedGas = {}; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + public final void testMappingCombination() { + String[] roles = { "role1", "role2", "role3", "role4", "role5", "role6", "role7", "role8", "role9", "role10", "role11" }; + String[] expectedGas = { "ga1", "ga2", "ga3", "ga4", "ga5", "ga6", "ga7", "ga8", "ga9", "ga10", "ga11", "ga12", "ga13", "ga14"}; + Attributes2GrantedAuthoritiesMapper mapper = getDefaultMapper(); + testGetGrantedAuthorities(mapper, roles, expectedGas); + } + + private HashMap getValidAttributes2GrantedAuthoritiesMap() { + HashMap m = new HashMap(); + m.put("role1","ga1"); + m.put("role2",new GrantedAuthorityImpl("ga2")); + m.put("role3",Arrays.asList(new Object[]{"ga3",new GrantedAuthorityImpl("ga4")})); + m.put("role4","ga5,ga6"); + m.put("role5",Arrays.asList(new Object[]{"ga7","ga8",new Object[]{new GrantedAuthorityImpl("ga9")}})); + m.put("role6",new Object[]{"ga10","ga11",new Object[]{new GrantedAuthorityImpl("ga12")}}); + m.put("role7",new String[]{"ga13","ga14"}); + m.put("role8",new String[]{"ga13","ga14",null}); + m.put("role9",null); + m.put("role10",new Object[]{}); + m.put("role11",Arrays.asList(new Object[]{null})); + return m; + } + + private MapBasedAttributes2GrantedAuthoritiesMapper getDefaultMapper() { + MapBasedAttributes2GrantedAuthoritiesMapper mapper = new MapBasedAttributes2GrantedAuthoritiesMapper(); + mapper.setAttributes2grantedAuthoritiesMap(getValidAttributes2GrantedAuthoritiesMap()); + mapper.afterPropertiesSet(); + return mapper; + } + + private void testGetGrantedAuthorities(Attributes2GrantedAuthoritiesMapper mapper, String[] roles, String[] expectedGas) { + GrantedAuthority[] result = mapper.getGrantedAuthorities(roles); + Collection resultColl = new ArrayList(result.length); + for (int i = 0; i < result.length; i++) { + resultColl.add(result[i].getAuthority()); + } + Collection expectedColl = Arrays.asList(expectedGas); + assertTrue("Role collections do not match; result: " + resultColl + ", expected: " + expectedColl, expectedColl + .containsAll(resultColl) + && resultColl.containsAll(expectedColl)); + } +}