diff --git a/projects/cadcAccessControl-Server/build.xml b/projects/cadcAccessControl-Server/build.xml index 9f319e5247c77ef09e92925b8bc55aa9f3ba2153..61e94bf0246cb0ab060277064d6719988a357ca0 100644 --- a/projects/cadcAccessControl-Server/build.xml +++ b/projects/cadcAccessControl-Server/build.xml @@ -145,6 +145,7 @@ <!--<test name="ca.nrc.cadc.ac.server.ldap.LdapDAOTestImpl" />--> <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" />--> <formatter type="plain" usefile="false" /> </junit> </target> diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java index 70556c684c7075afd4aafe4ddbc1191e67b4f2df..970749fdc63d7b5b19d1fa17861582ff6631c331 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/GroupPersistence.java @@ -71,8 +71,8 @@ package ca.nrc.cadc.ac.server; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.GroupNotFoundException; +import ca.nrc.cadc.ac.IdentityType; import ca.nrc.cadc.ac.Role; -import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.net.TransientException; import java.security.AccessControlException; @@ -145,35 +145,21 @@ public abstract interface GroupPersistence<T extends Principal> /** * Obtain a Collection of Groups that fit the given query. * - * @param user user + * @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 the query, or empty Collection. * Never null. * * @throws UserNotFoundException If owner or group members not valid users. + * @throws ca.nrc.cadc.ac.GroupNotFoundException * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ - public abstract Collection<Group> getGroups(User<T> user, Role role) - throws UserNotFoundException, TransientException, - AccessControlException; - - /** - * Check whether the user is a member of the group. - * - * @param user user - * @param groupID ID of group - * - * @return true or false - * - * @throws GroupNotFoundException If the group was not found. - * @throws TransientException If an temporary, unexpected problem occurred. - * @throws AccessControlException If the operation is not permitted. - * @throws ca.nrc.cadc.ac.UserNotFoundException - */ - public abstract boolean isMember(User<T> user, String groupID) - throws GroupNotFoundException, TransientException, - AccessControlException, UserNotFoundException; + public abstract Collection<Group> searchGroups(T userID, Role role, + String groupID) + throws UserNotFoundException, GroupNotFoundException, + TransientException, AccessControlException; } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/RequestValidator.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/RequestValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..cf0314829fde491147778ba8d6cc03fba197f7ad --- /dev/null +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/RequestValidator.java @@ -0,0 +1,179 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * <http://www.gnu.org/licenses/>. pas le cas, consultez : + * <http://www.gnu.org/licenses/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */ +package ca.nrc.cadc.ac.server; + +import ca.nrc.cadc.ac.IdentityType; +import ca.nrc.cadc.ac.Role; +import ca.nrc.cadc.uws.Parameter; +import ca.nrc.cadc.uws.ParameterUtil; +import java.util.List; +import org.apache.log4j.Logger; + +/** + * Request Validator. This class extracts and validates the ID, TYPE, ROLE + * and GURI parameters. + * + */ +public class RequestValidator +{ + private static final Logger log = Logger.getLogger(RequestValidator.class); + + private String id; + private IdentityType type; + private Role role; + private String guri; + + public RequestValidator() { } + + private void clear() + { + this.id = null; + this.type = null; + this.role = null; + this.guri = null; + } + + public void validate(List<Parameter> paramList) + { + clear(); + if (paramList == null || paramList.isEmpty()) + { + throw new IllegalArgumentException( + "Missing required parameters: ID and TYPE"); + } + + // ID + String param = ParameterUtil.findParameterValue("ID", paramList); + if (param == null || param.trim().isEmpty()) + { + throw new IllegalArgumentException( + "ID parameter required but not found"); + } + this.id = param.trim(); + log.debug("ID: " + id); + + // TYPE + param = ParameterUtil.findParameterValue("TYPE", paramList); + if (param == null || param.trim().isEmpty()) + { + throw new IllegalArgumentException( + "TYPE parameter required but not found"); + } + this.type = IdentityType.toValue(param); + log.debug("TYPE: " + type); + + // ROLE + param = ParameterUtil.findParameterValue("ROLE", paramList); + if (param == null || param.trim().isEmpty()) + { + throw new IllegalArgumentException( + "ROLE parameter required but not found"); + } + this.role = Role.toValue(param); + log.debug("ROLE: " + role); + + // GURI + param = ParameterUtil.findParameterValue("GURI", paramList); + if (param != null) + { + if (param.isEmpty()) + throw new IllegalArgumentException( + "GURI parameter specified without a value"); + this.guri = param.trim(); + } + log.debug("GURI: " + guri); + + if (role != null && guri != null) + { + throw new IllegalArgumentException( + "ROLE and GURI cannot be used in the same search"); + } + } + + public String getId() + { + return id; + } + + public IdentityType getType() + { + return type; + } + + public Role getRole() + { + return role; + } + + public String getGUri() + { + return guri; + } + +} diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java index 9409fc26591fe96fc054ecee6d753e27c6fc8e43..8db06efab2dc59e6f990b921b89c5fdd34157368 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java @@ -68,11 +68,13 @@ */ package ca.nrc.cadc.ac.server; +import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.net.TransientException; import java.security.AccessControlException; import java.security.Principal; +import java.util.Collection; public abstract interface UserPersistence<T extends Principal> { @@ -82,11 +84,41 @@ public abstract interface UserPersistence<T extends Principal> * @param userID The userID. * * @return User instance. - * @throws UserNotFoundException when the member is not found. + * + * @throws UserNotFoundException when the user is not found. * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ public abstract User<T> getUser(T userID) throws UserNotFoundException, TransientException, AccessControlException; + /** + * Get all groups the user specified by userID belongs to. + * + * @param userID The userID. + * + * @return Collection of Group instances. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public abstract Collection<Group> getUserGroups(T userID) + throws UserNotFoundException, TransientException, AccessControlException; + + /** + * Check whether the user is a member of the group. + * + * @param userID The userID. + * @param groupID The groupID. + * + * @return true or false + * + * @throws UserNotFoundException If the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public abstract boolean isMember(T userID, String groupID) + throws UserNotFoundException, TransientException, + AccessControlException; } 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 e6eb7d66f9b5869c5c4eb532e8ce4f15b4b2019e..78382666d69097bc1fa587bdcb716fd44b5b76ed 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 @@ -68,6 +68,7 @@ */ package ca.nrc.cadc.ac.server.ldap; +import ca.nrc.cadc.ac.ActivatedGroup; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.GroupNotFoundException; @@ -83,7 +84,6 @@ import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.LDAPResult; import com.unboundid.ldap.sdk.Modification; import com.unboundid.ldap.sdk.ModificationType; -import com.unboundid.ldap.sdk.ModifyDNRequest; import com.unboundid.ldap.sdk.ModifyRequest; import com.unboundid.ldap.sdk.SearchRequest; import com.unboundid.ldap.sdk.SearchResult; @@ -169,7 +169,33 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO catch (GroupNotFoundException ex) { try - { + { + try + { + Group inactiveGroup = getInactiveGroup(group.getID()); + + // Check requestor owns the group. + DN ownerDN = userPersist.getUserDN(group.getOwner()); + if (!ownerDN.equals(getSubjectDN())) + { + throw new AccessControlException( + "Unable to activate group " + group.getID() + + " because " + group.getOwner().getUserID().getName() + + " is not the owner"); + } + + List<Modification> mods = new ArrayList<Modification>(); + Modification mod = + new Modification(ModificationType.DELETE, + "nsaccountlock"); + mods.add(mod); + Group activatedGroup = + modifyGroup(group, inactiveGroup, mods); + return new ActivatedGroup(activatedGroup.getID(), + activatedGroup.getOwner()); + } + catch (GroupNotFoundException ignore) {} + if (!group.getProperties().isEmpty()) { throw new UnsupportedOperationException( @@ -285,19 +311,36 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO throws GroupNotFoundException, TransientException, AccessControlException { - Group group = getGroup(groupID, false); - DN groupDN = getGroupDN(group.getID()); - try + Group group = getGroup(groupID); + List<Modification> modifs = new ArrayList<Modification>(); + modifs.add(new Modification(ModificationType.ADD, "nsaccountlock", "true")); + + if (group.description != null) { - ModifyDNRequest modifyDNRequest = new ModifyDNRequest( - group.getID(), group.getID(), - true, config.getDeletedGroupsDN()); - - modifyDNRequest.addControl( - new ProxiedAuthorizationV2RequestControl("dn:" + - getSubjectDN().toNormalizedString())); + 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")); + } - LDAPResult result = getConnection().modifyDN(modifyDNRequest); + ModifyRequest modifyRequest = + new ModifyRequest(getGroupDN(group.getID()), modifs); + try + { + modifyRequest.addControl( + new ProxiedAuthorizationV2RequestControl( + "dn:" + getSubjectDN().toNormalizedString())); + LDAPResult result = getConnection().modify(modifyRequest); } catch (LDAPException e1) { @@ -312,12 +355,13 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } catch (GroupNotFoundException ignore) {} } - + /** * Obtain a Collection of Groups that fit the given query. * - * @param user<T> ID of user + * @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, @@ -325,88 +369,39 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO * Collection. Never null. * @throws TransientException If an temporary, unexpected problem occurred. * @throws UserNotFoundException + * @throws GroupNotFoundException */ - public Collection<Group> getGroups(User<T> user, Role role) + public Collection<Group> searchGroups(T userID, Role role, String groupID) throws TransientException, AccessControlException, - UserNotFoundException + GroupNotFoundException, UserNotFoundException { + User<T> user = new User<T>(userID); + DN userDN; try { - DN userDN = userPersist.getUserDN(user); - Filter filter = null; - if (role == Role.OWNER) - { - filter = Filter.createEqualityFilter("owner", userDN.toString()); - } - else if (role == Role.MEMBER) - { - throw new IllegalArgumentException("Member role not implemented"); - } - else if (role == Role.RW) - { - throw new IllegalArgumentException("RW role not implemented"); - } - - SearchRequest searchRequest = new SearchRequest( - config.getGroupsDN(), SearchScope.SUB, filter, - new String[] {"cn", "description", - "owner", "modifytimestamp"}); - - searchRequest.addControl( - new ProxiedAuthorizationV2RequestControl("dn:" + - getSubjectDN().toNormalizedString())); - - Collection<Group> groups = new ArrayList<Group>(); - SearchResult results = getConnection().search(searchRequest); - for (SearchResultEntry result : results.getSearchEntries()) - { - String groupName = result.getAttributeValue("cn"); - DN groupOwner = result.getAttributeValueAsDN("owner"); - - User<X500Principal> owner; - try - { - owner = userPersist.getMember(groupOwner); - } - catch (UserNotFoundException e) - { - throw new RuntimeException("BUG: group owner not found"); - } - - Group group = new Group(groupName, owner); - group.description = result.getAttributeValue("description"); - group.lastModified = result.getAttributeValueAsDate("modifytimestamp"); - groups.add(group); - } - - return groups; + userDN = userPersist.getUserDN(user); } - catch (LDAPException e1) + catch (LDAPException e) { // TODO check which LDAP exceptions are transient and which // ones are // access control - throw new TransientException("Error getting groups", e1); + throw new TransientException("Error getting user", e); } - } - - public boolean isMember(User<T> user, String groupID) - throws UserNotFoundException, TransientException, - AccessControlException - { - return false; -// try -// { -// -// -// } -// catch (LDAPException e1) -// { -// // TODO check which LDAP exceptions are transient and which -// // ones are -// // access control -// throw new TransientException("Error getting the group", e1); -// } + + 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); } private Group getGroup(String groupID, boolean withMembers) @@ -415,11 +410,16 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO { try { + Filter filter = Filter.createANDFilter( + Filter.createEqualityFilter("cn", groupID), + Filter.createNOTFilter( + Filter.createEqualityFilter("nsaccountlock", "true"))); + SearchRequest searchRequest = new SearchRequest( config.getGroupsDN(), SearchScope.SUB, - "(cn=" + groupID + ")", new String[] {"entrydn", "entryid", - "cn", "description", "owner", "uniquemember", "aci", - "modifytimestamp"}); + filter, new String[] {"entrydn", "cn", "description", + "owner", "uniquemember", "aci", + "modifytimestamp"}); searchRequest.addControl( new ProxiedAuthorizationV2RequestControl("dn:" + @@ -435,7 +435,6 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } String groupCN = group.getAttributeValue("cn"); DN groupOwner = group.getAttributeValueAsDN("owner"); - Long grID = group.getAttributeValueAsLong("entryid"); Date lastModified = group.getAttributeValueAsDate("modifytimestamp"); @@ -523,7 +522,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } } } - + return ldapGroup; } catch (LDAPException e1) @@ -539,58 +538,84 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } } + /** + * Modify the given group. + * + * @param group The group to update. + * + * @return The newly updated group. + * + * @throws GroupNotFoundException If the group was not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + * @throws UserNotFoundException If owner or group members not valid users. + */ public Group modifyGroup(Group group) throws GroupNotFoundException, TransientException, AccessControlException, UserNotFoundException { // check if group exists Group oldGroup = getGroup(group.getID()); - if (!group.getProperties().isEmpty()) + + return modifyGroup(group, oldGroup, null); + } + + private Group modifyGroup(Group newGroup, Group oldGroup, + List<Modification> modifications) + throws UserNotFoundException, TransientException, + AccessControlException + { + if (!newGroup.getProperties().isEmpty()) { throw new UnsupportedOperationException( "Support for groups properties not available"); } List<Modification> modifs = new ArrayList<Modification>(); - if (group.description == null) + if (modifications != null) + { + modifs.addAll(modifications); + } + + if (newGroup.description == null && oldGroup.description != null) { modifs.add(new Modification(ModificationType.DELETE, "description")); } - else + else if (newGroup.description != null) { modifs.add(new Modification(ModificationType.REPLACE, "description", - group.description)); + newGroup.description)); } List<String> acis = new ArrayList<String>(); - if (group.groupRead != null) + if (newGroup.groupRead != null) { - if (group.groupRead.equals(group)) + if (newGroup.groupRead.equals(newGroup)) { throw new IllegalArgumentException( "cyclical reference from groupRead to group"); } - DN readGrDN = getGroupDN(group.groupRead.getID()); + DN readGrDN = getGroupDN(newGroup.groupRead.getID()); acis.add(GROUP_READ_ACI.replace(ACTUAL_GROUP_TOKEN, readGrDN.toNormalizedString())); } - if (group.groupWrite != null) + if (newGroup.groupWrite != null) { - if (group.groupWrite.equals(group)) + if (newGroup.groupWrite.equals(newGroup)) { throw new IllegalArgumentException( "cyclical reference from groupWrite to group"); } - DN writeGrDN = getGroupDN(group.groupWrite.getID()); + DN writeGrDN = getGroupDN(newGroup.groupWrite.getID()); acis.add(GROUP_WRITE_ACI.replace(ACTUAL_GROUP_TOKEN, writeGrDN.toNormalizedString())); } - if (group.publicRead) + if (newGroup.publicRead) { acis.add(PUB_GROUP_ACI); } @@ -598,7 +623,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO acis.toArray(new String[acis.size()]))); List<String> newMembers = new ArrayList<String>(); - for (User<?> member : group.getUserMembers()) + for (User<?> member : newGroup.getUserMembers()) { if (!oldGroup.getUserMembers().remove(member)) { @@ -615,9 +640,9 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO newMembers.add(memberDN.toNormalizedString()); } } - for (Group gr : group.getGroupMembers()) + for (Group gr : newGroup.getGroupMembers()) { - if (gr.equals(group)) + if (gr.equals(newGroup)) { throw new IllegalArgumentException( "cyclical reference from group member to group"); @@ -662,7 +687,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } ModifyRequest modifyRequest = - new ModifyRequest(getGroupDN(group.getID()), modifs); + new ModifyRequest(getGroupDN(newGroup.getID()), modifs); try { modifyRequest.addControl( @@ -676,7 +701,7 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } try { - return getGroup(group.getID()); + return getGroup(newGroup.getID()); } catch (GroupNotFoundException e) { @@ -697,11 +722,10 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO protected Group getGroup(DN groupDN) throws LDAPException, GroupNotFoundException, UserNotFoundException { - SearchResultEntry searchResult = null; - - searchResult = + SearchResultEntry searchResult = getConnection().getEntry(groupDN.toNormalizedString(), - new String[] {"cn", "description", "owner"}); + new String[] {"cn", "description", "owner", + "modifytimestamp"}); if (searchResult == null) { @@ -713,7 +737,9 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO 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; } @@ -728,5 +754,283 @@ public class LdapGroupDAO<T extends Principal> extends LdapDAO } throw new IllegalArgumentException(groupID + " not a valid group ID"); } + + protected Collection<Group> getOwnerGroups(User<T> user, DN userDN, + String groupID) + throws TransientException, AccessControlException, + GroupNotFoundException, UserNotFoundException + { + try + { + Filter filter = Filter.createEqualityFilter("owner", + userDN.toString()); + if (groupID != null) + { + getGroup(groupID); + filter = Filter.createANDFilter(filter, + Filter.createEqualityFilter("cn", groupID)); + } + + SearchRequest searchRequest = new SearchRequest( + config.getGroupsDN(), SearchScope.SUB, filter, + new String[] {"cn", "description", "modifytimestamp"}); + + searchRequest.addControl( + new ProxiedAuthorizationV2RequestControl("dn:" + + getSubjectDN().toNormalizedString())); + + Collection<Group> groups = new ArrayList<Group>(); + SearchResult results = getConnection().search(searchRequest); + for (SearchResultEntry result : results.getSearchEntries()) + { + String groupName = result.getAttributeValue("cn"); + // Ignore existing illegal group names. + try + { + Group group = new Group(groupName, user); + group.description = result.getAttributeValue("description"); + group.lastModified = + result.getAttributeValueAsDate("modifytimestamp"); + groups.add(group); + } + catch (IllegalArgumentException ignore) { } + } + + return groups; + } + catch (LDAPException e1) + { + // TODO check which LDAP exceptions are transient and which + // ones are + // access control + throw new TransientException("Error getting groups", e1); + } + } + + protected Collection<Group> getMemberGroups(User<T> user, DN userDN, + String groupID) + throws TransientException, AccessControlException, + GroupNotFoundException, UserNotFoundException + { + if (groupID != null) + { + Collection<Group> groups = new ArrayList<Group>(); + if (userPersist.isMember(user.getUserID(), groupID)) + { + groups.add(getGroup(groupID)); + } + return groups; + } + else + { + return userPersist.getUserGroups(user.getUserID()); + } + } + + protected Collection<Group> getRWGroups(User<T> user, DN userDN, + String groupID) + throws TransientException, AccessControlException, + GroupNotFoundException, UserNotFoundException + { + try + { + Collection<Group> queryGroups = new ArrayList<Group>(); + if (groupID != null) + { + queryGroups.add(new Group(groupID, user)); + } + else + { + // List of Groups the user belongs to. + queryGroups.addAll(getMemberGroups(user, userDN, groupID)); + + // List of Groups the user owns; + queryGroups.addAll(getOwnerGroups(user, userDN, groupID)); + } + + System.out.println("# groups: " + queryGroups.size()); + + List<Filter> filters = new ArrayList<Filter>(); + for (Group member : queryGroups) + { + // Require both groupRead and groupWrite + if (member.groupRead != null && member.groupWrite != null) + { + DN groupRead = getGroupDN(member.groupRead.getID()); + String groupReadAci = + GROUP_READ_ACI.replace(ACTUAL_GROUP_TOKEN, + groupRead.toNormalizedString()); + DN groupWrite = getGroupDN(member.groupRead.getID()); + String groupWriteAci = + GROUP_WRITE_ACI.replace(ACTUAL_GROUP_TOKEN, + groupWrite.toNormalizedString()); + System.out.println(groupReadAci); + System.out.println(groupWriteAci); + + Filter filter = Filter.createANDFilter( + Filter.createEqualityFilter("aci", groupReadAci), + Filter.createEqualityFilter("aci", groupWriteAci)); + filters.add(filter); + } + } + + Collection<Group> groups = new ArrayList<Group>(); + if (filters.isEmpty()) + { + return groups; + } + + Filter filter = Filter.createORFilter(filters); + SearchRequest searchRequest = new SearchRequest( + config.getGroupsDN(), SearchScope.SUB, filter, + new String[] {"cn", "owner", "description", + "modifytimestamp"}); + + searchRequest.addControl( + new ProxiedAuthorizationV2RequestControl("dn:" + + getSubjectDN().toNormalizedString())); + + SearchResult results = getConnection().search(searchRequest); + for (SearchResultEntry result : results.getSearchEntries()) + { + String groupName = result.getAttributeValue("cn"); + DN ownerDN = result.getAttributeValueAsDN("owner"); + User<X500Principal> owner = userPersist.getMember(ownerDN); + + // Ignore existing illegal group names. + try + { + Group group = new Group(groupName, owner); + group.description = result.getAttributeValue("description"); + group.lastModified = + result.getAttributeValueAsDate("modifytimestamp"); + groups.add(group); + } + catch (IllegalArgumentException ignore) { } + } + return groups; + } + catch (LDAPException e) + { + // TODO check which LDAP exceptions are transient and which + // ones are + // access control + throw new TransientException("Error getting groups", e); + } + } + + protected Collection<Group> getRWGroups2(User<T> user, DN userDN, + String groupID) + throws TransientException, AccessControlException, + GroupNotFoundException, UserNotFoundException + { + try + { + Collection<Group> groups = new ArrayList<Group>(); + + Collection<Group> queryGroups = new ArrayList<Group>(); + if (groupID != null) + { + queryGroups.add(new Group(groupID, user)); + } + else + { + // List of Groups the user belongs to. + queryGroups.addAll(getMemberGroups(user, userDN, groupID)); + + // List of Groups the user owns; + queryGroups.addAll(getOwnerGroups(user, userDN, groupID)); + } + + for (Group member : queryGroups) + { + // Require both groupRead and groupWrite + if (member.groupRead != null && member.groupWrite != null) + { + DN groupRead = getGroupDN(member.groupRead.getID()); + String groupReadAci = + GROUP_READ_ACI.replace(ACTUAL_GROUP_TOKEN, + groupRead.toNormalizedString()); + DN groupWrite = getGroupDN(member.groupWrite.getID()); + String groupWriteAci = + GROUP_WRITE_ACI.replace(ACTUAL_GROUP_TOKEN, + groupWrite.toNormalizedString()); + + Filter filter = Filter.createANDFilter( + Filter.createEqualityFilter("aci", groupReadAci), + Filter.createEqualityFilter("aci", groupWriteAci)); + + SearchRequest searchRequest = new SearchRequest( + config.getGroupsDN(), SearchScope.SUB, filter, + new String[] {"cn", "owner", "description", + "modifytimestamp"}); + + searchRequest.addControl( + new ProxiedAuthorizationV2RequestControl("dn:" + + getSubjectDN().toNormalizedString())); + + SearchResult results = getConnection().search(searchRequest); + for (SearchResultEntry result : results.getSearchEntries()) + { + String groupName = result.getAttributeValue("cn"); + DN ownerDN = result.getAttributeValueAsDN("owner"); + User<X500Principal> owner = userPersist.getMember(ownerDN); + + // Ignore existing illegal group names. + try + { + Group group = new Group(groupName, owner); + group.description = result.getAttributeValue("description"); + group.lastModified = + result.getAttributeValueAsDate("modifytimestamp"); + groups.add(group); + } + catch (IllegalArgumentException ignore) { } + } + } + } + return groups; + } + catch (LDAPException e1) + { + // TODO check which LDAP exceptions are transient and which + // ones are + // access control + throw new TransientException("Error getting groups", e1); + } + } + + private Group getInactiveGroup(String groupID) + throws UserNotFoundException, GroupNotFoundException, LDAPException + { + Filter filter = Filter.createANDFilter( + Filter.createEqualityFilter("cn", groupID), + Filter.createEqualityFilter("nsaccountlock", "true")); + + SearchRequest searchRequest = new SearchRequest( + config.getGroupsDN(), SearchScope.SUB, + filter, new String[] {"cn", "owner"}); + + searchRequest.addControl( + new ProxiedAuthorizationV2RequestControl("dn:" + + getSubjectDN().toNormalizedString())); + + SearchResultEntry searchResult = + getConnection().searchForEntry(searchRequest); + + if (searchResult == null) + { + String msg = "Group not found " + groupID; + logger.debug(msg); + throw new GroupNotFoundException(msg); + } + + String groupCN = searchResult.getAttributeValue("cn"); + DN groupOwner = searchResult.getAttributeValueAsDN("owner"); + + User<X500Principal> owner = userPersist.getMember(groupOwner); + + return new Group(groupCN, owner); + } } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java index 65386490e3e4148146469e878db5fcd783181864..b45318643f6078e4cfb5d93c2074ae255686752e 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapGroupPersistence.java @@ -71,8 +71,8 @@ package ca.nrc.cadc.ac.server.ldap; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.GroupNotFoundException; +import ca.nrc.cadc.ac.IdentityType; import ca.nrc.cadc.ac.Role; -import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.server.GroupPersistence; import ca.nrc.cadc.net.TransientException; @@ -172,34 +172,15 @@ public class LdapGroupPersistence<T extends Principal> } } - public Collection<Group> getGroups(User<T> user, Role role) - throws UserNotFoundException, TransientException, AccessControlException + public Collection<Group> searchGroups(T userID, Role role, String groupID) + throws UserNotFoundException, GroupNotFoundException, + TransientException, AccessControlException { LdapGroupDAO<T> groupDAO = null; try { groupDAO = new LdapGroupDAO<T>(config, new LdapUserDAO<T>(config)); - Collection<Group> ret = groupDAO.getGroups(user, role); - return ret; - } - finally - { - if (groupDAO != null) - { - groupDAO.close(); - } - } - } - - public boolean isMember(User<T> user, String groupID) - throws GroupNotFoundException, TransientException, - AccessControlException, UserNotFoundException - { - LdapGroupDAO<T> groupDAO = null; - try - { - groupDAO = new LdapGroupDAO<T>(config, new LdapUserDAO<T>(config)); - boolean ret = groupDAO.isMember(user, groupID); + Collection<Group> ret = groupDAO.searchGroups(userID, role, groupID); return ret; } finally 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 645b5fda9829c9bab423a0c2f2b3b64e9437cc69..92849897aaf4556243beab8491ec3c5dabeda8f2 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,13 +68,16 @@ */ package ca.nrc.cadc.ac.server.ldap; +import ca.nrc.cadc.ac.Group; 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; -import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.Filter; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.SearchRequest; import com.unboundid.ldap.sdk.SearchResultEntry; @@ -84,8 +87,8 @@ 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 java.util.Set; import javax.security.auth.x500.X500Principal; import org.apache.log4j.Logger; @@ -106,11 +109,14 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO /** * Get the user specified by userID. - * - * @param userID The unique userID. + * + * @param userID The userID. + * * @return User instance. + * * @throws UserNotFoundException when the user is not found. * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. */ public User<T> getUser(T userID) throws UserNotFoundException, TransientException, AccessControlException @@ -158,6 +164,169 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO return user; } + /** + * Get all groups the user specified by userID belongs to. + * + * @param userID The userID. + * + * @return Collection of Group instances. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public Collection<Group> getUserGroups(T userID) + throws UserNotFoundException, TransientException, AccessControlException + { + try + { + String searchField = (String) attribType.get(userID.getClass()); + if (searchField == null) + { + throw new IllegalArgumentException( + "Unsupported principal type " + userID.getClass()); + } + + User user = getUser(userID); + Filter filter = Filter.createANDFilter( + Filter.createEqualityFilter(searchField, + user.getUserID().getName()), + Filter.createPresenceFilter("memberOf")); + + SearchRequest searchRequest = + new SearchRequest(config.getUsersDN(), SearchScope.SUB, + filter, new String[] {"memberOf"}); + + searchRequest.addControl( + new ProxiedAuthorizationV1RequestControl(getSubjectDN())); + + SearchResultEntry searchResult = + getConnection().searchForEntry(searchRequest); + + Collection<Group> groups = new HashSet<Group>(); + if (searchResult != null) + { + String[] members = + searchResult.getAttributeValues("memberOf"); + if (members != null) + { + for (String member : members) + { + String groupCN = DN.getRDNString(member); + int index = groupCN.indexOf("="); + String groupName = groupCN.substring(index + 1); + // Ignore existing illegal group names. + try + { + groups.add(new Group(groupName, user)); + } + catch (IllegalArgumentException ignore) { } + } + } + } + return groups; + } + catch (LDAPException e) + { + // TODO check which LDAP exceptions are transient and which + // ones are + // access control + throw new TransientException("Error getting user groups", e); + } + } + + /** + * Check whether the user is a member of the group. + * + * @param userID The userID. + * @param groupID The groupID. + * + * @return true or false + * + * @throws UserNotFoundException If the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public boolean isMemberX(T userID, String groupID) + throws UserNotFoundException, TransientException, + AccessControlException + { + try + { + String searchField = (String) attribType.get(userID.getClass()); + if (searchField == null) + { + throw new IllegalArgumentException( + "Unsupported principal type " + userID.getClass()); + } + + User user = getUser(userID); + Filter filter = Filter.createANDFilter( + Filter.createEqualityFilter(searchField, + user.getUserID().getName()), + Filter.createEqualityFilter("memberOf", groupID)); + + SearchRequest searchRequest = + new SearchRequest(config.getUsersDN(), SearchScope.SUB, + filter, new String[] {"cn"}); + + searchRequest.addControl( + new ProxiedAuthorizationV1RequestControl(getSubjectDN())); + + SearchResultEntry searchResults = + getConnection().searchForEntry(searchRequest); + + if (searchResults == null) + { + return false; + } + return true; + } + catch (LDAPException e1) + { + // TODO check which LDAP exceptions are transient and which + // ones are + // access control + throw new TransientException("Error getting the user", e1); + } + } + + public boolean isMember(T userID, String groupID) + throws UserNotFoundException, TransientException, + AccessControlException + { + try + { + String searchField = (String) attribType.get(userID.getClass()); + if (searchField == null) + { + throw new IllegalArgumentException( + "Unsupported principal type " + userID.getClass()); + } + + User user = getUser(userID); + DN userDN = getUserDN(user); + + CompareRequest compareRequest = + new CompareRequest(userDN.toNormalizedString(), + "memberOf", groupID); + + compareRequest.addControl( + new ProxiedAuthorizationV1RequestControl(getSubjectDN())); + + CompareResult compareResult = + getConnection().compare(compareRequest); + return compareResult.compareMatched(); + } + catch (LDAPException e) + { + // TODO check which LDAP exceptions are transient and which + // ones are + // access control + throw new TransientException("Error getting the user", e); + } + } + /** * Returns a member user identified by the X500Principal only. * @param userDN diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java index 4305fbe95a7613d8ba7bba93c93d027813829f29..ae28f5c12315d393aa0b3a87cc329be79344f598 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserPersistence.java @@ -68,12 +68,14 @@ */ package ca.nrc.cadc.ac.server.ldap; +import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.server.UserPersistence; import ca.nrc.cadc.net.TransientException; import java.security.AccessControlException; import java.security.Principal; +import java.util.Collection; import org.apache.log4j.Logger; public class LdapUserPersistence<T extends Principal> @@ -94,6 +96,17 @@ public class LdapUserPersistence<T extends Principal> } } + /** + * Get the user specified by userID. + * + * @param userID The userID. + * + * @return User instance. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ public User<T> getUser(T userID) throws UserNotFoundException, TransientException, AccessControlException { @@ -112,5 +125,67 @@ public class LdapUserPersistence<T extends Principal> } } } + + /** + * Get all groups the user specified by userID belongs to. + * + * @param userID The userID. + * + * @return Collection of Group instances. + * + * @throws UserNotFoundException when the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public Collection<Group> getUserGroups(T userID) + throws UserNotFoundException, TransientException, AccessControlException + { + LdapUserDAO<T> userDAO = null; + try + { + userDAO = new LdapUserDAO<T>(this.config); + Collection<Group> ret = userDAO.getUserGroups(userID); + return ret; + } + finally + { + if (userDAO != null) + { + userDAO.close(); + } + } + } + + /** + * Check whether the user is a member of the group. + * + * @param userID The userID. + * @param groupID The groupID. + * + * @return true or false + * + * @throws UserNotFoundException If the user is not found. + * @throws TransientException If an temporary, unexpected problem occurred. + * @throws AccessControlException If the operation is not permitted. + */ + public boolean isMember(T userID, String groupID) + throws UserNotFoundException, TransientException, + AccessControlException + { + LdapUserDAO<T> userDAO = null; + try + { + userDAO = new LdapUserDAO<T>(this.config); + boolean ret = userDAO.isMember(userID, groupID); + return ret; + } + finally + { + if (userDAO != null) + { + userDAO.close(); + } + } + } } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java index 0c85a4d545adb79824d454fe85d0c7491a238dff..9fac6d11bef93e130d427099ac8e57f4cab7dfa9 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java @@ -68,17 +68,47 @@ */ package ca.nrc.cadc.ac.server.web; +import ca.nrc.cadc.ac.Group; +import ca.nrc.cadc.ac.GroupNotFoundException; +import ca.nrc.cadc.ac.GroupsWriter; +import ca.nrc.cadc.ac.IdentityType; +import ca.nrc.cadc.ac.UserNotFoundException; +import ca.nrc.cadc.ac.server.GroupPersistence; +import ca.nrc.cadc.ac.server.PluginFactory; +import ca.nrc.cadc.ac.server.RequestValidator; +import ca.nrc.cadc.ac.server.UserPersistence; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.NumericPrincipal; +import ca.nrc.cadc.auth.OpenIdPrincipal; +import ca.nrc.cadc.net.TransientException; +import ca.nrc.cadc.uws.ErrorSummary; +import ca.nrc.cadc.uws.ErrorType; +import ca.nrc.cadc.uws.ExecutionPhase; import ca.nrc.cadc.uws.Job; +import ca.nrc.cadc.uws.server.JobNotFoundException; +import ca.nrc.cadc.uws.server.JobPersistenceException; import ca.nrc.cadc.uws.server.JobRunner; import ca.nrc.cadc.uws.server.JobUpdater; import ca.nrc.cadc.uws.server.SyncOutput; +import ca.nrc.cadc.uws.util.JobLogInfo; +import java.io.IOException; +import java.security.AccessControlException; +import java.security.Principal; +import java.util.Collection; +import java.util.Date; +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletResponse; +import org.apache.log4j.Logger; public class ACSearchRunner implements JobRunner { + private static Logger log = Logger.getLogger(ACSearchRunner.class); + private JobUpdater jobUpdater; private SyncOutput syncOut; private Job job; + private JobLogInfo logInfo; @Override public void setJobUpdater(JobUpdater jobUpdater) @@ -101,7 +131,193 @@ public class ACSearchRunner @Override public void run() { - // TODO Run the search query against GroupPersistence + log.debug("RUN ACSearchRunner: " + job.ownerSubject); + + logInfo = new JobLogInfo(job); + + String startMessage = logInfo.start(); + log.info(startMessage); + + long t1 = System.currentTimeMillis(); + search(); + long t2 = System.currentTimeMillis(); + + logInfo.setElapsedTime(t2 - t1); + + String endMessage = logInfo.end(); + log.info(endMessage); } + + private void search() + { + try + { + ExecutionPhase ep = + jobUpdater.setPhase(job.getID(), ExecutionPhase.QUEUED, + ExecutionPhase.EXECUTING, new Date()); + if ( !ExecutionPhase.EXECUTING.equals(ep) ) + { + String message = job.getID() + + ": QUEUED -> EXECUTING [FAILED] -- DONE"; + logInfo.setSuccess(false); + logInfo.setMessage(message); + return; + } + log.debug(job.getID() + ": QUEUED -> EXECUTING [OK]"); + RequestValidator rv = new RequestValidator(); + rv.validate(job.getParameterList()); + + Principal userID = getUserPrincipal(rv.getId(), rv.getType()); + + PluginFactory factory = new PluginFactory(); + GroupPersistence dao = factory.getGroupPersistence(); + Collection<Group> groups = + dao.searchGroups(userID, rv.getRole(), rv.getGUri()); + syncOut.setResponseCode(HttpServletResponse.SC_OK); + GroupsWriter.write(groups, syncOut.getOutputStream()); + + // Mark the Job as completed. + jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, + ExecutionPhase.COMPLETED, new Date()); + } + catch (TransientException t) + { + logInfo.setSuccess(false); + logInfo.setMessage(t.getMessage()); + log.debug("FAIL", t); + + syncOut.setResponseCode(400); + + ErrorSummary errorSummary = + new ErrorSummary(t.getMessage(), ErrorType.FATAL); + try + { + jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, + ExecutionPhase.ERROR, errorSummary, + new Date()); + } + catch(Throwable oops) + { + log.debug("failed to set final error status after " + t, oops); + } + } + catch (UserNotFoundException t) + { + logInfo.setSuccess(false); + logInfo.setMessage(t.getMessage()); + log.debug("FAIL", t); + + syncOut.setResponseCode(404); + + ErrorSummary errorSummary = + new ErrorSummary(t.getMessage(), ErrorType.FATAL); + try + { + jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, + ExecutionPhase.ERROR, errorSummary, + new Date()); + } + catch(Throwable oops) + { + log.debug("failed to set final error status after " + t, oops); + } + } + catch (GroupNotFoundException t) + { + logInfo.setSuccess(false); + logInfo.setMessage(t.getMessage()); + log.debug("FAIL", t); + + syncOut.setResponseCode(404); + + ErrorSummary errorSummary = + new ErrorSummary(t.getMessage(), ErrorType.FATAL); + try + { + jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, + ExecutionPhase.ERROR, errorSummary, + new Date()); + } + catch(Throwable oops) + { + log.debug("failed to set final error status after " + t, oops); + } + } + catch (AccessControlException t) + { + logInfo.setSuccess(false); + logInfo.setMessage(t.getMessage()); + log.debug("FAIL", t); + + syncOut.setResponseCode(401); + + ErrorSummary errorSummary = + new ErrorSummary(t.getMessage(), ErrorType.FATAL); + try + { + jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, + ExecutionPhase.ERROR, errorSummary, + new Date()); + } + catch(Throwable oops) + { + log.debug("failed to set final error status after " + t, oops); + } + } + catch (Throwable t) + { + logInfo.setSuccess(false); + logInfo.setMessage(t.getMessage()); + log.debug("FAIL", t); + + syncOut.setResponseCode(400); + + ErrorSummary errorSummary = + new ErrorSummary(t.getMessage(), ErrorType.FATAL); + try + { + jobUpdater.setPhase(job.getID(), ExecutionPhase.EXECUTING, + ExecutionPhase.ERROR, errorSummary, + new Date()); + } + catch(Throwable oops) + { + log.debug("failed to set final error status after " + t, oops); + } + } + } + + private Principal getUserPrincipal(String userID, IdentityType type) + { + if (type == IdentityType.OPENID) + { + return new OpenIdPrincipal(userID); + } + if (type == IdentityType.UID) + { + try + { + Long numericId = Long.valueOf(userID); + return new NumericPrincipal(numericId); + } + catch (NumberFormatException e) + { + throw new IllegalArgumentException("Illegal UID userID " + + userID + " because " + + e.getMessage()); + } + } + if (type == IdentityType.USERNAME) + { + return new HttpPrincipal(userID); + } + if (type == IdentityType.X500) + { + return new X500Principal(userID); + } + throw new IllegalArgumentException("Unknown user type " + + type.getValue()); + } + } diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java index 8213243891148bf8e3d3b79b8cd0ef1298cec165..47ae5cac9a91d71ca039ac345ef28905fbe98c3e 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapGroupDAOTest.java @@ -34,6 +34,7 @@ package ca.nrc.cadc.ac.server.ldap; +import ca.nrc.cadc.ac.ActivatedGroup; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -45,6 +46,7 @@ import javax.security.auth.x500.X500Principal; import org.junit.Test; import ca.nrc.cadc.ac.Group; +import ca.nrc.cadc.ac.GroupNotFoundException; import ca.nrc.cadc.ac.GroupProperty; import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.User; @@ -59,13 +61,11 @@ public class LdapGroupDAOTest { private static final Logger log = Logger.getLogger(LdapGroupDAOTest.class); + static User<X500Principal> cadctest; static User<X500Principal> authtest1; static User<X500Principal> authtest2; static User<X500Principal> regtest1; - static String groupID1; - static String groupID2; - static LdapConfig config; @BeforeClass @@ -73,10 +73,9 @@ public class LdapGroupDAOTest throws Exception { Log4jInit.setLevel("ca.nrc.cadc.ac", Level.DEBUG); - - groupID1 = "acs-daotest-group1-" + System.currentTimeMillis(); - groupID2 = "acs-daotest-group2-" + System.currentTimeMillis(); - + + cadctest = new User<X500Principal>( + new X500Principal("CN=CADCtest_636,OU=CADC,O=HIA,C=CA")); authtest1 = new User<X500Principal>( new X500Principal("cn=cadc authtest1 10627,ou=cadc,o=hia")); authtest2 = new User<X500Principal>( @@ -96,8 +95,13 @@ public class LdapGroupDAOTest return new LdapGroupDAO<X500Principal>(config, new LdapUserDAO<X500Principal>(config)); } + + String getGroupID() + { + return "acs-daotest-group1-" + System.currentTimeMillis(); + } -// @Test + @Test public void testOneGroup() throws Exception { Subject subject = new Subject(); @@ -110,18 +114,24 @@ public class LdapGroupDAOTest { try { - Group expectGroup = new Group(groupID1, authtest1); + Group expectGroup = new Group(getGroupID(), authtest1); Group actualGroup = getGroupDAO().addGroup(expectGroup); + log.debug("addGroup: " + expectGroup.getID()); assertGroupsEqual(expectGroup, actualGroup); - Group otherGroup = new Group(groupID2, authtest1); + Group otherGroup = new Group(getGroupID(), authtest1); otherGroup = getGroupDAO().addGroup(otherGroup); + log.debug("addGroup: " + otherGroup.getID()); // modify group fields // description expectGroup.description = "Happy testing"; actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); + + expectGroup.description = null; + actualGroup = getGroupDAO().modifyGroup(expectGroup); + assertGroupsEqual(expectGroup, actualGroup); // groupRead expectGroup.groupRead = otherGroup; @@ -137,88 +147,60 @@ public class LdapGroupDAOTest expectGroup.publicRead = true; actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); + + expectGroup.publicRead = false; + actualGroup = getGroupDAO().modifyGroup(expectGroup); + assertGroupsEqual(expectGroup, actualGroup); // userMembers expectGroup.getUserMembers().add(authtest2); actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); - // groupMembers - expectGroup.getGroupMembers().add(otherGroup); + expectGroup.getUserMembers().remove(authtest2); actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); - return null; - } - catch (Exception e) - { - throw new Exception("Problems", e); - } - } - }); - } - -// @Test - public void testMultipleGroups() throws Exception - { - Subject subject = new Subject(); - subject.getPrincipals().add(authtest1.getUserID()); - - // do everything as owner - Subject.doAs(subject, new PrivilegedExceptionAction<Object>() - { - public Object run() throws Exception - { - try - { - Group expectGroup = new Group(groupID1, authtest1); - Group actualGroup = getGroupDAO().addGroup(expectGroup); - assertGroupsEqual(expectGroup, actualGroup); - Group otherGroup = new Group(groupID2, authtest1); - otherGroup = getGroupDAO().addGroup(otherGroup); - - // modify group fields - // description - expectGroup.description = "Happy testing"; - actualGroup = getGroupDAO().modifyGroup(expectGroup); - assertGroupsEqual(expectGroup, actualGroup); - - // groupRead - expectGroup.groupRead = otherGroup; - actualGroup = getGroupDAO().modifyGroup(expectGroup); - assertGroupsEqual(expectGroup, actualGroup); - - // groupWrite - expectGroup.groupWrite = otherGroup; + // groupMembers + expectGroup.getGroupMembers().add(otherGroup); actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); - - // publicRead - expectGroup.publicRead = true; + + expectGroup.getGroupMembers().remove(otherGroup); actualGroup = getGroupDAO().modifyGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); - - // userMembers - expectGroup.getUserMembers().add(authtest2); - actualGroup = getGroupDAO().modifyGroup(expectGroup); + + // delete the group + getGroupDAO().deleteGroup(expectGroup.getID()); + try + { + getGroupDAO().getGroup(expectGroup.getID()); + fail("get on deleted group should throw exception"); + } + catch (GroupNotFoundException ignore) {} + + // reactivate the group + actualGroup = getGroupDAO().addGroup(expectGroup); + assertTrue(actualGroup instanceof ActivatedGroup); assertGroupsEqual(expectGroup, actualGroup); - - // groupMembers - expectGroup.getGroupMembers().add(otherGroup); - actualGroup = getGroupDAO().modifyGroup(expectGroup); + + // get the activated group + actualGroup = getGroupDAO().getGroup(expectGroup.getID()); assertGroupsEqual(expectGroup, actualGroup); + return null; } catch (Exception e) { + e.printStackTrace(); throw new Exception("Problems", e); } } }); } - @Test - public void testGetGroups() throws Exception +// @Test + public void testSearchOwnerGroups() throws Exception { Subject subject = new Subject(); subject.getPrincipals().add(authtest1.getUserID()); @@ -230,12 +212,14 @@ public class LdapGroupDAOTest { try { - Group expectGroup = new Group(groupID1, authtest1); + Group expectGroup = new Group(getGroupID(), authtest1); Group actualGroup = getGroupDAO().addGroup(expectGroup); assertGroupsEqual(expectGroup, actualGroup); - System.out.println("new group: " + groupID1); + System.out.println("new group: " + expectGroup.getID()); - Collection<Group> groups = getGroupDAO().getGroups(authtest1, Role.OWNER); + Collection<Group> groups = + getGroupDAO().searchGroups(authtest1.getUserID(), + Role.OWNER, null); System.out.println("# groups found: " + groups.size()); boolean found = false; for (Group group : groups) @@ -245,7 +229,7 @@ public class LdapGroupDAOTest { fail("returned group with wrong owner"); } - if (group.getID().equals(groupID1)) + if (group.getID().equals(expectGroup.getID())) { found = true; } @@ -254,6 +238,95 @@ public class LdapGroupDAOTest { fail(""); } + getGroupDAO().deleteGroup(expectGroup.getID()); + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + return null; + } + }); + } + +// @Test + public void testSearchMemberGroups() throws Exception + { + Subject subject = new Subject(); + subject.getPrincipals().add(cadctest.getUserID()); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + Collection<Group> groups = + getGroupDAO().searchGroups(cadctest.getUserID(), + Role.MEMBER, null); + System.out.println("# groups found: " + groups.size()); +// boolean found = false; +// for (Group group : groups) +// { +// System.out.println("found group: " + group.getID()); +// if (!group.getOwner().equals(cadctest)) +// { +// fail("returned group with wrong owner"); +// } +// if (group.getID().equals(groupID1)) +// { +// found = true; +// } +// } +// if (!found) +// { +// fail(""); +// } + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + return null; + } + }); + } + +// @Test + public void testSearchRWGroups() throws Exception + { + Subject subject = new Subject(); + subject.getPrincipals().add(authtest1.getUserID()); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + Collection<Group> groups = + getGroupDAO().searchGroups(authtest1.getUserID(), + Role.RW, null); + System.out.println("# groups found: " + groups.size()); +// boolean found = false; +// for (Group group : groups) +// { +// System.out.println("found group: " + group.getID()); +// if (!group.getOwner().equals(authtest1)) +// { +// fail("returned group with wrong owner"); +// } +// if (group.getID().equals(groupID1)) +// { +// found = true; +// } +// } +// if (!found) +// { +// fail(""); +// } } catch (Exception e) { 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 new file mode 100644 index 0000000000000000000000000000000000000000..8526a90a2ddd162e90872eb8eedd1bc0f77ec895 --- /dev/null +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java @@ -0,0 +1,215 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * <http://www.gnu.org/licenses/>. pas le cas, consultez : + * <http://www.gnu.org/licenses/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */ +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 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; + +/** + * + * @author jburke + */ +public class LdapUserDAOTest +{ + private static final Logger log = Logger.getLogger(LdapUserDAOTest.class); + + static final String cadcTestDN = "CN=CADCtest_636,OU=CADC,O=HIA,C=CA"; + + static User<X500Principal> cadcTest; + static LdapConfig config; + + @BeforeClass + public static void setUpBeforeClass() + throws Exception + { + Log4jInit.setLevel("ca.nrc.cadc.ac", Level.DEBUG); + + cadcTest = new User<X500Principal>(new X500Principal(cadcTestDN)); + + 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=TestGroups,ou=ds,dc=canfar,dc=net", + "ou=DeletedGroups,ou=ds,dc=canfar,dc=net"); + } + + LdapUserDAO<X500Principal> getUserDAO() + { + return new LdapUserDAO<X500Principal>(config); + } + + /** + * Test of getUser method, of class LdapUserDAO. + */ +// @Test + public void testGetUser() throws Exception + { + Subject subject = new Subject(); + subject.getPrincipals().add(cadcTest.getUserID()); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + User actual = getUserDAO().getUser(cadcTest.getUserID()); + assertEquals(cadcTest, actual); + + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + } + + /** + * Test of getUserGroups method, of class LdapUserDAO. + */ +// @Test + public void testGetUserGroups() throws Exception + { + Subject subject = new Subject(); + subject.getPrincipals().add(cadcTest.getUserID()); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + Collection<Group> groups = getUserDAO().getUserGroups(cadcTest.getUserID()); + assertNotNull(groups); + assertTrue(!groups.isEmpty()); + for (Group group : groups) + log.debug(group); + + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + } + + /** + * Test of getUserGroups method, of class LdapUserDAO. + */ + @Test + public void testIsMember() throws Exception + { + Subject subject = new Subject(); + subject.getPrincipals().add(cadcTest.getUserID()); + + // do everything as owner + Subject.doAs(subject, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + try + { + boolean isMember = getUserDAO().isMember(cadcTest.getUserID(), "foo"); + assertFalse(isMember); + + String groupID = "cn=cadcsw,cn=groups,ou=ds,dc=canfar,dc=net"; + isMember = getUserDAO().isMember(cadcTest.getUserID(), groupID); + assertTrue(isMember); + + return null; + } + catch (Exception e) + { + throw new Exception("Problems", e); + } + } + }); + } + +} diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/AC.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/AC.java index b38354626dd5cebcde44d86585d82ec45da2544e..44c83bb7541dd1896aa2cf05d86eb7243ee6c82c 100755 --- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/AC.java +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/AC.java @@ -90,8 +90,8 @@ public class AC // Group URI attribute once the group name is appended public static final String GROUP_URI = "ivo://cadc.nrc.ca/gms#"; - public static final String ID_TYPE_X500 = "X500"; - public static final String ID_TYPE_OPENID = "OpenID"; - public static final String ID_TYPE_USERNAME = "HTTP"; - public static final String ID_TYPE_UID = "UID"; +// public static final String ID_TYPE_X500 = "X500"; +// public static final String ID_TYPE_OPENID = "OpenID"; +// public static final String ID_TYPE_USERNAME = "HTTP"; +// public static final String ID_TYPE_UID = "UID"; } diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/ActivatedGroup.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/ActivatedGroup.java new file mode 100644 index 0000000000000000000000000000000000000000..6720c6434e08760b9fc862e05d68e13d25a5ec11 --- /dev/null +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/ActivatedGroup.java @@ -0,0 +1,85 @@ +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2014. (c) 2014. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * <http://www.gnu.org/licenses/>. pas le cas, consultez : + * <http://www.gnu.org/licenses/>. + * + * $Revision: 4 $ + * + ************************************************************************ + */ +package ca.nrc.cadc.ac; + +import java.security.Principal; + +/** + * + * @author jburke + */ +public class ActivatedGroup extends Group +{ + + public ActivatedGroup(String groupID, User<? extends Principal> owner) + { + super(groupID, owner); + } + +} diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsWriter.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsWriter.java index f98b38e15c5064cec6e4f226a2a01a6766f661b4..0bdcf1f09ebeb40da3610f6a5ce69be834f86540 100755 --- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsWriter.java +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsWriter.java @@ -7,7 +7,7 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.io.Writer; -import java.util.List; +import java.util.Collection; import org.jdom2.Document; import org.jdom2.Element; import org.jdom2.output.Format; @@ -22,7 +22,7 @@ public class GroupsWriter * @throws java.io.IOException * @throws ca.nrc.cadc.ac.WriterException */ - public static void write(List<Group> groups, StringBuilder builder) + public static void write(Collection<Group> groups, StringBuilder builder) throws IOException, WriterException { write(groups, new StringBuilderWriter(builder)); @@ -36,7 +36,7 @@ public class GroupsWriter * @throws IOException if the writer fails to write. * @throws ca.nrc.cadc.ac.WriterException */ - public static void write(List<Group> groups, OutputStream out) + public static void write(Collection<Group> groups, OutputStream out) throws IOException, WriterException { OutputStreamWriter outWriter; @@ -59,7 +59,7 @@ public class GroupsWriter * @throws IOException if the writer fails to write. * @throws ca.nrc.cadc.ac.WriterException */ - public static void write(List<Group> groups, Writer writer) + public static void write(Collection<Group> groups, Writer writer) throws IOException, WriterException { if (groups == null) @@ -76,7 +76,7 @@ public class GroupsWriter * @return Element of list of Group's. * @throws ca.nrc.cadc.ac.WriterException */ - public static Element getGroupsElement(List<Group> groups) + public static Element getGroupsElement(Collection<Group> groups) throws WriterException { Element groupsElement = new Element("groups");