FEIDE is Federated Electronic Identity for Education, providing a federated electronic identity for Norwegian academic users. Identity management is done locally. The three main parts are
FEIDE consists of several projects. Moria's goal is to create a HTTP based authentication service for web resource providers.
In FEIDE each academic organization has its own user management system for their students and employees. Services at one organization should be able to allow access to a user from another without importing the user account into its own user management system. FEIDE requires access to an LDAP front end of the user management system (Enterprise Directory Service) to provide such service. Potentially more than hundred organizations with a total of several hundred thousand users will participate in FEIDE. The number of services that requires access to user data from FEIDE are expected to be in the hundreds, if not thousands. In this scenario FEIDE cannot trust every one of the FEIDE enabled services (services that receives user data from FEIDE). Without such trust FEIDE will not allow service providers to get access to the user's user-name and password, requiring the authentication to be done by FEIDE and not by the service itself.
This paper describes the authentication model implemented by Moria. The model is based on the user being redirected to the Moria login system when the web resource requests authentication. The authentication consists of two steps:
Moria consists of two interfaces: a SOAP based interface for the client (web resource) and a HTML interface for the user.
Name | Explanation |
---|---|
Enterprise Directory Service | LDAP (Lightweight Directory Access Protocol) server used by each organization. Information about each user is available in a format specified in FEIDE schema definitions. |
Moria | FEIDE's login service |
Web resource | The service that requires authentication and user information |
User agent | The web client used by the end user. |
When a web resource requires user authentication, it requests an authentication session from Moria. The request contains two parameters: a list of requested attributes and a URL that the user agent will be redirected back to after successful authentication. The URL will be supplied with a ticket for retrieval of the requested user attributes. Moria requires that the web service itself has been authenticated. The request will be denied if the resource is unknown to Moria, or a known resource requests attributes (or operations) where it is not authorized. If Moria accepts the resource's request, a URL to Moria's login page is returned to the resource for redistribution to the user agent. The URL contains a ticket that connects the user to the created authentication session and client then sends a 302 redirect response to the users web browser, with the Location header set to be the URL returned from Moria.
The user agent now performs a GET request for Moria's login page. The supplied ticket (login ticket) is verified and if the session exists a login page is returned to the user. The login page contains the name of the resource and what kind of data it has requested about the user. The user fills in user-name and password, and the user agent then sends a POST request with the users user-name and password to Moria.
Moria binds to the LDAP server, using the supplied user-name and password as credentials. The required set of user attributes are fetched from the LDAP server and the user is redirected back to the web service that requested the authentication. The web resource (client) now receives a request from the user's browser, with a service ticket generated after the retrieval of the attributes. The client then requests user data from Moria by supplying the ticket in a SOAP request. Moria validates the ticket and return the user attributes to the client. An empty data set indicates that the user is registered in the LDAP server, but no attributes are requested (or the requested attributes aren't available from the LDAP server). A user is never redirected back to the web resource if the authentication failed.
When Moria has delivered user data to the client, FEIDE's web authentication service is finished. It is now up to the client to store the data as long as it needs it. If the client needs more data, or the same data once more, from FEIDE, it has to initiate a new authentication loop.
"Single Sign-On" is a term with various interpretations. For a user Single Sign-On is to supply his/her password once and be able to use a variety of different services without re-typing the password. In this paper we will use the term "Ticket based re-authentication" for this type of Single Sing-On.
From a service point of view "Single Sign-On" can bee seen as the ability to log the user into multiple independent subsystems. For instance a portal service might need to log the user into one or more subsystems. This kind of Single Sign-On is referred to as "Proxy authentication".
The ticket based re-authentication uses the existing Moria model. The first time a user logs into a service via Moria, a SSO ticket is stored in a cookie. The next time the user is redirected to Moria for login Moria uses the ticket to find the authentication session from last login. If it still exist (i.e. the session has not timed out), the user is immediately redirected back to the web service and the web service get access to the cached user data. If re-authentication cannot be used, the user is presented with a login form and a regular authentication process is performed.
There are three scenarios when ticket based re-authentication fails, and a normal authentication process is required:
For both of the following examples the following amendments to standard authentication process apply:
Service 1 (S1) requests, from Moria, a proxy ticket to log into service 2 (S2). S1 supplies the TGT obtained from Moria in the regular user authentication process.
Upon the request Moria looks up the cached user data using the TGT. A proxy ticket is generated for S2 and returned to S1. This ticket can only be used once and only by S2.
S1 relays the ticket to S2.
S2 uses the ticket to fetch attributes from Moria. The request must contain both the ticket and a list of attributes. S2 can also ask for a TGT that it can use to log into other sub systems.
Moria either returns the requested attributes or denies the request (due to timeout or if S2 has requested non-cached attributes or attributes it's not allowed to get access to)
Moria is designed to be extended with new authentication methods and services. The authorization model is flexible the ACL's can be extended without changes in the authorization software. The WSDL interface is also designed to be extended with full backward compatibility allowing Moria to be equipped with new functionality.
In addition to the previously described authentication methods, Moria support direct authentication and user existence lookup.
For services that cannot use the redirect model, Moria support the use of direct authentication. The requesting service must collect the username and password from the user and then do a direct authentication against Moria. The direct authentication is done in one SOAP request containing the requested attributes along with the user's username and password. If the authentication is successful the service will receive the requested attributes.
Moria consists of several modules that performs a specific task. All requests from the web service are sent through the Axis servlet, and the user's requests are sent through the Login servlet. From the servlets all requests are sent to the Controller intermediary for processing.
At startup the controller initiates all modules and if no problem occur the controller is ready for use.
All requests from the external interfaces (Login, Logout and Axis servlets) are processed by the controller. Validation of input is one of the controllers major tasks, and if a request is invalid an exception is thrown back to the caller. The other main function of the controller is to provide an easy interface for the servlets handling logging, exception and forwarding requests down to the proper module.
The configuration managers task is to watch the configuration files for changes. Initially a configuration file for each module (authorization, web, store and directory) are read and the content passed as Properties objects to the corresponding module through the controller. When a configuration file is changed the entire file is read and the updated configuration is passed to the corresponding module.
A configuration file for the Configuration Manager is required to be set as a system property in the VM before initialization, and this file must contain a property for the time interval for watching the files on the file system along with paths to the individual module configuration files. The content of the Configuration Manager's configuration file is described in detail in the Configuration Manager documentation.
Every requesting web service must be authorized to use Moria. The authentication of the web service is done outside of Moria and the service principal is supplied every request to the controller. When the controller receives a request it asks the authorization manager if the web service is authorized to perform the request.
The authorization manager requires a configuration containing information about every web service allowed to access Moria. Besides information about the service's name, affiliation, URL and so on, the configuration must contain information about which attributes, operations and subsystems the web service can access. The configuration documentation contains a detailed specification of the authorization managers configuration file.
The web module contains the servlets that are accessed by the requesting web service and the user. The following three servlets are used: Axis, Login and Logout.
The Axis servlet receives all the SOAP requests and forwards them to the Axis engine for decoding. It only acts as a thin transport layer without any real logic. Although Axis comes with an servlet that handles frontend http traffic, Moria uses it's own implementation of the frontend service. This was done to get control over request url mapping and simplify configuration and integration of Axis into the application as a whole. The servlet uses the request URI as service identifier as it forwards the request to the Axis Engine. The engine uses this identifier to map the request to Moria-specific classes that process the request data before calling the controller. See the configuration documentation for details.
After the authentication attempt has been initiated from the web service through the Axis servlet, the user is redirected to the login servlet. If the user has been authenticated previously, has a valid Single Sign-On ticket and the web service is authorized to use Single Sign-On, the user is not presented with the login page, but redirected back to the web service. Otherwise a login page is displayed to the user and he/she has to supply his/her username and password. After a successful authentication the user is redirected back to the web service that requested the authentication.
The logout servlet has a simple task: remove the Single Sign-On ticket from and prevent that the user is automatically signed into other web services without re-authentication. All web services can send the user to the logout page, but naturally the logout servlet cannot remove the web service's internal sessions. When a web service redirects a user to the logout servlet it can also specify a redirect URL that the logout servlet redirects the user back to. In other words the web service can implement a logout function that log the user out of the web service, redirects the user to Moria for removal of Single Sign-On ticket and redirects the user back to the web service (typically to a web page that informs the user that he/she has been logged out). Moria information about configuring the logout redirect parameter is located in the configuration documentation.
Additionally the web application contains an Servlet Context Listener that handles starting and stopping of the controller and underlying modules on web application creation and destruction.
The log api is quite simple. Using Log4J as a backend it has two modes of operation implemented by two separate classes: MessageLogger.java and AccessLogger.java.
The most commonly used mode is message logging; this mode has four log levels: debug, info, warn and critical. This mode is intended to be used anywhere throughout the code where log-worthy incidents occur.
The second mode, for access logging, is only used in the controller. This mode's intended use is for usage statistics. Each incident is logged in a predefined format using predefined identifiers. See the JavaDoc for more details.
The store managers primary function is creation of tickets, and later persistence and lookup of tickets and its associated data. As a side effect it also handles distribution of these data if Moria is run in a cluster configuration. The store also handles life-cycle management of tickets, validating them on retrieval and continuously removing tickets that have expired.
The current store implements the generic store interface using JBoss Cache. This API provides a tree structured cache implementation. To achieve distribution of cache data JBoss Cache uses JGroups as a distribution and transport layer.
Ticket ID generation is handled by the store. The current implementation uses a algorithm that is guaranteed to produce tickets unique across time and all nodes in the cluster. This is done using a predefined, and must be unique, three character node id combined with a time-stamp and a random sequence of bytes. The final sequence of bytes is then pseudo-Base64 encoded to be URI friendly.
The automatic removal of expired tickets is done with code specific to Moria, implemented using JBoss Caches' eviction policy framework. It uses a simple algorithm where each individual ticket, defined by its type, is given an absolute time to live. This period is a configurable percentage of the time the ticket stays in the cache. So the time the ticket is valid and usable is actually less than the time it stays in the cache. More on this in the configuration documentation.