diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java index 5e0b281b83bf3451473c1aae836f2abb3857497d..e559a5ec80d70346315997d7e9544b8a86a80cb2 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java @@ -68,6 +68,20 @@ */ 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.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.security.auth.x500.X500Principal; + +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.PosixDetails; import ca.nrc.cadc.ac.User; @@ -77,7 +91,9 @@ 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.auth.NumericPrincipal; import ca.nrc.cadc.net.TransientException; + import com.unboundid.ldap.sdk.AddRequest; import com.unboundid.ldap.sdk.Attribute; import com.unboundid.ldap.sdk.BindRequest; @@ -100,17 +116,6 @@ 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; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; public class LdapUserDAO<T extends Principal> extends LdapDAO @@ -129,6 +134,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO protected static final String LDAP_ENTRYDN = "entrydn"; protected static final String LDAP_COMMON_NAME = "cn"; protected static final String LDAP_DISTINGUISHED_NAME = "distinguishedName"; + protected static final String LDAP_NUMERICID = "numericid"; protected static final String LADP_USER_PASSWORD = "userPassword"; protected static final String LDAP_FIRST_NAME = "givenName"; protected static final String LDAP_LAST_NAME = "sn"; @@ -138,6 +144,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO protected static final String LDAP_EMAIL = "email"; protected static final String LDAP_INSTITUTE = "institute"; protected static final String LDAP_UID = "uid"; + private String[] userAttribs = new String[] { @@ -155,6 +162,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO super(config); this.userLdapAttrib.put(HttpPrincipal.class, LDAP_UID); this.userLdapAttrib.put(X500Principal.class, LDAP_DISTINGUISHED_NAME); + this.userLdapAttrib.put(NumericPrincipal.class, LDAP_NUMERICID); // add the id attributes to user and member attributes String[] princs = userLdapAttrib.values() @@ -350,16 +358,25 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO try { // add new user + + DN userX500DN = getUserRequestsDN(user.getUserID().getName()); List<Attribute> attributes = new ArrayList<Attribute>(); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_ORG_PERSON); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_CADC_ACCOUNT); addAttribute(attributes, LDAP_COMMON_NAME, user.getUserID() .getName()); - addAttribute(attributes, LDAP_DISTINGUISHED_NAME, userDN - .toNormalizedString()); addAttribute(attributes, LADP_USER_PASSWORD, userRequest - .getPassword()); - + .getPassword()); + addAttribute(attributes, LDAP_NUMERICID, + String.valueOf(genNextNumericId())); + for (Principal princ : user.getIdentities()) + { + if (princ instanceof X500Principal) + { + addAttribute(attributes, LDAP_DISTINGUISHED_NAME, + princ.getName()); + } + } for (UserDetails details : user.details) { if (details.getClass() == PersonalDetails.class) @@ -462,9 +479,15 @@ 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)))); + user.getIdentities().add(new NumericPrincipal( + searchResult.getAttributeValueAsLong( + userLdapAttrib.get(NumericPrincipal.class)))); + user.getIdentities().add(new X500Principal( + searchResult.getAttributeValue( + userLdapAttrib.get(X500Principal.class)))); String fname = searchResult.getAttributeValue(LDAP_FIRST_NAME); String lname = searchResult.getAttributeValue(LDAP_LAST_NAME); PersonalDetails personaDetails = new PersonalDetails(fname, lname); @@ -772,10 +795,9 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO "Unsupported principal type " + userID.getClass()); } - User<T> user = getUser(userID); Filter filter = Filter.createANDFilter( Filter.createEqualityFilter(searchField, - user.getUserID().getName()), + userID.getName()), Filter.createEqualityFilter(LDAP_MEMBEROF, groupID)); SearchRequest searchRequest = @@ -972,4 +994,18 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO LdapDAO.checkLdapResult(code); } } + + /** + * Method to return a randomly generated user numeric ID. The default + * implementation returns a value between 10000 and Integer.MAX_VALUE. + * @return + */ + protected int genNextNumericId() + { + Random rand = new Random(); + + // nextInt is normally exclusive of the top value, + // so add 1 to make it inclusive + return rand.nextInt(Integer.MAX_VALUE - 10000) + 10000; + } } diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java index 0e592c8012b889cd4b425b5bae0b3089a647f1f4..78a63a13285e89e87d18806b24dfcbae0c4953f8 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java @@ -68,39 +68,47 @@ */ package ca.nrc.cadc.ac.server.ldap; +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; + +import java.security.Principal; +import java.security.PrivilegedExceptionAction; +import java.util.Collection; +import java.util.Random; + +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.PersonalDetails; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserDetails; import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.util.Log4jInit; -import com.unboundid.ldap.sdk.DN; -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.Principal; -import java.security.PrivilegedExceptionAction; -import java.util.Collection; - -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; +import com.unboundid.ldap.sdk.DN; public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest { private static final Logger log = Logger.getLogger(LdapUserDAOTest.class); static final String testUserX509DN = "cn=cadcdaotest1,ou=cadc,o=hia,c=ca"; + static int nextUserNumericID = 666; static String testUserDN; static User<X500Principal> testUser; + static User<X500Principal> testMember; static LdapConfig config; + static Random ran = new Random(); // source of randomness for numeric ids @BeforeClass public static void setUpBeforeClass() @@ -110,17 +118,32 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest // get the configuration of the development server from and config files... config = getLdapConfig(); - - testUser = new User<X500Principal>(new X500Principal(testUserX509DN)); + X500Principal testUserX500Princ = new X500Principal(testUserX509DN); + testUser = new User<X500Principal>(testUserX500Princ); testUser.details.add(new PersonalDetails("CADC", "DAOTest1")); testUser.getIdentities().add(new HttpPrincipal("CadcDaoTest1")); + testUser.getIdentities().add(testUserX500Princ); + testUser.getIdentities().add(new NumericPrincipal(666)); testUserDN = "uid=cadcdaotest1," + config.getUsersDN(); + + + // member returned by getMember contains only the fields required by + // the GMS + testMember = new User<X500Principal>(testUserX500Princ); + testMember.details.add(new PersonalDetails("CADC", "DAOTest1")); + testMember.getIdentities().add(new HttpPrincipal("CadcDaoTest1")); + } LdapUserDAO getUserDAO() { - return new LdapUserDAO(config); + return new LdapUserDAO(config){ + protected int genNextNumericId() + { + return nextUserNumericID; + } + }; } String getUserID() @@ -134,8 +157,13 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest @Test public void testAddUser() throws Exception { - final User<HttpPrincipal> expected = new User<HttpPrincipal>(new HttpPrincipal(getUserID())); - expected.getIdentities().add(new HttpPrincipal(getUserID())); + String userID = getUserID(); + final User<HttpPrincipal> expected = new User<HttpPrincipal>(new HttpPrincipal(userID)); + expected.getIdentities().add(new HttpPrincipal(userID)); + expected.getIdentities().add(new X500Principal("cn=" + userID + ",ou=cadc,o=hia,c=ca")); + nextUserNumericID = ran.nextInt(Integer.MAX_VALUE); + expected.getIdentities().add(new NumericPrincipal(nextUserNumericID)); + expected.details.add(new PersonalDetails("foo", "bar")); final UserRequest<HttpPrincipal> userRequest = @@ -265,6 +293,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest Subject subject = new Subject(); subject.getPrincipals().add(testUser.getUserID()); + // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { @@ -273,7 +302,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest try { User<X500Principal> actual = getUserDAO().getMember(new DN(testUserDN)); - check(testUser, actual); + check(testMember, actual); return null; } catch (Exception e) @@ -296,7 +325,7 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest try { User<X500Principal> actual = getUserDAO().getMember(new DN(testUserDN)); - check(testUser, actual); + check(testMember, actual); return null; } catch (Exception e) @@ -490,6 +519,10 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest HttpPrincipal principal = new HttpPrincipal(username); testUser2 = new User<HttpPrincipal>(principal); testUser2.getIdentities().add(principal); + testUser2.getIdentities().add(new X500Principal("cn=" + username + ",ou=cadc,o=hia,c=ca")); + // update nextNumericId + nextUserNumericID = ran.nextInt(Integer.MAX_VALUE); + testUser2.getIdentities().add(new NumericPrincipal(nextUserNumericID)); testUser2.details.add(new PersonalDetails("firstName", "lastName")); final UserRequest userRequest = new UserRequest(testUser2, password); @@ -575,8 +608,21 @@ public class LdapUserDAOTest<T extends Principal> extends AbstractLdapDAOTest assertEquals(user1, user2); assertEquals(user1.details, user2.details); assertEquals(user1.details.size(), user2.details.size()); - assertEquals(user1.getIdentities(), user2.getIdentities()); - for (UserDetails d1 : user1.details) + assertEquals(user1.getIdentities().size(), user2.getIdentities().size()); + for( Principal princ1 : user1.getIdentities()) + { + boolean found = false; + for( Principal princ2 : user2.getIdentities()) + { + if (princ2.getClass() == princ1.getClass()) + { + assertEquals(princ1, princ2); + found = true; + } + } + assertTrue(princ1.getName(), found); + } + for(UserDetails d1 : user1.details) { assertTrue(user2.details.contains(d1)); if (d1 instanceof PersonalDetails)