This document explains the requirements and the design of user management.
User management provides the interfaces to manage users and groups.
The current functionality is limited to administering users and groups. Self-registration of users is not (yet) implemented.
The design is centered around a simple domain model with users and groups and relations between them. In addition, there is one interface (facade) through which all changes to users and groups must be made. If a change is made to a user or group object, the change will only become visible after notifying user administration of the change through the interface. This approach also lends itself to an implementation where user administration is a remote service.
To avoid the creation of separate Data Transfer Objects for users and groups and to guarantee consistency through the user administration interface, the following approach is taken:
Integration with application server authentication is provided through persistent storage of the users and groups and their relations in a database. Based on this the integration in an application server can be configured.
The design consists of two packages, a usermgt package with standard interfaces and implementations that are usable in any environment and a usermgt.hibernate package that provides specific implementations for persistence with hibernate.
The basic model is straightforward: a User can have relations with one or more Groups. Both objects implement AbstractPersistent to provide functionality for persistence. The User class guarantees that a user will always be part of at least one group. Both User and Group have package scope constructors and must be obtained through the user administration interface.
The interface of user administration is defined by (surprisingly) UserAdministration. The interface provides methods for creating, removing, renaming, and looking up users and groups. It also provides operations for managing the relations between users and groups and for notifying user administration of changes to a user or group. This is required since user administration returns copies of users and groups.
A straightforward implementation of user administration is to create an implementation of the user administration and map this to a database using Hibernate. Nevertheless, this design would depend heavily on the behavior of Hibernate for lazy loading in combination with, possibly large, numbers of objects. Therefore, we provide a lower level implementation whereby the implementation of user administration delegates to a UserSet and GroupSet respectively.
It is then the responsibility of UserAdministrationImpl to manage the rules governing consistency of the user administration and the UserSet and GroupSet simply manage storage of the users and groups.
The UserSet and GroupSet interface both have an in-memory implementation and a Hibernate implementation. The Hibernate implementation is the one which will be used for actual deployments. The Hibernate implementation also uses caching at application level of users. This is done because user information is accessed frequently. Caching in Hibernate had a much lower performance (in tests it was 100 time slower) so that caching at application level is done instead.
It is required to link together the security mechanism and user management to obtain a user object based on the currently logged in user. This functionality is defined by the UserAccessor. One implementation of this is the JaasUserAccessor which retrieves the user principal from JAAS (using the configured class of the user principal) and uses user administration to lookup the correct User object representing the user.
A small number of sequence diagrams is used to illustrate how user management should be used and to describe the responsibilities of the involved objects. The sequence diagrams do not cover the full functionality of user management.
To add a new user, first a group must be obtained from the user administration. This is because a user must always be part of at least one group. After that, the user can be created with the basic properties of the user and with a reference to the group. The user administration then checks whether the user does not already exist and if so through a UsermgtException. Otherwise, the new user is created.
To add a user to a group, the user and group must first be obtained from the user administration interface. After that, addUserToGroup is used to add the user to a group. Again, user administration checks that the user and group are valid before actually adding the user to the group. Since adding a user to a group modifies the user, the UserSet must be notified of this change by calling userModified() with the modified user.
To change the password of the user, the user must first be obtained from the user administration (not shown). Then, changePassword() must be called with both the old and new password as arguments. The password is then checked and if it is ok, the password is changed. Note that, for security reasons the interface of the user does not allow retrieval of the password.