diff --git a/projects/cadcAccessControl-Server/config/LdapConfig.properties b/projects/cadcAccessControl-Server/config/LdapConfig.properties
index 5eb874d802b890852e308e6880946751513437dc..7f84e0ef1ff8f879063bdcad791378acdf91ad83 100644
--- a/projects/cadcAccessControl-Server/config/LdapConfig.properties
+++ b/projects/cadcAccessControl-Server/config/LdapConfig.properties
@@ -3,5 +3,6 @@ server = <name of server>
 port = <389 or 636>
 proxyUser = <name of proxy user>
 usersDn = <DN of users branch>
+userRequestsDN = <DN of new users branch>
 groupsDn = <DN of groups branch>
 adminGroupsDn = <DN of admin groups>
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 4ca163f97df71f630742b26d0341566f28215339..f6d1e2e69aa45730707c07933b994f1a805236cd 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
@@ -70,6 +70,7 @@ package ca.nrc.cadc.ac.server;
 
 import ca.nrc.cadc.ac.User;
 import ca.nrc.cadc.ac.UserNotFoundException;
+import ca.nrc.cadc.ac.UserRequest;
 import ca.nrc.cadc.net.TransientException;
 import com.unboundid.ldap.sdk.DN;
 import java.security.AccessControlException;
@@ -98,7 +99,7 @@ public abstract interface UserPersistence<T extends Principal>
      * @throws TransientException If an temporary, unexpected problem occurred.
      * @throws AccessControlException If the operation is not permitted.
      */
-    public abstract User<T> addUser(User<T> user)
+    public abstract User<T> addUser(UserRequest<T> user)
         throws TransientException, AccessControlException;
     
     /**
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConfig.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConfig.java
index f745894987318a51e6bf99e8bdf1f9060d42c424..54c2676d46f9dc060d05de9b314ee99cebb4fc5c 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConfig.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapConfig.java
@@ -96,12 +96,14 @@ public class LdapConfig
     public static final String LDAP_PORT = "port";
     public static final String LDAP_SERVER_PROXY_USER = "proxyUser";
     public static final String LDAP_USERS_DN = "usersDn";
+    public static final String LDAP_USER_REQUESTS_DN = "userRequestsDN";
     public static final String LDAP_GROUPS_DN = "groupsDn";
     public static final String LDAP_ADMIN_GROUPS_DN  = "adminGroupsDn";
 
     private final static int SECURE_PORT = 636;
 
     private String usersDN;
+    private String userRequestsDN;
     private String groupsDN;
     private String adminGroupsDN;
     private String server;
@@ -166,6 +168,14 @@ public class LdapConfig
                                        LDAP_USERS_DN);
         }
         String ldapUsersDn = prop.get(0);
+        
+        prop = config.getProperty(LDAP_USER_REQUESTS_DN);
+        if ((prop == null) || (prop.size() != 1))
+        {
+            throw new RuntimeException("failed to read property " +
+                LDAP_USER_REQUESTS_DN);
+        }
+        String ldapUserRequestsDn = prop.get(0);
 
         prop = config.getProperty(LDAP_GROUPS_DN);
         if ((prop == null) || (prop.size() != 1))
@@ -203,14 +213,14 @@ public class LdapConfig
         }
         
         return new LdapConfig(server, Integer.valueOf(port), cc.getUsername(), 
-                              cc.getPassword(), ldapUsersDn, ldapGroupsDn,
-                              ldapAdminGroupsDn);
+                              cc.getPassword(), ldapUsersDn, ldapUserRequestsDn,
+                              ldapGroupsDn, ldapAdminGroupsDn);
     }
     
 
     public LdapConfig(String server, int port, String proxyUserDN, 
-                      String proxyPasswd, String usersDN, String groupsDN,
-                      String adminGroupsDN)
+                      String proxyPasswd, String usersDN, String userRequestsDN,
+                      String groupsDN, String adminGroupsDN)
     {
         if (!StringUtil.hasText(server))
         {
@@ -233,6 +243,10 @@ public class LdapConfig
         {
             throw new IllegalArgumentException("Illegal users LDAP DN");
         }
+        if (!StringUtil.hasText(userRequestsDN))
+        {
+            throw new IllegalArgumentException("Illegal userRequests LDAP DN");
+        }
         if (!StringUtil.hasText(groupsDN))
         {
             throw new IllegalArgumentException("Illegal groups LDAP DN");
@@ -247,6 +261,7 @@ public class LdapConfig
         this.proxyUserDN = proxyUserDN;
         this.proxyPasswd = proxyPasswd;
         this.usersDN = usersDN;
+        this.userRequestsDN = userRequestsDN;
         this.groupsDN = groupsDN;
         this.adminGroupsDN = adminGroupsDN;
         logger.debug(toString());
@@ -256,6 +271,11 @@ public class LdapConfig
     {
         return this.usersDN;
     }
+    
+    public String getUserRequestsDN()
+    {
+        return this.userRequestsDN;
+    }
 
     public String getGroupsDN()
     {
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 2fb7632f0af21a400995779302a56c32c59c59b5..5a58d0faa361410a4351f386deb75b8c3ed05a26 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAO.java
@@ -68,11 +68,7 @@
  */
 package ca.nrc.cadc.ac.server.ldap;
 
-import ca.nrc.cadc.ac.PersonalDetails;
-import ca.nrc.cadc.ac.PosixDetails;
-import ca.nrc.cadc.ac.User;
-import ca.nrc.cadc.ac.UserDetails;
-import ca.nrc.cadc.ac.UserNotFoundException;
+import ca.nrc.cadc.ac.*;
 import ca.nrc.cadc.auth.AuthenticationUtil;
 import ca.nrc.cadc.auth.HttpPrincipal;
 import ca.nrc.cadc.net.TransientException;
@@ -118,6 +114,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
     protected static final String LDAP_ENTRYDN = "entrydn";
     protected static final String LDAP_COMMON_NAME = "cn";
     protected static final String LDAP_DISTINGUISHED_NAME = "distinguishedName";
+    protected static final String LADP_USER_PASSWORD = "userPassword";
     protected static final String LDAP_FIRST_NAME = "givenName";
     protected static final String LDAP_LAST_NAME = "sn";
     protected static final String LDAP_ADDRESS = "address";
@@ -168,32 +165,32 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
     /**
      * Add the specified user..
      *
-     * @param user The user to add.
+     * @param userRequest The user to add.
      * @return User instance.
      * @throws TransientException     If an temporary, unexpected problem occurred.
      * @throws AccessControlException If the operation is not permitted.
      */
-    public User<T> addUser(final User<T> user)
+    public User<T> addUser(final UserRequest<T> userRequest)
         throws TransientException
     {
+        final User<T> user = userRequest.getUser();
         final Class userType = user.getUserID().getClass();
         String searchField = userLdapAttrib.get(userType);
         if (searchField == null)
         {
-            throw new IllegalArgumentException(
-                    "Unsupported principal type " + userType);
+            throw new IllegalArgumentException("Unsupported principal type " + userType);
         }
         
         try
         {
             // add new user
-            DN userDN = getUserDN(user.getUserID().getName());
+            DN userDN = getUserRequestsDN(user.getUserID().getName());
             List<Attribute> attributes = new ArrayList<Attribute>();
             addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_INET_ORG_PERSON);
-            addAttribute(attributes, LDAP_UID, LDAP_CADC_ACCOUNT);
             addAttribute(attributes, LDAP_OBJECT_CLASS, LDAP_CADC_ACCOUNT);
             addAttribute(attributes, LDAP_COMMON_NAME, user.getUserID().getName());
             addAttribute(attributes, LDAP_DISTINGUISHED_NAME, userDN.toNormalizedString());
+            addAttribute(attributes, LADP_USER_PASSWORD, userRequest.getPassword());
 
             for (UserDetails details : user.details)
             {
@@ -232,7 +229,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
             getConnection().reconnect();
             try
             {
-                return getUser(user.getUserID());
+                return getUser(user.getUserID(), config.getUserRequestsDN());
             }
             catch (UserNotFoundException e)
             {
@@ -249,7 +246,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
             throw new RuntimeException("Unexpected LDAP exception", e);
         }
     }
-    
+
     /**
      * Get the user specified by userID.
      *
@@ -261,6 +258,22 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
      */
     public User<T> getUser(final T userID)
         throws UserNotFoundException, TransientException, AccessControlException
+    {
+        return getUser(userID, config.getUsersDN());
+    }
+
+    /**
+     * Get the user specified by userID.
+     *
+     * @param userID The userID.
+     * @param usersDN The LDAP tree to search.
+     * @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.
+     */
+    private User<T> getUser(final T userID, final String usersDN)
+        throws UserNotFoundException, TransientException, AccessControlException
     {
         String searchField = userLdapAttrib.get(userID.getClass());
         if (searchField == null)
@@ -277,7 +290,7 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
         try
         {
             SearchRequest searchRequest = 
-                    new SearchRequest(config.getUsersDN(), SearchScope.SUB, 
+                    new SearchRequest(usersDN, SearchScope.SUB,
                                      searchField, userAttribs);
 
             searchRequest.addControl(
@@ -650,6 +663,21 @@ public class LdapUserDAO<T extends Principal> extends LdapDAO
         }
         throw new IllegalArgumentException(userID + " not a valid user ID");
     }
+
+    protected DN getUserRequestsDN(final String userID)
+        throws LDAPException, TransientException
+    {
+        try
+        {
+            return new DN(LDAP_UID + "=" + userID + "," + config.getUserRequestsDN());
+        }
+        catch (LDAPException e)
+        {
+            logger.debug("getUserRequestsDN Exception: " + e, e);
+            LdapDAO.checkLdapResult(e.getResultCode());
+        }
+        throw new IllegalArgumentException(userID + " not a valid user ID");
+    }
     
     void addAttribute(List<Attribute> attributes, final String name, final String value)
     {
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 971b9890dfe3523a82fb163475f130d20fa80fda..d15ca443db5b1223fc1bab924eb213cbb4feafa5 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
@@ -70,6 +70,7 @@ package ca.nrc.cadc.ac.server.ldap;
 
 import ca.nrc.cadc.ac.User;
 import ca.nrc.cadc.ac.UserNotFoundException;
+import ca.nrc.cadc.ac.UserRequest;
 import ca.nrc.cadc.ac.server.UserPersistence;
 import ca.nrc.cadc.net.TransientException;
 import com.unboundid.ldap.sdk.DN;
@@ -125,7 +126,7 @@ public class LdapUserPersistence<T extends Principal>
      * @throws TransientException If an temporary, unexpected problem occurred.
      * @throws AccessControlException If the operation is not permitted.
      */
-    public User<T> addUser(User<T> user)
+    public User<T> addUser(UserRequest<T> user)
         throws TransientException, AccessControlException
     {
         LdapUserDAO<T> userDAO = null;
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java
index 1e064e621c21c284da9f8165b8bae63385e1c165..df069f8bc4d5ca996d888616604e2198d4d4abed 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ACSearchRunner.java
@@ -86,7 +86,7 @@ import org.apache.log4j.Logger;
 
 import ca.nrc.cadc.ac.Group;
 import ca.nrc.cadc.ac.GroupNotFoundException;
-import ca.nrc.cadc.ac.GroupsWriter;
+import ca.nrc.cadc.ac.xml.GroupsWriter;
 import ca.nrc.cadc.ac.UserNotFoundException;
 import ca.nrc.cadc.ac.server.GroupPersistence;
 import ca.nrc.cadc.ac.server.PluginFactory;
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/CreateGroupAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/CreateGroupAction.java
index 32661345fc85f1042784a01421c27da98d4b9c48..47cdc9bc198a5bdc0e01c0e93aa501cb9bffc0bb 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/CreateGroupAction.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/CreateGroupAction.java
@@ -73,10 +73,10 @@ import java.util.ArrayList;
 import java.util.List;
 
 import ca.nrc.cadc.ac.Group;
-import ca.nrc.cadc.ac.GroupReader;
-import ca.nrc.cadc.ac.GroupWriter;
 import ca.nrc.cadc.ac.User;
 import ca.nrc.cadc.ac.server.GroupPersistence;
+import ca.nrc.cadc.ac.xml.GroupReader;
+import ca.nrc.cadc.ac.xml.GroupWriter;
 
 public class CreateGroupAction extends GroupsAction
 {
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupAction.java
index e72003567a83a2723ee6ce15376d5a5beee22027..97a2b52ea289c730ff74ae3637cfb16a0e6b205d 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupAction.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/GetGroupAction.java
@@ -68,8 +68,8 @@
  */package ca.nrc.cadc.ac.server.web;
 
 import ca.nrc.cadc.ac.Group;
-import ca.nrc.cadc.ac.GroupWriter;
 import ca.nrc.cadc.ac.server.GroupPersistence;
+import ca.nrc.cadc.ac.xml.GroupWriter;
 
 public class GetGroupAction extends GroupsAction
 {
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyGroupAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyGroupAction.java
index c7a03ca5688c0d2c697ff24296428310767edc29..425951d7c80820977ec32eaef9f7af85d2a967d9 100755
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyGroupAction.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/ModifyGroupAction.java
@@ -73,9 +73,9 @@ import java.util.ArrayList;
 import java.util.List;
 
 import ca.nrc.cadc.ac.Group;
-import ca.nrc.cadc.ac.GroupReader;
 import ca.nrc.cadc.ac.User;
 import ca.nrc.cadc.ac.server.GroupPersistence;
+import ca.nrc.cadc.ac.xml.GroupReader;
 
 public class ModifyGroupAction extends GroupsAction
 {
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java
index 63d4f258bbe2a84f8e2f0ef9cd9dfc3b496d0ce4..af90bfed5f07432bca766db7e402e56a703b138c 100644
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/CreateUserAction.java
@@ -70,9 +70,11 @@ package ca.nrc.cadc.ac.server.web.users;
 
 import java.io.InputStream;
 import ca.nrc.cadc.ac.User;
-import ca.nrc.cadc.ac.UserReader;
-import ca.nrc.cadc.ac.UserWriter;
+import ca.nrc.cadc.ac.UserRequest;
 import ca.nrc.cadc.ac.server.UserPersistence;
+import ca.nrc.cadc.ac.xml.UserRequestReader;
+import ca.nrc.cadc.ac.xml.UserWriter;
+
 import java.security.Principal;
 
 public class CreateUserAction extends UsersAction
@@ -89,8 +91,8 @@ public class CreateUserAction extends UsersAction
         throws Exception
     {
         UserPersistence userPersistence = getUserPersistence();
-        User<? extends Principal> user = UserReader.read(this.inputStream);
-        User<? extends Principal> newUser = userPersistence.addUser(user);
+        UserRequest userRequest = UserRequestReader.read(this.inputStream);
+        User<? extends Principal> newUser = userPersistence.addUser(userRequest);
         this.response.setContentType("application/xml");
         UserWriter.write(newUser, this.response.getOutputStream());
         logUserInfo(newUser.getUserID().getName());
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 3bf584cd41cd08ed67d895a7bd8c3789df2e4ade..a87116e7a0b9e1df17a7e7e027aa08ddfd45a04f 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
@@ -68,8 +68,9 @@
  */package ca.nrc.cadc.ac.server.web.users;
 
 import ca.nrc.cadc.ac.User;
-import ca.nrc.cadc.ac.UserWriter;
 import ca.nrc.cadc.ac.server.UserPersistence;
+import ca.nrc.cadc.ac.xml.UserWriter;
+
 import java.security.Principal;
 
 public class GetUserAction extends UsersAction
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java
index 9f7cc815de2c109d88e0f2a328ec05ae140056b8..c98c29683542a64d608bcaf623dc7bbfdfb13125 100644
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/ModifyUserAction.java
@@ -70,8 +70,9 @@ package ca.nrc.cadc.ac.server.web.users;
 
 import java.io.InputStream;
 import ca.nrc.cadc.ac.User;
-import ca.nrc.cadc.ac.UserReader;
 import ca.nrc.cadc.ac.server.UserPersistence;
+import ca.nrc.cadc.ac.xml.UserReader;
+
 import java.security.Principal;
 
 public class ModifyUserAction extends UsersAction
diff --git a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java
index 1a431670fa6e96f0af1134f87a345ba25d448e53..e78ae9803726a339b32a8c47077e10b7e38e9cad 100644
--- a/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java
+++ b/projects/cadcAccessControl-Server/src/ca/nrc/cadc/ac/server/web/users/UsersActionFactory.java
@@ -68,9 +68,12 @@
  */
 package ca.nrc.cadc.ac.server.web.users;
 
+import ca.nrc.cadc.ac.IdentityType;
 import ca.nrc.cadc.ac.User;
+import ca.nrc.cadc.auth.CookiePrincipal;
 import ca.nrc.cadc.auth.HttpPrincipal;
 import ca.nrc.cadc.auth.NumericPrincipal;
+import ca.nrc.cadc.auth.OpenIdPrincipal;
 import ca.nrc.cadc.util.StringUtil;
 import java.io.IOException;
 import java.net.URL;
@@ -127,8 +130,8 @@ public class UsersActionFactory
         }
         else if (segments.length == 1)
         {
-            String userName = segments[0];
-            User user = getUserFromUsername(userName);
+            User user = getUser(segments[0], request.getParameter("idType"),
+                                method, path);
             if (method.equals("GET"))
             {
                 action = new GetUserAction(logInfo, user.getUserID());
@@ -164,23 +167,43 @@ public class UsersActionFactory
             log.debug("Returning action: " + action.getClass());
             return action;
         }
-        throw new IllegalArgumentException("Bad users request: " + method + " on " + path);
+        final String error = "Bad users request: " + method + " on " + path;
+        throw new IllegalArgumentException(error);
     }
 
-    private static User<? extends Principal> getUserFromUsername(final String userName)
+    private static User<? extends Principal> getUser(final String userName, final String idType,
+                                                     final String method, final String path)
     {
-        try
+        if (idType == null || idType.isEmpty())
+        {
+            throw new IllegalArgumentException("User endpoint missing idType parameter");
+        }
+        else if (idType.equals(IdentityType.USERNAME.getValue()))
+        {
+            return new User(new HttpPrincipal(userName));
+        }
+        else if (idType.equals(IdentityType.X500.getValue()))
         {
             return new User(new X500Principal(userName));
         }
-        catch (IllegalArgumentException e) {}
-        
-        try
+        else if (idType.equals(IdentityType.UID.getValue()))
         {
             return new User(new NumericPrincipal(Long.parseLong(userName)));
         }
-        catch (NumberFormatException e) {}
-        
-        return new User((new HttpPrincipal(userName)));
+        else if (idType.equals(IdentityType.OPENID.getValue()))
+        {
+            return new User(new OpenIdPrincipal(userName));
+        }
+        else if (idType.equals(IdentityType.COOKIE.getValue()))
+        {
+            return new User(new CookiePrincipal(userName));
+        }
+        else
+        {
+            final String error = "Bad users request: " + method + " on " + path + 
+                                 " because of unknown principal type " + idType;
+            throw new IllegalArgumentException(error);
+        }
     }
+
 }
diff --git a/projects/cadcAccessControl-Server/test/LdapConfig.test.properties b/projects/cadcAccessControl-Server/test/LdapConfig.test.properties
index efcdb0ce03d25c609bccd2097f0a5c4e65d658b0..d576adc7e06cd7829edc3d1b980dae43c2795c95 100644
--- a/projects/cadcAccessControl-Server/test/LdapConfig.test.properties
+++ b/projects/cadcAccessControl-Server/test/LdapConfig.test.properties
@@ -3,5 +3,6 @@ server = proc5-03.cadc.dao.nrc.ca
 port = 636
 proxyUser = webproxy
 usersDn = ou=Users,ou=ds,dc=canfar,dc=net
+newUsersDn = ou=NewUsers,ou=ds,dc=canfar,dc=net
 groupsDn = ou=Groups,ou=ds,dc=canfar,dc=net
 adminGroupsDn = ou=adminGroups,ou=ds,dc=canfar,dc=net
\ No newline at end of file
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 99fba938224c256725ee730193e6f95292422b99..9a11b6abb24efbfa2d6388521a7281ab609e7af2 100644
--- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java
+++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/ldap/LdapUserDAOTest.java
@@ -68,30 +68,25 @@
  */
 package ca.nrc.cadc.ac.server.ldap;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.security.Principal;
-import java.security.PrivilegedExceptionAction;
-import java.util.Collection;
-
-import javax.security.auth.Subject;
-import javax.security.auth.x500.X500Principal;
-
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
 import ca.nrc.cadc.ac.PersonalDetails;
 import ca.nrc.cadc.ac.User;
 import ca.nrc.cadc.ac.UserDetails;
+import ca.nrc.cadc.ac.UserRequest;
 import ca.nrc.cadc.auth.HttpPrincipal;
 import ca.nrc.cadc.util.Log4jInit;
-
 import com.unboundid.ldap.sdk.DN;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.security.auth.Subject;
+import javax.security.auth.x500.X500Principal;
+import java.security.Principal;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+
+import static org.junit.Assert.*;
 
 public class LdapUserDAOTest extends AbstractLdapDAOTest
 {
@@ -135,9 +130,12 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
     @Test
     public void testAddUser() throws Exception
     {
-        final User<HttpPrincipal> newUser = new User<HttpPrincipal>(new HttpPrincipal(getUserID()));
-        newUser.details.add(new PersonalDetails("foo", "bar"));
-        
+        final User<HttpPrincipal> expected = new User<HttpPrincipal>(new HttpPrincipal(getUserID()));
+        expected.getIdentities().add(new HttpPrincipal(getUserID()));
+        expected.details.add(new PersonalDetails("foo", "bar"));
+
+        final UserRequest userRequest = new UserRequest(expected, "123456");
+
         Subject subject = new Subject();
         subject.getPrincipals().add(testUser.getUserID());
 
@@ -148,8 +146,8 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
             {
                 try
                 {
-                    User<? extends Principal> actual = getUserDAO().addUser(newUser);
-                    check(newUser, actual);
+                    User<? extends Principal> actual = getUserDAO().addUser(userRequest);
+                    check(expected, actual);
                     
                     return null;
                 }
@@ -164,7 +162,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
     /**
      * Test of getUser method, of class LdapUserDAO.
      */
-//    @Test
+    @Test
     public void testGetUser() throws Exception
     {
         Subject subject = new Subject();
@@ -194,7 +192,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
     /**
      * Test of getUserGroups method, of class LdapUserDAO.
      */
-//    @Test
+    @Test
     public void testGetUserGroups() throws Exception
     {
         Subject subject = new Subject();
@@ -232,7 +230,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
     /**
      * Test of getUserGroups method, of class LdapUserDAO.
      */
-//    @Test
+    @Test
     public void testIsMember() throws Exception
     {
         Subject subject = new Subject();
@@ -265,7 +263,7 @@ public class LdapUserDAOTest extends AbstractLdapDAOTest
     /**
      * Test of getMember.
      */
-//    @Test
+    @Test
     public void testGetMember() throws Exception
     {
         Subject subject = new Subject();
diff --git a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java
index 7b07355d11b2be86cb9c388c6f305d152b1152eb..3c78050fc4be572407d879036d8e63a039867da3 100644
--- a/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java
+++ b/projects/cadcAccessControl-Server/test/src/ca/nrc/cadc/ac/server/web/users/UserActionFactoryTest.java
@@ -87,7 +87,7 @@ public class UserActionFactoryTest
     }
 
     @Test
-    public void testCreateCreateUserAction()
+    public void testCreateUserAction()
     {
         try
         {
@@ -108,13 +108,14 @@ public class UserActionFactoryTest
     }
 
     @Test
-    public void testCreateDeleteUserAction()
+    public void testDeleteUserAction()
     {
         try
         {
             HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class);
             EasyMock.expect(request.getPathInfo()).andReturn("userName");
             EasyMock.expect(request.getMethod()).andReturn("DELETE");
+            EasyMock.expect(request.getParameter("idType")).andReturn("sessionID");
             EasyMock.replay(request);
             UsersAction action = UsersActionFactory.getUsersAction(request, null);
             EasyMock.verify(request);
@@ -128,13 +129,14 @@ public class UserActionFactoryTest
     }
 
     @Test
-    public void testCreateGetUserAction()
+    public void testGetUserAction()
     {
         try
         {
             HttpServletRequest request = EasyMock.createMock(HttpServletRequest.class);
             EasyMock.expect(request.getPathInfo()).andReturn("userName");
             EasyMock.expect(request.getMethod()).andReturn("GET");
+            EasyMock.expect(request.getParameter("idType")).andReturn("sessionID");
             EasyMock.replay(request);
             UsersAction action = UsersActionFactory.getUsersAction(request, null);
             EasyMock.verify(request);
@@ -148,7 +150,7 @@ public class UserActionFactoryTest
     }
 
     @Test
-    public void testCreateGetUserNamesAction()
+    public void testGetUserNamesAction()
     {
         try
         {
@@ -168,7 +170,7 @@ public class UserActionFactoryTest
     }
 
     @Test
-    public void testCreateModifyUserAction()
+    public void testModifyUserAction()
     {
         try
         {
@@ -182,6 +184,7 @@ public class UserActionFactoryTest
             EasyMock.expect(request.getContextPath()).andReturn("");
             EasyMock.expect(request.getServletPath()).andReturn("");
             EasyMock.expect(request.getInputStream()).andReturn(null);
+            EasyMock.expect(request.getParameter("idType")).andReturn("sessionID");
             EasyMock.replay(request);
             UsersAction action = UsersActionFactory.getUsersAction(request, null);
             EasyMock.verify(request);
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java
new file mode 100644
index 0000000000000000000000000000000000000000..fea1d0be2502e40f5ae6d99d13f98ef1fb7d98ee
--- /dev/null
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserRequest.java
@@ -0,0 +1,103 @@
+/*
+ ************************************************************************
+ *******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
+ **************  CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES  **************
+ *
+ *  (c) 2014.                            (c) 2014.
+ *  Government of Canada                 Gouvernement du Canada
+ *  National Research Council            Conseil national de recherches
+ *  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
+ *  All rights reserved                  Tous droits réservés
+ *
+ *  NRC disclaims any warranties,        Le CNRC dénie toute garantie
+ *  expressed, implied, or               énoncée, implicite ou légale,
+ *  statutory, of any kind with          de quelque nature que ce
+ *  respect to the software,             soit, concernant le logiciel,
+ *  including without limitation         y compris sans restriction
+ *  any warranty of merchantability      toute garantie de valeur
+ *  or fitness for a particular          marchande ou de pertinence
+ *  purpose. NRC shall not be            pour un usage particulier.
+ *  liable in any event for any          Le CNRC ne pourra en aucun cas
+ *  damages, whether direct or           être tenu responsable de tout
+ *  indirect, special or general,        dommage, direct ou indirect,
+ *  consequential or incidental,         particulier ou général,
+ *  arising from the use of the          accessoire ou fortuit, résultant
+ *  software.  Neither the name          de l'utilisation du logiciel. Ni
+ *  of the National Research             le nom du Conseil National de
+ *  Council of Canada nor the            Recherches du Canada ni les noms
+ *  names of its contributors may        de ses  participants ne peuvent
+ *  be used to endorse or promote        être utilisés pour approuver ou
+ *  products derived from this           promouvoir les produits dérivés
+ *  software without specific prior      de ce logiciel sans autorisation
+ *  written permission.                  préalable et particulière
+ *                                       par écrit.
+ *
+ *  This file is part of the             Ce fichier fait partie du projet
+ *  OpenCADC project.                    OpenCADC.
+ *
+ *  OpenCADC is free software:           OpenCADC est un logiciel libre ;
+ *  you can redistribute it and/or       vous pouvez le redistribuer ou le
+ *  modify it under the terms of         modifier suivant les termes de
+ *  the GNU Affero General Public        la “GNU Affero General Public
+ *  License as published by the          License” telle que publiée
+ *  Free Software Foundation,            par la Free Software Foundation
+ *  either version 3 of the              : soit la version 3 de cette
+ *  License, or (at your option)         licence, soit (à votre gré)
+ *  any later version.                   toute version ultérieure.
+ *
+ *  OpenCADC is distributed in the       OpenCADC est distribué
+ *  hope that it will be useful,         dans l’espoir qu’il vous
+ *  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
+ *  without even the implied             GARANTIE : sans même la garantie
+ *  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILITÉ
+ *  or FITNESS FOR A PARTICULAR          ni d’ADÉQUATION À UN OBJECTIF
+ *  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
+ *  General Public License for           Générale Publique GNU Affero
+ *  more details.                        pour plus de détails.
+ *
+ *  You should have received             Vous devriez avoir reçu une
+ *  a copy of the GNU Affero             copie de la Licence Générale
+ *  General Public License along         Publique GNU Affero avec
+ *  with OpenCADC.  If not, see          OpenCADC ; si ce n’est
+ *  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
+ *                                       <http://www.gnu.org/licenses/>.
+ *
+ *  $Revision: 4 $
+ *
+ ************************************************************************
+ */
+
+package ca.nrc.cadc.ac;
+
+import java.security.Principal;
+
+public class UserRequest<T extends Principal>
+{
+    private User<T> user;
+    private String password;
+
+    public UserRequest(final User<T> user, final String password)
+    {
+        if (user == null)
+        {
+            throw new IllegalArgumentException("null user");
+        }
+        if (password == null || password.isEmpty())
+        {
+            throw new IllegalArgumentException("null or empty password");
+        }
+        this.user = user;
+        this.password = password;
+    }
+
+    public User<T> getUser()
+    {
+        return this.user;
+    }
+
+    public String getPassword()
+    {
+        return this.password;
+    }
+
+}
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
index cb0ec4f65ed7605c44f0731fe0246200dccaf6cb..159e48eaddffdb4f62b6fea3a1eea8af3b29fc33 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/client/GMSClient.java
@@ -98,9 +98,9 @@ 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.GroupReader;
-import ca.nrc.cadc.ac.GroupWriter;
-import ca.nrc.cadc.ac.GroupsReader;
+import ca.nrc.cadc.ac.xml.GroupReader;
+import ca.nrc.cadc.ac.xml.GroupWriter;
+import ca.nrc.cadc.ac.xml.GroupsReader;
 import ca.nrc.cadc.ac.Role;
 import ca.nrc.cadc.ac.UserNotFoundException;
 import ca.nrc.cadc.auth.AuthenticationUtil;
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupReader.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupReader.java
similarity index 97%
rename from projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupReader.java
rename to projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupReader.java
index 70ef1830f10432669f5b0bbd27be53286fa8d2b4..1631dcc93a5f6f4139623af8ec75027ed80f581a 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupReader.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupReader.java
@@ -66,7 +66,7 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -80,6 +80,7 @@ import java.text.DateFormat;
 import java.text.ParseException;
 import java.util.List;
 
+import ca.nrc.cadc.ac.*;
 import org.jdom2.Document;
 import org.jdom2.Element;
 import org.jdom2.JDOMException;
@@ -95,7 +96,7 @@ public class GroupReader
      * 
      * @param xml String of the XML.
      * @return Group Group.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      * @throws java.net.URISyntaxException
      */
@@ -114,7 +115,7 @@ public class GroupReader
      * 
      * @param in InputStream.
      * @return Group Group.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      * @throws java.net.URISyntaxException
      */
@@ -142,7 +143,7 @@ public class GroupReader
      * 
      * @param reader Reader.
      * @return Group Group.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      * @throws java.net.URISyntaxException
      */
@@ -246,7 +247,7 @@ public class GroupReader
             List<Element> propertyElements = propertiesElement.getChildren("property");
             for (Element propertyElement : propertyElements)
             {
-                group.getProperties().add(GroupPropertyReader.read(propertyElement));
+                group.getProperties().add(ca.nrc.cadc.ac.xml.GroupPropertyReader.read(propertyElement));
             }
 
         }
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupWriter.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupWriter.java
similarity index 97%
rename from projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupWriter.java
rename to projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupWriter.java
index 93fcd13c61f9a5492beb3468049997cbeb908b25..8b77c7c7fe2027e7eb0b1892ad35ed70febfe7b1 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupWriter.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupWriter.java
@@ -66,7 +66,7 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
 import java.io.BufferedWriter;
 import java.io.IOException;
@@ -77,6 +77,7 @@ import java.io.Writer;
 import java.security.Principal;
 import java.text.DateFormat;
 
+import ca.nrc.cadc.ac.*;
 import org.jdom2.Attribute;
 import org.jdom2.Document;
 import org.jdom2.Element;
@@ -93,7 +94,7 @@ public class GroupWriter
      * @param group
      * @param builder
      * @throws java.io.IOException
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(Group group, StringBuilder builder)
         throws IOException, WriterException
@@ -107,7 +108,7 @@ public class GroupWriter
      * @param group Group to write.
      * @param out OutputStream to write to.
      * @throws IOException if the writer fails to write.
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(Group group, OutputStream out)
         throws IOException, WriterException
@@ -130,7 +131,7 @@ public class GroupWriter
      * @param group Group to write.
      * @param writer  Writer to write to.
      * @throws IOException if the writer fails to write.
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(Group group, Writer writer)
         throws IOException, WriterException
@@ -147,7 +148,7 @@ public class GroupWriter
      * 
      * @param group
      * @return 
-     * @throws ca.nrc.cadc.ac.WriterException 
+     * @throws WriterException
      */
     public static Element getGroupElement(Group group)
         throws WriterException
@@ -197,7 +198,7 @@ public class GroupWriter
                 Element propertiesElement = new Element("properties");
                 for (GroupProperty property : group.getProperties())
                 {
-                    propertiesElement.addContent(GroupPropertyWriter.write(property));
+                    propertiesElement.addContent(ca.nrc.cadc.ac.xml.GroupPropertyWriter.write(property));
                 }
                 groupElement.addContent(propertiesElement);
             }
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsReader.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupsReader.java
similarity index 96%
rename from projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsReader.java
rename to projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupsReader.java
index 656bdeccb031fb47872caa553a41ee7808909845..c4b0239096f3a0ba741fe037d2a935df0c3826e9 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsReader.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupsReader.java
@@ -66,8 +66,9 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
+import ca.nrc.cadc.ac.Group;
 import ca.nrc.cadc.xml.XmlUtil;
 import java.io.IOException;
 import java.io.InputStream;
@@ -89,7 +90,7 @@ public class GroupsReader
      * 
      * @param xml String of the XML.
      * @return Groups List of Group.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      * @throws java.net.URISyntaxException
      */
@@ -108,7 +109,7 @@ public class GroupsReader
      * 
      * @param in InputStream.
      * @return Groups List of Group.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      * @throws java.net.URISyntaxException
      */
@@ -136,7 +137,7 @@ public class GroupsReader
      * 
      * @param reader Reader.
      * @return Groups List of Group.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      * @throws java.net.URISyntaxException
      */
@@ -180,7 +181,7 @@ public class GroupsReader
         List<Element> groupElements = groupsElement.getChildren("group");
         for (Element groupElement : groupElements)
         {
-            groups.add(GroupReader.parseGroup(groupElement));
+            groups.add(ca.nrc.cadc.ac.xml.GroupReader.parseGroup(groupElement));
         }
 
         return groups;
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsWriter.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupsWriter.java
similarity index 93%
rename from projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsWriter.java
rename to projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupsWriter.java
index 0bdcf1f09ebeb40da3610f6a5ce69be834f86540..8d02173ec17ad7b25660d077a2f5315b487f6d1d 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/GroupsWriter.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/GroupsWriter.java
@@ -1,5 +1,6 @@
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
+import ca.nrc.cadc.ac.Group;
 import ca.nrc.cadc.util.StringBuilderWriter;
 import java.io.BufferedWriter;
 import java.io.IOException;
@@ -20,7 +21,7 @@ public class GroupsWriter
      * @param groups List of Group's to write.
      * @param builder
      * @throws java.io.IOException
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(Collection<Group> groups, StringBuilder builder)
         throws IOException, WriterException
@@ -34,7 +35,7 @@ public class GroupsWriter
      * @param groups List of Group's to write.
      * @param out OutputStream to write to.
      * @throws IOException if the writer fails to write.
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(Collection<Group> groups, OutputStream out)
         throws IOException, WriterException
@@ -57,7 +58,7 @@ public class GroupsWriter
      * @param groups List of Group's to write.
      * @param writer  Writer to write to.
      * @throws IOException if the writer fails to write.
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(Collection<Group> groups, Writer writer)
         throws IOException, WriterException
@@ -74,7 +75,7 @@ public class GroupsWriter
      * 
      * @param groups List of Group's to write.
      * @return Element of list of Group's.
-     * @throws ca.nrc.cadc.ac.WriterException 
+     * @throws WriterException
      */
     public static Element getGroupsElement(Collection<Group> groups)
         throws WriterException
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/ReaderException.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/ReaderException.java
similarity index 99%
rename from projects/cadcAccessControl/src/ca/nrc/cadc/ac/ReaderException.java
rename to projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/ReaderException.java
index 397d1e62113993fc59cee4f79bbf9a62ea27a62e..0b34ec634bcfd1dc4635cfe18c43e073dd3614b7 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/ReaderException.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/ReaderException.java
@@ -66,7 +66,7 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
 import java.io.IOException;
 
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserReader.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java
similarity index 94%
rename from projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserReader.java
rename to projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java
index a28883a34a6830c3ad1e4969284e09a6497d2615..b55143336a2d7591a4ada53fadbc2dc5c0d970e4 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserReader.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserReader.java
@@ -66,8 +66,9 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
+import ca.nrc.cadc.ac.User;
 import ca.nrc.cadc.xml.XmlUtil;
 import java.io.IOException;
 import java.io.InputStream;
@@ -89,7 +90,7 @@ public class UserReader
      * 
      * @param xml String of the XML.
      * @return User User.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      * @throws java.net.URISyntaxException
      */
@@ -108,7 +109,7 @@ public class UserReader
      * 
      * @param in InputStream.
      * @return User User.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      * @throws java.net.URISyntaxException
      */
@@ -136,7 +137,7 @@ public class UserReader
      * 
      * @param reader Reader.
      * @return User User.
-     * @throws ca.nrc.cadc.ac.ReaderException
+     * @throws ReaderException
      * @throws java.io.IOException
      */
     public static User<? extends Principal> read(Reader reader)
@@ -184,7 +185,7 @@ public class UserReader
             throw new ReaderException(error);
         }
 
-        Principal userID = IdentityReader.read(userIDIdentityElement);
+        Principal userID = ca.nrc.cadc.ac.xml.IdentityReader.read(userIDIdentityElement);
 
         User<Principal> user = new User<Principal>(userID);
 
@@ -195,7 +196,7 @@ public class UserReader
             List<Element> identityElements = identitiesElement.getChildren("identity");
             for (Element identityElement : identityElements)
             {
-                user.getIdentities().add(IdentityReader.read(identityElement));
+                user.getIdentities().add(ca.nrc.cadc.ac.xml.IdentityReader.read(identityElement));
             }
 
         }
@@ -207,7 +208,7 @@ public class UserReader
             List<Element> userDetailsElements = detailsElement.getChildren("userDetails");
             for (Element userDetailsElement : userDetailsElements)
             {
-                user.details.add(UserDetailsReader.read(userDetailsElement));
+                user.details.add(ca.nrc.cadc.ac.xml.UserDetailsReader.read(userDetailsElement));
             }
         }
 
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java
new file mode 100644
index 0000000000000000000000000000000000000000..94986a10b3215cbf38e7a4825fcce93cd3702498
--- /dev/null
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestReader.java
@@ -0,0 +1,196 @@
+/*
+ ************************************************************************
+ *******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
+ **************  CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES  **************
+ *
+ *  (c) 2014.                            (c) 2014.
+ *  Government of Canada                 Gouvernement du Canada
+ *  National Research Council            Conseil national de recherches
+ *  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
+ *  All rights reserved                  Tous droits réservés
+ *
+ *  NRC disclaims any warranties,        Le CNRC dénie toute garantie
+ *  expressed, implied, or               énoncée, implicite ou légale,
+ *  statutory, of any kind with          de quelque nature que ce
+ *  respect to the software,             soit, concernant le logiciel,
+ *  including without limitation         y compris sans restriction
+ *  any warranty of merchantability      toute garantie de valeur
+ *  or fitness for a particular          marchande ou de pertinence
+ *  purpose. NRC shall not be            pour un usage particulier.
+ *  liable in any event for any          Le CNRC ne pourra en aucun cas
+ *  damages, whether direct or           être tenu responsable de tout
+ *  indirect, special or general,        dommage, direct ou indirect,
+ *  consequential or incidental,         particulier ou général,
+ *  arising from the use of the          accessoire ou fortuit, résultant
+ *  software.  Neither the name          de l'utilisation du logiciel. Ni
+ *  of the National Research             le nom du Conseil National de
+ *  Council of Canada nor the            Recherches du Canada ni les noms
+ *  names of its contributors may        de ses  participants ne peuvent
+ *  be used to endorse or promote        être utilisés pour approuver ou
+ *  products derived from this           promouvoir les produits dérivés
+ *  software without specific prior      de ce logiciel sans autorisation
+ *  written permission.                  préalable et particulière
+ *                                       par écrit.
+ *
+ *  This file is part of the             Ce fichier fait partie du projet
+ *  OpenCADC project.                    OpenCADC.
+ *
+ *  OpenCADC is free software:           OpenCADC est un logiciel libre ;
+ *  you can redistribute it and/or       vous pouvez le redistribuer ou le
+ *  modify it under the terms of         modifier suivant les termes de
+ *  the GNU Affero General Public        la “GNU Affero General Public
+ *  License as published by the          License” telle que publiée
+ *  Free Software Foundation,            par la Free Software Foundation
+ *  either version 3 of the              : soit la version 3 de cette
+ *  License, or (at your option)         licence, soit (à votre gré)
+ *  any later version.                   toute version ultérieure.
+ *
+ *  OpenCADC is distributed in the       OpenCADC est distribué
+ *  hope that it will be useful,         dans l’espoir qu’il vous
+ *  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
+ *  without even the implied             GARANTIE : sans même la garantie
+ *  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILITÉ
+ *  or FITNESS FOR A PARTICULAR          ni d’ADÉQUATION À UN OBJECTIF
+ *  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
+ *  General Public License for           Générale Publique GNU Affero
+ *  more details.                        pour plus de détails.
+ *
+ *  You should have received             Vous devriez avoir reçu une
+ *  a copy of the GNU Affero             copie de la Licence Générale
+ *  General Public License along         Publique GNU Affero avec
+ *  with OpenCADC.  If not, see          OpenCADC ; si ce n’est
+ *  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
+ *                                       <http://www.gnu.org/licenses/>.
+ *
+ *  $Revision: 4 $
+ *
+ ************************************************************************
+ */
+package ca.nrc.cadc.ac.xml;
+
+import ca.nrc.cadc.ac.User;
+import ca.nrc.cadc.ac.UserRequest;
+import ca.nrc.cadc.xml.XmlUtil;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.security.Principal;
+
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.JDOMException;
+
+public class UserRequestReader
+{
+    /**
+     * Construct a UserRequest from an XML String source.
+     *
+     * @param xml String of the XML.
+     * @return UserRequest UserRequest.
+     * @throws ReaderException
+     * @throws java.io.IOException
+     * @throws java.net.URISyntaxException
+     */
+    public static UserRequest<? extends Principal> read(String xml)
+        throws ReaderException, IOException, URISyntaxException
+    {
+        if (xml == null)
+        {
+            throw new IllegalArgumentException("XML must not be null");
+        }
+        return read(new StringReader(xml));
+    }
+
+    /**
+     * Construct a User from a InputStream.
+     *
+     * @param in InputStream.
+     * @return UserRequest UserRequest.
+     * @throws ReaderException
+     * @throws java.io.IOException
+     * @throws java.net.URISyntaxException
+     */
+    public static UserRequest<? extends Principal> read(InputStream in)
+        throws ReaderException, IOException, URISyntaxException
+    {
+        if (in == null)
+        {
+            throw new IOException("stream closed");
+        }
+        InputStreamReader reader;
+        try
+        {
+            reader = new InputStreamReader(in, "UTF-8");
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            throw new RuntimeException("UTF-8 encoding not supported");
+        }
+        return read(reader);
+    }
+
+    /**
+     * Construct a UserRequest from a Reader.
+     *
+     * @param reader Reader.
+     * @return UserRequest UserRequest.
+     * @throws ReaderException
+     * @throws java.io.IOException
+     */
+    public static UserRequest<? extends Principal> read(Reader reader)
+        throws ReaderException, IOException
+    {
+        if (reader == null)
+        {
+            throw new IllegalArgumentException("reader must not be null");
+        }
+
+        // Create a JDOM Document from the XML
+        Document document;
+        try
+        {
+            document = XmlUtil.buildDocument(reader);
+        }
+        catch (JDOMException jde)
+        {
+            String error = "XML failed validation: " + jde.getMessage();
+            throw new ReaderException(error, jde);
+        }
+
+        // Root element and namespace of the Document
+        Element root = document.getRootElement();
+
+        return parseUserRequest(root);
+    }
+
+    protected static UserRequest parseUserRequest(Element userRequestElement)
+        throws ReaderException
+    {
+        // user element of the UserRequest element
+        Element userElement = userRequestElement.getChild("user");
+        if (userElement == null)
+        {
+            String error = "user element not found in userRequest element";
+            throw new ReaderException(error);
+        }
+        User<? extends Principal> user = ca.nrc.cadc.ac.xml.UserReader.parseUser(userElement);
+
+        // password element of the userRequest element
+        Element passwordElement = userRequestElement.getChild("password");
+        if (passwordElement == null)
+        {
+            String error = "password element not found in userRequest element";
+            throw new ReaderException(error);
+        }
+        String password = passwordElement.getText();
+
+        UserRequest userRequest = new UserRequest(user, password);
+
+        return userRequest;
+    }
+
+}
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestWriter.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestWriter.java
new file mode 100644
index 0000000000000000000000000000000000000000..c85a6e5fcd42c7a664cbfbcb215f28ff83a198d1
--- /dev/null
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserRequestWriter.java
@@ -0,0 +1,157 @@
+/*
+ ************************************************************************
+ *******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
+ **************  CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES  **************
+ *
+ *  (c) 2014.                            (c) 2014.
+ *  Government of Canada                 Gouvernement du Canada
+ *  National Research Council            Conseil national de recherches
+ *  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
+ *  All rights reserved                  Tous droits réservés
+ *
+ *  NRC disclaims any warranties,        Le CNRC dénie toute garantie
+ *  expressed, implied, or               énoncée, implicite ou légale,
+ *  statutory, of any kind with          de quelque nature que ce
+ *  respect to the software,             soit, concernant le logiciel,
+ *  including without limitation         y compris sans restriction
+ *  any warranty of merchantability      toute garantie de valeur
+ *  or fitness for a particular          marchande ou de pertinence
+ *  purpose. NRC shall not be            pour un usage particulier.
+ *  liable in any event for any          Le CNRC ne pourra en aucun cas
+ *  damages, whether direct or           être tenu responsable de tout
+ *  indirect, special or general,        dommage, direct ou indirect,
+ *  consequential or incidental,         particulier ou général,
+ *  arising from the use of the          accessoire ou fortuit, résultant
+ *  software.  Neither the name          de l'utilisation du logiciel. Ni
+ *  of the National Research             le nom du Conseil National de
+ *  Council of Canada nor the            Recherches du Canada ni les noms
+ *  names of its contributors may        de ses  participants ne peuvent
+ *  be used to endorse or promote        être utilisés pour approuver ou
+ *  products derived from this           promouvoir les produits dérivés
+ *  software without specific prior      de ce logiciel sans autorisation
+ *  written permission.                  préalable et particulière
+ *                                       par écrit.
+ *
+ *  This file is part of the             Ce fichier fait partie du projet
+ *  OpenCADC project.                    OpenCADC.
+ *
+ *  OpenCADC is free software:           OpenCADC est un logiciel libre ;
+ *  you can redistribute it and/or       vous pouvez le redistribuer ou le
+ *  modify it under the terms of         modifier suivant les termes de
+ *  the GNU Affero General Public        la “GNU Affero General Public
+ *  License as published by the          License” telle que publiée
+ *  Free Software Foundation,            par la Free Software Foundation
+ *  either version 3 of the              : soit la version 3 de cette
+ *  License, or (at your option)         licence, soit (à votre gré)
+ *  any later version.                   toute version ultérieure.
+ *
+ *  OpenCADC is distributed in the       OpenCADC est distribué
+ *  hope that it will be useful,         dans l’espoir qu’il vous
+ *  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
+ *  without even the implied             GARANTIE : sans même la garantie
+ *  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILITÉ
+ *  or FITNESS FOR A PARTICULAR          ni d’ADÉQUATION À UN OBJECTIF
+ *  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
+ *  General Public License for           Générale Publique GNU Affero
+ *  more details.                        pour plus de détails.
+ *
+ *  You should have received             Vous devriez avoir reçu une
+ *  a copy of the GNU Affero             copie de la Licence Générale
+ *  General Public License along         Publique GNU Affero avec
+ *  with OpenCADC.  If not, see          OpenCADC ; si ce n’est
+ *  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
+ *                                       <http://www.gnu.org/licenses/>.
+ *
+ *  $Revision: 4 $
+ *
+ ************************************************************************
+ */
+
+package ca.nrc.cadc.ac.xml;
+
+import ca.nrc.cadc.ac.UserRequest;
+import ca.nrc.cadc.util.StringBuilderWriter;
+import org.jdom2.Document;
+import org.jdom2.Element;
+import org.jdom2.output.Format;
+import org.jdom2.output.XMLOutputter;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.security.Principal;
+
+public class UserRequestWriter
+{
+    /**
+     * Write a UserRequest to a StringBuilder.
+     *
+     * @param userRequest UserRequest to write.
+     * @param builder StringBuilder to write to.
+     * @throws java.io.IOException if the writer fails to write.
+     * @throws WriterException
+     */
+    public static void write(UserRequest<? extends Principal> userRequest, StringBuilder builder)
+        throws IOException, WriterException
+    {
+        write(userRequest, new StringBuilderWriter(builder));
+    }
+
+    /**
+     * Write a UserRequest to a Writer.
+     *
+     * @param userRequest UserRequest to write.
+     * @param writer Writer to write to.
+     * @throws IOException if the writer fails to write.
+     * @throws WriterException
+     */
+    public static void write(UserRequest<? extends Principal> userRequest, Writer writer)
+        throws IOException, WriterException
+    {
+        if (userRequest == null)
+        {
+            throw new WriterException("null UserRequest");
+        }
+
+        write(getUserRequestElement(userRequest), writer);
+    }
+
+    /**
+     * Build the UserRequest element.
+     *
+     * @param userRequest UserRequest.
+     * @return member Element.
+     * @throws WriterException
+     */
+    public static Element getUserRequestElement(UserRequest<? extends Principal> userRequest)
+        throws WriterException
+    {
+        // Create the userRequest Element.
+        Element userRequestElement = new Element("userRequest");
+
+        // user element
+        Element userElement = UserWriter.getUserElement(userRequest.getUser());
+        userRequestElement.addContent(userElement);
+
+        // password element
+        Element passwordElement = new Element("password");
+        passwordElement.setText(userRequest.getPassword());
+        userRequestElement.addContent(passwordElement);
+
+        return userRequestElement;
+    }
+
+    /**
+     * Write to root Element to a writer.
+     *
+     * @param root Root Element to write.
+     * @param writer Writer to write to.
+     * @throws IOException if the writer fails to write.
+     */
+    private static void write(Element root, Writer writer)
+        throws IOException
+    {
+        XMLOutputter outputter = new XMLOutputter();
+        outputter.setFormat(Format.getPrettyFormat());
+        outputter.output(new Document(root), writer);
+    }
+}
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserWriter.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserWriter.java
similarity index 93%
rename from projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserWriter.java
rename to projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserWriter.java
index 832e41a612a9ed88cb1c5fff6cc5af33753c4275..b9be13ef69e65b30ef1931708a28c21c29b084ef 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/UserWriter.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/UserWriter.java
@@ -66,8 +66,10 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
+import ca.nrc.cadc.ac.User;
+import ca.nrc.cadc.ac.UserDetails;
 import ca.nrc.cadc.util.StringBuilderWriter;
 import java.io.BufferedWriter;
 import java.io.IOException;
@@ -90,7 +92,7 @@ public class UserWriter
      * @param user User to write.
      * @param builder StringBuilder to write to.
      * @throws java.io.IOException if the writer fails to write.
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(User<? extends Principal> user, StringBuilder builder)
         throws IOException, WriterException
@@ -104,7 +106,7 @@ public class UserWriter
      * @param user User to write.
      * @param out OutputStream to write to.
      * @throws IOException if the writer fails to write.
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(User<? extends Principal> user, OutputStream out)
         throws IOException, WriterException
@@ -127,7 +129,7 @@ public class UserWriter
      * @param user User to write.
      * @param writer Writer to write to.
      * @throws IOException if the writer fails to write.
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static void write(User<? extends Principal> user, Writer writer)
         throws IOException, WriterException
@@ -145,7 +147,7 @@ public class UserWriter
      *
      * @param user User.
      * @return member Element.
-     * @throws ca.nrc.cadc.ac.WriterException
+     * @throws WriterException
      */
     public static Element getUserElement(User<? extends Principal> user)
         throws WriterException
@@ -155,7 +157,7 @@ public class UserWriter
 
         // userID element
         Element userIDElement = new Element("userID");
-        userIDElement.addContent(IdentityWriter.write(user.getUserID()));
+        userIDElement.addContent(ca.nrc.cadc.ac.xml.IdentityWriter.write(user.getUserID()));
         userElement.addContent(userIDElement);
 
         // identities
@@ -165,7 +167,7 @@ public class UserWriter
             Element identitiesElement = new Element("identities");
             for (Principal identity : identities)
             {
-                identitiesElement.addContent(IdentityWriter.write(identity));
+                identitiesElement.addContent(ca.nrc.cadc.ac.xml.IdentityWriter.write(identity));
             }
             userElement.addContent(identitiesElement);
         }
@@ -177,7 +179,7 @@ public class UserWriter
             Set<UserDetails> userDetails = user.details;
             for (UserDetails userDetail : userDetails)
             {
-                detailsElement.addContent(UserDetailsWriter.write(userDetail));
+                detailsElement.addContent(ca.nrc.cadc.ac.xml.UserDetailsWriter.write(userDetail));
             }
             userElement.addContent(detailsElement);
         }
diff --git a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/WriterException.java b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/WriterException.java
similarity index 99%
rename from projects/cadcAccessControl/src/ca/nrc/cadc/ac/WriterException.java
rename to projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/WriterException.java
index 3bf5a2b87b05ce9cb0c2279cbf7ad72c466801d1..139003975b014adeec491c14dda711b039ed6425 100755
--- a/projects/cadcAccessControl/src/ca/nrc/cadc/ac/WriterException.java
+++ b/projects/cadcAccessControl/src/ca/nrc/cadc/ac/xml/WriterException.java
@@ -66,7 +66,7 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
 import java.io.IOException;
 
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserRequestTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserRequestTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9507d25e5b83156d2627652c90560565c4d30ee3
--- /dev/null
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserRequestTest.java
@@ -0,0 +1,94 @@
+/*
+ ************************************************************************
+ *******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
+ **************  CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES  **************
+ *
+ *  (c) 2014.                            (c) 2014.
+ *  Government of Canada                 Gouvernement du Canada
+ *  National Research Council            Conseil national de recherches
+ *  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
+ *  All rights reserved                  Tous droits réservés
+ *
+ *  NRC disclaims any warranties,        Le CNRC dénie toute garantie
+ *  expressed, implied, or               énoncée, implicite ou légale,
+ *  statutory, of any kind with          de quelque nature que ce
+ *  respect to the software,             soit, concernant le logiciel,
+ *  including without limitation         y compris sans restriction
+ *  any warranty of merchantability      toute garantie de valeur
+ *  or fitness for a particular          marchande ou de pertinence
+ *  purpose. NRC shall not be            pour un usage particulier.
+ *  liable in any event for any          Le CNRC ne pourra en aucun cas
+ *  damages, whether direct or           être tenu responsable de tout
+ *  indirect, special or general,        dommage, direct ou indirect,
+ *  consequential or incidental,         particulier ou général,
+ *  arising from the use of the          accessoire ou fortuit, résultant
+ *  software.  Neither the name          de l'utilisation du logiciel. Ni
+ *  of the National Research             le nom du Conseil National de
+ *  Council of Canada nor the            Recherches du Canada ni les noms
+ *  names of its contributors may        de ses  participants ne peuvent
+ *  be used to endorse or promote        être utilisés pour approuver ou
+ *  products derived from this           promouvoir les produits dérivés
+ *  software without specific prior      de ce logiciel sans autorisation
+ *  written permission.                  préalable et particulière
+ *                                       par écrit.
+ *
+ *  This file is part of the             Ce fichier fait partie du projet
+ *  OpenCADC project.                    OpenCADC.
+ *
+ *  OpenCADC is free software:           OpenCADC est un logiciel libre ;
+ *  you can redistribute it and/or       vous pouvez le redistribuer ou le
+ *  modify it under the terms of         modifier suivant les termes de
+ *  the GNU Affero General Public        la “GNU Affero General Public
+ *  License as published by the          License” telle que publiée
+ *  Free Software Foundation,            par la Free Software Foundation
+ *  either version 3 of the              : soit la version 3 de cette
+ *  License, or (at your option)         licence, soit (à votre gré)
+ *  any later version.                   toute version ultérieure.
+ *
+ *  OpenCADC is distributed in the       OpenCADC est distribué
+ *  hope that it will be useful,         dans l’espoir qu’il vous
+ *  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
+ *  without even the implied             GARANTIE : sans même la garantie
+ *  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILITÉ
+ *  or FITNESS FOR A PARTICULAR          ni d’ADÉQUATION À UN OBJECTIF
+ *  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
+ *  General Public License for           Générale Publique GNU Affero
+ *  more details.                        pour plus de détails.
+ *
+ *  You should have received             Vous devriez avoir reçu une
+ *  a copy of the GNU Affero             copie de la Licence Générale
+ *  General Public License along         Publique GNU Affero avec
+ *  with OpenCADC.  If not, see          OpenCADC ; si ce n’est
+ *  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
+ *                                       <http://www.gnu.org/licenses/>.
+ *
+ *  $Revision: 4 $
+ *
+ ************************************************************************
+ */
+
+package ca.nrc.cadc.ac;
+
+import ca.nrc.cadc.auth.HttpPrincipal;
+import org.apache.log4j.Logger;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class UserRequestTest
+{
+
+    private static Logger log = Logger.getLogger(UserRequestTest.class);
+
+    @Test
+    public void simpleEqualityTests() throws Exception
+    {
+        UserRequest<HttpPrincipal> ur1 = new UserRequest<HttpPrincipal>(new User(new HttpPrincipal(("foo"))), "password");
+        UserRequest<HttpPrincipal> ur2 = ur1;
+        assertEquals(ur1, ur2);
+        assertEquals(ur1.getUser(), ur2.getUser());
+        assertEquals(ur1.getPassword(), ur2.getPassword());
+        assertEquals(ur1.hashCode(), ur2.hashCode());
+    }
+
+}
\ No newline at end of file
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserTest.java
index 78b636ffbec33f7ca5276c9948b755900b1bca7f..4f9743d13a4634bbc91a4e6c1fd08da110126e25 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserTest.java
@@ -65,7 +65,9 @@
  *  $Revision: 4 $
  *
  ************************************************************************
- */package ca.nrc.cadc.ac;
+ */
+
+package ca.nrc.cadc.ac;
 
 import static org.junit.Assert.*;
 
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupPropertyReaderWriterTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupPropertyReaderWriterTest.java
similarity index 82%
rename from projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupPropertyReaderWriterTest.java
rename to projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupPropertyReaderWriterTest.java
index 189352538636b4f9561ec7ab2a472012f8fb6f0e..a2cd07efd35a1719bea2d96a3d2b2dd497c14e22 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupPropertyReaderWriterTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupPropertyReaderWriterTest.java
@@ -66,14 +66,11 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
+import ca.nrc.cadc.ac.GroupProperty;
 import org.apache.log4j.Logger;
 import org.jdom2.Element;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import static org.junit.Assert.*;
 
@@ -92,42 +89,42 @@ public class GroupPropertyReaderWriterTest
         Element element = null;
         try
         {
-            GroupProperty gp = GroupPropertyReader.read(element);
+            GroupProperty gp = ca.nrc.cadc.ac.xml.GroupPropertyReader.read(element);
             fail("null element should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element = new Element("foo");
         try
         {
-            GroupProperty gp = GroupPropertyReader.read(element);
+            GroupProperty gp = ca.nrc.cadc.ac.xml.GroupPropertyReader.read(element);
             fail("element not named 'property' should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element = new Element("property");
         try
         {
-            GroupProperty gp = GroupPropertyReader.read(element);
+            GroupProperty gp = ca.nrc.cadc.ac.xml.GroupPropertyReader.read(element);
             fail("element without 'key' attribute should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element.setAttribute("key", "foo");
         try
         {
-            GroupProperty gp = GroupPropertyReader.read(element);
+            GroupProperty gp = ca.nrc.cadc.ac.xml.GroupPropertyReader.read(element);
             fail("element without 'type' attribute should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element.setAttribute("type", "Double");
         try
         {
-            GroupProperty gp = GroupPropertyReader.read(element);
+            GroupProperty gp = ca.nrc.cadc.ac.xml.GroupPropertyReader.read(element);
             fail("Unsupported 'type' should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
     }
      
     @Test
@@ -136,15 +133,15 @@ public class GroupPropertyReaderWriterTest
     {
         try
         {
-            Element element = GroupPropertyWriter.write(null);
+            Element element = ca.nrc.cadc.ac.xml.GroupPropertyWriter.write(null);
             fail("null GroupProperty should throw WriterException");
         }
-        catch (WriterException e) {}
+        catch (ca.nrc.cadc.ac.xml.WriterException e) {}
          
         GroupProperty gp = new GroupProperty("key", new Double(1.0), true);
         try
         {
-            Element element = GroupPropertyWriter.write(gp);
+            Element element = ca.nrc.cadc.ac.xml.GroupPropertyWriter.write(gp);
             fail("Unsupported GroupProperty type should throw IllegalArgumentException");
         }
         catch (IllegalArgumentException e) {}
@@ -156,20 +153,20 @@ public class GroupPropertyReaderWriterTest
     {
         // String type
         GroupProperty expected = new GroupProperty("key", "value", true);
-        Element element = GroupPropertyWriter.write(expected);
+        Element element = ca.nrc.cadc.ac.xml.GroupPropertyWriter.write(expected);
         assertNotNull(element);
          
-        GroupProperty actual = GroupPropertyReader.read(element);
+        GroupProperty actual = ca.nrc.cadc.ac.xml.GroupPropertyReader.read(element);
         assertNotNull(actual);
          
         assertEquals(expected, actual);
          
         // Integer tuype
         expected = new GroupProperty("key", new Integer(1), false);
-        element = GroupPropertyWriter.write(expected);
+        element = ca.nrc.cadc.ac.xml.GroupPropertyWriter.write(expected);
         assertNotNull(element);
          
-        actual = GroupPropertyReader.read(element);
+        actual = ca.nrc.cadc.ac.xml.GroupPropertyReader.read(element);
         assertNotNull(actual);
          
         assertEquals(expected, actual);
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupReaderWriterTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupReaderWriterTest.java
similarity index 90%
rename from projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupReaderWriterTest.java
rename to projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupReaderWriterTest.java
index c54f6ee56d0787551e5c3fb7c45a1fad85b67523..fb95af54f166d27f63a4abaaeef708d2057300e9 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupReaderWriterTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupReaderWriterTest.java
@@ -66,7 +66,7 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -81,6 +81,9 @@ import java.util.Date;
 
 import javax.security.auth.x500.X500Principal;
 
+import ca.nrc.cadc.ac.Group;
+import ca.nrc.cadc.ac.GroupProperty;
+import ca.nrc.cadc.ac.User;
 import org.apache.log4j.Logger;
 import org.junit.Test;
 
@@ -103,7 +106,7 @@ public class GroupReaderWriterTest
         try
         {
             String s = null;
-            Group g = GroupReader.read(s);
+            Group g = ca.nrc.cadc.ac.xml.GroupReader.read(s);
             fail("null String should throw IllegalArgumentException");
         }
         catch (IllegalArgumentException e) {}
@@ -111,7 +114,7 @@ public class GroupReaderWriterTest
         try
         {
             InputStream in = null;
-            Group g = GroupReader.read(in);
+            Group g = ca.nrc.cadc.ac.xml.GroupReader.read(in);
             fail("null InputStream should throw IOException");
         }
         catch (IOException e) {}
@@ -119,7 +122,7 @@ public class GroupReaderWriterTest
         try
         {
             Reader r = null;
-            Group g = GroupReader.read(r);
+            Group g = ca.nrc.cadc.ac.xml.GroupReader.read(r);
             fail("null element should throw ReaderException");
         }
         catch (IllegalArgumentException e) {}
@@ -131,10 +134,10 @@ public class GroupReaderWriterTest
     {
         try
         {
-            GroupWriter.write(null, new StringBuilder());
+            ca.nrc.cadc.ac.xml.GroupWriter.write(null, new StringBuilder());
             fail("null Group should throw WriterException");
         }
-        catch (WriterException e) {}
+        catch (ca.nrc.cadc.ac.xml.WriterException e) {}
     }
      
     @Test
@@ -144,10 +147,10 @@ public class GroupReaderWriterTest
         Group expected = new Group("groupID", null);
                 
         StringBuilder xml = new StringBuilder();
-        GroupWriter.write(expected, xml);
+        ca.nrc.cadc.ac.xml.GroupWriter.write(expected, xml);
         assertFalse(xml.toString().isEmpty());
         
-        Group actual = GroupReader.read(xml.toString());
+        Group actual = ca.nrc.cadc.ac.xml.GroupReader.read(xml.toString());
         assertNotNull(actual);
         assertEquals(expected, actual);
     }
@@ -159,7 +162,7 @@ public class GroupReaderWriterTest
         Group expected = new Group("groupID", new User<Principal>(new HttpPrincipal("foo")));
         expected.description = "description";
         expected.lastModified = new Date();
-        expected.properties.add(new GroupProperty("key", "value", true));
+        expected.getProperties().add(new GroupProperty("key", "value", true));
         
         Group groupMember = new Group("member", new User<Principal>(new OpenIdPrincipal("bar")));
         User<Principal> userMember = new User<Principal>(new HttpPrincipal("baz"));
@@ -172,10 +175,10 @@ public class GroupReaderWriterTest
         expected.getUserAdmins().add(userAdmin);
         
         StringBuilder xml = new StringBuilder();
-        GroupWriter.write(expected, xml);
+        ca.nrc.cadc.ac.xml.GroupWriter.write(expected, xml);
         assertFalse(xml.toString().isEmpty());
         
-        Group actual = GroupReader.read(xml.toString());
+        Group actual = ca.nrc.cadc.ac.xml.GroupReader.read(xml.toString());
         assertNotNull(actual);
         assertEquals(expected, actual);
         assertEquals(expected.description, actual.description);
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupsReaderWriterTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupsReaderWriterTest.java
similarity index 91%
rename from projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupsReaderWriterTest.java
rename to projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupsReaderWriterTest.java
index 3a6d595ccca502e3a72dff9b814ea8d60fcf7f0c..b77be4b930ec51581a1f8c9f5ed8e58ba25d2168 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/GroupsReaderWriterTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/GroupsReaderWriterTest.java
@@ -66,18 +66,15 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
-import ca.nrc.cadc.auth.HttpPrincipal;
-import ca.nrc.cadc.auth.OpenIdPrincipal;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
-import java.security.Principal;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
-import javax.security.auth.x500.X500Principal;
+
+import ca.nrc.cadc.ac.Group;
 import org.apache.log4j.Logger;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -100,7 +97,7 @@ public class GroupsReaderWriterTest
         try
         {
             String s = null;
-            List<Group> g = GroupsReader.read(s);
+            List<Group> g = ca.nrc.cadc.ac.xml.GroupsReader.read(s);
             fail("null String should throw IllegalArgumentException");
         }
         catch (IllegalArgumentException e) {}
@@ -108,7 +105,7 @@ public class GroupsReaderWriterTest
         try
         {
             InputStream in = null;
-            List<Group> g = GroupsReader.read(in);
+            List<Group> g = ca.nrc.cadc.ac.xml.GroupsReader.read(in);
             fail("null InputStream should throw IOException");
         }
         catch (IOException e) {}
@@ -116,7 +113,7 @@ public class GroupsReaderWriterTest
         try
         {
             Reader r = null;
-            List<Group> g = GroupsReader.read(r);
+            List<Group> g = ca.nrc.cadc.ac.xml.GroupsReader.read(r);
             fail("null element should throw ReaderException");
         }
         catch (IllegalArgumentException e) {}
@@ -128,10 +125,10 @@ public class GroupsReaderWriterTest
     {
         try
         {
-            GroupsWriter.write(null, new StringBuilder());
+            ca.nrc.cadc.ac.xml.GroupsWriter.write(null, new StringBuilder());
             fail("null Group should throw WriterException");
         }
-        catch (WriterException e) {}
+        catch (ca.nrc.cadc.ac.xml.WriterException e) {}
     }
      
     @Test
@@ -143,10 +140,10 @@ public class GroupsReaderWriterTest
         expected.add(new Group("group2", null));
         
         StringBuilder xml = new StringBuilder();
-        GroupsWriter.write(expected, xml);
+        ca.nrc.cadc.ac.xml.GroupsWriter.write(expected, xml);
         assertFalse(xml.toString().isEmpty());
         
-        List<Group> actual = GroupsReader.read(xml.toString());
+        List<Group> actual = ca.nrc.cadc.ac.xml.GroupsReader.read(xml.toString());
         assertNotNull(actual);
         assertEquals(expected.size(), actual.size());
         assertEquals(expected.get(0), actual.get(0));
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/IdentityReaderWriterTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java
similarity index 83%
rename from projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/IdentityReaderWriterTest.java
rename to projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java
index cabd9e945345acd6c2aa10aff8b78d5460980cf5..74e25644d7841e9531b12383121e0d52dfd69285 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/IdentityReaderWriterTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java
@@ -66,7 +66,7 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
 import ca.nrc.cadc.auth.HttpPrincipal;
 import ca.nrc.cadc.auth.NumericPrincipal;
@@ -94,34 +94,34 @@ public class IdentityReaderWriterTest
         Element element = null;
         try
         {
-            Principal p = IdentityReader.read(element);
+            Principal p = ca.nrc.cadc.ac.xml.IdentityReader.read(element);
             fail("null element should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element = new Element("foo");
         try
         {
-            Principal p = IdentityReader.read(element);
+            Principal p = ca.nrc.cadc.ac.xml.IdentityReader.read(element);
             fail("element not named 'identity' should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element = new Element("identity");
         try
         {
-            Principal p = IdentityReader.read(element);
+            Principal p = ca.nrc.cadc.ac.xml.IdentityReader.read(element);
             fail("element without 'type' attribute should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element.setAttribute("type", "foo");
         try
         {
-            Principal p = IdentityReader.read(element);
+            Principal p = ca.nrc.cadc.ac.xml.IdentityReader.read(element);
             fail("element with unknown 'type' attribute should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
     }
      
     @Test
@@ -130,15 +130,15 @@ public class IdentityReaderWriterTest
     {
         try
         {
-            Element element = IdentityWriter.write(null);
+            Element element = ca.nrc.cadc.ac.xml.IdentityWriter.write(null);
             fail("null Identity should throw WriterException");
         }
-        catch (WriterException e) {}
+        catch (ca.nrc.cadc.ac.xml.WriterException e) {}
          
         Principal p = new JMXPrincipal("foo");
         try
         {
-            Element element = IdentityWriter.write(p);
+            Element element = ca.nrc.cadc.ac.xml.IdentityWriter.write(p);
             fail("Unsupported Principal type should throw IllegalArgumentException");
         }
         catch (IllegalArgumentException e) {}
@@ -150,40 +150,40 @@ public class IdentityReaderWriterTest
     {
         // X500
         Principal expected = new X500Principal("cn=foo,o=bar");
-        Element element = IdentityWriter.write(expected);
+        Element element = ca.nrc.cadc.ac.xml.IdentityWriter.write(expected);
         assertNotNull(element);
          
-        Principal actual = IdentityReader.read(element);
+        Principal actual = ca.nrc.cadc.ac.xml.IdentityReader.read(element);
         assertNotNull(actual);
          
         assertEquals(expected, actual);
          
         // UID
         expected = new NumericPrincipal(123l);
-        element = IdentityWriter.write(expected);
+        element = ca.nrc.cadc.ac.xml.IdentityWriter.write(expected);
         assertNotNull(element);
          
-        actual = IdentityReader.read(element);
+        actual = ca.nrc.cadc.ac.xml.IdentityReader.read(element);
         assertNotNull(actual);
          
         assertEquals(expected, actual);
         
         // OpenID
         expected = new OpenIdPrincipal("bar");
-        element = IdentityWriter.write(expected);
+        element = ca.nrc.cadc.ac.xml.IdentityWriter.write(expected);
         assertNotNull(element);
          
-        actual = IdentityReader.read(element);
+        actual = ca.nrc.cadc.ac.xml.IdentityReader.read(element);
         assertNotNull(actual);
          
         assertEquals(expected, actual);
         
         // HTTP
         expected = new HttpPrincipal("baz");
-        element = IdentityWriter.write(expected);
+        element = ca.nrc.cadc.ac.xml.IdentityWriter.write(expected);
         assertNotNull(element);
          
-        actual = IdentityReader.read(element);
+        actual = ca.nrc.cadc.ac.xml.IdentityReader.read(element);
         assertNotNull(actual);
          
         assertEquals(expected, actual);
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserDetailsReaderWriterTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserDetailsReaderWriterTest.java
similarity index 84%
rename from projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserDetailsReaderWriterTest.java
rename to projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserDetailsReaderWriterTest.java
index 159333bdda86d33cb8938558c3dabff602ee1ecc..5e7918ce6b47bdd17babfae50ad0d4fdf735fe23 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserDetailsReaderWriterTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserDetailsReaderWriterTest.java
@@ -66,14 +66,11 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
-import ca.nrc.cadc.auth.HttpPrincipal;
-import ca.nrc.cadc.auth.NumericPrincipal;
-import ca.nrc.cadc.auth.OpenIdPrincipal;
-import java.security.Principal;
-import javax.management.remote.JMXPrincipal;
-import javax.security.auth.x500.X500Principal;
+import ca.nrc.cadc.ac.PersonalDetails;
+import ca.nrc.cadc.ac.PosixDetails;
+import ca.nrc.cadc.ac.UserDetails;
 import org.apache.log4j.Logger;
 import org.jdom2.Element;
 import org.junit.Test;
@@ -94,34 +91,34 @@ public class UserDetailsReaderWriterTest
         Element element = null;
         try
         {
-            UserDetails ud = UserDetailsReader.read(element);
+            UserDetails ud = ca.nrc.cadc.ac.xml.UserDetailsReader.read(element);
             fail("null element should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element = new Element("foo");
         try
         {
-            UserDetails ud = UserDetailsReader.read(element);
+            UserDetails ud = ca.nrc.cadc.ac.xml.UserDetailsReader.read(element);
             fail("element not named 'userDetails' should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element = new Element(UserDetails.NAME);
         try
         {
-            UserDetails ud = UserDetailsReader.read(element);
+            UserDetails ud = ca.nrc.cadc.ac.xml.UserDetailsReader.read(element);
             fail("element without 'type' attribute should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
          
         element.setAttribute("type", "foo");
         try
         {
-            UserDetails ud = UserDetailsReader.read(element);
+            UserDetails ud = ca.nrc.cadc.ac.xml.UserDetailsReader.read(element);
             fail("element with unknown 'type' attribute should throw ReaderException");
         }
-        catch (ReaderException e) {}
+        catch (ca.nrc.cadc.ac.xml.ReaderException e) {}
     }
      
     @Test
@@ -130,10 +127,10 @@ public class UserDetailsReaderWriterTest
     {
         try
         {
-            Element element = UserDetailsWriter.write(null);
+            Element element = ca.nrc.cadc.ac.xml.UserDetailsWriter.write(null);
             fail("null UserDetails should throw WriterException");
         }
-        catch (WriterException e) {}
+        catch (ca.nrc.cadc.ac.xml.WriterException e) {}
     }
      
     @Test
@@ -146,10 +143,10 @@ public class UserDetailsReaderWriterTest
         expected.country = "country";
         expected.email = "email";
         expected.institute = "institute";
-        Element element = UserDetailsWriter.write(expected);
+        Element element = ca.nrc.cadc.ac.xml.UserDetailsWriter.write(expected);
         assertNotNull(element);
         
-        PersonalDetails actual = (PersonalDetails) UserDetailsReader.read(element);
+        PersonalDetails actual = (PersonalDetails) ca.nrc.cadc.ac.xml.UserDetailsReader.read(element);
         assertNotNull(actual);
         assertEquals(expected, actual);
         assertEquals(expected.address, actual.address);
@@ -164,10 +161,10 @@ public class UserDetailsReaderWriterTest
         throws Exception
     {
         UserDetails expected = new PosixDetails(123l, 456, "/dev/null");
-        Element element = UserDetailsWriter.write(expected);
+        Element element = ca.nrc.cadc.ac.xml.UserDetailsWriter.write(expected);
         assertNotNull(element);
         
-        UserDetails actual = UserDetailsReader.read(element);
+        UserDetails actual = ca.nrc.cadc.ac.xml.UserDetailsReader.read(element);
         assertNotNull(actual);
         assertEquals(expected, actual);
     }
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserReaderWriterTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserReaderWriterTest.java
similarity index 90%
rename from projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserReaderWriterTest.java
rename to projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserReaderWriterTest.java
index 5f4d3e8d31debc38a2add8a522553985260fd552..ed61d4bc0416c624087a15d6fd181ff94d92f470 100644
--- a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/UserReaderWriterTest.java
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserReaderWriterTest.java
@@ -66,8 +66,10 @@
  *
  ************************************************************************
  */
-package ca.nrc.cadc.ac;
+package ca.nrc.cadc.ac.xml;
 
+import ca.nrc.cadc.ac.PersonalDetails;
+import ca.nrc.cadc.ac.User;
 import ca.nrc.cadc.auth.HttpPrincipal;
 import ca.nrc.cadc.auth.NumericPrincipal;
 import java.io.IOException;
@@ -93,7 +95,7 @@ public class UserReaderWriterTest
         try
         {
             String s = null;
-            User<? extends Principal> u = UserReader.read(s);
+            User<? extends Principal> u = ca.nrc.cadc.ac.xml.UserReader.read(s);
             fail("null String should throw IllegalArgumentException");
         }
         catch (IllegalArgumentException e) {}
@@ -101,7 +103,7 @@ public class UserReaderWriterTest
         try
         {
             InputStream in = null;
-            User<? extends Principal> u = UserReader.read(in);
+            User<? extends Principal> u = ca.nrc.cadc.ac.xml.UserReader.read(in);
             fail("null InputStream should throw IOException");
         }
         catch (IOException e) {}
@@ -109,7 +111,7 @@ public class UserReaderWriterTest
         try
         {
             Reader r = null;
-            User<? extends Principal> u = UserReader.read(r);
+            User<? extends Principal> u = ca.nrc.cadc.ac.xml.UserReader.read(r);
             fail("null Reader should throw IllegalArgumentException");
         }
         catch (IllegalArgumentException e) {}
@@ -121,10 +123,10 @@ public class UserReaderWriterTest
     {
         try
         {
-            UserWriter.write(null, new StringBuilder());
+            ca.nrc.cadc.ac.xml.UserWriter.write(null, new StringBuilder());
             fail("null User should throw WriterException");
         }
-        catch (WriterException e) {}
+        catch (ca.nrc.cadc.ac.xml.WriterException e) {}
     }
      
     @Test
@@ -136,10 +138,10 @@ public class UserReaderWriterTest
         expected.details.add(new PersonalDetails("firstname", "lastname"));
         
         StringBuilder xml = new StringBuilder();
-        UserWriter.write(expected, xml);
+        ca.nrc.cadc.ac.xml.UserWriter.write(expected, xml);
         assertFalse(xml.toString().isEmpty());
         
-        User<? extends Principal> actual = UserReader.read(xml.toString());
+        User<? extends Principal> actual = ca.nrc.cadc.ac.xml.UserReader.read(xml.toString());
         assertNotNull(actual);
         assertEquals(expected, actual);
     }
diff --git a/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserRequestReaderWriterTest.java b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserRequestReaderWriterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c4a1d9a2d17679241c3fa1d7bd3fd5f83dd37032
--- /dev/null
+++ b/projects/cadcAccessControl/test/src/ca/nrc/cadc/ac/xml/UserRequestReaderWriterTest.java
@@ -0,0 +1,157 @@
+/*
+ ************************************************************************
+ *******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
+ **************  CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES  **************
+ *
+ *  (c) 2014.                            (c) 2014.
+ *  Government of Canada                 Gouvernement du Canada
+ *  National Research Council            Conseil national de recherches
+ *  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
+ *  All rights reserved                  Tous droits réservés
+ *
+ *  NRC disclaims any warranties,        Le CNRC dénie toute garantie
+ *  expressed, implied, or               énoncée, implicite ou légale,
+ *  statutory, of any kind with          de quelque nature que ce
+ *  respect to the software,             soit, concernant le logiciel,
+ *  including without limitation         y compris sans restriction
+ *  any warranty of merchantability      toute garantie de valeur
+ *  or fitness for a particular          marchande ou de pertinence
+ *  purpose. NRC shall not be            pour un usage particulier.
+ *  liable in any event for any          Le CNRC ne pourra en aucun cas
+ *  damages, whether direct or           être tenu responsable de tout
+ *  indirect, special or general,        dommage, direct ou indirect,
+ *  consequential or incidental,         particulier ou général,
+ *  arising from the use of the          accessoire ou fortuit, résultant
+ *  software.  Neither the name          de l'utilisation du logiciel. Ni
+ *  of the National Research             le nom du Conseil National de
+ *  Council of Canada nor the            Recherches du Canada ni les noms
+ *  names of its contributors may        de ses  participants ne peuvent
+ *  be used to endorse or promote        être utilisés pour approuver ou
+ *  products derived from this           promouvoir les produits dérivés
+ *  software without specific prior      de ce logiciel sans autorisation
+ *  written permission.                  préalable et particulière
+ *                                       par écrit.
+ *
+ *  This file is part of the             Ce fichier fait partie du projet
+ *  OpenCADC project.                    OpenCADC.
+ *
+ *  OpenCADC is free software:           OpenCADC est un logiciel libre ;
+ *  you can redistribute it and/or       vous pouvez le redistribuer ou le
+ *  modify it under the terms of         modifier suivant les termes de
+ *  the GNU Affero General Public        la “GNU Affero General Public
+ *  License as published by the          License” telle que publiée
+ *  Free Software Foundation,            par la Free Software Foundation
+ *  either version 3 of the              : soit la version 3 de cette
+ *  License, or (at your option)         licence, soit (à votre gré)
+ *  any later version.                   toute version ultérieure.
+ *
+ *  OpenCADC is distributed in the       OpenCADC est distribué
+ *  hope that it will be useful,         dans l’espoir qu’il vous
+ *  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
+ *  without even the implied             GARANTIE : sans même la garantie
+ *  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILITÉ
+ *  or FITNESS FOR A PARTICULAR          ni d’ADÉQUATION À UN OBJECTIF
+ *  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
+ *  General Public License for           Générale Publique GNU Affero
+ *  more details.                        pour plus de détails.
+ *
+ *  You should have received             Vous devriez avoir reçu une
+ *  a copy of the GNU Affero             copie de la Licence Générale
+ *  General Public License along         Publique GNU Affero avec
+ *  with OpenCADC.  If not, see          OpenCADC ; si ce n’est
+ *  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
+ *                                       <http://www.gnu.org/licenses/>.
+ *
+ *  $Revision: 4 $
+ *
+ ************************************************************************
+ */
+package ca.nrc.cadc.ac.xml;
+
+import ca.nrc.cadc.ac.PersonalDetails;
+import ca.nrc.cadc.ac.User;
+import ca.nrc.cadc.ac.UserRequest;
+import ca.nrc.cadc.auth.HttpPrincipal;
+import ca.nrc.cadc.auth.NumericPrincipal;
+import org.apache.log4j.Logger;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.security.Principal;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author jburke
+ */
+public class UserRequestReaderWriterTest
+{
+    private static Logger log = Logger.getLogger(UserRequestReaderWriterTest.class);
+
+    @Test
+    public void testReaderExceptions()
+        throws Exception
+    {
+        try
+        {
+            String s = null;
+            UserRequest u = UserRequestReader.read(s);
+            fail("null String should throw IllegalArgumentException");
+        }
+        catch (IllegalArgumentException e) {}
+        
+        try
+        {
+            InputStream in = null;
+            UserRequest u = UserRequestReader.read(in);
+            fail("null InputStream should throw IOException");
+        }
+        catch (IOException e) {}
+        
+        try
+        {
+            Reader r = null;
+            UserRequest u = UserRequestReader.read(r);
+            fail("null Reader should throw IllegalArgumentException");
+        }
+        catch (IllegalArgumentException e) {}
+    }
+     
+    @Test
+    public void testWriterExceptions()
+        throws Exception
+    {
+        try
+        {
+            UserRequestWriter.write(null, new StringBuilder());
+            fail("null UserRequest should throw WriterException");
+        }
+        catch (ca.nrc.cadc.ac.xml.WriterException e) {}
+    }
+     
+    @Test
+    public void testReadWrite()
+        throws Exception
+    {
+        User<? extends Principal> expectedUser = new User<Principal>(new HttpPrincipal("foo"));
+        expectedUser.getIdentities().add(new NumericPrincipal(123l));
+        expectedUser.details.add(new PersonalDetails("firstname", "lastname"));
+
+        String expectedPassword = "123456";
+
+        UserRequest expected = new UserRequest(expectedUser, expectedPassword);
+
+        StringBuilder xml = new StringBuilder();
+        UserRequestWriter.write(expected, xml);
+        assertFalse(xml.toString().isEmpty());
+        
+        UserRequest actual = UserRequestReader.read(xml.toString());
+        assertNotNull(actual);
+        assertEquals(expected.getUser(), actual.getUser());
+        assertEquals(expected.getPassword(), actual.getPassword());
+    }
+    
+}