/////////////////////////////////////////////////////////////////////////////
//
// 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.verify;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.projectforge.test.TestBase;
import org.projectforge.user.GroupDO;
import org.projectforge.user.GroupDao;
import org.projectforge.user.Login;
import org.projectforge.user.LoginResult;
import org.projectforge.user.LoginResultStatus;
import org.projectforge.user.PFUserDO;
import org.springframework.util.CollectionUtils;
// Create
// ~/ProjectForge/testldapConfig.xml
//<?xml version="1.0" encoding="UTF-8" ?>
//<ldapConfig>
// <server>ldaps://192.168.76.177</server>
// <port>636</port>
// <userBase>ou=pf-test-users</userBase>
// <groupBase>ou=pf-test-groups</groupBase>
// <baseDN>dc=acme,dc=priv</baseDN>
// <authentication>simple</authentication>
// <managerUser>cn=manager</managerUser>
// <managerPassword>test</managerPassword>
// <sslCertificateFile>/Users/kai/ProjectForge/testldap.cert</sslCertificateFile>
//</ldapConfig>
public class LdapMasterLoginHandlerTest extends TestBase
{
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LdapMasterLoginHandlerTest.class);
private GroupDao groupDao;
private LdapGroupDao ldapGroupDao;
private LdapUserDao ldapUserDao;
private LdapRealTestHelper ldapRealTestHelper;
private String getPath()
{
return ldapRealTestHelper.getUserPath();
}
@Before
public void setup()
{
ldapRealTestHelper = new LdapRealTestHelper().setup();
ldapUserDao = ldapRealTestHelper.ldapUserDao;
ldapGroupDao = ldapRealTestHelper.ldapGroupDao;
}
@After
public void tearDown()
{
ldapRealTestHelper.tearDown();
}
@Test
public void loginAndCreateLdapUser()
{
final String userBase = "ou=pf-mock-test-users";
final LdapUserDao ldapUserDao = mock(LdapUserDao.class);
final LdapMasterLoginHandler loginHandler = new LdapMasterLoginHandler();
loginHandler.ldapConfig = new LdapConfig().setUserBase(userBase);
loginHandler.userDao = userDao;
loginHandler.ldapUserDao = ldapUserDao;
loginHandler.ldapOrganizationalUnitDao = mock(LdapOrganizationalUnitDao.class);
loginHandler.initialize();
Login.getInstance().setLoginHandler(loginHandler);
logon(TEST_ADMIN_USER);
final PFUserDO user = new PFUserDO().setUsername("kai").setFirstname("Kai").setLastname("Reinhard");
userDao.createEncryptedPassword(user, "successful");
userDao.internalSave(user);
Assert.assertEquals(LoginResultStatus.SUCCESS, loginHandler.checkLogin("kai", "successful").getLoginResultStatus());
final ArgumentCaptor<LdapUser> argumentCaptor = ArgumentCaptor.forClass(LdapUser.class);
verify(ldapUserDao).createOrUpdate(Mockito.anyString(), argumentCaptor.capture());
final LdapUser createdLdapUser = argumentCaptor.getValue();
Assert.assertEquals("kai", createdLdapUser.getUid());
Assert.assertEquals("Kai", createdLdapUser.getGivenName());
Assert.assertEquals("Reinhard", createdLdapUser.getSurname());
// Assert.assertEquals("successful", createdLdapUser.get());
}
@Test
public void realTest()
{
if (ldapRealTestHelper.isAvailable() == false) {
log.info("No LDAP server configured for tests. Skipping test.");
return;
}
logon(TEST_ADMIN_USER);
final LdapMasterLoginHandler loginHandler = createLoginHandler();
// Create users and group.
final Integer userId1 = createUser("ldapMaster1", "test123", "firstname1", "lastname1");
final Integer userId2 = createUser("ldapMaster2", "test123", "firstname2", "lastname2");
final Integer userId3 = createUser("ldapMaster3", "test123", "firstname3", "lastname3");
final Integer userId4 = createUser("ldapMaster4", "test123", "firstname4", "lastname4");
final Integer groupId1 = createGroup("ldapMasterGroup1", "This is a stupid description.");
GroupDO group = groupDao.internalGetById(groupId1);
synchronizeLdapUsers(loginHandler);
LdapGroup ldapGroup = ldapGroupDao.findById(groupId1);
Assert.assertTrue(isMembersEmpty(ldapGroup));
// Assign users to group
group.setAssignedUsers(new HashSet<PFUserDO>());
group.addUser(userDao.getUserGroupCache().getUser(userId1));
group.addUser(userDao.getUserGroupCache().getUser(userId2));
group.addUser(userDao.getUserGroupCache().getUser(userId3));
groupDao.internalUpdate(group);
synchronizeLdapUsers(loginHandler);
ldapGroup = ldapGroupDao.findById(groupId1);
assertMembers(ldapGroup, "ldapMaster1", "ldapMaster2", "ldapMaster3");
Assert.assertFalse(isMembersEmpty(ldapGroup));
LdapUser ldapUser = ldapUserDao.findById(userId1, getPath());
Assert.assertEquals("ldapMaster1", ldapUser.getUid());
// Renaming one user, deleting one user and assigning third user
userDao.internalMarkAsDeleted(userDao.getById(userId2));
PFUserDO user3 = userDao.getById(userId3);
user3.setUsername("ldapMasterRenamed3");
userDao.internalUpdate(user3);
group = userDao.getUserGroupCache().getGroup(groupId1);
group.addUser(userDao.getById(userId4));
groupDao.internalUpdate(group);
synchronizeLdapUsers(loginHandler);
ldapGroup = ldapGroupDao.findById(groupId1);
assertMembers(ldapGroup, "ldapMaster1", "ldapMasterRenamed3", "ldapMaster4");
// Renaming one user and mark him as restricted
user3 = userDao.getById(userId3);
user3.setUsername("ldapMaster3");
user3.setRestrictedUser(true);
userDao.internalUpdate(user3);
synchronizeLdapUsers(loginHandler);
ldapUser = ldapUserDao.findById(userId3, getPath());
Assert.assertEquals("ldapMaster3", ldapUser.getUid());
Assert.assertTrue(ldapUser.getOrganizationalUnit().contains("ou=restricted"));
ldapGroup = ldapGroupDao.findById(groupId1);
assertMembers(ldapGroup, "ldapMaster1", "ldapMaster3,ou=restricted", "ldapMaster4");
// Renaming group
group = groupDao.getById(groupId1);
group.setName("ldapMasterGroupRenamed1");
groupDao.internalUpdate(group);
synchronizeLdapUsers(loginHandler);
ldapGroup = ldapGroupDao.findById(groupId1);
assertMembers(ldapGroup, "ldapMaster1", "ldapMaster3,ou=restricted", "ldapMaster4");
Assert.assertEquals("ldapMasterGroupRenamed1", ldapGroup.getCommonName());
// Change password
final PFUserDO user1 = userDao.getById(userId1);
final LoginResult loginResult = Login.getInstance().checkLogin(user1.getUsername(), "test123");
Assert.assertEquals(LoginResultStatus.SUCCESS, loginResult.getLoginResultStatus());
Assert.assertNotNull(ldapUserDao.authenticate(user1.getUsername(), "test123"));
Login.getInstance().passwordChanged(user1, "newpassword");
Assert.assertNotNull(ldapUserDao.authenticate(user1.getUsername(), "newpassword"));
// Delete all groups
final Collection<GroupDO> groups = userDao.getUserGroupCache().getAllGroups();
for (final GroupDO g : groups) {
groupDao.internalMarkAsDeleted(g);
}
synchronizeLdapUsers(loginHandler);
Assert.assertEquals("LDAP groups must be empty (all groups are deleted in the PF data-base).", 0,
ldapGroupDao.findAll(ldapRealTestHelper.ldapConfig.getGroupBase()).size());
final Collection<PFUserDO> users = userDao.getUserGroupCache().getAllUsers();
for (final PFUserDO user : users) {
userDao.internalMarkAsDeleted(user);
}
synchronizeLdapUsers(loginHandler);
Assert.assertEquals("LDAP users must be empty (all user are deleted in the PF data-base).", 0,
ldapUserDao.findAll(ldapRealTestHelper.ldapConfig.getGroupBase()).size());
ldapUser = ldapUserDao.findById(userId1, getPath());
Assert.assertNull(ldapUser);
}
private boolean isMembersEmpty(final LdapGroup ldapGroup)
{
final Set<String> members = ldapGroup.getMembers();
if (CollectionUtils.isEmpty(members) == true) {
return true;
}
if (members.size() > 1) {
return false;
}
final String member = members.iterator().next();
return member == null || member.startsWith("cn=none") == true;
}
private void assertMembers(final LdapGroup ldapGroup, final String... usernames)
{
final Set<String> members = ldapGroup.getMembers();
Assert.assertFalse(CollectionUtils.isEmpty(members));
Assert.assertEquals(usernames.length, members.size());
final LdapConfig ldapConfig = ldapRealTestHelper.ldapConfig;
for (final String username : usernames) {
final String user = "uid=" + username + "," + ldapConfig.getUserBase() + "," + ldapConfig.getBaseDN();
Assert.assertTrue(members.contains(user));
}
}
private Integer createUser(final String username, final String password, final String firstname, final String lastname)
{
final PFUserDO user = new PFUserDO().setUsername(username).setFirstname(firstname).setLastname(lastname);
userDao.createEncryptedPassword(user, password);
return (Integer) userDao.internalSave(user);
}
private Integer createGroup(final String name, final String description)
{
final GroupDO group = new GroupDO().setName(name).setDescription(description);
return (Integer) groupDao.internalSave(group);
}
private LdapMasterLoginHandler createLoginHandler()
{
final LdapMasterLoginHandler loginHandler = new LdapMasterLoginHandler();
loginHandler.ldapConfig = ldapRealTestHelper.ldapConfig;
loginHandler.userDao = userDao;
loginHandler.ldapUserDao = ldapUserDao;
loginHandler.ldapOrganizationalUnitDao = ldapRealTestHelper.ldapOrganizationalUnitDao;
loginHandler.initialize();
Login.getInstance().setLoginHandler(loginHandler);
return loginHandler;
}
private void synchronizeLdapUsers(final LdapMasterLoginHandler 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;
}
}
}
/**
* @param groupDao the groupDao to set
* @return this for chaining.
*/
public void setGroupDao(final GroupDao groupDao)
{
this.groupDao = groupDao;
}
}