6.11 Security

The login of a user is handled automatically by the XMA runtime. The application programmer does not interact with the client or servers side login plugin directly. But he will lookup the authorisation plugin for permission checks.

When the first component of a XMA application is requested from the runtime, the runtime tries to log in the user. For this purpose the client side login plugin is used. XMA uses Java Authentication and Authorization Service (JAAS) for user logins. JAAS is the standard technology for Java to handle logins.

Every client side login plugin for XMA must implement the JAAS interface LoginModule . The LoginModule authenticates the user and creates a Principal object which contains the user information. For being usable in XMA this object must implement the interface XMAContext . The LoginModule may add some Credential objects to enable the server login module to verify the validity of the user information.

JAAS defines Callbacks as mechanism for LoginModules to gather information about the user. The XMA runtime provides a standard CallbackHandler which handles the user interaction in a dialog box which contains an input field for each callback. This callback handler additionally provides a special callback: ChallengeCallback . This callback is send to the server by the XMA runtime. On the server the XMA runtime calls LoginModuleServer.getChallange() on the server side login plugin. The challenge is send back to the client and returned to the LoginModule by the ChallengeCallback. The challenge can be used in the encryption of credentials by the LoginModule.

After a successful login on the client, the XMA runtime creates a client side session ( XMASessionClient) and stores the user information returned by the LoginModule there.

For permission checks, the authorisation plugin is used. Every authorisation plugin must implement the interface Authorisation . XMA uses the same interface for client side authorisation plugins and server side authorisation plugins. It is up to the implementer of the plugins, if he uses the same or different implementation classes on client and server side.

To check a permission, the programmer calls checkPermission() on your session. This method uses Authorisation.isAuthorized() internally. The first parameter for Authorisation.isAuthorized() is the subject as supplied by the login module. The second parameter is the operation to check mapped to the plugin specific code.

For more information see Permissions.

The Login of a user is handled automatically by the runtime. Before the first component is instantiated, the configured login plugin is used to log in the user. The context information is propagated automatically to the server.

So while programming a component or page you can always relay on the fact, that a valid user is already logged in. You obtain the user context by calling

getComponent().getContext().

The returned XMAContext contains information about

  • the user name. This my only be unique inside of the mandant.

  • the mandant the user belongs to.

  • the locale to use. This contains the country and the language.

  • the execution environment (local developers PC, development, quality, qsys, production).

Permissions can be defined for applications, components, pages and events. They are defined in the file at/spardat/xma/security/Authorisation.properties, which must be in the classpath on client and server side.

To define the permission needed to use a component, you write <componentname>=<permissioncode>.

For pages you write <componentname>/<pagename>=<permissioncode>.

For events implemented directly in the component you write <componentname>/<eventname>=<permissioncode>.

For events implemented in a page you write <componentname>/<pagename>/<eventname>=<permissioncode>.

If you need, you can supply a comma separated list of permission codes for each event, page or component. The permission will be granted, if the logged in user has one of the permissions in the list.

    getComponent().getSession().checkPermission("Spardetail");
To check the permission for a given component, page or event you call XMASession.checkPermission(). It returns true if the permission is granted, false otherwise.

You can use this method to hide buttons and menu entries for which the logged in use has no permission. You should check for the permission of the server side event behind the button or menu entry.

Login plugins may or may not support user change. In both cases the default behaviour is to suppress user changes.

Any change of the XMAContext is reported by the events of the user change procedure. If user change is suppressed, no change in the XMAContext is allowed.

Changing the environment is not supported in XMA, since this could require the download of a new version of the XMA-Components and even XMA-Runtime form a different server.

If a login plugin supports user change, its client side implements the interface LoginModuleWithContextChange . To initially enable user change, you have to register a ContextChangeListener and call the method setContextChangeAllowed() on the login module. The user change can not be allowed without any registered listener. The listener is nesseccary to handle errors while propagating the user change to the server side of the XMA-Application.

        LoginModule module = (LoginModule)getComponent().getSession().getPluginManager().getPlugin(LoginModule.class);
        if(module instanceof LoginModuleWithContextChange) {
            ((LoginModuleWithContextChange)module).addContextChangeListener(this);
            ((LoginModuleWithContextChange)module).setContextChangeAllowed(true);
        }  

To dynamically disable and enable the user change you can call setContextChangeAllowed() again with true for enabling and false for disabling.

To implement a ContextChangeListener you have to implement three methods:

  1. contextWillChange() is called before a context change will take place. A VotingEvent is passed in as parameter. You can prevent the user change by calling its method setDoit(boolean) with false. The user change only takes place if no ContextChangeListener and no other application voted against it.

  2. contextChanged() is called after the user has been successfully changed. A ContextChangeEvent is passed in as parameter. It contains the old and new XMAContext .

  3. contextChangeFailed() is called if there happened any errors during user change. The ContextChangeEvent containing old and new XMAContext and the exception preventing the success of the user change are passed in as parameters. Reasons can be communication problems to the server, a server restart or a tried environment change. You should show the exception and close the application.

It is possible to activate HTTPS as protocol for a certain RPC. This is done by the method RemoteCallClient.setNeedEncryption(boolean needEncryption). This activates HTTPS for this individual RPC only and does not affect other RPCs or other client - server communications.

This section presents the details, you need to know if you want to implement your own authentication or authorisation plugins. If you only want to use the existing security plugins, you can skip this section.

In XMA user authentication ins done by configurable plugins. On the client side a JAAS (Java Authentication and Authorisation System) conforming LoginModule is used. JAAS is the standard way of handling logins in Java and part of JRE 1.4.

In JAAS a user is represented by an Object of type Subject. A Subject contains three collections. A set of principals which contains the system specific information about the user. There can potentially be more than one principal per user, e.g. one for each security system which authenticated the user. The subject further contains a set of public credentials which are intended to be shared, such as Kerberos tickets and a set of private credentials like passwords.

For more information about JAAS see http://java.sun.com/products/jaas/overview.html

This section shows the detailed steps performed during login procedure. Since the exact behaviour of the login plugins is implementation dependent, the plugin used in the XMA-application KrimiAPS is used as an example. The behaviour of the classes of the XMA runtime involved in login procedure is the same for all plugin implementations.


When the first component of a web application is called, the XMA-Boot-Runtime creates a XMASessionClient-Object. On the client side one XMASessionClient-Object exists for each used server side application. Before the XMASessionClient can be used and the component can be invoked, the user must be authenticated successfully.

A special XMALoginContext is used to be able to use the same configuration mechanisms for the LoginModule as for any other XMA-Plugin. This avoids the necessity of a client side configuration file for JAAS. The LoginModule is configured in the xma-app.xml and plugin.xml – files of the web application. The XMALoginContext loads the LoginModule via the PluginManager. Then it performs the JAAS-conform sequence of function calls on it.

First initialize() is called on the LoginModule to initialize it with the subject and a callback-handler. The subject is used to store the user information gathered by the LoginModule. The callback-handler can be used for user interaction. For information about the callback-handler please read the JAAS-Documentation.

Then login() is called on the LoginModule to actually perform the user authentication. The LoginModule used for KrimiAPS first calls serverGetPreLoginInfo() in the XMASessionClient. This call is propagated to the server where a LoginServlet is listening. The LoginServlet loads the server side LoginModuleServer via the PluginManager and calls getPreLoginInfo() on it. This method is intended to provide some defaults for the login process. The LoginModuleServer used by KrimiAPS reads a default locale and the list of different mandants from its database. The LoginServlet sends back this information.

The LoginModule of KrimiAPS calls setNeedEncryption(true) on XMASessionClient, to enforce the encryption of the communication of all login data. The XMA-Runtime use https to provide encryption.

Then the LoginModule used for KrimiAPS asks the user for username and password using the callback-handler. This information is stored in a subject and loginServer() is called on the XMASessionClient with this subject as argument. This call is propagated to the LoginServlet on the server side. The LoginServlet again looks up the server side LoginModuleServer via the PluginManager and calls login on it. The LoginModuleServer used by KrimiAPS checks the username, institute and password gathered from this subject against its database. On success it loads additional user data and adds it to the subject. If the login was successful the LoginModuleServer sends back the changed subject. If the login was not successful only a flag indicating this status is send back. On failure the LoginModule used by KrimiAPS retries two more times. After a successful login exactly one Principal implementing the interface XMAContext is contained in the subject.

If the login was successful the XMALoginContext calls commit()on the LoginModule. This method adds the information contained in the temporary subject send from the server to the subject provided by the initialize()-method. If the LoginModule did not call loginServer() on the XMASessionClient, e.g. because it authenticated the user against a common backend, the XMASessionClient calls loginServer() itself to do the server side login which only has to check the data now.

After the login components can be used. The user information is available to the XMA-programmer by calling getContext() on the XMASessionClient.

If the login was not successful the XMALoginContext calls abort() on the LoginModule. This method removes any gathered user information. The XMA-Boot-Runtime aborts the loading of the component with an error message.

XMA provides the possibility of completely changing the implementation of the user authentication. For this purpose you can provide your own implementations for the authentication plugins LoginModule and LoginModuleServer. Additionally you have to provide an implementation for the interface XMAContext.

The client side plugin must implement the interface javax.security.auth.spi.LoginModule (see API Reference). It must be a JAAS-Conforming LoginModule. Do not forget to call setNeedEncryption(true) on XMASessionClient, to make sure all login data is transferred encrypted using https.

The server side plugin must implement the interface at.spardat.xma.security.LoginModuleServer.

The two plugins have to interoperate in order to gather and validate the login information. For communication between the two plugins the methods XMASessionClient.getPreLoginInfo() and XMASessionClient.loginServer() can be used.

For use in XMA exactly one principal implementing the interface at.spardat.xma.security.XMAContext must be added to the subject. There my be added additional subjects and credentials for use by the plugins. XMA transparently replicates all principals and public credentials between client and server side.

To use these plugins, they must be configured in the plugin.xml-file of the XMA-webapplication:

   <plugin-impl
       implClient="<your client plugin implementation class>"
       implements="javax.security.auth.spi.LoginModule" >
       <resourceLink href="<url to your jar-file> " />
   </plugin-impl>

   <plugin-impl
       implServer="<your server plugin implementation class>"
       implements="at.spardat.xma.security.LoginModuleServer" >
   </plugin-impl>

In XMA authorisation is done by configurable plugins. There can be used different plugins on client and server side.

The authorisation plugin is used every time an authorisation check is made by calling XMASession.checkPermission(). Whenever a server event is send to the client, the permission of the user to perform the desired action is checked before the server side event method is called. Additional permission checks can be made by the application programmer, e.g. to hide menu items or buttons for which the user does not have permissions. Permission checks can be made on the client and on the server side.

The following diagram shows the automatic permission checks performed whenever an RPC occurs.


The client runtime sends the RPC-data in a HTTP-Post Request to the server. There the RPCServletServer is listening for such requests. It first calls XMASesion.checkPermission(). In this method the name of the event is mapped to a security-code. Then the authorisation-plugin is loaded via the PluginManager and Authorisation.isAuthorised() is called with the subject stored in the XMASession and the mapped security-code. The subject was created by the configured LoginModule during the login procedure. Authorisation has to check the permission against its backend system or database. The event method servicing the specific RPC is only called, if this permission check succeeds.

Application programmers usually adds additional permission checks on the client side to hide menu items or buttons not allowed for the current user. They do this by calling XMASesion.checkPermission(), too.

XMA provides the possibility of completely changing the implementation of the authorisation. For this purpose you can provide your own implementations for the authorisation plugin Authorisation.

The plugin must implement the interface at.spardat.xma.security.Authorisation. It must be able to use the subject provided by the authentication plugins and the security codes defined in the AuthorisatonMapping-file.

You can provide one implementation for client and server side, or different implementations.

To use these plugins, they must be configured in the plugin.xml-file of the XMA-webapplication:

   <plugin-impl
       implClient="<your client plugin implementation class>"
       implServer="<your server plugin implementation class>"
       implements="at.spardat.xma.security.Authorisation" >
       <resourceLink href="< url to your jar-file >" />
   </plugin-impl>