/** * Licensed to The Apereo Foundation under one or more contributor license * agreements. See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * * The Apereo Foundation licenses this file to you under the Educational * Community 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://opensource.org/licenses/ecl2.txt * * 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.opencastproject.kernel.userdirectory; import static java.lang.String.format; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ldap.core.DirContextOperations; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; public class LdapAttributeAuthoritiesPopulatorTest { private static final Logger logger = LoggerFactory.getLogger(LdapAttributeAuthoritiesPopulatorTest.class); private static final String USERNAME = "username"; private HashMap<String, String[]> mappings; @Before public void setUp() { mappings = new HashMap<String, String[]>(); } @Test public void testNullConstructorArgument() { try { new LdapAttributeAuthoritiesPopulator(null); } catch (NullPointerException e) { // OK return; } fail(format("A null constructor argument for %s did not raise an exception", LdapAttributeAuthoritiesPopulator.class.getName())); } @Test public void testEmptyConstructorArgument() { try { new LdapAttributeAuthoritiesPopulator(mappings.keySet()); } catch (IllegalArgumentException e) { // OK return; } fail(format("A null constructor argument for %s did not raise an exception", LdapAttributeAuthoritiesPopulator.class.getName())); } @Test public void testNonEmptyConstructorArgument() { // Add a test entry to 'mappings' mappings.put("test", null); mappings.put("test2", null); mappings.put("test3", null); try { // Create test object LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); // Check the attribute names have been correctly set assertEquals("Unexpected value of the \"attributeNames\" parameter", mappings.keySet(), populator.getAttributeNames()); } catch (Throwable t) { fail(format("Constructor shall not fail for a non-null, non-empty argument. Received unexpected exception %s: %s", t.getClass().getName(), t.getMessage())); } } @Test public void testSetConvertToUpperCase() { // Add a test entry to 'mappings' mappings.put("test", null); LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); populator.setConvertToUpperCase(true); assertTrue("Unexpected value of the property \"convertToUpperCase\": getter or setter failed", populator.getConvertToUpperCase()); populator.setConvertToUpperCase(false); assertFalse("Unexpected value of the property \"convertToUpperCase\": getter or setter failed", populator.getConvertToUpperCase()); } @Test public void testSetRolePrefix() { // Add a test entry to 'mappings' mappings.put("test", null); // Sample prefixes final String nullPrefix = null; final String emptyPrefix = ""; final String normalPrefix = "testprefix_"; final String whitespacePrefix = " testPrefiX_with_\twhitespaces"; LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); populator.setRolePrefix(nullPrefix); assertEquals("Setting a null rolePrefix failed: it should yield an empty string", populator.getRolePrefix(), emptyPrefix); populator.setRolePrefix(normalPrefix); assertEquals("Setting a null rolePrefix failed: prefixes do not match", populator.getRolePrefix(), normalPrefix); populator.setRolePrefix(whitespacePrefix); assertEquals("Setting a rolePrefix with whitespaces failed: prefixes do not match", populator.getRolePrefix(), whitespacePrefix); populator.setRolePrefix(""); assertEquals("Setting an empty rolePrefix failed: prefixes do not match", populator.getRolePrefix(), ""); } @Test public void testSetAdditionalAuthorities() { // Add a test entry to 'mappings' mappings.put("test", new String[] { "auth1, auth2", "auth3, auth4" }); // Create a test set of additional authorities Set<String> additional = new HashSet<String>(); additional.add("additional_auth1"); additional.add("additional_auth2"); additional.add("additional_auth3"); LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); populator.setAdditionalAuthorities(null); assertTrue("Setting a null set of additional authorities failed: it should yield an empty set", populator.getAdditionalAuthorities().isEmpty()); doTest(populator, mappings); populator.setAdditionalAuthorities(additional); assertEquals("Setting additional authorities failed: sets do not match", populator.getAdditionalAuthorities(), additional); doTest(populator, mappings); populator.setAdditionalAuthorities(new HashSet<String>()); assertEquals("Setting an empty set of additional authorities failed: additional authorities are still not empty", populator.getAdditionalAuthorities(), Collections.emptySet()); doTest(populator, mappings); } @Test public void testAttributeNotFound() { // Prepare the mappings mappings.put("myAttribute", null); // Prepare the expectations // In this case, we expect an empty collection, so nothing to do // Create a test class LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); doTest(populator, mappings); } @Test public void testEmptyAttributeArray() { // Prepare the mappings mappings.put("myAttribute", new String[] {}); // Prepare the expectations // In this case, we expect an empty collection, so nothing to do // Create a test class LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); doTest(populator, mappings); } @Test public void testEmptySingleAttribute() { // Prepare the mappings mappings.put("myAttribute", new String[] { "" }); // Prepare the expectations // In this case, we expect an empty collection, so nothing to do // Create a test class LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); doTest(populator, mappings); } @Test public void testMultivaluedAttributeSimpleRoles() { // Prepare the mappings mappings.put("myAttribute", new String[] { " value1 ", " value2 ", " value3 ", " value4 " }); // Create a test class LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); doTest(populator, mappings); // Do the same test with uppercase turned off populator.setConvertToUpperCase(false); doTest(populator, mappings); } @Test public void testSingleAttributeMultipleRoles() { // Prepare the mappings mappings.put("myAttribute", new String[] { " value1, value2, value3 , value4 " }); // Create a test class LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); doTest(populator, mappings); // Do the same test with uppercase turned off populator.setConvertToUpperCase(false); doTest(populator, mappings); } @Test public void testAttributesWithWhitespaces() { // Prepare the mappings mappings.put("attribute1", new String[] { " ", "\n", "\t", "\r", " \n \t", " \nthis\tis an attribute" }); mappings.put("attribute2", new String[] { "value_2_1 , value\nwith\n\n multiple\t whitespaces, value____with several_underscores", "normal_value , normalvalue2" }); // Create a test class LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); doTest(populator, mappings); // Do the same test with uppercase turned off populator.setConvertToUpperCase(false); doTest(populator, mappings); } @Test public void testRolePrefix() { // Prepare the mappings mappings.put("attribute1", new String[] { " ", "\n", "\t", "\r", " \n \t", " \nthis\tis an attribute" }); mappings.put("attribute2", new String[] { "value_2_1 , value\nwith\n\n multiple\t whitespaces, value____with several_underscores", "normal_value , normalvalue2" }); // Define prefixes String[] prefixes = new String[] { "normal_", "many_underscores____", "cApItAlS_", " WH\n\niTE\tspA cE ", " \n \t\t\n \r" }; // Create a test class LdapAttributeAuthoritiesPopulator populator = new LdapAttributeAuthoritiesPopulator(mappings.keySet()); for (String prefix : prefixes) { populator.setRolePrefix(prefix); for (boolean b : new boolean[] { true, false }) { populator.setConvertToUpperCase(b); doTest(populator, mappings); } } } /** * Perform the test of an instance of the class LdapAttributeAuthoritiesPopulator. * * @param populator * an instance of {@link LdapAttributeAuthoritiesPopulator} to test * @param mappings * a {@link Map} containing the LDAP attribute name - value pairs, where the name is a {@link String} and the * value an array of {@code String}s, possibly {@code null} or empty. * @param expected * a {@link Collection} containing the expected result produced by the {@code populator} */ private void doTest(LdapAttributeAuthoritiesPopulator populator, Map<String, String[]> mappings) { DirContextOperations dirContextMock = EasyMock.createNiceMock(DirContextOperations.class); // Populate the DirContextOperations class for (String attrName : mappings.keySet()) { EasyMock.expect(dirContextMock.getStringAttributes(attrName)).andReturn(mappings.get(attrName)).anyTimes(); } EasyMock.replay(dirContextMock); // Prepare the expected result HashSet<GrantedAuthority> expectedResult = new HashSet<GrantedAuthority>(); for (String attrName : populator.getAttributeNames()) { if (mappings.get(attrName) != null) { for (String attrValues : mappings.get(attrName)) { addRoles(expectedResult, Arrays.asList(attrValues.split(",")), populator.getRolePrefix(), populator.getConvertToUpperCase()); } } } // Add the additional authorities addRoles(expectedResult, populator.getAdditionalAuthorities(), populator.getRolePrefix(), populator.getConvertToUpperCase()); // Check the response is correct checkResponse(populator.getGrantedAuthorities(dirContextMock, USERNAME), expectedResult); } private void addRoles(Set<GrantedAuthority> roles, Collection<? extends String> roleStrings, String prefix, boolean toUpper) { for (String roleString : roleStrings) { String role = roleString.trim(); if (!role.isEmpty()) { if (toUpper) { role = (prefix.trim() + role).replaceAll("[\\s_]+", "_").toUpperCase(); } else { role = (prefix.trim() + role).replaceAll("[\\s_]+", "_"); } logger.debug("Creating expected attribute '{}'", role); roles.add(new SimpleGrantedAuthority(role)); } } } /** * Compare the result returned by the method {@link LdapAttributeAuthoritiesPopulator#getGrantedAuthorities} and * {@link Collection} of {@link GrantedAuthority}'s containing the expected results. * * @param actual * the actual output of the method; it should match the contents in {@code expected} * @param expected * the expected output */ private void checkResponse(Collection<? extends GrantedAuthority> actual, Collection<? extends GrantedAuthority> expected) { for (GrantedAuthority auth : actual) { assertTrue(format("Authorities populator returned unexpected authority: %s", auth), expected.contains(auth)); } for (GrantedAuthority auth : expected) { assertTrue(format("Authorities populator did not return expected authority: %s", auth), actual.contains(auth)); } } }