diff --git a/projects/cadcAccessControl-Server/build.xml b/projects/cadcAccessControl-Server/build.xml index e0c3d437bd12e91bc5d87e5548d35b5cfc66d065..c9b7e5c538100ffbf94bf9bf5c529ecfd8b66de1 100644 --- a/projects/cadcAccessControl-Server/build.xml +++ b/projects/cadcAccessControl-Server/build.xml @@ -149,7 +149,7 @@ <pathelement path="${jars}:${testingJars}"/> </classpath> <sysproperty key="ca.nrc.cadc.util.PropertiesReader.dir" value="test"/> - <test name="ca.nrc.cadc.ac.server.web.users.UserActionFactoryTest" /> + <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/UserPersistence.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/UserPersistence.java index 070080806602418dc3d0b5cacfc8849e375b0869..a384111bc699d2365af43f5f19b25bf123ba7570 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 @@ -133,7 +133,22 @@ public interface UserPersistence<T extends Principal> User<T> getPendingUser(T userID) throws UserNotFoundException, TransientException, AccessControlException; - + + /** + * Get the user specified by userID with all of the users identities. + * + * @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. + */ + User<T> getAugmentedUser(T userID) + throws UserNotFoundException, TransientException, + AccessControlException; + /** * Attempt to login the specified user. * @@ -148,7 +163,7 @@ public interface UserPersistence<T extends Principal> */ Boolean doLogin(String userID, String password) throws UserNotFoundException, TransientException, - AccessControlException; + AccessControlException; /** * Updated the user specified by User. diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java index dae9d245d651331b3a0994cbbfa5d63141c60eaf..9df8ef92109a19d612bd3aab99630494bce9a301 100755 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapDAO.java @@ -68,22 +68,17 @@ */ package ca.nrc.cadc.ac.server.ldap; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.auth.NumericPrincipal; -import ca.nrc.cadc.auth.OpenIdPrincipal; +import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.net.TransientException; import com.unboundid.ldap.sdk.DN; import com.unboundid.ldap.sdk.LDAPConnection; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.ResultCode; -import com.unboundid.ldap.sdk.SearchResult; -import com.unboundid.ldap.sdk.SearchScope; import org.apache.log4j.Logger; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; import java.security.AccessControlException; import java.security.AccessController; import java.security.GeneralSecurityException; @@ -159,12 +154,12 @@ public abstract class LdapDAO } } - protected DN getSubjectDN() throws LDAPException + protected DN getSubjectDN() + throws LDAPException { if (subjDN == null) { - Subject callerSubject = - Subject.getSubject(AccessController.getContext()); + Subject callerSubject = getSubject(); if (callerSubject == null) { throw new AccessControlException("Caller not authenticated."); @@ -176,48 +171,18 @@ public abstract class LdapDAO throw new AccessControlException("Caller not authenticated."); } - String ldapField = null; for (Principal p : principals) { - if (p instanceof HttpPrincipal) + if (p instanceof DNPrincipal) { - ldapField = "(uid=" + p.getName() + ")"; - break; - } - if (p instanceof NumericPrincipal) - { - ldapField = "(numericid=" + p.getName() + ")"; - break; - } - if (p instanceof X500Principal) - { - ldapField = "(distinguishedname=" + p.getName() + ")"; - break; - } - if (p instanceof OpenIdPrincipal) - { - ldapField = "(openid=" + p.getName() + ")"; - break; + subjDN = new DN(p.getName()); } } - if (ldapField == null) + if (subjDN == null) { throw new AccessControlException("Identity of caller unknown."); } - - SearchResult searchResult = - getConnection().search(config.getUsersDN(), SearchScope.ONE, - ldapField, "entrydn"); - - if (searchResult.getEntryCount() < 1) - { - throw new AccessControlException( - "No LDAP account when search with rule " + ldapField); - } - - subjDN = (searchResult.getSearchEntries().get(0)) - .getAttributeValueAsDN("entrydn"); } return subjDN; } @@ -268,4 +233,9 @@ public abstract class LdapDAO throw new RuntimeException("Ldap error (" + code.getName() + ")"); } + protected Subject getSubject() + { + return Subject.getSubject(AccessController.getContext()); + } + } 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 5108b0828c2c1618262d3aa22e63eedc69057829..a886b900f76e043157b596a0f45c147d62effac4 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 @@ -80,6 +80,7 @@ import java.util.Random; import javax.security.auth.x500.X500Principal; +import ca.nrc.cadc.auth.DNPrincipal; import org.apache.log4j.Logger; import ca.nrc.cadc.ac.PersonalDetails; @@ -146,7 +147,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO protected static final String LDAP_INSTITUTE = "institute"; protected static final String LDAP_UID = "uid"; - + private String[] userAttribs = new String[] { LDAP_FIRST_NAME, LDAP_LAST_NAME, LDAP_ADDRESS, LDAP_CITY, @@ -156,6 +157,10 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO { LDAP_FIRST_NAME, LDAP_LAST_NAME }; + private String[] identityAttribs = new String[] + { + LDAP_UID, LDAP_DISTINGUISHED_NAME, LDAP_NUMERICID, LDAP_ENTRYDN + }; public LdapUserDAO(LdapConfig config) { @@ -307,7 +312,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO catch (UserNotFoundException e) { throw new RuntimeException("BUG: new user " + userDN.toNormalizedString() + - " not found because " + e.getMessage()); + " not found"); } } catch (LDAPException e) @@ -367,8 +372,8 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO try { // add new user - - DN userX500DN = getUserRequestsDN(user.getUserID().getName()); + + DN userX500DN = getUserRequestsDN(user.getUserID().getName()); List<Attribute> attributes = new ArrayList<Attribute>(); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_ORG_PERSON); addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_USER); @@ -377,13 +382,13 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO .getName()); addAttribute(attributes, LADP_USER_PASSWORD, new String(userRequest .getPassword())); - addAttribute(attributes, LDAP_NUMERICID, + addAttribute(attributes, LDAP_NUMERICID, String.valueOf(genNextNumericId())); for (Principal princ : user.getIdentities()) { if (princ instanceof X500Principal) { - addAttribute(attributes, LDAP_DISTINGUISHED_NAME, + addAttribute(attributes, LDAP_DISTINGUISHED_NAME, princ.getName()); } } @@ -545,6 +550,57 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO return user; } + public User<T> getAugmentedUser(final T userID) + throws UserNotFoundException, TransientException + { + String searchField = userLdapAttrib.get(userID.getClass()); + if (searchField == null) + { + throw new IllegalArgumentException( + "Unsupported principal type " + userID.getClass()); + } + + try + { + + searchField = "(" + searchField + "=" + userID.getName() + ")"; + + logger.debug("search field: " + searchField); + + // TODO: Search must take into account deleted users (nsaccountlock attr) + + SearchRequest searchRequest = + new SearchRequest(config.getUsersDN(), SearchScope.ONE, + searchField, identityAttribs); + + SearchResultEntry searchResult = getConnection().searchForEntry(searchRequest); + + if (searchResult == null) + { + String msg = "User not found " + userID.toString(); + logger.debug(msg); + throw new UserNotFoundException(msg); + } + + User<T> user = new User<T>(userID); + user.getIdentities().add(new HttpPrincipal( + searchResult.getAttributeValue(LDAP_UID))); + user.getIdentities().add(new NumericPrincipal( + searchResult.getAttributeValueAsLong(LDAP_NUMERICID))); + user.getIdentities().add(new X500Principal( + searchResult.getAttributeValue(LDAP_DISTINGUISHED_NAME))); + user.getIdentities().add(new DNPrincipal( + searchResult.getAttributeValue(LDAP_ENTRYDN))); + return user; + } + catch (LDAPException e) + { + logger.debug("getGroup Exception: " + e, e); + LdapDAO.checkLdapResult(e.getResultCode()); + throw new RuntimeException("BUG: checkLdapResult didn't throw an exception"); + } + } + /** * Obtain whether the given DN tree requires authentication. * @@ -1037,9 +1093,9 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO LdapDAO.checkLdapResult(code); } } - + /** - * Method to return a randomly generated user numeric ID. The default + * Method to return a randomly generated user numeric ID. The default * implementation returns a value between 10000 and Integer.MAX_VALUE. * Services that support a different mechanism for generating numeric * IDs overide this method. 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 fd8b41ec1abb427b629fc026f53eda34b767937a..f39a41af9f1c305945416d3b2961b559a5938bd3 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 @@ -115,14 +115,14 @@ public class LdapUserPersistence<T extends Principal> } } } - + /** * Add the new user. * * @param user * * @return User instance. - * + * * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. */ @@ -151,7 +151,7 @@ public class LdapUserPersistence<T extends Principal> * @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. @@ -202,13 +202,42 @@ public class LdapUserPersistence<T extends Principal> } } + /** + * Get the user specified by userID with all of the users identities. + * + * @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> getAugmentedUser(T userID) + throws UserNotFoundException, TransientException + { + LdapUserDAO<T> userDAO = null; + try + { + userDAO = new LdapUserDAO<T>(this.config); + return userDAO.getAugmentedUser(userID); + } + finally + { + if (userDAO != null) + { + userDAO.close(); + } + } + } + /** * Get the user specified by userID. * * @param userID The userID. * * @return Boolean. - * + * * @throws UserNotFoundException when the user is not found. * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. @@ -237,13 +266,13 @@ public class LdapUserPersistence<T extends Principal> * @param user The user to update. * * @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> modifyUser(User<T> user) - throws UserNotFoundException, TransientException, + throws UserNotFoundException, TransientException, AccessControlException { LdapUserDAO<T> userDAO = null; @@ -288,18 +317,18 @@ public class LdapUserPersistence<T extends Principal> } } } - + /** * Delete the user specified by userID. * * @param userID The userID. - * + * * @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 void deleteUser(T userID) - throws UserNotFoundException, TransientException, + throws UserNotFoundException, TransientException, AccessControlException { LdapUserDAO<T> userDAO = null; @@ -316,17 +345,17 @@ public class LdapUserPersistence<T extends Principal> } } } - + /** * Get all groups the user specified by userID belongs to. This method is created * to provide optimization for the LDAP server. - * + * * @param userID The userID. * @param isAdmin return only admin Groups when true, else return non-admin * Groups. - * + * * @return Collection of Group DN. - * + * * @throws UserNotFoundException when the user is not found. * @throws TransientException If an temporary, unexpected problem occurred. * @throws AccessControlException If the operation is not permitted. @@ -348,7 +377,7 @@ public class LdapUserPersistence<T extends Principal> } } } - + /** * Check whether the user is a member of the group. This method is created * to provide optimization for the LDAP server. diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/AbstractUserAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/AbstractUserAction.java index af79d45ffa72d6f8adcbe4db50a154d006aca303..0bc7392038066642dccb6dc7d7dca583a7f68042 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/AbstractUserAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/AbstractUserAction.java @@ -108,7 +108,7 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob static final String DEFAULT_CONTENT_TYPE = "text/xml"; static final String JSON_CONTENT_TYPE = "application/json"; - protected String augmentUserDN; + protected boolean isAugmentUser; protected UserLogInfo logInfo; protected SyncOutput syncOut; @@ -116,18 +116,19 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob AbstractUserAction() { + this.isAugmentUser = false; } public abstract void doAction() throws Exception; - public void setAugmentUserDN(final String dn) + public void setAugmentUser(final boolean isAugmentUser) { - this.augmentUserDN = dn; + this.isAugmentUser = isAugmentUser; } - public String getAugmentUserDN() + public boolean isAugmentUser() { - return this.augmentUserDN; + return this.isAugmentUser; } public void setLogInfo(UserLogInfo logInfo) diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java index 7442a6896a6438ea878d7809a69645198be3af7f..ee81cfd60b063125547483e437c89e58a1d5cb13 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/GetUserAction.java @@ -71,25 +71,18 @@ import ca.nrc.cadc.ac.PersonalDetails; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.server.UserPersistence; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.auth.NumericPrincipal; +import org.apache.log4j.Logger; -import java.security.AccessControlContext; +import javax.security.auth.Subject; import java.security.AccessController; import java.security.Principal; -import java.security.PrivilegedExceptionAction; import java.util.Set; -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; - -import org.apache.log4j.Logger; - - public class GetUserAction extends AbstractUserAction { private static final Logger log = Logger.getLogger(GetUserAction.class); + private final Principal userID; private final String detail; @@ -102,56 +95,58 @@ public class GetUserAction extends AbstractUserAction public void doAction() throws Exception { - User<Principal> user; - - if (isAugmentUser()) - { - Subject subject = new Subject(); - subject.getPrincipals().add(this.userID); - user = Subject.doAs(subject, new PrivilegedExceptionAction<User<Principal>>() - { - @Override - public User<Principal> run() throws Exception - { - return getUser(userID); - } - - }); - } - else - { - user = getUser(this.userID); - } - + User<Principal> user = getUser(this.userID); writeUser(user); } protected User<Principal> getUser(Principal principal) throws Exception { + User<Principal> user; final UserPersistence<Principal> userPersistence = getUserPersistence(); - User<Principal> user; - - try + + /** + * Special case 1 + * If the calling Subject user is the notAugmentedX500User, AND it is + * a GET, call the userDAO to get the User with all identities. + */ + if (isAugmentUser()) { - user = userPersistence.getUser(principal); + log.debug("getting augmented user " + principal.getName()); + user = userPersistence.getAugmentedUser(principal); } - catch (UserNotFoundException e) + + /** + * Special case 2 + * If detail=identity, AND if the calling Subject user is the same as + * the requested User, then return the User with the principals from the + * Subject which has already been augmented. + */ + else if (detail != null && + detail.equalsIgnoreCase("identity") && + isSubjectUser(principal)) { - user = userPersistence.getPendingUser(principal); + log.debug("augmenting " + principal.getName() + " from subject"); + Subject subject = Subject.getSubject(AccessController.getContext()); + user = new User<Principal>(principal); + user.getIdentities().addAll(subject.getPrincipals()); } - - if (detail != null) + else { - // Only return user principals - if (detail.equals("identity")) + log.debug("getting user " + principal.getName()); + try { - user.details.clear(); + user = userPersistence.getUser(principal); } + catch (UserNotFoundException e) + { + user = userPersistence.getPendingUser(principal); + } + // Only return user profile info, first and last name. - else if (detail.equals("display")) + if (detail != null && detail.equalsIgnoreCase("display")) { user.getIdentities().clear(); - Set<PersonalDetails> details = user.getDetails(PersonalDetails.class); + Set<PersonalDetails> details = user.getDetails(PersonalDetails.class); if (details.isEmpty()) { String error = principal.getName() + " missing required PersonalDetails"; @@ -161,30 +156,27 @@ public class GetUserAction extends AbstractUserAction user.details.clear(); user.details.add(new PersonalDetails(pd.getFirstName(), pd.getLastName())); } - else - { - throw new IllegalArgumentException("Illegal detail parameter " + detail); - } + } - return user; + return user; } - - protected boolean isAugmentUser() + + protected boolean isSubjectUser(Principal userPrincipal) { - AccessControlContext acc = AccessController.getContext(); - Subject subject = Subject.getSubject(acc); + boolean isSubjectUser = false; + Subject subject = Subject.getSubject(AccessController.getContext()); if (subject != null) { - for (Principal principal : subject.getPrincipals(HttpPrincipal.class)) + for (Principal subjectPrincipal : subject.getPrincipals()) { - if (principal.getName().equals(this.getAugmentUserDN())) + if (subjectPrincipal.getName().equals(userPrincipal.getName())) { - return true; + isSubjectUser = true; + break; } } } - - return false; + return isSubjectUser; } } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java index 30583c7ff083819565324705e964097eb6cc743f..a369ac4944ab4cfbe55bf02dcabbf13ada37a5dd 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java @@ -75,16 +75,14 @@ import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.IdentityType; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.auth.OpenIdPrincipal; +import org.apache.log4j.Logger; +import javax.security.auth.x500.X500Principal; +import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.net.URL; import java.security.Principal; -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServletRequest; - -import org.apache.log4j.Logger; - public abstract class UserActionFactory { diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserServlet.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserServlet.java index 6dedcc71833bd72d4206f9e0b989b17e05b2a046..e73a9ae960f0fe30961108681ca9c8964c1b34b3 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserServlet.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UserServlet.java @@ -68,30 +68,37 @@ */ package ca.nrc.cadc.ac.server.web.users; -import java.io.IOException; -import java.security.PrivilegedActionException; +import ca.nrc.cadc.ac.server.web.SyncOutput; +import ca.nrc.cadc.auth.AuthenticationUtil; +import ca.nrc.cadc.auth.ServletPrincipalExtractor; +import ca.nrc.cadc.auth.X509CertificateChain; +import ca.nrc.cadc.util.ArrayUtil; +import ca.nrc.cadc.util.StringUtil; +import org.apache.log4j.Logger; import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import ca.nrc.cadc.util.StringUtil; - -import org.apache.log4j.Logger; - -import ca.nrc.cadc.ac.server.web.SyncOutput; -import ca.nrc.cadc.auth.AuthenticationUtil; +import java.io.IOException; +import java.security.AccessController; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Set; public class UserServlet extends HttpServlet { private static final long serialVersionUID = 5289130885807305288L; private static final Logger log = Logger.getLogger(UserServlet.class); - private String augmentUser; - + + private String notAugmentedX500User; + @Override public void init(final ServletConfig config) throws ServletException { @@ -99,8 +106,8 @@ public class UserServlet extends HttpServlet try { - this.augmentUser = config.getInitParameter(UserServlet.class.getName() + ".augmentUser"); - log.info("augmentUser: " + augmentUser); + this.notAugmentedX500User = config.getInitParameter(UserServlet.class.getName() + ".NotAugmentedX500User"); + log.info("notAugmentedX500User: " + notAugmentedX500User); } catch(Exception ex) { @@ -120,13 +127,25 @@ public class UserServlet extends HttpServlet try { log.info(logInfo.start()); - Subject subject = AuthenticationUtil.getSubject(request); + AbstractUserAction action = factory.createAction(request); + + // Special case: if the calling subject has a servops X500Principal, + // AND it is a GET request, do not augment the subject. + Subject subject; + if (action instanceof GetUserAction && isNotAugmentedSubject(request)) + { + subject = Subject.getSubject(AccessController.getContext()); + log.debug("subject not augmented: " + subject); + action.setAugmentUser(true); + } + else + { + subject = AuthenticationUtil.getSubject(request); + log.debug("augmented subject: " + subject); + } logInfo.setSubject(subject); - AbstractUserAction action = factory.createAction(request); SyncOutput syncOut = new SyncOutput(response); - - action.setAugmentUserDN(this.augmentUser); action.setLogInfo(logInfo); action.setSyncOut(syncOut); action.setAcceptedContentType(getAcceptedContentType(request)); @@ -236,4 +255,25 @@ public class UserServlet extends HttpServlet return AbstractUserAction.DEFAULT_CONTENT_TYPE; } } + + protected boolean isNotAugmentedSubject(HttpServletRequest request) + { + ServletPrincipalExtractor extractor = new ServletPrincipalExtractor(request); + Set<Principal> principals = extractor.getPrincipals(); + log.debug("Principals: " + principals); + + for (Principal principal : principals) + { + if (principal instanceof X500Principal) + { + if (principal.getName().equalsIgnoreCase(notAugmentedX500User)) + { + return true; + } + } + } + + return false; + + } } diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/auth/AuthenticatorImpl.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/auth/AuthenticatorImpl.java index 024549e6ea3053593c4734ac608638b875154193..1812fc7eaa9cc6704f2022fe4b3085fda9eb5a5e 100644 --- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/auth/AuthenticatorImpl.java +++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/auth/AuthenticatorImpl.java @@ -72,10 +72,13 @@ package ca.nrc.cadc.auth; import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserNotFoundException; import ca.nrc.cadc.ac.server.ldap.LdapUserPersistence; +import ca.nrc.cadc.net.TransientException; import ca.nrc.cadc.profiler.Profiler; import org.apache.log4j.Logger; import javax.security.auth.Subject; + +import java.security.AccessControlException; import java.security.Principal; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -123,34 +126,31 @@ public class AuthenticatorImpl implements Authenticator protected void augmentSubject(final Subject subject) { + try { - PrivilegedExceptionAction<Object> action = - new PrivilegedExceptionAction<Object>() - { - public Object run() throws Exception - { - try - { - LdapUserPersistence<Principal> dao = new LdapUserPersistence<Principal>(); - User<Principal> user = dao.getUser(subject.getPrincipals().iterator().next()); - subject.getPrincipals().addAll(user.getIdentities()); - } - catch (UserNotFoundException e) - { - // ignore, could be an anonymous user - } - return null; - } - }; - - Subject.doAs(subject, action); + LdapUserPersistence<Principal> dao = new LdapUserPersistence<Principal>(); + User<Principal> user = dao.getAugmentedUser(subject.getPrincipals().iterator().next()); + if (user.getIdentities() != null) + { + log.debug("Found " + user.getIdentities().size() + " principals after agument"); + } + else + { + log.debug("Null identities after augment"); + } + subject.getPrincipals().addAll(user.getIdentities()); } - catch (PrivilegedActionException e) + catch (UserNotFoundException e) { - String msg = "Error augmenting subject " + subject; - throw new RuntimeException(msg, e); + // ignore, could be an anonymous user + log.debug("could not find user for augmenting", e); } + catch (TransientException e) + { + throw new IllegalStateException("Internal error", e); + } + } } diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapDAOTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapDAOTest.java index 05e33b33e00b65a6d6cc2a48201937f339377647..18b0b109aa38cbf9f89a699d67225b18e522527b 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapDAOTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapDAOTest.java @@ -68,22 +68,23 @@ package ca.nrc.cadc.ac.server.ldap; -import java.security.PrivilegedExceptionAction; - -import javax.net.ssl.SSLSocketFactory; -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; - +import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import ca.nrc.cadc.util.Log4jInit; - +import com.unboundid.ldap.sdk.DN; import com.unboundid.ldap.sdk.LDAPConnection; - import org.apache.log4j.Level; -import org.junit.Test; import org.junit.BeforeClass; -import static org.junit.Assert.*; +import org.junit.Test; + +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; +import java.security.PrivilegedExceptionAction; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; public class LdapDAOTest extends AbstractLdapDAOTest @@ -172,6 +173,31 @@ public class LdapDAOTest extends AbstractLdapDAOTest } + @Test + public void testGetSubjectDN() throws Exception + { + DN expected = new DN("uid=foo,ou=bar,dc=net"); + final DNPrincipal dnPrincipal = new DNPrincipal(expected.toNormalizedString()); + + LdapConfig config = LdapConfig.getLdapConfig("LdapConfig.test.properties"); + LdapDAO ldapDAO = new LdapDAO(config) + { + @Override + protected Subject getSubject() + { + Subject subject = new Subject(); + subject.getPrincipals().add(new HttpPrincipal("foo")); + subject.getPrincipals().add(new X500Principal("uid=foo,o=bar")); + subject.getPrincipals().add(dnPrincipal); + return subject; + } + }; + + DN actual = ldapDAO.getSubjectDN(); + assertNotNull("DN is null", actual); + assertEquals("DN's do not match", expected.toNormalizedString(), actual.toNormalizedString()); + } + private void testConnection(final LDAPConnection ldapCon) { assertTrue("Not connected but should be.", ldapCon.isConnected()); 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 24b055459faa0ebe77d4fb669f3431118b147869..5ec862782981d86de578bb287bb8e6c234e82a8e 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 @@ -74,6 +74,7 @@ import ca.nrc.cadc.ac.GroupNotFoundException; import ca.nrc.cadc.ac.GroupProperty; import ca.nrc.cadc.ac.Role; import ca.nrc.cadc.ac.User; +import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.util.Log4jInit; import org.apache.log4j.Level; @@ -104,7 +105,13 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest static String daoTestDN2 = "cn=" + daoTestUid2 + ",ou=cadc,o=hia,c=ca"; static String daoTestDN3 = "cn=" + daoTestUid3 + ",ou=cadc,o=hia,c=ca"; static String unknownDN = "cn=foo,ou=cadc,o=hia,c=ca"; - + + static String daoTestEntryDN1 = "uid=cadcdaotest1,ou=users,ou=ds,dc=testcanfar"; + static String daoTestEntryDN2 = "uid=cadcdaotest2,ou=users,ou=ds,dc=testcanfar"; + + static DNPrincipal daoDNPrincipal1; + static DNPrincipal daoDNPrincipal2; + static X500Principal daoTestPrincipal1; static X500Principal daoTestPrincipal2; static X500Principal daoTestPrincipal3; @@ -135,6 +142,9 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest daoTestPrincipal3 = new X500Principal(daoTestDN3); unknownPrincipal = new X500Principal(unknownDN); + daoDNPrincipal1 = new DNPrincipal(daoTestEntryDN1); + daoDNPrincipal2 = new DNPrincipal(daoTestEntryDN2); + daoTestUser1 = new User<X500Principal>(daoTestPrincipal1); daoTestUser2 = new User<X500Principal>(daoTestPrincipal2); daoTestUser3 = new User<X500Principal>(daoTestPrincipal3); @@ -142,9 +152,11 @@ public class LdapGroupDAOTest extends AbstractLdapDAOTest daoTestUser1Subject = new Subject(); daoTestUser1Subject.getPrincipals().add(daoTestUser1.getUserID()); + daoTestUser1Subject.getPrincipals().add(daoDNPrincipal1); daoTestUser2Subject = new Subject(); daoTestUser2Subject.getPrincipals().add(daoTestUser2.getUserID()); + daoTestUser2Subject.getPrincipals().add(daoDNPrincipal2); anonSubject = new Subject(); anonSubject.getPrincipals().add(unknownUser.getUserID()); diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java index cb143e90e8fedc9c87677763f09ac55b3c23b67f..68ca8ae3855d9854db2b82281ac95d13f1de7bfb 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java @@ -82,6 +82,7 @@ import java.util.Random; import javax.security.auth.Subject; import javax.security.auth.x500.X500Principal; +import ca.nrc.cadc.auth.DNPrincipal; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.BeforeClass; @@ -103,12 +104,16 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest private static final Logger log = Logger.getLogger(LdapUserDAOTest.class); static final String testUserX509DN = "cn=cadcdaotest1,ou=cadc,o=hia,c=ca"; + static final String testUser1EntryDN = "uid=cadcdaotest1,ou=users,ou=ds,dc=testcanfar"; + static final String testUser2EntryDN = "uid=cadcdaotest2,ou=users,ou=ds,dc=testcanfar"; static int nextUserNumericID = 666; static String testUserDN; static User<X500Principal> testUser; static User<X500Principal> testMember; static User<HttpPrincipal> testPendingUser; + static DNPrincipal testUser1DNPrincipal; + static DNPrincipal testUser2DNPrincipal; static LdapConfig config; static Random ran = new Random(); // source of randomness for numeric ids @@ -117,7 +122,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest public static void setUpBeforeClass() throws Exception { - Log4jInit.setLevel("ca.nrc.cadc.ac", Level.DEBUG); + Log4jInit.setLevel("ca.nrc.cadc.ac", Level.INFO); // get the configuration of the development server from and config files... config = getLdapConfig(); @@ -128,10 +133,10 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest new User<HttpPrincipal>(new HttpPrincipal("CADCtestRequest")); testPendingUser.details.add(new PersonalDetails("CADCtest", "Request")); testPendingUser.getIdentities().add( - new HttpPrincipal("CADCtestRequest")); + new HttpPrincipal("CADCtestRequest")); testPendingUser.getIdentities().add( - new X500Principal( - "uid=CADCtestRequest,ou=userrequests,ou=ds,dc=testcanfar")); + new X500Principal( + "uid=CADCtestRequest,ou=userrequests,ou=ds,dc=testcanfar")); testPendingUser.getIdentities().add(new NumericPrincipal(66666)); testUser.details.add(new PersonalDetails("CADC", "DAOTest1")); @@ -147,7 +152,9 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest testMember = new User<X500Principal>(testUserX500Princ); testMember.details.add(new PersonalDetails("CADC", "DAOTest1")); testMember.getIdentities().add(new HttpPrincipal("CadcDaoTest1")); - + + testUser1DNPrincipal = new DNPrincipal(testUser1EntryDN); + testUser2DNPrincipal = new DNPrincipal(testUser2EntryDN); } <T extends Principal> LdapUserDAO<T> getUserDAO() throws Exception @@ -227,6 +234,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { Subject subject = new Subject(); subject.getPrincipals().add(testUser.getUserID()); + subject.getPrincipals().add(testUser1DNPrincipal); // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() @@ -258,6 +266,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { Subject subject = new Subject(); subject.getPrincipals().add(testUser.getUserID()); + subject.getPrincipals().add(testUser1DNPrincipal); // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() @@ -267,7 +276,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest try { Collection<DN> groups = getUserDAO().getUserGroups(testUser.getUserID(), - false); + false); assertNotNull("Groups should not be null.", groups); for (DN groupDN : groups) @@ -301,6 +310,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { Subject subject = new Subject(); subject.getPrincipals().add(testUser.getUserID()); + subject.getPrincipals().add(testUser1DNPrincipal); // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() @@ -314,7 +324,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest String groupDN = "cn=cadcdaotestgroup1," + config.getGroupsDN(); isMember = getUserDAO().isMember(testUser.getUserID(), - groupDN); + groupDN); assertTrue("Membership should exist.", isMember); return null; @@ -335,7 +345,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest { Subject subject = new Subject(); subject.getPrincipals().add(testUser.getUserID()); - + subject.getPrincipals().add(testUser1DNPrincipal); // do everything as owner Subject.doAs(subject, new PrivilegedExceptionAction<Object>() @@ -579,6 +589,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest // add the user Subject subject = new Subject(); subject.getPrincipals().add(testUser2.getUserID()); + subject.getPrincipals().add(testUser2DNPrincipal); Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { public Object run() @@ -633,6 +644,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest // update the user subject.getPrincipals().add(testUser2.getUserID()); + subject.getPrincipals().add(testUser2DNPrincipal); User<? extends Principal> updatedUser = (User<? extends Principal>) Subject.doAs(subject, new PrivilegedExceptionAction<Object>() { @@ -662,7 +674,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest assertEquals(user1, user2); assertEquals(user1.details, user2.details); assertEquals(user1.details.size(), user2.details.size()); - assertEquals(user1.getIdentities().size(), user2.getIdentities().size()); + assertEquals("# principals not equal", user1.getIdentities().size(), user2.getIdentities().size()); for( Principal princ1 : user1.getIdentities()) { boolean found = false; diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java index 7727194981084f8d071205b6861e394b99762e28..8c77cf530780e5e285dd29a49a376cedbd12ea85 100644 --- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java +++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/GetUserActionTest.java @@ -78,12 +78,14 @@ import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.NumericPrincipal; import org.junit.Test; +import javax.security.auth.Subject; import javax.security.auth.x500.X500Principal; import javax.servlet.http.HttpServletResponse; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.security.Principal; +import java.security.PrivilegedExceptionAction; import java.util.HashSet; import java.util.Set; @@ -135,13 +137,85 @@ public class GetUserActionTest @Test public void writeUserWithDetailIdentity() throws Exception + { + final HttpPrincipal httpPrincipal = new HttpPrincipal("CADCtest"); + final NumericPrincipal numericPrincipal = new NumericPrincipal(789); + final X500Principal x500Principal = new X500Principal("cn=foo,o=bar"); + + Subject testUser = new Subject(); + testUser.getPrincipals().add(httpPrincipal); + testUser.getPrincipals().add(numericPrincipal); + testUser.getPrincipals().add(x500Principal); + + Subject.doAs(testUser, new PrivilegedExceptionAction<Object>() + { + public Object run() throws Exception + { + + final HttpServletResponse mockResponse = createMock(HttpServletResponse.class); + final UserPersistence<HttpPrincipal> mockUserPersistence = + createMock(UserPersistence.class); + + + final GetUserAction testSubject = new GetUserAction(httpPrincipal, "identity") + { + @Override + UserPersistence<HttpPrincipal> getUserPersistence() + { + return mockUserPersistence; + } + }; + + final User<HttpPrincipal> expected = new User<HttpPrincipal>(httpPrincipal); + expected.getIdentities().add(httpPrincipal); + expected.getIdentities().add(numericPrincipal); + expected.getIdentities().add(x500Principal); + + StringBuilder sb = new StringBuilder(); + UserWriter userWriter = new UserWriter(); + userWriter.write(expected, sb); + String expectedUser = sb.toString(); + + final PersonalDetails personalDetails = new PersonalDetails("cadc", "test"); + personalDetails.city = "city"; + expected.details.add(personalDetails); + + final PosixDetails posixDetails = new PosixDetails(123L, 456L, "/dev/null"); + expected.details.add(posixDetails); + + final Writer writer = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(writer); + + mockResponse.setHeader("Content-Type", "text/xml"); + expectLastCall().once(); + expect(mockResponse.getWriter()).andReturn(printWriter).once(); + + replay(mockUserPersistence, mockResponse); + + SyncOutput syncOutput = new SyncOutput(mockResponse); + testSubject.setSyncOut(syncOutput); + testSubject.doAction(); + + String actualUser = writer.toString(); + + assertEquals(expectedUser, actualUser); + + verify(mockUserPersistence, mockResponse); + + return null; + } + }); + } + + @Test + public void writeUserWithDetailDisplay() throws Exception { final HttpServletResponse mockResponse = createMock(HttpServletResponse.class); final UserPersistence<HttpPrincipal> mockUserPersistence = createMock(UserPersistence.class); final HttpPrincipal userID = new HttpPrincipal("CADCtest"); - final GetUserAction testSubject = new GetUserAction(userID, "identity") + final GetUserAction testSubject = new GetUserAction(userID, "display") { @Override UserPersistence<HttpPrincipal> getUserPersistence() @@ -151,17 +225,21 @@ public class GetUserActionTest }; final User<HttpPrincipal> expected = new User<HttpPrincipal>(userID); - expected.getIdentities().add(new NumericPrincipal(789)); - expected.getIdentities().add(new X500Principal("cn=foo,o=bar")); + + final PersonalDetails personalDetails = new PersonalDetails("cadc", "test"); + expected.details.add(personalDetails); StringBuilder sb = new StringBuilder(); UserWriter userWriter = new UserWriter(); userWriter.write(expected, sb); String expectedUser = sb.toString(); - final PersonalDetails personalDetails = new PersonalDetails("cadc", "test"); - personalDetails.city = "city"; - expected.details.add(personalDetails); + Set<PersonalDetails> details = expected.getDetails(PersonalDetails.class); + PersonalDetails pd = details.iterator().next(); + pd.city = "city"; + + expected.getIdentities().add(new NumericPrincipal(789)); + expected.getIdentities().add(new X500Principal("cn=foo,o=bar")); final PosixDetails posixDetails = new PosixDetails(123L, 456L, "/dev/null"); expected.details.add(posixDetails); @@ -188,46 +266,40 @@ public class GetUserActionTest } @Test - public void writeUserWithDetailDisplay() throws Exception + public void writeAugmentedUser() throws Exception { - final HttpServletResponse mockResponse = createMock(HttpServletResponse.class); - final UserPersistence<HttpPrincipal> mockUserPersistence = + final UserPersistence<Principal> mockUserPersistence = createMock(UserPersistence.class); - final HttpPrincipal userID = new HttpPrincipal("CADCtest"); + final HttpServletResponse mockResponse = createMock(HttpServletResponse.class); - final GetUserAction testSubject = new GetUserAction(userID, "display") + final HttpPrincipal userID = new HttpPrincipal("CADCtest"); + final GetUserAction testSubject = new GetUserAction(userID, null) { @Override - UserPersistence<HttpPrincipal> getUserPersistence() + UserPersistence<Principal> getUserPersistence() { return mockUserPersistence; } }; + testSubject.setAugmentUser(true); - final User<HttpPrincipal> expected = new User<HttpPrincipal>(userID); + final NumericPrincipal numericPrincipal = new NumericPrincipal(789); + final X500Principal x500Principal = new X500Principal("cn=foo,o=bar"); - final PersonalDetails personalDetails = new PersonalDetails("cadc", "test"); - expected.details.add(personalDetails); + final User<Principal> expected = new User<Principal>(userID); + expected.getIdentities().add(userID); + expected.getIdentities().add(numericPrincipal); + expected.getIdentities().add(x500Principal); StringBuilder sb = new StringBuilder(); UserWriter userWriter = new UserWriter(); userWriter.write(expected, sb); String expectedUser = sb.toString(); - Set<PersonalDetails> details = expected.getDetails(PersonalDetails.class); - PersonalDetails pd = details.iterator().next(); - pd.city = "city"; - - expected.getIdentities().add(new NumericPrincipal(789)); - expected.getIdentities().add(new X500Principal("cn=foo,o=bar")); - - final PosixDetails posixDetails = new PosixDetails(123L, 456L, "/dev/null"); - expected.details.add(posixDetails); - final Writer writer = new StringWriter(); final PrintWriter printWriter = new PrintWriter(writer); - expect(mockUserPersistence.getUser(userID)).andReturn(expected).once(); + expect(mockUserPersistence.getAugmentedUser(userID)).andReturn(expected).once(); mockResponse.setHeader("Content-Type", "text/xml"); expectLastCall().once(); expect(mockResponse.getWriter()).andReturn(printWriter).once(); diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java index 732e406596b8cadc758526c86342742ebd4ccd1c..2e64ba5f286d43d54fc6d9f6d2573d121de8c981 100644 --- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java +++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java @@ -79,6 +79,7 @@ import ca.nrc.cadc.ac.User; import ca.nrc.cadc.ac.UserDetails; import ca.nrc.cadc.ac.UserRequest; import ca.nrc.cadc.ac.WriterException; +import ca.nrc.cadc.auth.DNPrincipal; import ca.nrc.cadc.auth.HttpPrincipal; import ca.nrc.cadc.auth.IdentityType; import ca.nrc.cadc.auth.NumericPrincipal; @@ -266,6 +267,10 @@ public abstract class AbstractReaderWriter { principal = new X500Principal(identity); } + else if (type.equals(IdentityType.ENTRY_DN.getValue())) + { + principal = new DNPrincipal(identity); + } else { String error = "Unknown type attribute: " + type; @@ -729,6 +734,10 @@ public abstract class AbstractReaderWriter { identityElement.setAttribute("type", IdentityType.X500.getValue()); } + else if ((identity instanceof DNPrincipal)) + { + identityElement.setAttribute("type", IdentityType.ENTRY_DN.getValue()); + } else { String error = "Unsupported Principal type " + diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/UserClientTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/UserClientTest.java index 6a84fb04bcb8e5c1789b0d3a160dd3df356937ec..8b7f3a617ef2c673b5d81ebd28de329bc7fc3506 100644 --- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/UserClientTest.java +++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/client/UserClientTest.java @@ -69,9 +69,22 @@ package ca.nrc.cadc.ac.client; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.Principal; + +import javax.management.remote.JMXPrincipal; +import javax.security.auth.Subject; + import org.apache.log4j.Level; import org.apache.log4j.Logger; -import ca.nrc.cadc.ac.client.UserClient; + +import ca.nrc.cadc.ac.AC; +import ca.nrc.cadc.auth.HttpPrincipal; +import ca.nrc.cadc.auth.NumericPrincipal; +import ca.nrc.cadc.reg.client.RegistryClient; import ca.nrc.cadc.util.Log4jInit; import org.junit.Assert; @@ -123,4 +136,75 @@ public class UserClientTest Assert.fail("Unexpected exception: " + t.getMessage()); } } + + @Test + public void testSubjectWithNoPrincipal() + { + try + { + // test subject augmentation given a subject with no principal + Subject subject = new Subject(); + this.createUserClient().augmentSubject(subject); + Assert.assertEquals("Should have no principal.", 0, subject.getPrincipals().size()); + } + catch(Throwable t) + { + Assert.fail("Unexpected exception: " + t.getMessage()); + } + } + + @Test + public void testSubjectWithMultiplePrincipal() + { + try + { + // test subject augmentation given a subject with more than one principal + Subject subject = new Subject(); + subject.getPrincipals().add(new NumericPrincipal(4)); + subject.getPrincipals().add(new HttpPrincipal("cadcauthtest1")); + this.createUserClient().augmentSubject(subject); + Assert.fail("Expecting an IllegalArgumentException."); + } + catch(IllegalArgumentException e) + { + String expected = "Subject has more than one principal."; + Assert.assertEquals(expected, e.getMessage()); + } + catch(Throwable t) + { + Assert.fail("Unexpected exception: " + t.getMessage()); + } + } + + @Test + public void testSubjectWithUnsupportedPrincipal() + { + Principal principal = new JMXPrincipal("APIName"); + try + { + // test subject augmentation given a subject with more than one principal + Subject subject = new Subject(); + subject.getPrincipals().add(principal); + this.createUserClient().augmentSubject(subject); + Assert.fail("Expecting an IllegalArgumentException."); + } + catch(IllegalArgumentException e) + { + String expected = "Subject has unsupported principal " + principal.getName(); + Assert.assertEquals(expected, e.getMessage()); + } + catch(Throwable t) + { + Assert.fail("Unexpected exception: " + t.getMessage()); + } + } + + protected UserClient createUserClient() throws URISyntaxException, MalformedURLException + { + RegistryClient regClient = new RegistryClient(); + URI serviceURI = new URI(AC.GMS_SERVICE_URI); + URL baseURL = regClient.getServiceURL(serviceURI, "https"); + return new UserClient(baseURL.toString()); + + } }