/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/providers/trunk/jldap-integration-test/src/test/java/edu/amc/sakai/user/JLDAPDirectoryProviderIntegrationTest.java $ * $Id: JLDAPDirectoryProviderIntegrationTest.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed 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://www.opensource.org/licenses/ECL-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 edu.amc.sakai.user; import java.util.ArrayList; import java.util.List; import org.sakaiproject.test.SakaiTestBase; import org.sakaiproject.user.api.UserEdit; import org.springframework.util.StringUtils; import com.novell.ldap.LDAPConnection; import com.novell.ldap.LDAPException; /** * Has more sys.outs than normal in a unit test... mainly for the * benefit of UArts. * * @author Dan McCallum, Unicon Inc * @author John Lewis, Unicon Inc * */ public class JLDAPDirectoryProviderIntegrationTest extends SakaiTestBase { public static final String AUTHENTICATABLE_USER_BEAN_NAME_CONFIG_KEY = "authenticatable-user-bean-name"; public static final String NON_AUTHENTICATABLE_USER_BEAN_NAME_CONFIG_KEY = "non-authenticatable-user-bean-name"; public static final String GETTABLE_BY_EID_USER_BEAN_NAMES_CONFIG_KEY = "gettable-by-eid-user-bean-names"; public static final String GETTABLE_BY_EID_USER_BEAN_NAME_CONFIG_KEY = "gettable-by-eid-user-bean-name"; public static final String UNGETTABLE_BY_EID_USER_BEAN_NAME_CONFIG_KEY = "ungettable-by-eid-user-bean-name"; public static final String GETTABLE_BY_EMAIL_USER_BEAN_NAME_CONFIG_KEY = "gettable-by-email-user-bean-name"; public static final String UNGETTABLE_BY_EMAIL_USER_BEAN_NAME_CONFIG_KEY = "ungettable-by-email-user-bean-name"; public static final String BLACKLISTED_EID = "blacklisted-eid"; public static final String BLACKLISTED_EID_PASSWORD = "blacklisted-password"; /** Encapsulates test configuration and convenience utilities */ private JLDAPDirectoryProviderIntegrationTestSupport support; protected void setUp() throws Exception { super.setUp(); support = new JLDAPDirectoryProviderIntegrationTestSupport(); support.setUp(); } protected void tearDown() throws Exception { support.tearDown(); super.tearDown(); } public void testAuthenticatesValidUserCredentials() { String userBeanName = support.getConfiguredValue(AUTHENTICATABLE_USER_BEAN_NAME_CONFIG_KEY); UserEditStub authenticatableUser = support.getConfiguredUserEditStub(userBeanName); String login = authenticatableUser.getLogin(); String pass = authenticatableUser.getPassword(); assertTrue("Expected successful authentication", support.udp.authenticateUser(login, null, pass)); } public void testFailsToAuthenticateInvalidUserCredentials() { String userBeanName = support.getConfiguredValue(NON_AUTHENTICATABLE_USER_BEAN_NAME_CONFIG_KEY); UserEditStub nonAuthenticatableUser = support.getConfiguredUserEditStub(userBeanName); String login = nonAuthenticatableUser.getLogin(); String pass = nonAuthenticatableUser.getPassword(); assertFalse("Expected unsuccessful authentication", support.udp.authenticateUser(login, null, pass)); } public void testFailsToAuthenticateValidLoginPairedWithInvalidPassword() { String authenticatableUserBeanName = support.getConfiguredValue(AUTHENTICATABLE_USER_BEAN_NAME_CONFIG_KEY); String nonAuthenticatableUserBeanName = support.getConfiguredValue(NON_AUTHENTICATABLE_USER_BEAN_NAME_CONFIG_KEY); UserEditStub authenticatableUser = support.getConfiguredUserEditStub(authenticatableUserBeanName); UserEditStub nonAuthenticatableUser = support.getConfiguredUserEditStub(nonAuthenticatableUserBeanName); String login = authenticatableUser.getLogin(); String pass = nonAuthenticatableUser.getPassword(); assertFalse("Expected unsuccessful authentication", support.udp.authenticateUser(login, null, pass)); } /** * Iterates over a set of configured {@link UserEditStub} objects, * looks each up by eid, and compares each to the resulting * {@link UserEdit} object. This is intended to give * local implementations a chance to verify unique mapping * strategies, e.g. {@link UserTypeMapper}. * * <p>Configure {@link GETTABLE_BY_EID_USER_BEAN_NAMES_CONFIG_KEY} * with a comma-delimited list of {@link UserEditStub} bean names * which can resolve successfully to LDAP user entries.</p> */ public void testMapsLdapAttributesOntoSakaiUserEditInstanceWhenSearchingByEid() { String userBeanNames = support.getConfiguredValue(GETTABLE_BY_EID_USER_BEAN_NAMES_CONFIG_KEY); String[] splitUserBeanNames = userBeanNames.split(","); for ( String userBeanName : splitUserBeanNames ) { UserEditStub expectedUser = support.getConfiguredUserEditStub(userBeanName); String eid = expectedUser.getEid(); UserEditStub actualUser = support.newUserEditStub(eid); boolean foundUser = support.udp.getUser(actualUser); assertTrue("Expected to find user entry by eid [eid = " + eid + "][configured user bean name = " + userBeanName +"]", foundUser); assertEquals("UserEdit was not correctly updated [eid = " + eid + "][configured user bean name =" + userBeanName +"])", expectedUser, actualUser); } } /** * Identical to {@link #testMapsLdapAttributesOntoSakaiUserEditInstanceWhenSearchingByEid()} * but exercises {@link JLDAPDirectoryProvider#getUsers(java.util.Collection)} * rather than {@link JLDAPDirectoryProvider#getUser(UserEdit)}. */ public void testMapsLdapAttributesOntoCandidateSakaiUserEditInstancesPassedInBulk() { String userBeanNames = support.getConfiguredValue(GETTABLE_BY_EID_USER_BEAN_NAMES_CONFIG_KEY); List expectedUsers = new ArrayList(); List actualUsers = new ArrayList(); String[] splitUserBeanNames = userBeanNames.split(","); for ( String userBeanName : splitUserBeanNames ) { UserEditStub expectedUser = support.getConfiguredUserEditStub(userBeanName); String eid = expectedUser.getEid(); UserEditStub actualUser = support.newUserEditStub(eid); expectedUsers.add(expectedUser); actualUsers.add(actualUser); } support.udp.getUsers(actualUsers); assertEquals(expectedUsers, actualUsers); } /** * Very similar to {@link #testMapsLdapAttributesOntoCandidateSakaiUserEditInstancesPassedInBulk()} * but expects to be configured with at least one user who will not resolve * to an LDAP entry. Reuses {@link #GETTABLE_BY_EID_USER_BEAN_NAMES_CONFIG_KEY} and * {@link #UNGETTABLE_BY_EID_USER_BEAN_NAME_CONFIG_KEY} to build the list * of {@link UserEdits} to pass into * {@link JLDAPDirectoryProvider#getUsers(java.util.Collection)}. */ public void testMapsLdapAttributesOntoSakaiUserEditInstancesAndRemovesReferencesToUnknownUserEditsWhenCandidateUserEditsPassedInBulk() { String gettableUserBeanNames = support.getConfiguredValue(GETTABLE_BY_EID_USER_BEAN_NAMES_CONFIG_KEY); String ungettableUserBeanName = support.getConfiguredValue(UNGETTABLE_BY_EID_USER_BEAN_NAME_CONFIG_KEY); List expectedUsers = new ArrayList(); List actualUsers = new ArrayList(); String[] splitUserBeanNames = gettableUserBeanNames.split(","); for ( String userBeanName : splitUserBeanNames ) { UserEditStub expectedUser = support.getConfiguredUserEditStub(userBeanName); String eid = expectedUser.getEid(); UserEditStub actualUser = support.newUserEditStub(eid); expectedUsers.add(expectedUser); actualUsers.add(actualUser); } UserEditStub ungettableUser = support.getConfiguredUserEditStub(ungettableUserBeanName); actualUsers.add(ungettableUser); support.udp.getUsers(actualUsers); assertEquals(expectedUsers, actualUsers); } public void testLeavesUserEditUntouchedIfEidDoesNotResolveToLdapEntry() { String userBeanName = support.getConfiguredValue(UNGETTABLE_BY_EID_USER_BEAN_NAME_CONFIG_KEY); UserEditStub expectedUser = support.getConfiguredUserEditStub(userBeanName); UserEditStub actualUser = support.getConfiguredUserEditStub(userBeanName); assertNotSame("UserEditStub beans must be prototypes", expectedUser, actualUser); // we need an "empty" user with only this eid so we can verify that // the user is not updated boolean foundUser = support.udp.getUser(actualUser); assertFalse("Did not expect to find user record",foundUser); assertEquals("UserEdit should not have been modified", expectedUser, actualUser); } public void testConfirmsUserExistenceIfPassedValidEid() { String userBeanName = support.getConfiguredValue(GETTABLE_BY_EID_USER_BEAN_NAME_CONFIG_KEY); UserEditStub expectedUser = support.getConfiguredUserEditStub(userBeanName); String eid = expectedUser.getEid(); assertTrue("Should have confirmed existence of user [eid = " + eid + "]", support.udp.userExists(eid)); } public void testDeniesUserExistenceIfPassedUnrecognizedEid() { String userBeanName = support.getConfiguredValue(UNGETTABLE_BY_EID_USER_BEAN_NAME_CONFIG_KEY); UserEditStub expectedUser = support.getConfiguredUserEditStub(userBeanName); String eid = expectedUser.getEid(); assertFalse("Should have denied existence of user [eid = " + eid + "]", support.udp.userExists(eid)); } public void testMapsLdapAttributesOntoSakaiUserEditInstanceWhenSearchingByEmail() { String userBeanName = support.getConfiguredValue(GETTABLE_BY_EMAIL_USER_BEAN_NAME_CONFIG_KEY); UserEditStub expectedUser = support.getConfiguredUserEditStub(userBeanName); String email = expectedUser.getEmail(); UserEditStub actualUser = support.newUserEditStub(null); boolean foundUser = support.udp.findUserByEmail(actualUser, email); assertTrue("Should have found user by email [" + email + "]", foundUser); assertEquals("Failed to map user attributes correctly when finding a user by email [" + email + "]", expectedUser, actualUser); } public void testLeavesUserEditUntouchedIfEmailDoesNotResolveToLdapEntry() { String userBeanName = support.getConfiguredValue(UNGETTABLE_BY_EMAIL_USER_BEAN_NAME_CONFIG_KEY); UserEditStub expectedUser = support.getConfiguredUserEditStub(userBeanName); String email = expectedUser.getEmail(); UserEditStub actualUser = support.newUserEditStub(null); expectedUser = support.newUserEditStub(null); // TODO better variable names boolean foundUser = support.udp.findUserByEmail(actualUser, email); assertFalse("Should have failed to find user by email [" + email + "]", foundUser); assertEquals("Should have left user attributes untouched if search by email [" + email + "] failed", expectedUser, actualUser); } /** * Verifies that disconnecting an LDAP connection before * returning it to the pool does not corrupt the pool. * * <p> * TODO more valuable if we could toggle between pooled and unpooled configurations * </p> * */ public void testPoolSurvivesDisconnectedConnection() throws LDAPException { if ( !(support.udp.isPooling()) ) { // Pooled not enabled. No point in executing this test return; } LdapConnectionManager connMgr = support.udp.getLdapConnectionManager(); LDAPConnection conn = connMgr.getConnection(); // We don't actually know that disconnect() hasn't been overridden // to return the conn to the pool, a la JDBC. So we cover all bases // by attempting both a direct disconnect() and a finalize() which // we fully expect to disconnect a deactivated, i.e. in-pool connection. conn.disconnect(); connMgr.returnConnection(conn); ((PooledLDAPConnection)conn).finalize(); // should be able to allocate an LDAP connection and pass the following simple test testConfirmsUserExistenceIfPassedValidEid(); } public void testBlacklistedEidCannotAuthenticate() { String blacklistedEid = support.getConfiguredValue(BLACKLISTED_EID); String blacklistedEidPassword = support.getConfiguredValue(BLACKLISTED_EID_PASSWORD); if ( !(StringUtils.hasText(blacklistedEid)) ) { // no blacklisted EID configured, not able to perform test return; } if ( support.udp.isSearchableEid(blacklistedEid) ) { fail("Test configuration is not valid. JLDAPDirectoryProvider.isSearchableEid() " + "reports that the configured blacklisted EID [" + blacklistedEid + "] _is_ searchable. Please set [" + BLACKLISTED_EID + "] to a blacklisted EID."); } if ( !(StringUtils.hasText(blacklistedEidPassword)) ) { fail("Test configuration is not valid. A blacklisted EID has been configured [" + blacklistedEid + "], but a corresponding password has not. Please set [" + BLACKLISTED_EID_PASSWORD + "] to a valid password for EID [" + blacklistedEid + "]"); } // We have no good way to guarantee that the corresponding directory entry // doesn't exist, so some of this test is really taking a portion of the // implementation on faith. assertFalse("Should have refused to authenticate a blacklisted EID [" + blacklistedEid + "]", support.udp.authenticateUser(blacklistedEid, null, blacklistedEidPassword)); } public void testBlacklistedEidCannotRetrieveAttributes() { // most of this is boilerplate copied from testBlacklistedEidCannotAuthenticate() String blacklistedEid = support.getConfiguredValue(BLACKLISTED_EID); String blacklistedEidPassword = support.getConfiguredValue(BLACKLISTED_EID_PASSWORD); if ( !(StringUtils.hasText(blacklistedEid)) ) { // no blacklisted EID configured, not able to perform test return; } if ( support.udp.isSearchableEid(blacklistedEid) ) { fail("Test configuration is not valid. JLDAPDirectoryProvider.isSearchableEid() " + "reports that the configured blacklisted EID [" + blacklistedEid + "] _is_ searchable. Please set [" + BLACKLISTED_EID + "] to a blacklisted EID."); } if ( !(StringUtils.hasText(blacklistedEidPassword)) ) { fail("Test configuration is not valid. A blacklisted EID has been configured [" + blacklistedEid + "], but a corresponding password has not. Please set [" + BLACKLISTED_EID_PASSWORD + "] to a valid password for EID [" + blacklistedEid + "]"); } // we expect the stub to remain effectively "empty" except for the EID field, // hence the two instances here for asserting unchanged state UserEditStub expectedEdit = support.newUserEditStub(blacklistedEid); UserEditStub actualEdit = support.newUserEditStub(blacklistedEid); assertFalse(support.udp.getUser(actualEdit)); assertEquals("Expected the search to short-circuit and for the passed UserEdit to consequently remain unchanged", expectedEdit, actualEdit); } }