Skip to content
Snippets Groups Projects
Commit 45d56e37 authored by Jeff Burke's avatar Jeff Burke
Browse files

ac2: update LDAP user and set password

parents 5032c231 74a05aa0
Branches
Tags
No related merge requests found
......@@ -137,5 +137,34 @@
<property name="lib.commons-logging"
value="${ext.lib}/commons-logging.jar"/>
<property name="testingJars"
<<<<<<< HEAD
value="${lib.commons-logging}:${dev.junit}:${dev.jsonassert}:${dev.httpunit}:${dev.easyMock}:${dev.selenium.server}:${dev.objenesis}:${lib.js}:${lib.nekoHTML}:${lib.xerces}"/>
=======
value="${lib.commons-logging}:${dev.junit}:${dev.httpunit}:${dev.easyMock}:${dev.selenium.server}:${dev.objenesis}:${lib.js}:${lib.nekoHTML}:${lib.xerces}"/>
<target name="setup-test">
<echo>******************</echo>
<echo>******************</echo>
<echo>Don't forget to set the ca.nrc.cadc.util.PropertiesReader.dir system property first!</echo>
<echo>e.g. ant -Dca.nrc.cadc.util.PropertiesReader.dir=test clean build test</echo>
<echo>******************</echo>
<echo>******************</echo>
</target>
<target name="test" depends="compile,compile-test">
<echo message="Running test suite..." />
<junit printsummary="yes" haltonfailure="yes" fork="yes">
<classpath>
<pathelement path="${build}/class"/>
<pathelement path="${build}/test/class"/>
<pathelement path="${jars}:${testingJars}"/>
</classpath>
<sysproperty key="ca.nrc.cadc.util.PropertiesReader.dir" value="test"/>
<test name="ca.nrc.cadc.ac.server.ldap.LdapUserDAOTest" />
<!--<test name="ca.nrc.cadc.ac.server.ldap.LdapGroupDAOTest" />-->
<formatter type="plain" usefile="false" />
</junit>
</target>
>>>>>>> s1734
</project>
......@@ -68,7 +68,6 @@
*/
package ca.nrc.cadc.ac.server.ldap;
import ca.nrc.cadc.ac.UserAlreadyExistsException;
import ca.nrc.cadc.auth.HttpPrincipal;
import ca.nrc.cadc.auth.NumericPrincipal;
import ca.nrc.cadc.auth.OpenIdPrincipal;
......@@ -79,18 +78,17 @@ import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchScope;
import org.apache.log4j.Logger;
import java.nio.file.FileAlreadyExistsException;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.security.Principal;
import java.util.Set;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
import org.apache.log4j.Logger;
public abstract class LdapDAO
......@@ -236,6 +234,7 @@ public abstract class LdapDAO
throws TransientException
{
logger.debug("Ldap result: " + code);
System.out.println("Ldap result: " + code);
if (code == ResultCode.INSUFFICIENT_ACCESS_RIGHTS)
{
......
......@@ -68,18 +68,6 @@
*/
package ca.nrc.cadc.ac.server.ldap;
import java.security.AccessControlException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
import org.apache.log4j.Logger;
import ca.nrc.cadc.ac.ActivatedGroup;
import ca.nrc.cadc.ac.Group;
import ca.nrc.cadc.ac.GroupAlreadyExistsException;
......@@ -89,7 +77,6 @@ import ca.nrc.cadc.ac.User;
import ca.nrc.cadc.ac.UserNotFoundException;
import ca.nrc.cadc.net.TransientException;
import ca.nrc.cadc.util.StringUtil;
import com.unboundid.ldap.sdk.AddRequest;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.DN;
......@@ -106,6 +93,16 @@ import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;
import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl;
import org.apache.log4j.Logger;
import javax.security.auth.x500.X500Principal;
import java.security.AccessControlException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class LdapGroupDAO<T extends Principal> extends LdapDAO
{
......
......@@ -68,23 +68,41 @@
*/
package ca.nrc.cadc.ac.server.ldap;
import ca.nrc.cadc.ac.*;
import ca.nrc.cadc.ac.PersonalDetails;
import ca.nrc.cadc.ac.PosixDetails;
import ca.nrc.cadc.ac.User;
import ca.nrc.cadc.ac.UserAlreadyExistsException;
import ca.nrc.cadc.ac.UserDetails;
import ca.nrc.cadc.ac.UserNotFoundException;
import ca.nrc.cadc.ac.UserRequest;
import ca.nrc.cadc.auth.AuthenticationUtil;
import ca.nrc.cadc.auth.HttpPrincipal;
import ca.nrc.cadc.net.TransientException;
import com.unboundid.ldap.sdk.AddRequest;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.BindRequest;
import com.unboundid.ldap.sdk.BindResult;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.DN;
import com.unboundid.ldap.sdk.Filter;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.LDAPSearchException;
import com.unboundid.ldap.sdk.Modification;
import com.unboundid.ldap.sdk.ModificationType;
import com.unboundid.ldap.sdk.ModifyRequest;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.ldap.sdk.SearchRequest;
import com.unboundid.ldap.sdk.SearchResult;
import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;
import com.unboundid.ldap.sdk.SimpleBindRequest;
import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl;
import com.unboundid.ldap.sdk.extensions.PasswordModifyExtendedRequest;
import com.unboundid.ldap.sdk.extensions.PasswordModifyExtendedResult;
import org.apache.log4j.Logger;
import javax.security.auth.x500.X500Principal;
import java.security.AccessControlException;
import java.security.Principal;
import java.util.ArrayList;
......@@ -93,8 +111,6 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import javax.security.auth.x500.X500Principal;
import org.apache.log4j.Logger;
public class LdapUserDAO<T extends Principal> extends LdapDAO
......@@ -163,6 +179,40 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
memberAttribs = tmp;
}
/**
* Verifies the username and password for an existing User.
*
* @param username username to verify.
* @param password password to verify.
* @return User
* @throws TransientException
* @throws UserNotFoundException
*/
public User<T> loginUser(final String username, final String password)
throws TransientException, UserNotFoundException
{
try
{
BindRequest bindRequest = new SimpleBindRequest(getUserDN(username), password);
BindResult bindResult = getConnection().bind(bindRequest);
if (bindResult != null && bindResult.getResultCode() == ResultCode.SUCCESS)
{
return getUser((T) new HttpPrincipal(username));
}
else
{
throw new AccessControlException("Invalid username or password");
}
}
catch (LDAPException e)
{
logger.debug("addUser Exception: " + e, e);
throw new RuntimeException("Unexpected LDAP exception", e);
}
}
/**
* @return
* @throws TransientException
......@@ -208,10 +258,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
throw new IllegalStateException("Unexpected exception: " +
e1.getMatchedDN(), e1);
}
}
/**
* Add the specified user..
*
......@@ -298,8 +346,6 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
}
catch (LDAPException e)
{
System.out.println("LDAPe: " + e);
System.out.println("LDAPrc: " + e.getResultCode());
logger.debug("addUser Exception: " + e, e);
LdapUserDAO.checkUserLDAPResult(e.getResultCode());
throw new RuntimeException("Unexpected LDAP exception", e);
......@@ -376,9 +422,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
throw new UserNotFoundException(msg);
}
User<T> user = new User<T>(userID);
user.getIdentities().add(new HttpPrincipal(searchResult
.getAttributeValue(userLdapAttrib
.get(HttpPrincipal.class))));
user.getIdentities().add(new HttpPrincipal(searchResult.getAttributeValue(
userLdapAttrib.get(HttpPrincipal.class))));
String fname = searchResult.getAttributeValue(LDAP_FIRST_NAME);
String lname = searchResult.getAttributeValue(LDAP_LAST_NAME);
......@@ -487,11 +532,99 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
*/
public User<T> modifyUser(User<T> user)
throws UserNotFoundException, TransientException,
AccessControlException
public User<T> modifyUser(final User<T> user)
throws UserNotFoundException, TransientException, AccessControlException
{
User existingUser = getUser(user.getUserID());
List<Modification> mods = new ArrayList<Modification>();
for (UserDetails details : user.details)
{
if (details.getClass() == PersonalDetails.class)
{
PersonalDetails pd = (PersonalDetails) details;
mods.add(new Modification(ModificationType.REPLACE, LDAP_FIRST_NAME, pd.getFirstName()));
mods.add(new Modification(ModificationType.REPLACE, LDAP_LAST_NAME, pd.getLastName()));
mods.add(new Modification(ModificationType.REPLACE, LDAP_ADDRESS, pd.address));
mods.add(new Modification(ModificationType.REPLACE, LDAP_CITY, pd.city));
mods.add(new Modification(ModificationType.REPLACE, LDAP_COUNTRY, pd.country));
mods.add(new Modification(ModificationType.REPLACE, LDAP_EMAIL, pd.email));
mods.add(new Modification(ModificationType.REPLACE, LDAP_INSTITUTE, pd.institute));
}
else if (details.getClass() == PosixDetails.class)
{
return null;
PosixDetails pd = (PosixDetails) details;
mods.add(new Modification(ModificationType.REPLACE, LDAP_OBJECT_CLASS, LDAP_POSIX_ACCOUNT));
mods.add(new Modification(ModificationType.REPLACE, LDAP_UID, Long.toString(pd.getUid())));
mods.add(new Modification(ModificationType.REPLACE, LDAP_UID_NUMBER, Long.toString(pd.getUid())));
mods.add(new Modification(ModificationType.REPLACE, LDAP_GID_NUMBER, Long.toString(pd.getGid())));
mods.add(new Modification(ModificationType.REPLACE, LDAP_HOME_DIRECTORY, pd.getHomeDirectory()));
mods.add(new Modification(ModificationType.REPLACE, LDAP_LOGIN_SHELL, pd.loginShell));
}
}
try
{
ModifyRequest modifyRequest = new ModifyRequest(getUserDN(user), mods);
modifyRequest.addControl(
new ProxiedAuthorizationV2RequestControl(
"dn:" + getSubjectDN().toNormalizedString()));
LdapDAO.checkLdapResult(getConnection().modify(modifyRequest).getResultCode());
}
catch (LDAPException e1)
{
logger.debug("Modify Exception: " + e1, e1);
LdapDAO.checkLdapResult(e1.getResultCode());
}
try
{
return getUser(user.getUserID());
}
catch (UserNotFoundException e)
{
throw new RuntimeException(
"BUG: modified user not found (" + user.getUserID() + ")");
}
}
/**
* Update a user's password. The given user and authenticating user must match.
*
* @param user
* @param oldPassword current password.
* @param newPassword new password.
* @throws UserNotFoundException If the given user does not exist.
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
*/
public void setPassword(User<T> user, final String oldPassword, final String newPassword)
throws UserNotFoundException, TransientException, AccessControlException
{
try
{
DN userDN = getUserDN(user);
DN subjectDN = getSubjectDN();
if (!userDN.equals(subjectDN))
{
throw new AccessControlException("Given user and authenticating user do not match");
}
ProxiedAuthorizationV2RequestControl control =
new ProxiedAuthorizationV2RequestControl("dn:" + getSubjectDN().toNormalizedString());
Control[] controls = new Control[] {control};
PasswordModifyExtendedRequest passwordModifyRequest =
new PasswordModifyExtendedRequest(userDN.toNormalizedString(), oldPassword, newPassword, controls);
PasswordModifyExtendedResult passwordModifyResult = (PasswordModifyExtendedResult)
getConnection().processExtendedOperation(passwordModifyRequest);
LdapDAO.checkLdapResult(passwordModifyResult.getResultCode());
}
catch (LDAPException e)
{
logger.debug("setPassword Exception: " + e);
LdapDAO.checkLdapResult(e.getResultCode());
}
}
/**
......@@ -595,7 +728,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
* @throws TransientException If an temporary, unexpected problem occurred.
* @throws AccessControlException If the operation is not permitted.
*/
public boolean isMember(T userID, String groupID)
public boolean isMember(final T userID, final String groupID)
throws UserNotFoundException, TransientException,
AccessControlException
{
......
# This are the configuration fields required by the Ldap ldap-dao unit tests
server = proc5-03.cadc.dao.nrc.ca
port = 636
proxyUser = webproxy
usersDn = ou=Users,ou=ds,dc=canfar,dc=net
port = 389
proxyUser = testproxy
usersDn = ou=Users,ou=ds,dc=testcanfar
userRequestsDN = ou=UserRequests,ou=ds,dc=testcanfar
newUsersDn = ou=NewUsers,ou=ds,dc=canfar,dc=net
groupsDn = ou=Groups,ou=ds,dc=canfar,dc=net
adminGroupsDn = ou=adminGroups,ou=ds,dc=canfar,dc=net
\ No newline at end of file
groupsDn = ou=Groups,ou=ds,dc=testcanfar
adminGroupsDn = ou=adminGroups,ou=ds,dc=testcanfar
\ No newline at end of file
......@@ -67,23 +67,6 @@
package ca.nrc.cadc.ac.server.ldap;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.security.AccessControlException;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.nrc.cadc.ac.ActivatedGroup;
import ca.nrc.cadc.ac.Group;
import ca.nrc.cadc.ac.GroupAlreadyExistsException;
......@@ -91,8 +74,23 @@ import ca.nrc.cadc.ac.GroupNotFoundException;
import ca.nrc.cadc.ac.GroupProperty;
import ca.nrc.cadc.ac.Role;
import ca.nrc.cadc.ac.User;
import ca.nrc.cadc.util.Log4jInit;
import ca.nrc.cadc.auth.HttpPrincipal;
import ca.nrc.cadc.util.Log4jInit;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.security.auth.Subject;
import javax.security.auth.x500.X500Principal;
import java.security.AccessControlException;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class LdapGroupDAOTest extends AbstractLdapDAOTest
{
......
......@@ -69,6 +69,7 @@
package ca.nrc.cadc.ac.server.ldap;
import ca.nrc.cadc.ac.PersonalDetails;
import ca.nrc.cadc.ac.PosixDetails;
import ca.nrc.cadc.ac.User;
import ca.nrc.cadc.ac.UserDetails;
import ca.nrc.cadc.ac.UserRequest;
......@@ -86,7 +87,11 @@ import java.security.Principal;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class LdapUserDAOTest extends AbstractLdapDAOTest
{
......@@ -127,7 +132,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
/**
* Test of addUser method, of class LdapUserDAO.
*/
@Test
// @Test
public void testAddUser() throws Exception
{
final User<HttpPrincipal> expected = new User<HttpPrincipal>(new HttpPrincipal(getUserID()));
......@@ -147,7 +152,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
/**
* Test of getUser method, of class LdapUserDAO.
*/
@Test
// @Test
public void testGetUser() throws Exception
{
Subject subject = new Subject();
......@@ -156,7 +161,8 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
// do everything as owner
Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
{
public Object run() throws Exception
public Object run()
throws Exception
{
try
{
......@@ -177,7 +183,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
/**
* Test of getUserGroups method, of class LdapUserDAO.
*/
@Test
// @Test
public void testGetUserGroups() throws Exception
{
Subject subject = new Subject();
......@@ -215,7 +221,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
/**
* Test of getUserGroups method, of class LdapUserDAO.
*/
@Test
// @Test
public void testIsMember() throws Exception
{
Subject subject = new Subject();
......@@ -248,7 +254,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
/**
* Test of getMember.
*/
@Test
// @Test
public void testGetMember() throws Exception
{
Subject subject = new Subject();
......@@ -279,7 +285,8 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
// do everything as owner
Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
{
public Object run() throws Exception
public Object run()
throws Exception
{
try
{
......@@ -298,7 +305,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
/**
* Test of testGetCadcUserIDs.
*/
@Test
// @Test
public void testGetCadcUserIDs() throws Exception
{
Subject subject = new Subject();
......@@ -346,6 +353,166 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
users1, users2);
}
@Test
public void testSetPassword() throws Exception
{
// Create a test user with a known password
final User<HttpPrincipal> teststUser2;
final String username = getUserID();
final String password = "foo";
final String newPassword = "bar";
User<HttpPrincipal> user = new User<HttpPrincipal>(new HttpPrincipal(username));
user.details.add(new PersonalDetails("firstName", "lastName"));
UserRequest userRequest = new UserRequest(user, password);
teststUser2 = getUserDAO().addUser(userRequest);
Subject subject = new Subject();
// authenticate new useranme and password
Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
{
public Object run()
throws Exception
{
try
{
getUserDAO().loginUser(username, password);
}
catch (Exception e)
{
fail("exception during login: " + e.getMessage());
}
return null;
}
});
// anonymous access should throw exception
Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
{
public Object run() throws Exception
{
try
{
getUserDAO().setPassword(teststUser2, password, newPassword);
fail("should throw exception if subject and user are not the same");
}
catch (Exception ignore){}
return null;
}
});
// change the password
subject.getPrincipals().add(teststUser2.getUserID());
Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
{
public Object run()
throws Exception
{
try
{
getUserDAO().setPassword(teststUser2, password, newPassword);
}
catch (Exception e)
{
fail("exception setting password: " + e.getMessage());
}
return null;
}
});
// verify new password
Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
{
public Object run()
throws Exception
{
try
{
getUserDAO().loginUser(username, password);
}
catch (Exception e)
{
fail("exception during login: " + e.getMessage());
}
return null;
}
});
}
@Test
public void testUpdateUser() throws Exception
{
// Create a test user with a known password
final User<HttpPrincipal> testUser2;
final String username = getUserID();
final String password = "foo";
final String newPassword = "bar";
User<HttpPrincipal> user = new User<HttpPrincipal>(new HttpPrincipal(username));
user.details.add(new PersonalDetails("firstName", "lastName"));
UserRequest userRequest = new UserRequest(user, password);
testUser2 = getUserDAO().addUser(userRequest);
// update the user
for (UserDetails details : user.details)
{
if (details instanceof PersonalDetails)
{
PersonalDetails pd = (PersonalDetails) details;
pd.email = "email2";
pd.address = "address2";
pd.institute = "institute2";
pd.city = "city2";
pd.country = "country2";
}
}
user.details.add(new PosixDetails(123L, 456L, "/dev/null"));
Subject subject = new Subject();
// anonymous access should throw exception
Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
{
public Object run()
throws Exception
{
try
{
getUserDAO().modifyUser(testUser2);
fail("should throw exception if subject and user are not the same");
}
catch (Exception ignore)
{
}
return null;
}
});
// update the user
subject.getPrincipals().add(testUser2.getUserID());
User<? extends Principal> updatedUser =
(User<? extends Principal>) Subject.doAs(subject, new PrivilegedExceptionAction<Object>()
{
public Object run()
throws Exception
{
try
{
return getUserDAO().modifyUser(testUser2);
}
catch (Exception e)
{
fail("exception updating user: " + e.getMessage());
}
return null;
}
});
assertNotNull(updatedUser);
check(testUser2, updatedUser);
}
private static void check(final User<? extends Principal> user1, final User<? extends Principal> user2)
{
assertEquals(user1, user2);
......@@ -375,6 +542,24 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
assertTrue(found);
}
}
if (d1 instanceof PosixDetails)
{
PosixDetails pd1 = (PosixDetails) d1;
boolean found = false;
for(UserDetails d2 : user2.details)
{
if(d2 instanceof PosixDetails)
{
PosixDetails pd2 = (PosixDetails) d2;
assertEquals(pd1, pd2);
assertEquals(pd1.getUid(), pd2.getUid());
assertEquals(pd1.getGid(), pd2.getGid());
assertEquals(pd1.getHomeDirectory(), pd2.getHomeDirectory());
found = true;
}
assertTrue(found);
}
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment