diff --git a/cadc-access-control-server/build.gradle b/cadc-access-control-server/build.gradle index d0d66f7b66a1287472a9488c4cfa2be0f793cc7e..8685386b1007613901251b41dd64da0b682b302b 100644 --- a/cadc-access-control-server/build.gradle +++ b/cadc-access-control-server/build.gradle @@ -13,7 +13,7 @@ repositories { sourceCompatibility = 1.7 group = 'org.opencadc' -version = '1.1.0' +version = '1.1.1' dependencies { compile 'log4j:log4j:1.2.+' @@ -22,7 +22,7 @@ dependencies { compile 'xerces:xercesImpl:2.+' compile 'com.unboundid:unboundid-ldapsdk:2.3.+' - compile 'org.opencadc:cadc-access-control:1.1.+' + compile 'org.opencadc:cadc-access-control:[1.1.1,)' compile 'org.opencadc:cadc-util:1.+' compile 'org.opencadc:cadc-log:1.+' compile 'org.opencadc:cadc-registry:1.+' diff --git a/cadc-access-control/build.gradle b/cadc-access-control/build.gradle index 1ff4624ce0cc69a5f1febeb4d86e22e761c5e8af..ee3e1a0c1bee6c67a385fac84e4bb09af5abe170 100644 --- a/cadc-access-control/build.gradle +++ b/cadc-access-control/build.gradle @@ -15,9 +15,9 @@ sourceCompatibility = 1.7 group = 'org.opencadc' -version = '1.1.0' +version = '1.1.3' -mainClassName = 'ca.nrc.cadc.ac.client.GMSClientMain' +mainClassName = 'ca.nrc.cadc.ac.client.Main' dependencies { compile 'log4j:log4j:1.2.+' @@ -25,6 +25,7 @@ dependencies { compile 'org.json:json:20160212' compile 'org.opencadc:cadc-util:1.+' + compile 'org.opencadc:cadc-cdp:[1.0,)' compile 'org.opencadc:cadc-registry:1.+' testCompile 'junit:junit:4.+' diff --git a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/GroupURI.java b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/GroupURI.java index 16265fbfbd6bca861a4710138a0413c20df8d914..68a87acd53e6edc2c59ddfaced6b0813dae0b324 100644 --- a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/GroupURI.java +++ b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/GroupURI.java @@ -83,7 +83,6 @@ public class GroupURI private static Logger log = Logger.getLogger(GroupURI.class); private URI uri; - private String name; /** * Attempts to create a URI using the specified uri. @@ -99,8 +98,6 @@ public class GroupURI throw new IllegalArgumentException("Null URI"); } - this.uri = uri; - // Ensure the scheme is correct if (uri.getScheme() == null) { @@ -117,13 +114,9 @@ public class GroupURI throw new IllegalArgumentException("Missing authority and/or path."); } - log.debug("URI: " + uri); - log.debug(" scheme: " + uri.getScheme()); - log.debug(" authority: " + uri.getAuthority()); - log.debug(" path: " + uri.getPath()); - String fragment = uri.getFragment(); String query = uri.getQuery(); + String name = null; if (query == null) { if (fragment != null) @@ -144,6 +137,9 @@ public class GroupURI } name = query; } + + this.uri = URI.create( + uri.getScheme() + "://" + uri.getAuthority() + uri.getPath() + "?" + name); } /** @@ -156,16 +152,16 @@ public class GroupURI } @Override - public boolean equals(Object rhs) + public boolean equals(Object other) { - if (rhs == null) + if (other == null) return false; - if (this == rhs) + if (this == other) return true; - if (rhs instanceof GroupURI) + if (other instanceof GroupURI) { - GroupURI vu = (GroupURI) rhs; - return uri.toString().equals(vu.uri.toString()); + GroupURI otherURI = (GroupURI) other; + return uri.equals(otherURI.getURI()); } return false; } @@ -180,16 +176,6 @@ public class GroupURI return uri; } - /** - * Returns the decoded authority component of the URI. - * - * @return authority of the URI, or null if the authority is undefined. - */ - public String getAuthority() - { - return uri.getAuthority(); - } - /** * Returns the decoded fragment component of the URI. * @@ -197,18 +183,18 @@ public class GroupURI */ public String getName() { - return name; + return uri.getQuery(); } public URI getServiceID() { - String serviceID = uri.getScheme() + + String serviceIDString = uri.getScheme() + "://" + uri.getAuthority() + uri.getPath(); try { - return new URI(serviceID); + return new URI(serviceIDString); } catch (URISyntaxException e) { @@ -220,7 +206,7 @@ public class GroupURI @Override public String toString() { - return getServiceID() + "?" + name; + return uri.toString(); } } diff --git a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GMSClient.java b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GMSClient.java index 2e58a8a5a68804a170f21f34796ff5756b1d65c4..68d94dd1d68ecf77db2d6eeffd1c9cf2cd46f9a0 100755 --- a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GMSClient.java +++ b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GMSClient.java @@ -94,7 +94,6 @@ import org.apache.log4j.Logger; import ca.nrc.cadc.ac.Group; import ca.nrc.cadc.ac.GroupAlreadyExistsException; import ca.nrc.cadc.ac.GroupNotFoundException; -import ca.nrc.cadc.ac.GroupURI; import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.WriterException; @@ -129,11 +128,20 @@ public class GMSClient implements TransferListener private SSLSocketFactory sslSocketFactory; private SSLSocketFactory mySocketFactory; + private URI serviceID; + /** * Constructor. + * + * @param serviceID The service ID. */ - public GMSClient() + public GMSClient(URI serviceID) { + if (serviceID == null) + throw new IllegalArgumentException("invalid serviceID: " + serviceID); + if (serviceID.getFragment() != null) + throw new IllegalArgumentException("invalid serviceID (fragment not allowed): " + serviceID); + this.serviceID = serviceID; } public void transferEvent(TransferEvent te) @@ -173,9 +181,8 @@ public class GMSClient implements TransferListener throws GroupAlreadyExistsException, AccessControlException, UserNotFoundException, WriterException, IOException { - URL createGroupURL = getRegistryClient() - .getServiceURL(group.getID().getServiceID(), Standards.GMS_GROUPS_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); log.debug("createGroupURL request to " + createGroupURL.toString()); // reset the state of the cache @@ -237,19 +244,18 @@ public class GMSClient implements TransferListener /** * Get the group object. * - * @param groupID Identifies the group to get. + * @param groupName Identifies the group to get. * @return The group. * @throws GroupNotFoundException If the group was not found. * @throws AccessControlException If unauthorized to perform this operation. * @throws java.io.IOException */ - public Group getGroup(GroupURI groupID) + public Group getGroup(String groupName) throws GroupNotFoundException, AccessControlException, IOException { - URL groupsURL = getRegistryClient() - .getServiceURL(groupID.getServiceID(), Standards.GMS_GROUPS_01, AuthMethod.CERT); - URL getGroupURL = new URL(groupsURL.toExternalForm() + "/" + groupID.getName()); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); + URL getGroupURL = new URL(groupsURL.toExternalForm() + "/" + groupName); log.debug("getGroup request to " + getGroupURL.toString()); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -300,11 +306,11 @@ public class GMSClient implements TransferListener * @throws AccessControlException If unauthorized to perform this operation. * @throws java.io.IOException */ - public List<String> getGroupNames(URI serviceID) + public List<String> getGroupNames() throws AccessControlException, IOException { URL getGroupNamesURL = getRegistryClient() - .getServiceURL(serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); log.debug("getGroupNames request to " + getGroupNamesURL.toString()); @@ -382,7 +388,7 @@ public class GMSClient implements TransferListener AccessControlException, WriterException, IOException { URL groupsURL = getRegistryClient() - .getServiceURL(group.getID().getServiceID(), Standards.GMS_GROUPS_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); URL updateGroupURL = new URL(groupsURL.toExternalForm() + "/" + group.getID().getName()); log.debug("updateGroup request to " + updateGroupURL.toString()); @@ -442,17 +448,17 @@ public class GMSClient implements TransferListener /** * Delete the group. * - * @param groupID Identifies the group to delete. + * @param groupName Identifies the group to delete. * @throws GroupNotFoundException If the group was not found. * @throws AccessControlException If unauthorized to perform this operation. * @throws java.io.IOException */ - public void deleteGroup(GroupURI groupID) + public void deleteGroup(String groupName) throws GroupNotFoundException, AccessControlException, IOException { URL groupsURL = getRegistryClient() - .getServiceURL(groupID.getServiceID(), Standards.GMS_GROUPS_01, AuthMethod.CERT); - URL deleteGroupURL = new URL(groupsURL.toExternalForm() + "/" + groupID.getName()); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); + URL deleteGroupURL = new URL(groupsURL.toExternalForm() + "/" + groupName); log.debug("deleteGroup request to " + deleteGroupURL.toString()); // reset the state of the cache @@ -506,21 +512,21 @@ public class GMSClient implements TransferListener /** * Add a group as a member of another group. * - * @param targetGroup The group in which to add the group member. + * @param targetGroupName The group in which to add the group member. * @param groupMemberName The group member to add. * @throws IllegalArgumentException If cyclical membership is detected. * @throws GroupNotFoundException If the group was not found. * @throws AccessControlException If unauthorized to perform this operation. * @throws java.io.IOException */ - public void addGroupMember(GroupURI targetGroup, String groupMemberName) + public void addGroupMember(String targetGroupName, String groupMemberName) throws IllegalArgumentException, GroupNotFoundException, AccessControlException, IOException { - String path = "/" + targetGroup.getName() + "/groupMembers/" + groupMemberName; + String path = "/" + targetGroupName + "/groupMembers/" + groupMemberName; URL groupsURL = getRegistryClient() - .getServiceURL(targetGroup.getServiceID(), Standards.GMS_GROUPS_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); URL addGroupMemberURL = new URL(groupsURL.toExternalForm() + path); log.debug("addGroupMember request to " + addGroupMemberURL.toString()); @@ -560,28 +566,28 @@ public class GMSClient implements TransferListener /** * Add a user as a member of a group. * - * @param targetGroup The group in which to add the group member. + * @param targetGroupName The group in which to add the group member. * @param userID The user to add. * @throws GroupNotFoundException If the group was not found. * @throws UserNotFoundException If the member was not found. * @throws java.io.IOException * @throws AccessControlException If unauthorized to perform this operation. */ - public void addUserMember(GroupURI targetGroup, Principal userID) + public void addUserMember(String targetGroupName, Principal userID) throws GroupNotFoundException, UserNotFoundException, AccessControlException, IOException { - if (targetGroup == null) - throw new IllegalArgumentException("targetGroup required"); + if (targetGroupName == null) + throw new IllegalArgumentException("targetGroupName required"); if (userID == null) throw new IllegalArgumentException("userID required"); - log.debug("addUserMember: " + targetGroup + " + " + userID.getName()); + log.debug("addUserMember: " + targetGroupName + " + " + userID.getName()); String userIDType = AuthenticationUtil.getPrincipalType(userID); - String path = "/" + targetGroup.getName() + "/userMembers/" + NetUtil.encode(userID.getName()) + "?idType=" + userIDType; + String path = "/" + targetGroupName + "/userMembers/" + NetUtil.encode(userID.getName()) + "?idType=" + userIDType; URL groupsURL = getRegistryClient() - .getServiceURL(targetGroup.getServiceID(), Standards.GMS_GROUPS_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); URL addUserMemberURL = new URL(groupsURL.toExternalForm() + path); log.debug("addUserMember request to " + addUserMemberURL.toString()); @@ -625,20 +631,20 @@ public class GMSClient implements TransferListener /** * Remove a group as a member of another group. * - * @param targetGroup The group from which to remove the group member. + * @param targetGroupName The group from which to remove the group member. * @param groupMemberName The group member to remove. * @throws GroupNotFoundException If the group was not found. * @throws java.io.IOException * @throws AccessControlException If unauthorized to perform this operation. */ - public void removeGroupMember(GroupURI targetGroup, + public void removeGroupMember(String targetGroupName, String groupMemberName) throws GroupNotFoundException, AccessControlException, IOException { - String path = "/" + targetGroup.getName() + "/groupMembers/" + groupMemberName; + String path = "/" + targetGroupName + "/groupMembers/" + groupMemberName; URL groupsURL = getRegistryClient() - .getServiceURL(targetGroup.getServiceID(), Standards.GMS_GROUPS_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); URL removeGroupMemberURL = new URL(groupsURL.toExternalForm() + path); log.debug("removeGroupMember request to " + removeGroupMemberURL.toString()); @@ -692,22 +698,22 @@ public class GMSClient implements TransferListener /** * Remove a user as a member of a group. * - * @param targetGroup The group from which to remove the group member. + * @param targetGroupName The group from which to remove the group member. * @param userID The user to remove. * @throws GroupNotFoundException If the group was not found. * @throws UserNotFoundException If the member was not found. * @throws java.io.IOException * @throws AccessControlException If unauthorized to perform this operation. */ - public void removeUserMember(GroupURI targetGroup, Principal userID) + public void removeUserMember(String targetGroupName, Principal userID) throws GroupNotFoundException, UserNotFoundException, AccessControlException, IOException { String userIDType = AuthenticationUtil.getPrincipalType(userID); - log.debug("removeUserMember: " + targetGroup + " - " + userID.getName() + " type: " + userIDType); - String path = "/" + targetGroup.getName() + "/userMembers/" + NetUtil.encode(userID.getName()) + "?idType=" + userIDType; + log.debug("removeUserMember: " + targetGroupName + " - " + userID.getName() + " type: " + userIDType); + String path = "/" + targetGroupName + "/userMembers/" + NetUtil.encode(userID.getName()) + "?idType=" + userIDType; URL groupsURL = getRegistryClient() - .getServiceURL(targetGroup.getServiceID(), Standards.GMS_GROUPS_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT); URL removeUserMemberURL = new URL(groupsURL.toExternalForm() + path); log.debug("removeUserMember: " + removeUserMemberURL.toString()); @@ -783,14 +789,14 @@ public class GMSClient implements TransferListener * @throws ca.nrc.cadc.ac.UserNotFoundException * @throws java.io.IOException */ - public List<Group> getMemberships(URI serviceID, Role role) + public List<Group> getMemberships(Role role) throws UserNotFoundException, AccessControlException, IOException { - return getMemberships(serviceID, null, role); + return getMemberships(null, role); } - private List<Group> getMemberships(URI serviceID, Principal ignore, Role role) + private List<Group> getMemberships(Principal ignore, Role role) throws UserNotFoundException, AccessControlException, IOException { if (role == null) @@ -801,7 +807,7 @@ public class GMSClient implements TransferListener Principal userID = getCurrentUserID(); if (userID != null) { - List<Group> cachedGroups = getCachedGroups(serviceID, userID, role, true); + List<Group> cachedGroups = getCachedGroups(userID, role, true); if (cachedGroups != null) { return cachedGroups; @@ -819,7 +825,7 @@ public class GMSClient implements TransferListener searchGroupPath.append("&ROLE=").append(NetUtil.encode(roleString)); URL searchURL = getRegistryClient() - .getServiceURL(serviceID, Standards.GMS_SEARCH_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_SEARCH_01, AuthMethod.CERT); URL getMembershipsURL = new URL(searchURL.toExternalForm() + searchGroupPath.toString()); log.debug("getMemberships request to " + getMembershipsURL.toString()); @@ -857,7 +863,7 @@ public class GMSClient implements TransferListener log.debug("getMemberships returned: " + groupsXML); GroupListReader groupListReader = new GroupListReader(); List<Group> groups = groupListReader.read(groupsXML); - setCachedGroups(serviceID, userID, groups, role); + setCachedGroups(userID, groups, role); return groups; } catch (Exception bug) @@ -874,17 +880,17 @@ public class GMSClient implements TransferListener * * This call is identical to getMemberShip(userID, groupName, Role.MEMBER) * - * @param groupID Identifies the group. + * @param groupName Identifies the group. * @return The group or null of the user is not a member. * @throws UserNotFoundException If the user does not exist. * @throws AccessControlException If not allowed to peform the search. * @throws IllegalArgumentException If a parameter is null. * @throws IOException If an unknown error occured. */ - public Group getMembership(GroupURI groupID) + public Group getMembership(String groupName) throws UserNotFoundException, AccessControlException, IOException { - return getMembership(groupID, Role.MEMBER); + return getMembership(groupName, Role.MEMBER); } /** @@ -892,7 +898,7 @@ public class GMSClient implements TransferListener * identified by userID, is a member (of type role) of that group. * Return null otherwise. * - * @param groupID Identifies the group. + * @param groupName Identifies the group. * @param role The membership role to search. * @return The group or null of the user is not a member. * @throws UserNotFoundException If the user does not exist. @@ -900,10 +906,10 @@ public class GMSClient implements TransferListener * @throws IllegalArgumentException If a parameter is null. * @throws IOException If an unknown error occured. */ - public Group getMembership(GroupURI groupID, Role role) + public Group getMembership(String groupName, Role role) throws UserNotFoundException, AccessControlException, IOException { - if (groupID == null || role == null) + if (groupName == null || role == null) { throw new IllegalArgumentException("groupName and role are required."); } @@ -911,7 +917,7 @@ public class GMSClient implements TransferListener Principal userID = getCurrentUserID(); if (userID != null) { - Group cachedGroup = getCachedGroup(userID, groupID, role); + Group cachedGroup = getCachedGroup(userID, groupName, role); if (cachedGroup != null) { return cachedGroup; @@ -927,10 +933,10 @@ public class GMSClient implements TransferListener //searchGroupURL.append("ID=").append(NetUtil.encode(id)); //searchGroupURL.append("&IDTYPE=").append(NetUtil.encode(idType)); searchGroupPath.append("&ROLE=").append(NetUtil.encode(roleString)); - searchGroupPath.append("&GROUPID=").append(NetUtil.encode(groupID.getName())); + searchGroupPath.append("&GROUPID=").append(NetUtil.encode(groupName)); URL searchURL = getRegistryClient() - .getServiceURL(groupID.getServiceID(), Standards.GMS_SEARCH_01, AuthMethod.CERT); + .getServiceURL(this.serviceID, Standards.GMS_SEARCH_01, AuthMethod.CERT); URL getMembershipURL = new URL(searchURL.toExternalForm() + searchGroupPath.toString()); log.debug("getMembership request to " + getMembershipURL.toString()); @@ -979,7 +985,7 @@ public class GMSClient implements TransferListener return ret; } throw new IllegalStateException( - "Duplicate membership for " + userID + " in group " + groupID); + "Duplicate membership for " + userID + " in group " + groupName); } catch (Exception bug) { @@ -991,37 +997,37 @@ public class GMSClient implements TransferListener /** * Check group membership of the current Subject. * - * @param groupID + * @param groupName * @return true if the current Subject is a member of the group, false otherwise * @throws UserNotFoundException * @throws AccessControlException * @throws IOException */ - public boolean isMember(GroupURI groupID) + public boolean isMember(String groupName) throws UserNotFoundException, AccessControlException, IOException { - return isMember(groupID, Role.MEMBER); + return isMember(groupName, Role.MEMBER); } /** * - * @param groupID + * @param groupName * @param role * @return true if the current Subject is a member of the group with the specified role, false otherwise * @throws UserNotFoundException * @throws AccessControlException * @throws IOException */ - public boolean isMember(GroupURI groupID, Role role) + public boolean isMember(String groupName, Role role) throws UserNotFoundException, AccessControlException, IOException { - return isMember(getCurrentUserID(), groupID, role); + return isMember(getCurrentUserID(), groupName, role); } - private boolean isMember(Principal userID, GroupURI groupID, Role role) + private boolean isMember(Principal userID, String groupName, Role role) throws UserNotFoundException, AccessControlException, IOException { - Group group = getMembership(groupID, role); + Group group = getMembership(groupName, role); return group != null; } @@ -1077,7 +1083,7 @@ public class GMSClient implements TransferListener } } - protected GroupMemberships getGroupCache(URI serviceID, Principal userID) + protected GroupMemberships getGroupCache(Principal userID) { AccessControlContext acContext = AccessController.getContext(); Subject subject = Subject.getSubject(acContext); @@ -1107,21 +1113,21 @@ public class GMSClient implements TransferListener return null; // no cache } - protected Group getCachedGroup(Principal userID, GroupURI groupID, Role role) + protected Group getCachedGroup(Principal userID, String groupID, Role role) { - List<Group> groups = getCachedGroups(groupID.getServiceID(), userID, role, false); + List<Group> groups = getCachedGroups(userID, role, false); if (groups == null) return null; // no cache for (Group g : groups) { - if (g.getID().equals(groupID)) + if (g.getID().getName().equals(groupID)) return g; } return null; } - protected List<Group> getCachedGroups(URI serviceID, Principal userID, Role role, boolean complete) + protected List<Group> getCachedGroups(Principal userID, Role role, boolean complete) { - GroupMemberships mems = getGroupCache(serviceID, userID); + GroupMemberships mems = getGroupCache(userID); if (mems == null) return null; // no cache @@ -1135,16 +1141,16 @@ public class GMSClient implements TransferListener protected void addCachedGroup(Principal userID, Group group, Role role) { - GroupMemberships mems = getGroupCache(group.getID().getServiceID(), userID); + GroupMemberships mems = getGroupCache(userID); if (mems == null) return; // no cache mems.add(group, role); } - protected void setCachedGroups(URI serviceID, Principal userID, List<Group> groups, Role role) + protected void setCachedGroups(Principal userID, List<Group> groups, Role role) { - GroupMemberships mems = getGroupCache(serviceID, userID); + GroupMemberships mems = getGroupCache(userID); if (mems == null) return; // no cache diff --git a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GroupAuthorizer.java b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GroupAuthorizer.java new file mode 100644 index 0000000000000000000000000000000000000000..11b8ac2a3495b8c5cd771e87cdd21ab86907b089 --- /dev/null +++ b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GroupAuthorizer.java @@ -0,0 +1,155 @@ +/* +************************************************************************ +******************* CANADIAN ASTRONOMY DATA CENTRE ******************* +************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** +* +* (c) 2016. (c) 2016. +* 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/>. +* +************************************************************************ +*/ + +package ca.nrc.cadc.ac.client; + +import ca.nrc.cadc.ac.GroupURI; +import ca.nrc.cadc.ac.Role; +import ca.nrc.cadc.auth.Authorizer; +import ca.nrc.cadc.cred.client.CredUtil; +import ca.nrc.cadc.net.TransientException; +import java.io.FileNotFoundException; +import java.net.URI; +import java.security.AccessControlException; +import org.apache.log4j.Logger; + +/** + * + * @author pdowler + */ +public class GroupAuthorizer implements Authorizer +{ + private static final Logger log = Logger.getLogger(GroupAuthorizer.class); + + private GroupURI groupURI; + + private GroupAuthorizer() { } + + /** + * Create an authorizer that allows members of the specified group and denies + * all other users. The string argument must be a valid GroupURI. + * + * @param uri group identifier for the allow group + */ + public GroupAuthorizer(String uri) + { + try + { + this.groupURI = new GroupURI(uri); + } + finally { } + } + + @Override + public Object getReadPermission(URI uri) + throws AccessControlException, FileNotFoundException, TransientException + { + checkMembership(); + return null; + } + + @Override + public Object getWritePermission(URI uri) throws AccessControlException, FileNotFoundException, TransientException + { + checkMembership(); + return null; + } + + private void checkMembership() + { + try + { + if ( CredUtil.checkCredentials()) + { + GMSClient gms = new GMSClient(groupURI.getServiceID()); + if ( gms.isMember(groupURI.getName(), Role.MEMBER)) + return; + + throw new AccessControlException("permission denied"); + } + throw new AccessControlException("permission denied (no credentials)"); + } + catch (AccessControlException e) + { + throw e; + } + catch (Throwable e) + { + String errorMessage = "Failed to check " + groupURI + " group membership: " + e + .getMessage(); + log.error(errorMessage, e); + Throwable cause = e.getCause(); + while (cause != null) + { + log.error(" reason: " + + cause.getCause()); + cause = cause.getCause(); + } + throw new IllegalStateException(errorMessage); + } + } +} diff --git a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GMSClientMain.java b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/Main.java similarity index 85% rename from cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GMSClientMain.java rename to cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/Main.java index 14e8db6ebe28c802d8a604bc7721fe3f7a4cb290..87bfca844bb120487f76a02238f741c8fb35abc8 100644 --- a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/GMSClientMain.java +++ b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/client/Main.java @@ -69,6 +69,7 @@ package ca.nrc.cadc.ac.client; +import java.net.URI; import java.security.AccessControlContext; import java.security.AccessController; import java.security.Principal; @@ -95,10 +96,10 @@ import ca.nrc.cadc.util.Log4jInit; * only used for testing. Should not be used for production * work. */ -public class GMSClientMain implements PrivilegedAction<Object> +public class Main implements PrivilegedAction<Object> { - private static Logger log = Logger.getLogger(GMSClientMain.class); + private static Logger log = Logger.getLogger(Main.class); public static final String ARG_ADD_MEMBER = "add-member"; public static final String ARG_DEL_MEMBER = "remove-member"; @@ -118,12 +119,11 @@ public class GMSClientMain implements PrivilegedAction<Object> public static final String ARG_V = "v"; public static final String ARG_D = "d"; - private GMSClient client; private ArgumentMap argMap; - private GMSClientMain() + private Main(ArgumentMap args) { - client = new GMSClient(); + this.argMap = args; } public static void main(String[] args) @@ -149,8 +149,7 @@ public class GMSClientMain implements PrivilegedAction<Object> else Log4jInit.setLevel("ca", Level.WARN); - GMSClientMain main = new GMSClientMain(); - main.argMap = argMap; + Main main = new Main(argMap); Subject subject = CertCmdArgUtil.initSubject(argMap, true); @@ -192,15 +191,15 @@ public class GMSClientMain implements PrivilegedAction<Object> private static void usage() { - System.out.println("--create --group=<g>"); - System.out.println("--get --group=<g>"); - System.out.println("--delete --group=<g>"); + System.out.println("--create --group=<uri>"); + System.out.println("--get --group=<uri>"); + System.out.println("--delete --group=<uri>"); System.out.println(); - System.out.println("--add-member --group=<g> --userid=<u>"); - System.out.println("--remove-member --group=<g> --userid=<u>"); + System.out.println("--add-member --group=<uri> --userid=<u>"); + System.out.println("--remove-member --group=<uri> --userid=<u>"); System.out.println(); - System.out.println("--add-admin --group=<g> --userid=<u>"); - System.out.println("--remove-admin --group=<g> --userid=<u>"); + System.out.println("--add-admin --group=<uri> --userid=<u>"); + System.out.println("--remove-admin --group=<uri> --userid=<u>"); } @Override @@ -209,12 +208,14 @@ public class GMSClientMain implements PrivilegedAction<Object> try { String command = getCommand(); - - GroupURI groupID = null; + String suri = argMap.getValue(ARG_GROUP); + GroupURI guri = new GroupURI(new URI(suri)); + GMSClient client = new GMSClient(guri.getServiceID()); + String group = guri.getName(); if (command.equals(ARG_ADD_MEMBER)) { - String group = argMap.getValue(ARG_GROUP); + String userID = argMap.getValue(ARG_USERID); if (group == null) @@ -223,11 +224,10 @@ public class GMSClientMain implements PrivilegedAction<Object> if (userID == null) throw new IllegalArgumentException("No userid specified"); - client.addUserMember(new GroupURI(group), new HttpPrincipal(userID)); + client.addUserMember(group, new HttpPrincipal(userID)); } else if (command.equals(ARG_DEL_MEMBER)) { - String group = argMap.getValue(ARG_GROUP); if (group == null) throw new IllegalArgumentException("No group specified"); @@ -235,11 +235,10 @@ public class GMSClientMain implements PrivilegedAction<Object> if (member == null) throw new IllegalArgumentException("No user specified"); - client.removeUserMember(new GroupURI(group), new HttpPrincipal(member)); + client.removeUserMember(group, new HttpPrincipal(member)); } else if (command.equals(ARG_ADD_ADMIN)) { - String group = argMap.getValue(ARG_GROUP); String userID = argMap.getValue(ARG_USERID); if (group == null) @@ -249,7 +248,7 @@ public class GMSClientMain implements PrivilegedAction<Object> throw new IllegalArgumentException("No userid specified"); HttpPrincipal hp = new HttpPrincipal(userID); - Group cur = client.getGroup(new GroupURI(group)); + Group cur = client.getGroup(group); boolean update = true; for (User admin : cur.getUserAdmins()) { @@ -280,7 +279,6 @@ public class GMSClientMain implements PrivilegedAction<Object> } else if (command.equals(ARG_DEL_ADMIN)) { - String group = argMap.getValue(ARG_GROUP); if (group == null) throw new IllegalArgumentException("No group specified"); @@ -289,7 +287,7 @@ public class GMSClientMain implements PrivilegedAction<Object> throw new IllegalArgumentException("No user specified"); HttpPrincipal hp = new HttpPrincipal(userID); - Group cur = client.getGroup(new GroupURI(group)); + Group cur = client.getGroup(group); boolean update = false; Iterator<User> iter = cur.getUserAdmins().iterator(); while (iter.hasNext()) @@ -319,29 +317,15 @@ public class GMSClientMain implements PrivilegedAction<Object> } else if (command.equals(ARG_CREATE_GROUP)) { - String group = argMap.getValue(ARG_GROUP); if (group == null) throw new IllegalArgumentException("No group specified"); - GroupURI groupURI = null; - try - { - groupURI = new GroupURI(group); - } - catch (Exception e) - { - String message = "Invalid group URI format '" + - group + "': " + e.getMessage(); - log.debug(message, e); - throw new IllegalArgumentException(message); - } - AccessControlContext accessControlContext = AccessController.getContext(); Subject subject = Subject.getSubject(accessControlContext); Set<X500Principal> principals = subject.getPrincipals(X500Principal.class); X500Principal p = principals.iterator().next(); - Group g = new Group(groupURI); + Group g = new Group(guri); User member = new User(); member.getIdentities().add(p); @@ -350,11 +334,10 @@ public class GMSClientMain implements PrivilegedAction<Object> } else if (command.equals(ARG_GET_GROUP)) { - String group = argMap.getValue(ARG_GROUP); if (group == null) throw new IllegalArgumentException("No group specified"); - Group g = client.getGroup(new GroupURI(group)); + Group g = client.getGroup(group); System.out.println("found: " + g.getID()); System.out.println("\t" + g.description); System.out.println("owner: " + g.getOwner()); @@ -374,11 +357,10 @@ public class GMSClientMain implements PrivilegedAction<Object> } else if (command.equals(ARG_DELETE_GROUP)) { - String group = argMap.getValue(ARG_GROUP); if (group == null) throw new IllegalArgumentException("No group specified"); - client.deleteGroup(new GroupURI(group)); + client.deleteGroup(group); } return null; @@ -389,4 +371,4 @@ public class GMSClientMain implements PrivilegedAction<Object> return t; } } -} +} \ No newline at end of file diff --git a/cadc-access-control/src/test/java/ca/nrc/cadc/ac/GroupURITest.java b/cadc-access-control/src/test/java/ca/nrc/cadc/ac/GroupURITest.java index 423f7df9f070bf2d8771c67a31bdb40e3adf28f0..db202c749558b9fa17c202d7d667894105840280 100644 --- a/cadc-access-control/src/test/java/ca/nrc/cadc/ac/GroupURITest.java +++ b/cadc-access-control/src/test/java/ca/nrc/cadc/ac/GroupURITest.java @@ -18,6 +18,18 @@ public class GroupURITest Log4jInit.setLevel("ca.nrc.cadc.ac", Level.DEBUG); } + @Test + public void testEquals() + { + GroupURI uri1 = new GroupURI("ivo://example.org/gms?name"); + GroupURI uri2 = new GroupURI("ivo://example.org/gms?name"); + Assert.assertTrue(uri1.equals(uri2)); + + uri1 = new GroupURI("ivo://example.org/gms?name"); + uri2 = new GroupURI("ivo://example.org/gms#name"); + Assert.assertTrue(uri1.equals(uri2)); + } + @Test public void testMalformed() { @@ -46,7 +58,6 @@ public class GroupURITest { GroupURI g = new GroupURI("ivo://my.authority/gms?name"); Assert.assertEquals("ivo", g.getURI().getScheme()); - Assert.assertEquals("my.authority", g.getAuthority()); Assert.assertEquals("/gms", g.getURI().getPath()); Assert.assertEquals("name", g.getName()); Assert.assertEquals("ivo://my.authority/gms", g.getServiceID().toString()); @@ -65,7 +76,6 @@ public class GroupURITest { GroupURI g = new GroupURI("ivo://my.authority/gms#name"); Assert.assertEquals("ivo", g.getURI().getScheme()); - Assert.assertEquals("my.authority", g.getAuthority()); Assert.assertEquals("/gms", g.getURI().getPath()); Assert.assertEquals("name", g.getName()); Assert.assertEquals("ivo://my.authority/gms", g.getServiceID().toString()); diff --git a/cadc-access-control/src/test/java/ca/nrc/cadc/ac/client/GMSClientTest.java b/cadc-access-control/src/test/java/ca/nrc/cadc/ac/client/GMSClientTest.java index cfdc3a1847de3b94c53c5bd1812cb469c3bf2b43..d68ca7f6e17d93cb0b12266f7994f67a3734742e 100644 --- a/cadc-access-control/src/test/java/ca/nrc/cadc/ac/client/GMSClientTest.java +++ b/cadc-access-control/src/test/java/ca/nrc/cadc/ac/client/GMSClientTest.java @@ -115,11 +115,13 @@ public class GMSClientTest final RegistryClient mockRegistryClient = createMock(RegistryClient.class); -// expect(mockRegistryClient.getServiceURL(serviceID, Standards.UMS_USERS_01, AuthMethod.CERT)) -// .andReturn(new URL("http://mysite.com/users")); + final URI serviceID = URI.create("ivo://mysite.com/users"); + + expect(mockRegistryClient.getServiceURL(serviceID, Standards.UMS_USERS_01, AuthMethod.CERT)) + .andReturn(new URL("http://mysite.com/users")); replay(mockRegistryClient); - GMSClient client = new GMSClient() + GMSClient client = new GMSClient(serviceID) { @Override protected RegistryClient getRegistryClient() @@ -149,15 +151,15 @@ public class GMSClientTest final HttpPrincipal test1UserID = new HttpPrincipal("test"); subject.getPrincipals().add(test1UserID); - final URI serviceID = URI.create("ivo://example.org/gms"); + final URI serviceID = URI.create("ivo://mysite.com/users"); final RegistryClient mockRegistryClient = createMock(RegistryClient.class); expect(mockRegistryClient.getServiceURL(serviceID, Standards.GMS_GROUPS_01, AuthMethod.CERT )) - .andReturn(new URL("http://example.org/gms")); + .andReturn(new URL("http://mysite.com/users")); replay(mockRegistryClient); - final GMSClient client = new GMSClient() + final GMSClient client = new GMSClient(serviceID) { @Override protected RegistryClient getRegistryClient() @@ -173,42 +175,46 @@ public class GMSClientTest { List<Group> initial = client - .getCachedGroups(serviceID, test1UserID, Role.MEMBER, true); + .getCachedGroups(test1UserID, Role.MEMBER, true); Assert.assertNull("Cache should be null", initial); // add single group as isMember might do GroupURI group0uri = new GroupURI("ivo://example.org/gms?0"); Group group0 = new Group(group0uri); client.addCachedGroup(test1UserID, group0, Role.MEMBER); - List<Group> actual = client.getCachedGroups(serviceID, test1UserID, Role.MEMBER, true); + List<Group> actual = client + .getCachedGroups(test1UserID, Role.MEMBER, true); Assert.assertNull("Cache should be null", actual); - Group g = client.getCachedGroup(test1UserID, group0uri, Role.MEMBER); + Group g = client + .getCachedGroup(test1UserID, "0", Role.MEMBER); Assert.assertNotNull("cached group from incomplete cache", g); // add all groups like getMemberships might do List<Group> expected = new ArrayList<Group>(); - Group group1 = new Group(new GroupURI("ivo://example.org/gms?1")); - Group group2 = new Group(new GroupURI("ivo://example.org/gms?2")); + GroupURI group1uri = new GroupURI("ivo://example.org/gms?1"); + GroupURI group2uri = new GroupURI("ivo://example.org/gms?2"); + Group group1 = new Group(group1uri); + Group group2 = new Group(group2uri); expected.add(group0); expected.add(group1); expected.add(group2); - client.setCachedGroups(serviceID, test1UserID, expected, Role.MEMBER); + client.setCachedGroups(test1UserID, expected, Role.MEMBER); actual = client - .getCachedGroups(serviceID, test1UserID, Role.MEMBER, true); + .getCachedGroups(test1UserID, Role.MEMBER, true); Assert.assertEquals("Wrong cached groups", expected, actual); // check against another role actual = client - .getCachedGroups(serviceID, test1UserID, Role.OWNER, true); + .getCachedGroups(test1UserID, Role.OWNER, true); Assert.assertNull("Cache should be null", actual); // check against another userid final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser"); actual = client - .getCachedGroups(serviceID, anotherUserID, Role.MEMBER, true); + .getCachedGroups(anotherUserID, Role.MEMBER, true); Assert.assertNull("Cache should be null", actual); return null; @@ -228,7 +234,7 @@ public class GMSClientTest { List<Group> initial = client - .getCachedGroups(serviceID, test2UserID, Role.MEMBER, true); + .getCachedGroups(test2UserID, Role.MEMBER, true); Assert.assertNull("Cache should be null", initial); List<Group> expected = new ArrayList<Group>(); @@ -237,21 +243,21 @@ public class GMSClientTest expected.add(group1); expected.add(group2); - client.setCachedGroups(serviceID, test2UserID, expected, Role.MEMBER); + client.setCachedGroups(test2UserID, expected, Role.MEMBER); List<Group> actual = client - .getCachedGroups(serviceID, test2UserID, Role.MEMBER, true); + .getCachedGroups(test2UserID, Role.MEMBER, true); Assert.assertEquals("Wrong cached groups", expected, actual); // check against another role actual = client - .getCachedGroups(serviceID, test2UserID, Role.OWNER, true); + .getCachedGroups(test2UserID, Role.OWNER, true); Assert.assertNull("Cache should be null", actual); // check against another userid final HttpPrincipal anotherUserID = new HttpPrincipal("anotheruser"); actual = client - .getCachedGroups(serviceID, anotherUserID, Role.MEMBER, true); + .getCachedGroups(anotherUserID, Role.MEMBER, true); Assert.assertNull("Cache should be null", actual); return null; @@ -261,7 +267,7 @@ public class GMSClientTest // do the same without a subject List<Group> initial = client - .getCachedGroups(serviceID, test1UserID, Role.MEMBER, true); + .getCachedGroups(test1UserID, Role.MEMBER, true); Assert.assertNull("Cache should be null", initial); List<Group> newgroups = new ArrayList<Group>(); @@ -270,10 +276,10 @@ public class GMSClientTest newgroups.add(group1); newgroups.add(group2); - client.setCachedGroups(serviceID, test1UserID, newgroups, Role.MEMBER); + client.setCachedGroups(test1UserID, newgroups, Role.MEMBER); List<Group> actual = client - .getCachedGroups(serviceID, test1UserID, Role.MEMBER, true); + .getCachedGroups(test1UserID, Role.MEMBER, true); Assert.assertNull("Cache should still be null", actual); }