/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.ldap;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.projectforge.test.TestBase;
import org.projectforge.user.Login;
import org.projectforge.user.LoginHandler;
import org.projectforge.user.LoginResult;
import org.projectforge.user.LoginResultStatus;
import org.projectforge.user.PFUserDO;
import org.projectforge.user.PasswordCheckResult;
public class LdapSlaveLoginHandlerTest extends TestBase
{
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LdapSlaveLoginHandlerTest.class);
private LdapUserDao ldapUserDao;
private LdapRealTestHelper ldapRealTestHelper;
@Before
public void setup()
{
ldapRealTestHelper = new LdapRealTestHelper().setup();
ldapUserDao = ldapRealTestHelper.ldapUserDao;
}
@After
public void tearDown()
{
ldapRealTestHelper.tearDown();
}
@Test
public void testMockedSimpleMode()
{
final String userBase = "ou=pf-mock-test-users";
final String testUsername = "mockedLdapSlaveTestuser";
ldapUserDao = mock(LdapUserDao.class);
when(ldapUserDao.authenticate(Mockito.eq(testUsername), Mockito.eq("successful"), Mockito.eq(userBase))).thenReturn(
(LdapUser) new LdapUser().setUid(testUsername));
when(ldapUserDao.authenticate(Mockito.anyString(), Mockito.eq("fail"), Mockito.eq(userBase))).thenReturn(null);
final LdapSlaveLoginHandler loginHandler = new LdapSlaveLoginHandler();
loginHandler.ldapConfig = new LdapConfig().setUserBase(userBase);
loginHandler.userDao = userDao;
loginHandler.ldapUserDao = ldapUserDao;
loginHandler.ldapOrganizationalUnitDao = mock(LdapOrganizationalUnitDao.class);
loginHandler.initialize();
loginHandler.setMode(LdapSlaveLoginHandler.Mode.SIMPLE);
testSimpleMode(loginHandler, testUsername);
}
@Test
public void testSimpleMode()
{
if (ldapRealTestHelper.isAvailable() == false) {
log.info("No LDAP server configured for tests. Skipping test.");
return;
}
final LdapSlaveLoginHandler loginHandler = createLoginHandler();
loginHandler.setMode(LdapSlaveLoginHandler.Mode.SIMPLE);
final String testUsername = "ldapSlaveTestuser";
final LdapUser ldapUser = (LdapUser) new LdapUser().setUid(testUsername).setGivenName("Kai").setSurname("Reinhard")
.setEmployeeNumber("42");
createLdapUser(ldapUser, "successful");
testSimpleMode(loginHandler, testUsername);
ldapUserDao.delete(ldapUser);
}
private LdapSlaveLoginHandler createLoginHandler()
{
final LdapSlaveLoginHandler loginHandler = new LdapSlaveLoginHandler();
loginHandler.ldapConfig = ldapRealTestHelper.ldapConfig;
loginHandler.userDao = userDao;
loginHandler.ldapUserDao = ldapUserDao;
loginHandler.ldapOrganizationalUnitDao = ldapRealTestHelper.ldapOrganizationalUnitDao;
loginHandler.initialize();
Login.getInstance().setLoginHandler(loginHandler);
return loginHandler;
}
private void createLdapUser(final LdapUser ldapUser, final String password)
{
final String userBase = ldapRealTestHelper.ldapConfig.getUserBase();
ldapUser.setOrganizationalUnit(userBase);
ldapUserDao.create(userBase, ldapUser);
ldapUserDao.changePassword(ldapUser, null, password);
}
private void testSimpleMode(final LoginHandler loginHandler, final String testUsername)
{
logon(TEST_ADMIN_USER);
Assert.assertNull("If failed, a previous test run didn't cleared the data-base.", userDao.getUserGroupCache().getUser(testUsername));
// Check failed login:
LoginResult result = loginHandler.checkLogin(testUsername, "fail");
Assert.assertEquals("User login failed against LDAP therefore login should be failed.", LoginResultStatus.FAILED,
result.getLoginResultStatus());
// Check successful login for new ProjectForge users:
result = loginHandler.checkLogin(testUsername, "successful");
Assert.assertEquals(LoginResultStatus.SUCCESS, result.getLoginResultStatus());
Assert.assertNotNull("User should be returned.", result.getUser());
PFUserDO user = userDao.getInternalByName(testUsername);
Assert.assertNotNull("User should be created by login handler.", user);
Assert.assertEquals(testUsername, user.getUsername());
Assert.assertEquals(result.getUser().getId(), user.getId());
// Check successful login for existing ProjectForge users:
result = loginHandler.checkLogin(testUsername, "successful");
Assert.assertEquals(LoginResultStatus.SUCCESS, result.getLoginResultStatus());
Assert.assertNotNull("User should be returned.", result.getUser());
user = userDao.getInternalByName(testUsername);
Assert.assertNotNull("User should be created by login handler.", user);
Assert.assertEquals(testUsername, user.getUsername());
Assert.assertEquals(result.getUser().getId(), user.getId());
// Check that LDAP is ignored for local users:
user.setLocalUser(true);
userDao.internalUpdate(user);
result = loginHandler.checkLogin(testUsername, "successful");
Assert.assertEquals("User is a local user, thus the LDAP authentication should be ignored.", LoginResultStatus.FAILED,
result.getLoginResultStatus());
userDao.createEncryptedPassword(user, "test");
userDao.internalUpdate(user);
result = loginHandler.checkLogin(testUsername, "test");
Assert.assertEquals("User is a local user, thus authentication should be done by the login default handler.",
LoginResultStatus.SUCCESS, result.getLoginResultStatus());
user = result.getUser();
Assert.assertEquals(testUsername, user.getUsername());
}
@Test
public void loginInMockedSlaveMode()
{
final String userBase = "ou=pf-mock-test-users";
final LdapUserDao ldapUserDao = mock(LdapUserDao.class);
LoginResult loginResult;
final LdapUser kai = (LdapUser) new LdapUser().setUid("kai").setDescription("Developer").setGivenName("Kai")
.setMail("k.reinhard@acme.com").setOrganization("Micromata").setSurname("Reinhard");
when(ldapUserDao.authenticate("kai", "successful", userBase)).thenReturn(kai);
when(ldapUserDao.authenticate("kai", "fail", userBase)).thenReturn(null);
when(ldapUserDao.findByUsername("kai", userBase)).thenReturn(kai);
final LdapSlaveLoginHandler loginHandler = new LdapSlaveLoginHandler();
loginHandler.ldapUserDao = ldapUserDao;
loginHandler.ldapConfig = new LdapConfig().setUserBase(userBase);
loginHandler.userDao = userDao;
Assert.assertEquals(LoginResultStatus.FAILED, loginHandler.checkLogin("kai", "fail").getLoginResultStatus());
Assert.assertFalse("User shouldn't be available yet in the data-base.",
userDao.doesUsernameAlreadyExist(new PFUserDO().setUsername("kai")));
loginResult = loginHandler.checkLogin("kai", "successful");
Assert.assertEquals(LoginResultStatus.SUCCESS, loginResult.getLoginResultStatus());
LdapTestUtils.assertUser(loginResult.getUser(), "kai", "Kai", "Reinhard", "k.reinhard@acme.com", "Micromata", "Developer");
Assert.assertTrue("User should be created in data-base as a new user (in ldap).",
userDao.doesUsernameAlreadyExist(new PFUserDO().setUsername("kai")));
final PFUserDO user = userDao.getInternalByName("kai");
LdapTestUtils.assertUser(user, "kai", "Kai", "Reinhard", "k.reinhard@acme.com", "Micromata", "Developer");
Assert.assertEquals(userDao.checkPassword(user, "successful"), PasswordCheckResult.OK);
userDao.internalMarkAsDeleted(user);
Assert.assertEquals("User is deleted in data-base. Login not possible.", LoginResultStatus.LOGIN_EXPIRED,
loginHandler.checkLogin("kai", "successful").getLoginResultStatus());
}
@Test
public void testUserMode()
{
if (ldapRealTestHelper.isAvailable() == false) {
log.info("No LDAP server configured for tests. Skipping test.");
return;
}
final LdapSlaveLoginHandler loginHandler = createLoginHandler();
loginHandler.setMode(LdapSlaveLoginHandler.Mode.USERS);
final String testUsername1 = "ldapSlaveTestuserUserMode1";
final String testUsername2 = "ldapSlaveTestuserUserMode2";
final LdapUser ldapUser1 = (LdapUser) new LdapUser().setUid(testUsername1).setGivenName("Kai").setSurname("Reinhard")
.setEmployeeNumber("100");
createLdapUser(ldapUser1, "successful");
final LdapUser ldapUser2 = (LdapUser) new LdapUser().setUid(testUsername2).setGivenName("Kai").setSurname("Reinhard")
.setEmployeeNumber("101");
createLdapUser(ldapUser2, "successful");
logon(TEST_ADMIN_USER);
Assert.assertNull("If failed, a previous test run didn't cleared the data-base.", userDao.getUserGroupCache().getUser(testUsername1));
Assert.assertNull("If failed, a previous test run didn't cleared the data-base.", userDao.getUserGroupCache().getUser(testUsername2));
// Check failed login:
LoginResult result = loginHandler.checkLogin(testUsername1, "fail");
Assert.assertEquals("User login failed against LDAP therefore login should be failed.", LoginResultStatus.FAILED,
result.getLoginResultStatus());
// Check successful login for new ProjectForge users:
result = loginHandler.checkLogin(testUsername1, "successful");
Assert.assertEquals(LoginResultStatus.SUCCESS, result.getLoginResultStatus());
Assert.assertNotNull("User should be returned.", result.getUser());
synchronizeLdapUsers(loginHandler);
PFUserDO user = userDao.authenticateUser(testUsername1, "successful");
Assert.assertNotNull("User should be created by login handler.", user);
Assert.assertEquals(testUsername1, user.getUsername());
result = loginHandler.checkLogin(testUsername1, "successful");
Assert.assertEquals(result.getUser().getId(), user.getId());
user = userDao.getInternalByName(testUsername2);
result = loginHandler.checkLogin(testUsername2, "successful");
Assert.assertNotNull("User should be created by login handler.", user);
Assert.assertEquals(testUsername2, user.getUsername());
Assert.assertEquals(result.getUser().getId(), user.getId());
// Delete user2
ldapUserDao.delete(ldapUser2);
synchronizeLdapUsers(loginHandler);
user = userDao.getInternalByName(testUsername2);
Assert.assertTrue("User isn't available in LDAP, therefore should be deleted.", user.isDeleted());
createLdapUser(ldapUser2, "successful");
synchronizeLdapUsers(loginHandler);
user = userDao.getInternalByName(testUsername2);
Assert.assertFalse("User isn't available in LDAP, therefore should be deleted.", user.isDeleted());
// Check that LDAP is ignored for local users:
user.setLocalUser(true);
userDao.createEncryptedPassword(user, "test");
userDao.internalUpdate(user);
result = loginHandler.checkLogin(testUsername2, "successful");
Assert.assertEquals("User is a local user, thus the LDAP authentication should be ignored.", LoginResultStatus.FAILED,
result.getLoginResultStatus());
result = loginHandler.checkLogin(testUsername2, "test");
Assert.assertEquals("User is a local user, thus the data-base authentication should be used.", LoginResultStatus.SUCCESS,
result.getLoginResultStatus());
// Delete all users
ldapUserDao.delete(ldapUser1);
ldapUserDao.delete(ldapUser2);
}
private void synchronizeLdapUsers(final LdapSlaveLoginHandler loginHandler)
{
userDao.getUserGroupCache().forceReload(); // Synchronize ldap users.
while (true) {
try {
Thread.sleep(200);
} catch (final InterruptedException ex) {
}
if (userDao.getUserGroupCache().isRefreshInProgress() == false && loginHandler.isRefreshInProgress() == false) {
break;
}
}
}
}