Friday, March 26, 2010

Java Authentication and Authorization Service (JAAS)

Introduction
Java™ Authentication and Authorization Service (JAAS). Im trying to explain some of the options available to help you enable security on the JBOSS Application Server, version 4.x, and how to choose between these options. Here i will discusses various aspects of J2EE security, common pitfalls found during implementing JAAS in one of my earlier tasks, and mechanisms I followed for overcoming these pitfalls.

Introduction to JAAS
JAAS delivers a framework for providing authentication and authorization for all the Java applications. Authentication is a mechanism to verify the client; authorization is a mechanism to ensure that the client has the permissions required to access a secured resource.
At a high level, the steps to enable JAAS-based security are as follows:

1. Identify the resource that needs to be secured. For the purpose of this paper, let’s consider a Web application and an Enterprise Java Bean (EJB) application.

2. Identify a suitable security provider. The security manager that comes with JAVA 2 provides the security. In the case of JBOSS, the security is provided by the JBOSS security manager.

3. Use a security implementation to secure the identified resources.

4. Make the clients of the secured resources aware of the security implementation and usage mechanisms. This is important as it is expected that the client will provide some sort of identifier before allowing access to secured resources. The identifiers in most cases are either username/password combinations or digital certificates. The clients must be aware of the required identifier before accessing the resource and should provide it when required.

The JAAS classes that enable the above are:

• LoginModule: This is the security implementation that authenticates and authorizes the clients. A typical implementation involves validating the username/password combination.

• LoginContext: Using this LoginContext, the client will be able to perform a login.

• CallbackHandler and Callback: These are the classes that allow interaction/data-transfer between the clients and the LoginModule. The LoginModule uses a Callback class to request information from the clients. The CallbackHandler class on the client side provides the required information based on the type of Callback class.

• Principal and Group: The LoginModule populates identification information (for example, Name, Address, etc.) about the client into the Principal class and authorization information (role list) into the Group class.

• Subject: This is the result of a successful login. This contains the authenticated Principal and Group. A Subject can also be viewed as a secure representation of the client after authentication.
1. The client initiates the login using the LoginContext. The inputs to the LoginContext are the    CallbackHandler and the type of login configuration to use. The LoginContext internally instantiates the LoginModule and calls the initialization method.
2. The client then calls login() on the context. This results in the LoginContext calling the login() method of the LoginModule. The LoginModule would need some client verification information. This will be obtained using Callbacks. The CallbackHandler handles these Callbacks and provides the requested information. Note: The CallbackHandler is a client implementation that handles specific Callbacks. The handler must know the exact Callbacks (or have a list of all potential Callbacks) that the LoginModule uses so that it can provide the required information to the LoginModule.

3. The LoginModule verifies this information. If the information is invalid, then a LoginException is thrown. If the information is correct, authorization information for the client is obtained.

4. The LoginContext then calls the commit method. In this method, the LoginModule sets the principal and authorization information into the Subject.

5. The LoginContext returns this authenticated information back to the client.

6.The client uses the Subject to access a protected resource.

Security mechanisms in JBOSS
The JBOSS application server provides pluggable security managers. The Web and the EJB Containers use the security managers to perform authentication and authorization. The JAAS-based security manager is the default security manager provided with JBOSS. Though it is easy to replace the security manager with a custom implementation, this is not recommended.
Note: The JAAS security manager obtains the required configuration information from the login-config.xml file located in the conf folder.
The XML file provides a list of security domains that are available on the server. Each domain specifies a list of LoginModules that protect the domain. The list of LoginModules can be specified as “required” or “optional”. To gain access to the resources protected by a domain, the client must be able to satisfy all the LoginModules that are configured as required. If any of the required LoginModules are not satisfied, the client will not be able to access the resource.
Any options to the LoginModule can be specified in a configuration file. These will be passed to the module during the call to initialize().
Note: Each security domain will be read by the JAAS security manager, converted into a SecurityDomainContext object, and bound in JNDI at java:/jass/
An application can choose from one (and only one) of the configured security domains to protect itself from the client access.

LoginModule implementation in JBOSS
The JAAS security manager doesn't perform the authentication. Instead, it instantiates the LoginModules that performs the actual authentication and authorization.
JBOSS provides LoginModules out of the box. Some of these LoginModules are:

• UserRolesLoginModule: This module reads the username, password and role information from files that are packaged with the applications.

• DatabaseServerLoginModule: This module reads the username, password and role information from the tables in a database. The database is accessed using JDBC and the JDBC driver needs to be available in the application classpath.

• LDAPLoginModule: This module requires the username and password. This is used to connect to LDAP as a means of verification. If successful, the roles are based on the group memberships of the user. This module is not very configurable as it doesn’t expose enough configuration options to work with all LDAPs.

• BaseCertLoginModule: This module uses client certificates to perform authentication. It cannot provide role information. This is typically used in conjunction with one of the other LoginModules to obtain the role memberships.

Custom LoginModule implementations
If the available login modules in JBOSS are insufficient, we can provide a custom implementation of the login module. In most enterprise applications, the user and the role information is stored in LDAP. As the LDAPLoginModule that comes with JBOSS not extensible enough to search for the group memberships, we must provide a custom implementation of the LoginModule interface.
We have a couple of options for doing so:

• Extend the abstract UsernamePasswordLoginModule: JBOSS provides an abstract UsernamePasswordLoginModule that is the super class for all Authentication and Authorization (A&A) based on the username and password. This can be extended to perform the required authentication against LDAP and to search for group memberships.

• Write an independent LoginModule: We could use this option if we don’t want the LoginModule to use JBOSS specific classes and to remain totally portable.

Let’s look at the latter option with a sample.
A custom implementation of the LoginModule interface involves implementation of the following methods:
• initialize (Subject, CallbackHandler, Map, Map): This is called by the security manager after the object instantiation. The purpose of this method is for the LoginModule to initialize itself based on the configuration options. The example of these configuration options could either be (in case of LDAP) the LDAP server address that holds the user or the LDAP context where the roles can be searched. These options are specific to the LoginModule implementation and this determines its behavior. The Subject is used to store the Principal and role information after a successful login() and commit().

• login(): This is the core method. This method is supposed to perform the authentication and get the authorization (role) information from the information store. However, it’s important to note that this method should not store the authentication and the role information in the Subject. This information must be stored in the Subject only in the commit method.

• commit(): This method is called only if all the required LoginModules in the security domain successfully execute the login() method. This method should store the A&A information in the Subject.

• logout(): This method is called when the client does a logout. Here, the implementation should delete the A&A information from the stored Subject.

• abort(): This method is called when the client aborts during a login. This method is used to free up any resources that are held by the implementation.

In the case of the LoginModule implementations (JBOSS supplied or custom), the A&A information is stored in the Subject. The information is stored using implementations of the two interfaces. One interface is used for the user data and the other for specifying the role information.

• Interface java.security.Principal: A principal represents the information related to an authenticated client.

• Interface java.security.acl.Group: Implementation used to hold a collection of Principals under a common name. The interface provides methods to add and remove Principals and to query if a Principal is part of the group.

Notes:

• java.security.acl.Group extends java.security.Principal. So in reality, all the information is stored in the form of a Principal.
Any information about an authenticated client is stored using a Principal. Typically, this includes name, address, phone number, email etc.

• It’s important to note that the role memberships are also Principals. In these cases, every role that the client belongs to is a Principal and all these Principals are collected into a group with a common name.

In the case of JBOSS, for the JAAS security manager to be able to identify the principals that identify the role memberships, the principals need to be consolidated into a Group named “Roles.”

Securing a Web application in JBOSS
Let’s examine what it takes to secure a J2EE web application in JBOSS. In this section, we will examine only the declarative security mechanisms; we won’t cover programmatic security.
Declarative security for a web application involves providing select access to web resources based on certain roles that the client is assigned.
Note: In J2EE web applications, a web resource is secured based on the URL pattern and the HTTP method (GET, POST etc) used to access the resource.
In the web.xml file, collections of resources that can be accessed by certain roles must be defined along with the list of roles that can access the resources. An example of web.xml settings for declarative security is shown below:
<security-constraint>
<web-resource-collection>
<http-method>HEAD</http-method> 
<http-method>GET</http-method> 
<http-method>POST</http-method> 
<http-method>PUT</http-method> 
<http-method>DELETE</http-method> 
</web-resource-collection> 
<auth-constraint> 
<role-name>Secure</role-name> 
</auth-constraint> 
</security-constraint> 
In the above example, all the resources with the URL pattern /secure/* are protected, and the client must belong to the “Secure” role to access these resources.
Note: Any number of tags may be defined in web.xml.

During application packaging, the administrator must choose the security domain that will protect the application. This is specified in the JBOSS specific deployment descriptor, jboss-web.xml. A sample jboss-web.xml is shown below:
<jboss-web> 
<security-domain>java:/jaas/securedomain tag. 
• org.jboss.security.SecurityProxy: This interface provides methods that permit or disallow the access to an EJB method.
Notes:

o The invokeHome() and the invoke() methods provide hooks to check whether or not the EJB method should be allowed to execute.

o The out-of-the-box org.jboss.security.SubjectSecurityProxy provides the implementation of the interface.

o An alternate proxy can be installed on a per EJB basis in the jboss.xml using the tag at the XPATH /jboss/enterprise-beans/session.

Some common pitfalls in JBOSS
HTTPServletRequest.getUserPrincipal()
The “getUserPrincipal()” method defined in the HTTPServletRequest interface is used by the web clients to access the Principal called the resource. In the case of custom implementations of the LoginModule interface, it is likely that this method will return a null to JBOSS. To prevent this and to ensure that the correct Principal is available, a Group must be created with the name “CallerPrincipal” in the LoginModule. This group must be added to the Subject within the commit() method. As there can be any number of principals in an authenticated Subject, this indicates to the JBOSS to pick this as the principal to return when the “getUserPrincipal()” method is called.
JBOSS SimplePrincipal and SimpleGroup Vs Custom Principal and Group
As described above, JAAS requires that we use the Principal and Group interfaces to store the authentication and the authorization data. The two options given below discuss this.
JBOSS-provided SimplePrincipal and SimpleGroup implementations
JBOSS provides implementations of the Principal and Group interfaces. However, the use of these implementations binds us to JBOSS, which results in the LoginModule not being portable. Using these implementations is recommended only if a JBOSS provided LoginModule is being extended.
Custom implementations
This is recommended if a completely new LoginModule is written. However, when used with JBOSS, the following must be noted.While implementing the isMember(Principal) : boolean method of the Group interface, comparison must be made based on the String contained within the Principal rather than by directly checking for the Principal. The reason for this is that the Principals within the group might have a different implementation class compared to the implementation class of the method parameter. Therefore, although the Principals contain the same String within them, the result might be false (with a direct comparison).