Playing with Jaas and Apache.

If you havent read my blog post “Playing with JAAS” i wouldd suggest you read that before reading this one. Here is a quick primer on configuring Jaas with apache.

  • In this case our jaas.config will have just one LoginContext called ApacheExample
    ApacheExample {
    	com.module.DummyLoginModule required username="user" password="pass" role="admin";
    };
  • As part of the login process, JAASRealm registers its own CallbackHandler, called (unsurprisingly) JAASCallbackHandler. This handler supplies the HTTP requests’s username and credentials to the user-supplied LoginModule. At present, JAASCallbackHandler knows how to handle callbacks of type NameCallback and PasswordCallback.
     
    Here is the login method of our DummyLoginModule. As soon as the user would click on ‘Login’ button on the UI, the login method of this DummyLoginModule is called. Within the login method we call the callbackhandler’s handle method (callbackHandler.handle(…)) which would expect JAASCallbackHandler to populate NameCallback and PasswordCallback objects.

    On success we create the HelloWorldUser and HelloWorldRole which we will use later. Both implement Principal.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
    public boolean login() throws LoginException {
     
    	if ( callbackHandler == null ) {
    		throw new LoginException("no handler");
    	}
     
    	// Callback is just like a VO object, that the handler will populate!
    	NameCallback nameCallback=new NameCallback("username");
    	PasswordCallback passwordCallback=new PasswordCallback("password", false);
    	Callback[] callbacks = new Callback[] { nameCallback, passwordCallback };
     
    	try {
    		callbackHandler.handle(callbacks);		
    	} catch (IOException e) {			
    		throw new LoginException("handler io error");
    	} catch (UnsupportedCallbackException e) {		
    		throw new LoginException("unsupported callback error");
    	}
     
    	String username = nameCallback.getName();
    	String password = new String(passwordCallback.getPassword());
     
    	if ( options.get("username").equals(username) && options.get("password").equals(password) ) {			
    		// add these if commit was called!
    		myUser=new HelloWorldUser(username);
    		myRole=new HelloWorldRole(String.valueOf(options.get("role")));			
    		success = true;				
    	} else {			
    		throw new LoginException("incorrect username/password");
    	}
     
    	return true;
    }
  • You can download the whole JAAS implementation from here [Source] or the [binary which is jar+jaas.config]. Place the jar and jaas.config into your lib folder.
  • Apache uses realms to authenticate users. By default its set to UserDatabaseRealm which authenticates users from the conf/tomcat-users.xml. We need to switch that to JAASRealm in the conf/server.xml. Locate Realm element with class=org.apache.catalina.realm.UserDatabaseRealm, comment it out and add the following realm code.
    1
    2
    3
    4
    
    <Realm className="org.apache.catalina.realm.JAASRealm"
                    appName="ApacheExample"
    					userClassNames="com.principal.HelloWorldUser"
    						roleClassNames="com.principal.HelloWorldRole"/>
  • You need to make changes in your webapps web.xml to specify “login-config” and “security-constraint” elements (which are out of scope of this article). Here is a good article explaining Tomcat Security Overview and Analysis. Here is a sample web.xml for our helloworld webapp. You can download the sample helloworld apache jaas webapp from here. Notice how we have added the “role-name” element with value “admin” under the “auth-constraint” element. This means that the subject who was authenticated has to have a admin role. We are taking care of that in our jaas implementation by adding HelloWorldRole as one of our Principals in our Subject.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.or<a href='http://www.softwareeverydayblog.com/wp-content/uploads/2012/11/helloworld.zip'>Apache+Jaas helloworld app</a>g/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
        version="2.5">
        <description>Hello World</description>
        <display-name>Hello World</display-name>
     
    	<context-param>
    		<param-name>Name</param-name>
    		<param-value>Hello World</param-value>
    	</context-param>
     
    	<security-constraint>
    		<web-resource-collection>
    			<web-resource-name>Wildcard means whole app requires authentication</web-resource-name>
    			<url-pattern>/*</url-pattern>
    			<http-method>GET</http-method>
    			<http-method>POST</http-method>
    		</web-resource-collection>
     
    		<auth-constraint>
    			<role-name>admin</role-name>
    		</auth-constraint>
     
    		<user-data-constraint>
    			<!-- transport-guarantee can be CONFIDENTIAL, INTEGRAL, or NONE -->
    			<transport-guarantee>NONE</transport-guarantee>
    		</user-data-constraint>
    	</security-constraint>
     
    	<login-config>
    		<auth-method>FORM</auth-method>
    		<form-login-config>
    		<form-login-page>/login.jsp</form-login-page>
    		<form-error-page>/fail_login.html</form-error-page>
    		</form-login-config>
    	</login-config>
     
    </web-app>