Commit 89ca1ad6 authored by Jeff Burke's avatar Jeff Burke
Browse files

s1651: removed test tree from LdapConfig, made owner optional in Group and updated tests

parent 14e720b3
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -141,11 +141,10 @@
                <pathelement path="${build}/test/class"/>
                <pathelement path="${testingJars}"/>
            </classpath>
            <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapDAOTest" />-->
            <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapDAOTestImpl" />-->
            <test name="ca.nrc.cadc.ac.server.ldap.LdapDAOTest" />
            <test name="ca.nrc.cadc.ac.server.ldap.LdapGroupDAOTest" />
            <!--<test name="ca.nrc.cadc.ac.server.web.GroupActionFactoryTest" />-->
            <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapUserDAOTest" />-->
            <test name="ca.nrc.cadc.ac.server.web.GroupActionFactoryTest" />
            <test name="ca.nrc.cadc.ac.server.ldap.LdapUserDAOTest" />
            <formatter type="plain" usefile="false" />
        </junit>
    </target>
+2 −24
Original line number Diff line number Diff line
@@ -86,11 +86,9 @@ public class LdapConfig
    public static final String LDAP_PASSWD = "passwd";
    public static final String LDAP_USERS_DN = "usersDn";
    public static final String LDAP_GROUPS_DN = "groupsDn";
    public static final String LDAP_DELETED_GROUPS_DN = "deletedGroupsDn";

    private String usersDN;
    private String groupsDN;
    private String deletedGroupsDN;
    private String server;
    private int port;
    private String adminUserDN;
@@ -159,21 +157,12 @@ public class LdapConfig
                                       LDAP_GROUPS_DN);
        }

        String ldapDeletedGroupsDn = config.getProperty(LDAP_DELETED_GROUPS_DN);
        if (!StringUtil.hasText(ldapDeletedGroupsDn))
        {
            throw new RuntimeException("failed to read property " + 
                                       LDAP_DELETED_GROUPS_DN);
        }

        return new LdapConfig(server, Integer.valueOf(port), ldapAdmin, 
                              ldapPasswd, ldapUsersDn, ldapGroupsDn, 
                              ldapDeletedGroupsDn);
                              ldapPasswd, ldapUsersDn, ldapGroupsDn);
    }

    public LdapConfig(String server, int port, String adminUserDN, 
                      String adminPasswd, String usersDN, String groupsDN, 
                      String deletedGroupsDN)
                      String adminPasswd, String usersDN, String groupsDN)
    {
        if (!StringUtil.hasText(server))
        {
@@ -205,11 +194,6 @@ public class LdapConfig
            throw new IllegalArgumentException("Illegal groups LDAP DN: " + 
                                               groupsDN);
        }
        if (!StringUtil.hasText(deletedGroupsDN))
        {
            throw new IllegalArgumentException("Illegal groups LDAP DN: " + 
                                               deletedGroupsDN);
        }

        this.server = server;
        this.port = port;
@@ -217,7 +201,6 @@ public class LdapConfig
        this.adminPasswd = adminPasswd;
        this.usersDN = usersDN;
        this.groupsDN = groupsDN;
        this.deletedGroupsDN = deletedGroupsDN;
    }

    public String getUsersDN()
@@ -230,11 +213,6 @@ public class LdapConfig
        return this.groupsDN;
    }

    public String getDeletedGroupsDN()
    {
        return this.deletedGroupsDN;
    }

    public String getServer()
    {
        return this.server;
+172 −153
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import javax.security.auth.x500.X500Principal;
import org.apache.log4j.Logger;

@@ -128,23 +129,6 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
        this.userPersist = userPersist;
    }

    /**
     * Get the group with the given Group ID.
     * 
     * @param groupID The Group unique ID.
     * 
     * @return A Group instance
     * 
     * @throws GroupNotFoundException If the group was not found.
     * @throws TransientException  If an temporary, unexpected problem occurred.
     */
    public Group getGroup(String groupID)
        throws GroupNotFoundException, TransientException,
               AccessControlException
    {
        return getGroup(groupID, true);
    }

    /**
     * Creates the group.
     * 
@@ -161,6 +145,11 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
        throws GroupAlreadyExistsException, TransientException,
               UserNotFoundException, AccessControlException
    {
        if (group.getOwner() == null)
        {
            throw new IllegalArgumentException("Group owner must be specified");
        }
        
        try
        {
            getGroup(group.getID());
@@ -180,7 +169,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
                    {
                       throw new AccessControlException(
                           "Unable to activate group " + group.getID() + 
                           " because " + group.getOwner().getUserID().getName() 
                           " because " + getSubjectDN().toString()
                           + " is not the owner"); 
                    }
                    
@@ -189,10 +178,23 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
                        new Modification(ModificationType.DELETE, 
                                         "nsaccountlock");
                    mods.add(mod);
                    
                    Group modifiedGroup = modifyGroup(group, inactiveGroup, 
                                                      mods);
                    Group activatedGroup = 
                        modifyGroup(group, inactiveGroup, mods);
                    return new ActivatedGroup(activatedGroup.getID(),
                                              activatedGroup.getOwner());
                            new ActivatedGroup(modifiedGroup.getID(),
                                               modifiedGroup.getOwner());
                    activatedGroup.description = modifiedGroup.description;
                    activatedGroup.publicRead = modifiedGroup.publicRead;
                    activatedGroup.groupRead = modifiedGroup.groupRead;
                    activatedGroup.groupWrite = modifiedGroup.groupWrite;
                    activatedGroup.getProperties()
                            .addAll(modifiedGroup.getProperties());
                    activatedGroup.getGroupMembers()
                            .addAll(modifiedGroup.getGroupMembers());
                    activatedGroup.getUserMembers()
                            .addAll(modifiedGroup.getUserMembers());
                    return activatedGroup;
                }
                catch (GroupNotFoundException ignore) {}
                
@@ -300,108 +302,20 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
    }

    /**
     * Deletes the group.
     * Get the group with the given Group ID.
     * 
     * @param groupID The group to delete
     * @param groupID The Group unique ID.
     * 
     * @return A Group instance
     * 
     * @throws GroupNotFoundException If the group was not found.
     * @throws TransientException  If an temporary, unexpected problem occurred.
     */
    public void deleteGroup(String groupID)
    public Group getGroup(String groupID)
        throws GroupNotFoundException, TransientException,
               AccessControlException
    {
        Group group = getGroup(groupID);
        List<Modification> modifs = new ArrayList<Modification>();
        modifs.add(new Modification(ModificationType.ADD, "nsaccountlock", "true"));
        
        if (group.description != null)
        {
            modifs.add(new Modification(ModificationType.DELETE, "description"));
        }
        
        if (group.groupRead != null || 
            group.groupWrite != null || 
            group.publicRead)
        {
            modifs.add(new Modification(ModificationType.DELETE, "aci"));
        }
        
        if (!group.getGroupMembers().isEmpty() || 
            !group.getUserMembers().isEmpty())
        {
            modifs.add(new Modification(ModificationType.DELETE, "uniquemember"));
        }

        ModifyRequest modifyRequest = 
                new ModifyRequest(getGroupDN(group.getID()), modifs);
        try
        {
            modifyRequest.addControl(
                    new ProxiedAuthorizationV2RequestControl(
                            "dn:" + getSubjectDN().toNormalizedString()));
            LDAPResult result = getConnection().modify(modifyRequest);
        }
        catch (LDAPException e1)
        {
            throw new RuntimeException("LDAP problem", e1);
        }
        
        try
        {
            getGroup(group.getID());
            throw new RuntimeException("BUG: group not deleted " + 
                                       group.getID());
        }
        catch (GroupNotFoundException ignore) {}
    }
    
    /**
     * Obtain a Collection of Groups that fit the given query.
     * 
     * @param userID The userID.
     * @param role Role of the user, either owner, member, or read/write.
     * @param groupID The Group ID.
     * 
     * @return Collection of Groups
     *         matching GROUP_READ_ACI.replace(ACTUAL_GROUP_TOKEN,
     *         readGrDN.toNormalizedString()) the query, or empty
     *         Collection. Never null.
     * @throws TransientException  If an temporary, unexpected problem occurred.
     * @throws UserNotFoundException
     * @throws GroupNotFoundException
     */
    public Collection<Group> searchGroups(T userID, Role role, String groupID)
        throws TransientException, AccessControlException,
               GroupNotFoundException, UserNotFoundException
    {
        User<T> user = new User<T>(userID);
        DN userDN;
        try
        {   
            userDN = userPersist.getUserDN(user);
        }
        catch (LDAPException e)
        {
            // TODO check which LDAP exceptions are transient and which
            // ones are
            // access control
            throw new TransientException("Error getting user", e);
        }
        
        if (role == Role.OWNER)
        {
            return getOwnerGroups(user, userDN, groupID);
        }
        else if (role == Role.MEMBER)
        {
            return getMemberGroups(user, userDN, groupID);
        }
        else if (role == Role.RW)
        {
            return getRWGroups(user, userDN, groupID);
        }
        throw new IllegalArgumentException("Unknown role " + role);
        return getGroup(groupID, true);
    }

    private Group getGroup(String groupID, boolean withMembers)
@@ -462,17 +376,17 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
                        DN memberDN = new DN(member);
                        if (memberDN.isDescendantOf(config.getUsersDN(), false))
                        {
                            User<X500Principal> usr;
                            User<X500Principal> user;
                            try
                            {
                                usr = userPersist.getMember(memberDN);
                                user = userPersist.getMember(memberDN);
                            }
                            catch (UserNotFoundException e)
                            {
                                throw new RuntimeException(
                                    "BUG: group member not found");
                            }
                            ldapGroup.getUserMembers().add(usr);
                            ldapGroup.getUserMembers().add(user);
                        }
                        else if (memberDN.isDescendantOf(config.getGroupsDN(),
                                                         false))
@@ -582,7 +496,12 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
            modifs.add(new Modification(ModificationType.DELETE, 
                                        "description"));
        }
        else if (newGroup.description != null)
        else if (newGroup.description != null && oldGroup.description == null)
        {
            modifs.add(new Modification(ModificationType.ADD, "description", 
                                        newGroup.description));
        }
        else if (newGroup.description != null && oldGroup.description != null)
        {
            modifs.add(new Modification(ModificationType.REPLACE, "description", 
                                        newGroup.description));
@@ -705,54 +624,113 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
        }
        catch (GroupNotFoundException e)
        {
            throw new RuntimeException("BUG: new group not found");
            throw new RuntimeException("BUG: modified group not found");
        }
    }

    /**
     * Returns a group based on its LDAP DN. The returned group is bared
     * (contains only group ID, owner and description).
     * Deletes the group.
     * 
     * @param groupDN
     * @return
     * @throws com.unboundid.ldap.sdk.LDAPException
     * @throws ca.nrc.cadc.ac.GroupNotFoundException
     * @throws ca.nrc.cadc.ac.UserNotFoundException
     * @param groupID The group to delete
     * 
     * @throws GroupNotFoundException If the group was not found.
     * @throws TransientException If an temporary, unexpected problem occurred.
     */
    protected Group getGroup(DN groupDN)
        throws LDAPException, GroupNotFoundException, UserNotFoundException
    public void deleteGroup(String groupID)
        throws GroupNotFoundException, TransientException,
               AccessControlException
    {
        SearchResultEntry searchResult = 
                getConnection().getEntry(groupDN.toNormalizedString(),
                                new String[] {"cn", "description", "owner", 
                                              "modifytimestamp"});
        Group group = getGroup(groupID);
        List<Modification> modifs = new ArrayList<Modification>();
        modifs.add(new Modification(ModificationType.ADD, "nsaccountlock", "true"));
        
        if (searchResult == null)
        if (group.description != null)
        {
            String msg = "Group not found " + groupDN;
            logger.debug(msg);
            throw new GroupNotFoundException(groupDN.toNormalizedString());
            modifs.add(new Modification(ModificationType.DELETE, "description"));
        }
        
        DN ownerDN = searchResult.getAttributeValueAsDN("owner");
        User<X500Principal> owner = userPersist.getMember(ownerDN);
        Group group = new Group(searchResult.getAttributeValue("cn"), owner);
        group.description = searchResult.getAttributeValue("description");
        group.lastModified = 
                searchResult.getAttributeValueAsDate("modifytimestamp");
        return group;
        if (group.groupRead != null || 
            group.groupWrite != null || 
            group.publicRead)
        {
            modifs.add(new Modification(ModificationType.DELETE, "aci"));
        }
        
    protected DN getGroupDN(String groupID)
        if (!group.getGroupMembers().isEmpty() || 
            !group.getUserMembers().isEmpty())
        {
            modifs.add(new Modification(ModificationType.DELETE, "uniquemember"));
        }

        ModifyRequest modifyRequest = 
                new ModifyRequest(getGroupDN(group.getID()), modifs);
        try
        {
            modifyRequest.addControl(
                    new ProxiedAuthorizationV2RequestControl(
                            "dn:" + getSubjectDN().toNormalizedString()));
            LDAPResult result = getConnection().modify(modifyRequest);
        }
        catch (LDAPException e1)
        {
            throw new RuntimeException("LDAP problem", e1);
        }
        
        try
        {
            return new DN("cn=" + groupID + "," + config.getGroupsDN());
            getGroup(group.getID());
            throw new RuntimeException("BUG: group not deleted " + 
                                       group.getID());
        }
        catch (GroupNotFoundException ignore) {}
    }
    
    /**
     * Obtain a Collection of Groups that fit the given query.
     * 
     * @param userID The userID.
     * @param role Role of the user, either owner, member, or read/write.
     * @param groupID The Group ID.
     * 
     * @return Collection of Groups
     *         matching GROUP_READ_ACI.replace(ACTUAL_GROUP_TOKEN,
     *         readGrDN.toNormalizedString()) the query, or empty
     *         Collection. Never null.
     * @throws TransientException  If an temporary, unexpected problem occurred.
     * @throws UserNotFoundException
     * @throws GroupNotFoundException
     */
    public Collection<Group> searchGroups(T userID, Role role, String groupID)
        throws TransientException, AccessControlException,
               GroupNotFoundException, UserNotFoundException
    {
        User<T> user = new User<T>(userID);
        DN userDN;
        try
        {   
            userDN = userPersist.getUserDN(user);
        }
        catch (LDAPException e)
        {
            // TODO check which LDAP exceptions are transient and which
            // ones are
            // access control
            throw new TransientException("Error getting user", e);
        }
        throw new IllegalArgumentException(groupID + " not a valid group ID");
        
        if (role == Role.OWNER)
        {
            return getOwnerGroups(user, userDN, groupID);
        }
        else if (role == Role.MEMBER)
        {
            return getMemberGroups(user, userDN, groupID);
        }
        else if (role == Role.RW)
        {
            return getRWGroups(user, userDN, groupID);
        }
        throw new IllegalArgumentException("Unknown role " + role);
    }
    
    protected Collection<Group> getOwnerGroups(User<T> user, DN userDN,
@@ -1020,7 +998,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
        
        if (searchResult == null)
        {
            String msg = "Group not found " + groupID;
            String msg = "Inactive Group not found " + groupID;
            logger.debug(msg);
            throw new GroupNotFoundException(msg);
        }
@@ -1033,4 +1011,45 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO
        return new Group(groupCN, owner);
    }

    /**
     * Returns a group based on its LDAP DN. The returned group is bare
     * (contains only group ID, description, modifytimestamp).
     * 
     * @param groupDN
     * @return
     * @throws com.unboundid.ldap.sdk.LDAPException
     * @throws ca.nrc.cadc.ac.GroupNotFoundException
     * @throws ca.nrc.cadc.ac.UserNotFoundException
     */
    protected Group getGroup(DN groupDN)
        throws LDAPException, GroupNotFoundException, UserNotFoundException
    {
        SearchResultEntry searchResult = 
                getConnection().getEntry(groupDN.toNormalizedString(),
                                new String[] {"cn", "description"});

        if (searchResult == null)
        {
            String msg = "Group not found " + groupDN;
            logger.debug(msg);
            throw new GroupNotFoundException(groupDN.toNormalizedString());
        }

        Group group = new Group(searchResult.getAttributeValue("cn"));
        group.description = searchResult.getAttributeValue("description");
        return group;
    }

    protected DN getGroupDN(String groupID)
    {
        try
        {
            return new DN("cn=" + groupID + "," + config.getGroupsDN());
        }
        catch (LDAPException e)
        {
        }
        throw new IllegalArgumentException(groupID + " not a valid group ID");
    }

}
+29 −11
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ 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;
@@ -138,7 +139,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
                    new String[] {"cn", "entryid", "entrydn", "dn"});

            searchRequest.addControl(
                    new ProxiedAuthorizationV1RequestControl(getSubjectDN()));
                    new ProxiedAuthorizationV2RequestControl("dn:" + 
                            getSubjectDN().toNormalizedString()));

            searchResult = getConnection().searchForEntry(searchRequest);
        }
@@ -198,7 +200,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
                                      filter, new String[] {"memberOf"});

            searchRequest.addControl(
                    new ProxiedAuthorizationV1RequestControl(getSubjectDN()));
                    new ProxiedAuthorizationV2RequestControl("dn:" + 
                            getSubjectDN().toNormalizedString()));

            SearchResultEntry searchResult = 
                    getConnection().searchForEntry(searchRequest);
@@ -271,7 +274,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
                                      filter, new String[] {"cn"});

            searchRequest.addControl(
                    new ProxiedAuthorizationV1RequestControl(getSubjectDN()));
                    new ProxiedAuthorizationV2RequestControl("dn:" + 
                            getSubjectDN().toNormalizedString()));
            
            SearchResultEntry searchResults = 
                    getConnection().searchForEntry(searchRequest);
@@ -312,7 +316,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
                                      "memberOf", groupID);
            
            compareRequest.addControl(
                    new ProxiedAuthorizationV1RequestControl(getSubjectDN()));
                    new ProxiedAuthorizationV2RequestControl("dn:" + 
                            getSubjectDN().toNormalizedString()));
            
            CompareResult compareResult = 
                    getConnection().compare(compareRequest);
@@ -337,11 +342,23 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
    User<X500Principal> getMember(DN userDN)
        throws UserNotFoundException, LDAPException
    {
        SearchResultEntry searchResult = getConnection().getEntry(
                userDN.toNormalizedString(), 
        Filter filter = 
            Filter.createEqualityFilter("entrydn", 
                                        userDN.toNormalizedString());
        
        SearchRequest searchRequest = 
                new SearchRequest(this.config.getUsersDN(), SearchScope.SUB, 
                                  filter, 
                                  (String[]) this.attribType.values().toArray(
                                  new String[this.attribType.values().size()]));
        
        searchRequest.addControl(
                    new ProxiedAuthorizationV2RequestControl("dn:" + 
                            getSubjectDN().toNormalizedString()));
        
        SearchResultEntry searchResult = 
                getConnection().searchForEntry(searchRequest);

        if (searchResult == null)
        {
            String msg = "User not found " + userDN;
@@ -373,7 +390,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
                                 searchField, new String[] {"entrydn"});
        
        searchRequest.addControl(
                new ProxiedAuthorizationV1RequestControl(getSubjectDN()));
                    new ProxiedAuthorizationV2RequestControl("dn:" + 
                            getSubjectDN().toNormalizedString()));

        SearchResultEntry searchResult = 
                getConnection().searchForEntry(searchRequest);
+11 −9
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@

package ca.nrc.cadc.ac.server.ldap;

import static ca.nrc.cadc.ac.server.ldap.LdapGroupDAOTest.config;
import static org.junit.Assert.assertTrue;

import java.security.PrivilegedExceptionAction;
@@ -84,13 +85,14 @@ import com.unboundid.ldap.sdk.LDAPConnection;

public class LdapDAOTest
{
    LdapConfig config = new LdapConfig(
            "mach275.cadc.dao.nrc.ca",
            389,
            "uid=webproxy,ou=administrators,ou=topologymanagement,o=netscaperoot",
            "go4it", "ou=Users,ou=ds,dc=canfar,dc=net",
            "ou=Groups,ou=ds,dc=canfar,dc=net",
            "ou=DeletedGroups,ou=ds,dc=canfar,dc=net");
    static String server = "mach275.cadc.dao.nrc.ca";
    static int port = 389;
    static String adminDN = "uid=webproxy,ou=administrators,ou=topologymanagement,o=netscaperoot";
    static String adminPW = "go4it";
    static String userBaseDN = "ou=Users,ou=ds,dc=canfartest,dc=net";
    static String groupBaseDN = "ou=Groups,ou=ds,dc=canfartest,dc=net";
    
    LdapConfig config = new LdapConfig(server, port, adminDN, adminPW, userBaseDN, groupBaseDN);
    
    @Test
    public void testLdapBindConnection() throws Exception
@@ -99,7 +101,7 @@ public class LdapDAOTest
        //LdapUserDAO<X500Principal> userDAO = new LdapUserDAO<X500Principal>();

        // User authenticated with HttpPrincipal
        HttpPrincipal httpPrincipal = new HttpPrincipal("cadcauthtest2");
        HttpPrincipal httpPrincipal = new HttpPrincipal("CadcDaoTest1");
        Subject subject = new Subject();

        subject.getPrincipals().add(httpPrincipal);
@@ -125,7 +127,7 @@ public class LdapDAOTest
               
        
        X500Principal subjPrincipal = new X500Principal(
                "cn=cadc authtest2 10635,ou=cadc,o=hia");
                "cn=cadcdaotest1,ou=cadc,o=hia,c=ca");
        subject = new Subject();
        subject.getPrincipals().add(subjPrincipal);
        
Loading