diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java index 2b3768988a5bcc5986555283a2255bd33c2205c0..1ed5f14bd0cb0225c6eeb2120d29ddd9c84af012 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAO.java @@ -102,20 +102,11 @@ 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 java.util.logging.Level; public class LdapGroupDAO<T extends Principal> extends LdapDAO { private static final Logger logger = Logger.getLogger(LdapGroupDAO.class); - - private static final String ACTUAL_GROUP_TOKEN = "<ACTUAL_GROUP>"; - private static final String GROUP_READ_ACI = "(targetattr = \"*\") " + - "(version 3.0;acl \"Group Read\";allow (read,compare,search)" + - "(groupdn = \"ldap:///<ACTUAL_GROUP>\");)"; - private static final String GROUP_WRITE_ACI = "(targetattr = \"*\") " + - "(version 3.0;acl \"Group Write\";allow " + - "(read,compare,search,selfwrite,write,add)" + - "(groupdn = \"ldap:///<ACTUAL_GROUP>\");)"; + private LdapUserDAO<T> userPersist; @@ -282,7 +273,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO User<X500Principal> user; try { - user = userPersist.getMember(memberDN, false); + user = userPersist.getMember(memberDN); } catch (UserNotFoundException e) { 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 b58ade6f8eec036820fbff5e77c8d1640c964039..f21c086068bedcb41d713b92a511df1911c4a3d7 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,12 +68,25 @@ */ package ca.nrc.cadc.ac.server.ldap; +import java.security.AccessControlException; +import java.security.Principal; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; + +import javax.security.auth.x500.X500Principal; + +import org.apache.log4j.Logger; + import ca.nrc.cadc.ac.Group; +import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.net.TransientException; + import com.unboundid.ldap.sdk.CompareRequest; import com.unboundid.ldap.sdk.CompareResult; import com.unboundid.ldap.sdk.DN; @@ -82,30 +95,39 @@ import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.SearchRequest; import com.unboundid.ldap.sdk.SearchResultEntry; import com.unboundid.ldap.sdk.SearchScope; -import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV1RequestControl; import com.unboundid.ldap.sdk.controls.ProxiedAuthorizationV2RequestControl; -import java.security.AccessControlException; -import java.security.Principal; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import javax.security.auth.x500.X500Principal; -import org.apache.log4j.Logger; public class LdapUserDAO<T extends Principal> extends LdapDAO { private static final Logger logger = Logger.getLogger(LdapUserDAO.class); // Map of identity type to LDAP attribute - private Map<Class<?>, String> attribType = new HashMap<Class<?>, String>(); + private Map<Class<?>, String> userLdapAttrib = new HashMap<Class<?>, String>(); + + // User attributes returned to the GMS + private static final String LDAP_FNAME = "givenname"; + private static final String LDAP_LNAME = "sn"; + //TODO to add the rest + private String[] userAttribs = new String[]{LDAP_FNAME, LDAP_LNAME}; + private String[] memberAttribs = new String[]{LDAP_FNAME, LDAP_LNAME}; public LdapUserDAO(LdapConfig config) { super(config); - this.attribType.put(HttpPrincipal.class, "cn"); - this.attribType.put(X500Principal.class, "distinguishedname"); - this.attribType.put(NumericPrincipal.class, "entryid"); + this.userLdapAttrib.put(HttpPrincipal.class, "uid"); + this.userLdapAttrib.put(X500Principal.class, "distinguishedname"); + + // add the id attributes to user and member attributes + String[] princs = userLdapAttrib.values().toArray(new String[userLdapAttrib.values().size()]); + String[] tmp = new String[userAttribs.length + princs.length]; + System.arraycopy(princs, 0, tmp, 0, princs.length); + System.arraycopy(userAttribs, 0, tmp, princs.length, userAttribs.length); + userAttribs = tmp; + + tmp = new String[memberAttribs.length + princs.length]; + System.arraycopy(princs, 0, tmp, 0, princs.length); + System.arraycopy(memberAttribs, 0, tmp, princs.length, memberAttribs.length); + memberAttribs = tmp; } /** @@ -122,7 +144,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO public User<T> getUser(T userID) throws UserNotFoundException, TransientException, AccessControlException { - String searchField = (String) attribType.get(userID.getClass()); + String searchField = (String) userLdapAttrib.get(userID.getClass()); if (searchField == null) { throw new IllegalArgumentException( @@ -135,8 +157,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO try { SearchRequest searchRequest = new SearchRequest(config.getUsersDN(), - SearchScope.SUB, searchField, - new String[] {"cn", "entryid", "entrydn", "dn"}); + SearchScope.SUB, searchField, userAttribs); searchRequest.addControl( new ProxiedAuthorizationV2RequestControl("dn:" + @@ -157,12 +178,13 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } User<T> user = new User<T>(userID); user.getIdentities().add( - new HttpPrincipal(searchResult.getAttributeValue("cn"))); - - user.getIdentities().add( - new NumericPrincipal( - searchResult.getAttributeValueAsInteger("entryid"))); - + new HttpPrincipal(searchResult.getAttributeValue(userLdapAttrib + .get(HttpPrincipal.class)))); + + String fname = searchResult.getAttributeValue(LDAP_FNAME); + String lname = searchResult.getAttributeValue(LDAP_LNAME); + user.details.add(new PersonalDetails(fname, lname)); + //TODO populate user with the other returned personal or posix attributes return user; } @@ -182,14 +204,14 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO { try { - String searchField = (String) attribType.get(userID.getClass()); + String searchField = (String) userLdapAttrib.get(userID.getClass()); if (searchField == null) { throw new IllegalArgumentException( "Unsupported principal type " + userID.getClass()); } - User user = getUser(userID); + User<T> user = getUser(userID); Filter filter = Filter.createANDFilter( Filter.createEqualityFilter(searchField, user.getUserID().getName()), @@ -256,14 +278,14 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO { try { - String searchField = (String) attribType.get(userID.getClass()); + String searchField = (String) userLdapAttrib.get(userID.getClass()); if (searchField == null) { throw new IllegalArgumentException( "Unsupported principal type " + userID.getClass()); } - User user = getUser(userID); + User<T> user = getUser(userID); Filter filter = Filter.createANDFilter( Filter.createEqualityFilter(searchField, user.getUserID().getName()), @@ -301,14 +323,14 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO { try { - String searchField = (String) attribType.get(userID.getClass()); + String searchField = (String) userLdapAttrib.get(userID.getClass()); if (searchField == null) { throw new IllegalArgumentException( "Unsupported principal type " + userID.getClass()); } - User user = getUser(userID); + User<T> user = getUser(userID); DN userDN = getUserDN(user); CompareRequest compareRequest = @@ -333,16 +355,16 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO } /** - * Returns a member user identified by the X500Principal only. + * Returns a member user identified by the X500Principal only. The + * returned object has the fields required by the GMS. + * Note that this method binds as a proxy user and not as the + * subject. * @param userDN - * @param bindAsSubject - true if Ldap commands executed as subject - * (proxy authorization) or false if they are executed as the user - * in the connection. * @return * @throws UserNotFoundException * @throws LDAPException */ - User<X500Principal> getMember(DN userDN, boolean bindAsSubject) + User<X500Principal> getMember(DN userDN) throws UserNotFoundException, LDAPException { Filter filter = @@ -351,50 +373,37 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO SearchRequest searchRequest = new SearchRequest(this.config.getUsersDN(), SearchScope.SUB, - filter, - (String[]) this.attribType.values().toArray( - new String[this.attribType.values().size()])); - - if (bindAsSubject) - { - searchRequest.addControl( - new ProxiedAuthorizationV2RequestControl("dn:" + - getSubjectDN().toNormalizedString())); - } + filter, memberAttribs); SearchResultEntry searchResult = getConnection().searchForEntry(searchRequest); if (searchResult == null) { - String msg = "User not found " + userDN; + String msg = "Member not found " + userDN; logger.debug(msg); throw new UserNotFoundException(msg); } User<X500Principal> user = new User<X500Principal>( new X500Principal(searchResult.getAttributeValue( - (String) attribType.get(X500Principal.class)))); - + (String) userLdapAttrib.get(X500Principal.class)))); + String princ = searchResult.getAttributeValue( + (String) userLdapAttrib.get(HttpPrincipal.class)); + if (princ != null) + { + user.getIdentities().add(new HttpPrincipal(princ)); + } + String fname = searchResult.getAttributeValue(LDAP_FNAME); + String lname = searchResult.getAttributeValue(LDAP_LNAME); + user.details.add(new PersonalDetails(fname, lname)); return user; } - /** - * Returns a member user identified by the X500Principal only. - * @param userDN - * @return - * @throws UserNotFoundException - * @throws LDAPException - */ - User<X500Principal> getMember(DN userDN) - throws UserNotFoundException, LDAPException - { - return getMember(userDN, true); - } DN getUserDN(User<? extends Principal> user) throws LDAPException, UserNotFoundException { - String searchField = (String) attribType.get(user.getUserID().getClass()); + String searchField = (String) userLdapAttrib.get(user.getUserID().getClass()); if (searchField == null) { throw new IllegalArgumentException( 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 2825cdc67eb244bc2d8ca669cb4e253ab7ef2c6e..f02c0f12c21689c61b6625bac768e3fd91efe835 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,22 +68,33 @@ */ package ca.nrc.cadc.ac.server.ldap; -import ca.nrc.cadc.ac.Group; -import ca.nrc.cadc.ac.User; -import ca.nrc.cadc.util.Log4jInit; +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 java.security.Principal; 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 static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import org.junit.BeforeClass; import org.junit.Test; +import ca.nrc.cadc.ac.Group; +import ca.nrc.cadc.ac.PersonalDetails; +import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.ac.UserDetails; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.NumericPrincipal; +import ca.nrc.cadc.util.Log4jInit; + +import com.unboundid.ldap.sdk.DN; + /** * * @author jburke @@ -102,7 +113,9 @@ public class LdapUserDAOTest // static String userBaseDN = "ou=Users,ou=ds,dc=canfar,dc=net"; // static String groupBaseDN = "ou=Groups,ou=ds,dc=canfar,dc=net"; - static final String testUserDN = "cn=cadcdaotest1,ou=cadc,o=hia,c=ca"; + static final String testUserX509DN = "cn=cadcdaotest1,ou=cadc,o=hia,c=ca"; + static final String testUserDN = "uid=cadcdaotest1," + usersDN; + static User<X500Principal> testUser; static LdapConfig config; @@ -113,9 +126,12 @@ public class LdapUserDAOTest { Log4jInit.setLevel("ca.nrc.cadc.ac", Level.DEBUG); - testUser = new User<X500Principal>(new X500Principal(testUserDN)); + testUser = new User<X500Principal>(new X500Principal(testUserX509DN)); config = new LdapConfig(server, port, adminDN, adminPW, usersDN, groupsDN, adminGroupsDN); + + testUser.details.add(new PersonalDetails("CADC", "DAOTest1")); + testUser.getIdentities().add(new HttpPrincipal("CadcDaoTest1")); } LdapUserDAO<X500Principal> getUserDAO() @@ -139,8 +155,8 @@ public class LdapUserDAOTest { try { - User actual = getUserDAO().getUser(testUser.getUserID()); - assertEquals(testUser, actual); + User<X500Principal> actual = getUserDAO().getUser(testUser.getUserID()); + check(testUser, actual); return null; } @@ -150,6 +166,7 @@ public class LdapUserDAOTest } } }); + } /** @@ -217,4 +234,90 @@ public class LdapUserDAOTest }); } + + /** + * Test of getMember. + */ + @Test + public void testGetMember() throws Exception + { + Subject subject = new Subject(); + subject.getPrincipals().add(testUser.getUserID()); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + User<X500Principal> actual = getUserDAO().getMember(new DN(testUserDN)); + check(testUser, actual); + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + + + // should also work as a different user + subject = new Subject(); + subject.getPrincipals().add(new HttpPrincipal("CadcDaoTest2")); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + User<X500Principal> actual = getUserDAO().getMember(new DN(testUserDN)); + check(testUser, actual); + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + } + + + private static void check(final User<? extends Principal> user1, final User<? extends Principal> user2) + { + 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) + { + assertTrue(user2.details.contains(d1)); + if(d1 instanceof PersonalDetails) + { + PersonalDetails pd1 = (PersonalDetails)d1; + boolean found = false; + for(UserDetails d2 : user2.details) + { + if(d2 instanceof PersonalDetails) + { + PersonalDetails pd2 = (PersonalDetails)d2; + assertEquals(pd1, pd2); // already done in contains above but just in case + assertEquals(pd1.address, pd2.address); + assertEquals(pd1.city, pd2.city); + assertEquals(pd1.country, pd2.country); + assertEquals(pd1.email, pd2.email); + assertEquals(pd1.institute, pd2.institute); + found = true; + } + assertTrue(found); + } + } + } + + } + }