blob: 644724757908cf0c35c287a09ec41c2e5e3eaf3f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.catalina.realm;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.apache.juli.logging.LogFactory;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.sdk.AddRequest;
import com.unboundid.ldap.sdk.LDAPConnection;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
@RunWith(Parameterized.class)
public class TestJNDIRealmIntegration {
private static final String USER_PATTERN = "cn={0},ou=people,dc=example,dc=com";
private static final String USER_SEARCH = "cn={0}";
private static final String USER_BASE = "ou=people,dc=example,dc=com";
private static final String ROLE_SEARCH_A = "member={0}";
private static final String ROLE_SEARCH_B = "member=cn={1},ou=people,dc=example,dc=com";
private static final String ROLE_SEARCH_C = "member=cn={2},ou=people,dc=example,dc=com";
private static final String ROLE_BASE = "ou=people,dc=example,dc=com";
private static InMemoryDirectoryServer ldapServer;
@Parameterized.Parameters(name = "{index}: user[{5}], pwd[{6}]")
public static Collection<Object[]> parameters() {
List<Object[]> parameterSets = new ArrayList<>();
for (String userRoleAttribute : new String[] { "cn", null }) {
for (String roleSearch : new String[] { ROLE_SEARCH_A, ROLE_SEARCH_B, ROLE_SEARCH_C }) {
if (userRoleAttribute != null) {
addUsers(USER_PATTERN, null, null, roleSearch, ROLE_BASE, userRoleAttribute, parameterSets, 1);
addUsers(USER_PATTERN, null, null, roleSearch, ROLE_BASE, userRoleAttribute, parameterSets, 4);
addUsers(null, USER_SEARCH, USER_BASE, roleSearch, ROLE_BASE, userRoleAttribute, parameterSets, 1);
addUsers(null, USER_SEARCH, USER_BASE, roleSearch, ROLE_BASE, userRoleAttribute, parameterSets, 4);
}
}
parameterSets.add(new Object[] { "cn={0},ou=s\\;ub,ou=people,dc=example,dc=com", null, null, ROLE_SEARCH_A,
"{3},ou=people,dc=example,dc=com", "testsub", "test", new String[] { "TestGroup4" },
userRoleAttribute, Integer.valueOf(1) });
parameterSets.add(new Object[] { "cn={0},ou=s\\;ub,ou=people,dc=example,dc=com", null, null, ROLE_SEARCH_A,
"{3},ou=people,dc=example,dc=com", "testsub", "test", new String[] { "TestGroup4" },
userRoleAttribute, Integer.valueOf(4) });
}
return parameterSets;
}
private static void addUsers(String userPattern, String userSearch, String userBase, String roleSearch,
String roleBase, String userRoleAttribute, List<Object[]> parameterSets, int poolSize) {
parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
"test", "test", new String[] {"TestGroup"}, userRoleAttribute, Integer.valueOf(poolSize) });
parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
"t;", "test", new String[] {"TestGroup"}, userRoleAttribute, Integer.valueOf(poolSize) });
parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
"t*", "test", new String[] {"TestGroup"}, userRoleAttribute, Integer.valueOf(poolSize) });
parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
"t=", "test", new String[] {"Test<Group*2", "Test>Group*3"}, userRoleAttribute, Integer.valueOf(poolSize) });
parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
"norole", "test", new String[0], userRoleAttribute, Integer.valueOf(poolSize) });
// Bug 65373
parameterSets.add(new Object[] { userPattern, userSearch, userBase, roleSearch, roleBase,
"<>+=\"#;,rrr", "<>+=\"#;,rrr", new String[0], userRoleAttribute, Integer.valueOf(poolSize) });
}
@Parameter(0)
public String realmConfigUserPattern;
@Parameter(1)
public String realmConfigUserSearch;
@Parameter(2)
public String realmConfigUserBase;
@Parameter(3)
public String realmConfigRoleSearch;
@Parameter(4)
public String realmConfigRoleBase;
@Parameter(5)
public String username;
@Parameter(6)
public String credentials;
@Parameter(7)
public String[] groups;
@Parameter(8)
public String realmConfigUserRoleAttribute;
@Parameter(9)
public int poolSize;
@Test
public void testAuthentication() throws Exception {
JNDIRealm realm = new JNDIRealm();
realm.containerLog = LogFactory.getLog(TestJNDIRealmIntegration.class);
realm.setConnectionURL("ldap://localhost:" + ldapServer.getListenPort());
realm.setUserPattern(realmConfigUserPattern);
realm.setUserSearch(realmConfigUserSearch);
realm.setUserBase(realmConfigUserBase);
realm.setUserRoleAttribute(realmConfigUserRoleAttribute);
realm.setRoleName("cn");
realm.setRoleBase(realmConfigRoleBase);
realm.setRoleSearch(realmConfigRoleSearch);
realm.setRoleNested(true);
realm.setConnectionPoolSize(poolSize);
// If using pooling, simply try more to see what happens
for (int i = 0; i < poolSize; i++) {
GenericPrincipal p = (GenericPrincipal) realm.authenticate(username, credentials);
Assert.assertNotNull(p);
Assert.assertEquals(username, p.name);
Set<String> actualGroups = new HashSet<>(Arrays.asList(p.getRoles()));
Set<String> expectedGroups = new HashSet<>(Arrays.asList(groups));
Assert.assertEquals(expectedGroups.size(), actualGroups.size());
Set<String> tmp = new HashSet<>();
tmp.addAll(expectedGroups);
tmp.removeAll(actualGroups);
Assert.assertEquals(0, tmp.size());
}
}
@BeforeClass
public static void createLDAP() throws Exception {
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig("dc=example,dc=com");
InetAddress localhost = InetAddress.getByName("localhost");
InMemoryListenerConfig listenerConfig =
new InMemoryListenerConfig("localListener", localhost, 0, null, null, null);
config.setListenerConfigs(listenerConfig);
config.addAdditionalBindCredentials("cn=admin", "password");
ldapServer = new InMemoryDirectoryServer(config);
ldapServer.startListening();
try (LDAPConnection conn = ldapServer.getConnection()) {
// Note: Only the DNs need attribute value escaping
AddRequest addBase = new AddRequest(
"dn: dc=example,dc=com",
"objectClass: top",
"objectClass: domain",
"dc: example");
LDAPResult result = conn.processOperation(addBase);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addPeople = new AddRequest(
"dn: ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: organizationalUnit");
result = conn.processOperation(addPeople);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addUserTest = new AddRequest(
"dn: cn=test,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"cn: test",
"sn: Test",
"userPassword: test");
result = conn.processOperation(addUserTest);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addUserTestSemicolon = new AddRequest(
"dn: cn=t\\;,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"cn: t;",
"sn: Tsemicolon",
"userPassword: test");
result = conn.processOperation(addUserTestSemicolon);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addUserTestAsterisk = new AddRequest(
"dn: cn=t*,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"cn: t*",
"sn: Tasterisk",
"userPassword: test");
result = conn.processOperation(addUserTestAsterisk);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addUserTestEquals = new AddRequest(
"dn: cn=t\\=,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"cn: t=",
"sn: Tequals",
"userPassword: test");
result = conn.processOperation(addUserTestEquals);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addUserNoRole = new AddRequest(
"dn: cn=norole,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"cn: norole",
"sn: No Role",
"userPassword: test");
result = conn.processOperation(addUserNoRole);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addGroupTest = new AddRequest(
"dn: cn=TestGroup,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: groupOfNames",
"cn: TestGroup",
"member: cn=test,ou=people,dc=example,dc=com",
"member: cn=t\\;,ou=people,dc=example,dc=com",
"member: cn=t\\*,ou=people,dc=example,dc=com");
result = conn.processOperation(addGroupTest);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addGroupTest2 = new AddRequest(
"dn: cn=Test\\<Group*2,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: groupOfNames",
"cn: Test<Group*2",
"member: cn=t\\=,ou=people,dc=example,dc=com");
result = conn.processOperation(addGroupTest2);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addGroupTest3 = new AddRequest(
"dn: cn=Test\\>Group*3,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: groupOfNames",
"cn: Test>Group*3",
"member: cn=Test\\<Group*2,ou=people,dc=example,dc=com");
result = conn.processOperation(addGroupTest3);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addPeopleSub = new AddRequest(
"dn: ou=s\\;ub,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: organizationalUnit");
result = conn.processOperation(addPeopleSub);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addUserTestSub = new AddRequest(
"dn: cn=testsub,ou=s\\;ub,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"cn: testsub",
"sn: Testsub",
"userPassword: test");
result = conn.processOperation(addUserTestSub);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
AddRequest addGroupTest4 = new AddRequest(
"dn: cn=TestGroup4,ou=s\\;ub,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: groupOfNames",
"cn: TestGroup4",
"member: cn=testsub,ou=s\\;ub,ou=people,dc=example,dc=com");
result = conn.processOperation(addGroupTest4);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
// Bug 65373
AddRequest addUserBug65373 = new AddRequest(
"dn: cn=\\3C\\3E\\2B=\\22#\\3B\\2Crrr,ou=people,dc=example,dc=com",
"objectClass: top",
"objectClass: person",
"objectClass: organizationalPerson",
"cn: <>+=\"#;,rrr",
"sn: Bug 65373",
"userPassword: <>+=\"#;,rrr");
result = conn.processOperation(addUserBug65373);
Assert.assertEquals(ResultCode.SUCCESS, result.getResultCode());
}
}
@AfterClass
public static void destroyLDAP() {
ldapServer.shutDown(true);
}
}