Integrating Apache Beehive authentication with JBoss security

Each Beehive page flow controller implementation inherits from org.apache.beehive.netui.pageflow.FlowController two methods related to authentication:

void login(String username, String password)
void logout(boolean invalidateSessions)

You typically call these methods in actions resulting from a login form or logout link/button. They use a servlet container adapter interface (org.apache.beehive.netui.pageflow.ServletContainerAdapter) which is a glue between the generic authentication mechanism and an underlying application server. Beehive distribution comes with a org.apache.beehive.netui.pageflow.DefaultServletContainerAdapter implementation whose login() and logout() methods throw UnsupportedOperationException. You have to write your own ServletContainerAdapter implementation for the application server you are using.

If you want to connect Beehive security with a JBoss security domain, you need JBoss at least in 4.2.0.GA version. Starting from this release JBoss ships with a WebAuthentication class. The class allows a programmatic web login.

First what you need to do is to configure a JBoss security. You can do it in 3 easy steps:

1. Create user and role files in $JBOSS_HOME/server/default/conf/props.

test-users.properties:

jboss=jboss

test-roles.properties:

test=jboss

2. Define a simple security domain; create a test-login-config-service.xml file in $JBOSS_HOME/server/default/deploy. Doing it in this way you don’t have to modify any JBoss configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE server>
<server>
  <mbean code="org.jboss.security.auth.login.DynamicLoginConfig"
    name="jboss.security:service=TestDynamicLoginConfig">
    <attribute name="PolicyConfig" serialDataType="jbxb">
      <jaas:policy
        xsi:schemaLocation="urn:jboss:security-config:4.1 resource:security-config_4_1.xsd"
        xmlns:jaas="urn:jboss:security-config:4.1"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <jaas:application-policy name="test-realm">
          <jaas:authentication>
            <jaas:login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
              <jaas:module-option name="usersProperties">../conf/props/test-users.properties</jaas:module-option>
              <jaas:module-option name="rolesProperties">../conf/props/test-roles.properties</jaas:module-option>
            </jaas:login-module>
          </jaas:authentication>
        </jaas:application-policy>
      </jaas:policy>
    </attribute>
    <depends optional-attribute-name="LoginConfigService">
      jboss.security:service=XMLLoginConfig
    </depends>
    <depends optional-attribute-name="SecurityManagerService">
      jboss.security:service=JaasSecurityManager
    </depends>
 </mbean>
</server>

3. In your web application create a jboss-web.xml file in WEB-INF directory:

<jboss-web>
  <security-domain>java:/jaas/test-realm</security-domain>
</jboss-web>

That’s all, now you should have a BASIC HTTP authentication working. If you want to test it, add following lines to web.xml, restart the application and check if a login window pop up in the browser.

<security-constraint>
    <web-resource-collection>
        <web-resource-name>all</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>test</role-name>
    </auth-constraint>
</security-constraint>

<security-role>
    <role-name>test</role-name>
</security-role>

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>test-realm</realm-name>
</login-config>

Let’s follow then the Beehive manual chapter Writing a Servlet Container Adapter and go through steps required to implement an adapter for JBoss server:

1. Beehive manual:

Write a class that implements org.apache.beehive.netui.pageflow.ServletContainerAdapter. You can extend org.apache.beehive.netui.pageflow.DefaultServletContainerAdapter

Here is the class definition:

package net.mgr.jboss;

import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.beehive.netui.pageflow.DefaultServletContainerAdapter;
import org.apache.beehive.netui.pageflow.adapter.AdapterContext;
import org.jboss.web.tomcat.security.login.WebAuthentication;

public class JBossServletContainerAdapter extends DefaultServletContainerAdapter {

    /**
     * This method must always return true, so Beehive will use this adapter.
     */
    public boolean accept(AdapterContext aContext) {
        return true;
    }

    /**
     * @see org.apache.beehive.netui.pageflow.DefaultServletContainerAdapter#login(java.lang.String,
     *      java.lang.String, javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse)
     */
    @Override
    public void login(String username, String password, HttpServletRequest request,
        HttpServletResponse response) throws LoginException {

        WebAuthentication webAuth = new WebAuthentication();
        boolean loginOk = webAuth.login(username, password);
        if (!loginOk ) {
            throw new LoginException("Login failed");
        }

        System.out.println("Login ok, user principal: " + request.getUserPrincipal());
    }

    /**
     * invalidateSessions is used to invalidate a session on all sigle sign-on applications;
     * in this adapter is ignored - there is no possibility to achieve this with WebAuthentication.
     *
     * @see org.apache.beehive.netui.pageflow.DefaultServletContainerAdapter#logout(boolean,
     *      javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    public void logout(boolean invalidateSessions, HttpServletRequest request,
        HttpServletResponse response) {

        WebAuthentication webAuth = new WebAuthentication();
        webAuth .logout();

        System.out.println("Logout ok, user principal: " + request.getUserPrincipal());
    }
}

2. Beehive manual:

Package the class in a JAR file which also contains a text file in directory META-INF/services called org.apache.beehive.netui.pageflow.ServletContainerAdapter. The text file should have a single line that is the full class name of your ServletContainerAdapter

Here is the file contents:

net.mgr.JBossServletContainerAdapter

3. Beehive manual:

Drop the JAR into the WEB-INF/lib directory of your web application. The NetUI runtime will automatically pick up the first “discovered” adapter that answers true when its accept method is called.

accept method of our servlet container adapter returns true, so it will be used by Beehive.

The final step is to create a fake security constraint in web.xml. There is a bug in JBoss that prevents persisting the security principal between two requests without any security constraint defined. Just add to web.xml:

<security-constraint>
    <web-resource-colection>
        <web-resource-name>fake</web-resource-name>
        <url-pattern>/fake/*</url-pattern>
    </web-resource-collection>
</security-constraint>

Links:

Advertisements