Introduction......................................................................................................................................... 2 Introduction to JAAS............................................................................................................................. 2 Security mechanisms in JBOSS .............................................................................................................. 3 LoginModule implementation in JBOSS................................................................................................... 4 Custom LoginModule implementations.................................................................................................... 4 Securing a Web application in JBOSS ................................................................................................... 5 Securing an EJB application in JBOSS .................................................................................................... 6 Some advanced topics ......................................................................................................................... 7 JAAS chaining ................................................................................................................................. 7 LDAPExtLoginModule........................................................................................................................ 7 Pluggable security manager for JBOSS ............................................................................................... 7 Standalone JBOSS clients ..................................................................................................................... 8 JAAS login on the client side ............................................................................................................. 8 Using JNDI .................................................................................................................................... 11 Some common pitfalls in JBOSS .......................................................................................................... 12 HTTPServletRequest.getUserPrincipal()............................................................................................... 12 JBOSS SimplePrincipal and SimpleGroup Vs Custom Principal and Group............................................ 12 JBOSS-provided SimplePrincipal and SimpleGroup Implementations .................................................... 12 Custom implementations ................................................................................................................. 12 JBOSS standalone client ..................................................................................................................... 12 Acknowledgements ............................................................................................................................ 13 About the author................................................................................................................................ 13 For more information.......................................................................................................................... 14 Call to action .................................................................................................................................... 14
Introduction
This paper introduces the Java Authentication and Authorization Service (JAAS). The paper also explains some of the options available to you as a developer to help you enable security on the JBOSS Application Server, version 4.0.2, and discusses how to choose between these options. It discusses various aspects of J2EE security, common pitfalls found during JBOSS implementations and mechanisms available for overcoming these pitfalls. Finally, this paper provides information on how to access secured applications from outside the JBOSS container using standalone clients.
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, lets consider a Web
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. The whole login process can be represented using a sequence diagram, as shown in Figure 1.
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. and authorization information into the Subject.
4. The LoginContext then calls the commit method. In this method, the LoginModule sets the principal 5. The LoginContext returns this authenticated information back to the client. 6. The client uses the Subject to access a protected resource.
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/<domain_name> An application can choose from one (and only one) of the configured security domains to protect itself from the client access.
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, its 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. Its 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.
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> <!-- A collection of protected resources along with the access mechanism --> <web-resource-collection> <web-resource-name>Restricted to Secure role</web-resource-name> <description>Declarative security</description> <url-pattern>/secure/*</url-pattern> <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> <!-- The list of roles that can access the resource. --> <auth-constraint> <role-name>Secure</role-name> </auth-constraint> </security-constraint>
Listing 1: jbossweb.xml settings for declarative security 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 <security-constraint> 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:
<?xml version="1.0" encoding="UTF-8"?> <jboss-web> <security-domain>java:/jaas/securedomain</security-domain> </jboss-web>
Listing 2: jboss-web.xml settings to enable security for a web application The file lists the securedomain as the security domain that will provide A&A to the web application.
<method-permission> <role-name>Secure</role-name> <method> <ejb-name>Fibo</ejb-name> <method-name>factorial</method-name> </method> </method-permission> <method-permission> <unchecked/> <method> <ejb-name>Fibo</ejb-name> <method-name>compute</method-name> </method> </method-permission>
Listing 3: ejb-jar.xml settings for declarative security In the above example, the method factorial in the EJB Fibo is available only to the client belonging to the Secure role. However, the method compute in the same bean is available to all the clients. During the application packaging, the administrator must choose the security domain used to protect the application. This is specified in the JBOSS specific deployment descriptor, jboss.xml. A sample jboss.xml is shown below:
<?xml version="1.0" encoding="UTF-8"?> <jboss> <security-domain>java:/jaas/securedomain</security-domain> </jboss>
LDAPExtLoginModule
As mentioned earlier, the LDAPLoginModule in JBOSS is not flexible. To overcome this, JBOSS has provided the LDAPExtLoginModule. This module is more flexible than the original and its use must be considered before writing a custom LoginModule. See http://wiki.jboss.org/wiki/Wiki.jsp?page=LdapExtLoginModule for more information on the LDAPExtLoginModule.
itself provides considerable flexibility. Therefore, the use of an alternative security manager must be given great consideration. If you decide to go ahead, a custom security manger can be programmed by implementing the following interfaces: org.jboss.security.AuthenticationManager: As the name suggests, this is responsible for providing the authentication (and getting the role information from the info store). Note: The isValid() method in the interface is used to perform the authentication. org.jboss.security.RealmMapping: This interface maps principals from the operation environment (info store) to the application domain. The interface also provides a method to check if the client has a specific role. Notes: o The getPrincipal(Principal): Principal method is used to perform the mapping and the doesUserHaveRole(Principal, Set) : boolean is used to determine if the client has a specific role. The out-of-the-box org.jboss.security.plugins.JaasSecurityManager implements both the AuthenticationManager and the RealmMapping interfaces. A custom security manager can be installed by creating a class that implements the AuthenticationManager and the RealmMapping interfaces. A custom JMX service needs to be created and started during the JBOSS server startup. The service should instantiate the custom written class and bind it to JNDI. The EJBs and Web tiers can now use the custom security manager by pointing the JNDI location in the <security-domain> tag.
o o
org.jboss.security.SecurityProxy: This interface provides methods that permit or disallow the access to an EJB method. Notes: o o o The invokeHome() and the invoke() methods provide hooks to check whether or not the EJB method should be allowed to execute. The out-of-the-box org.jboss.security.SubjectSecurityProxy provides the implementation of the interface. An alternate proxy can be installed on a per EJB basis in the jboss.xml using the <securityproxy> tag at the XPATH /jboss/enterprise-beans/session.
This module doesnt perform the actual A&A. It only stores the data to be passed along to the server during EJB invocation of create methods. The clients can now look up the EJB HOME interface in the Server JNDI tree. When the create method is called on this interface, the HOME interface implementation sends across the authentication information as well. The Security proxy on the Server side uses this authentication information to perform a JAAS login on the server side. Upon successful authentication and on the availability of sufficient roles with the client, the EJB invocation is allowed to pass through; otherwise, the security proxy on the server side throws a SecurityException which is transported back to the client and sent back to the caller of the create method. The sample code to execute a Client side Login is given below:
/** * Performs the JAAS client side login and returns the subject * @return * @throws LoginException */ public Subject login() throws LoginException { Subject ret = null; LoginContext lc = new LoginContext("other",new ClientCallBackHandler("username","password")); lc.login(); ret = lc.getSubject(); return ret; }
/** * A sample implementation of the CallbackHandler Interface that handles * username and password callbacks */ private class ClientCallBackHandler implements CallbackHandler { private String user,pass; /** * Constructor that takes username and password */ public ClientCallBackHandler(String user, String pass) { this.user = user; this.pass = pass; } /* (non-Javadoc) * @see javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[]) */ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { int len = callbacks.length; Callback cb; for(int i=0;i<len;i++) { cb = callbacks[i]; if(cb instanceof NameCallback) { NameCallback ncb = (NameCallback)cb; ncb.setName(user); } else if (cb instanceof PasswordCallback) { PasswordCallback pcb = (PasswordCallback)cb; pcb.setPassword(pass.toCharArray()); } else { throw new UnsupportedCallbackException(cb, "Dont know what to do with this!!"); } }//end of for-loop } }
Listing 7: The JAAS configuration used by standalone client Note: The path to the auth.conf file must be given as a JVM argument using the D option as Djava.security.auth.login.config=<full_path_to_file> Now that the client side pseudo login is complete, lets examine how to use the Subject to call the EJB method.
Subject sub = fc.login(); Subject.doAs(sub,fc.new SimpleAction());
10
* @see java.security.PrivilegedAction#run() */ public Object run() { try { InitialContext context = null; Hashtable ht = new Hashtable(); String value = null; FiboHome home; Fibo bean; ht.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory"); ht.put(Context.PROVIDER_URL,"localhost:1099"); context = new InitialContext(ht); //Now get the home interface Object ref = context.lookup("ejb/tutorial/Fibo"); home = (FiboHome) PortableRemoteObject.narrow(ref, FiboHome.class); //This create method results in the client side auth data being transported over to the jboss server where the actual login takes place. bean = home.create(); int fact = bean.factorial(5); System.out.println("The factorial of 5 is:" + fact); double[] fib = bean.compute(10); System.out.println("The first 10 fibonacci numbers are:"); for(int i=0;i<fib.length;i++) { System.out.print((int)fib[i] + ","); } }catch(Exception e) { e.printStackTrace(); } return null; } }
Listing 9: The privileged action that calls the EJB methods Note: You can find a link to the complete Client at the end of the document.
Using JNDI
It is possible to avoid the explicit client side JAAS pseudo login by using a special connection factory to connect to the JBOSS server JNDI. This factory is org.jboss.security.jndi.LoginInitialContextFactory. The exact configuration of the factory is available at http://wiki.jboss.org/wiki/Wiki.jsp?page=LoginInitialContextFactory (this class executes the client side login). Note: The auth.conf is still required and the path must still be specified using the D option to the JVM. A sample code for using this factory is specified below.
Properties env = new Properties(); // Try with a login that should succeed env.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.security.jndi.LoginInitialContextFactory"); env.setProperty(Context.PROVIDER_URL, "jnp://localhost:1099/"); env.setProperty(Context.SECURITY_CREDENTIALS, "iso*help"); env.setProperty(Context.SECURITY_PRINCIPAL, "akarkala"); env.setProperty(Context.SECURITY_PROTOCOL, "jwdomain"); InitialContext context = new InitialContext(env); Object ref = context.lookup("ejb/tutorial/Fibo"); FiboHome home; Fibo bean; home = (FiboHome) PortableRemoteObject.narrow(ref, FiboHome.class); bean = home.create(); int fact = bean.factorial(5);
11
System.out.println("The factorial of 5 is:" + fact); double[] fib = bean.compute(10); System.out.println("The first 10 fibonacci numbers are:"); for(int i=0;i<fib.length;i++) { System.out.print((int)fib[i] + ","); }
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). You can get a summary of the discussion I initiated on the JBOSS forums at the links below. EJB SecurityException even though roles are present (http://www.jboss.com/index.html?module=bb&op=viewtopic&t=67345) Different Role check mechanism for EJB and Web? (http://www.jboss.com/index.html?module=bb&op=viewtopic&t=67395)
12
Acknowledgements
I would like to acknowledge my manager Prabir Goswamee, who inspired me to write this paper. I would also like to thank Sudarshan Murty for his technical assistance.
13
http://managementsoftware.hp.com/ http://h20338.www2.hp.com/hpux11i/cache/3237520-0-225-121.html
Call to action
Enhance your ability to create managed applications by subscribing to the HP Software Partner News newsletter. White papers, program updates, marketing and technical tools and downloads, and technical tips are delivered monthly. Visit http://devresource.hp.com/drc/newsletters/subscriptions.jsp to subscribe.
All brand and product names are trademarks or registered trademarks of their respective companies.
2006 Hewlett-Packard Development Company, L.P. The information contained herein is subject to change without notice. The only warranties for HP products and services are set forth in the express warranty statements accompanying such products and services. Nothing herein should be construed as constituting an additional warranty. HP shall not be liable for technical or editorial errors or omissions contained herein.