Avoid duplicate <http> element exception with Spring Security and JRebel

I was using classpath*: resource for Spring application context loading. All context definition files are in the
/WEB-INF/classes/appCtx directory and its subdirectories.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:appCtx/**/*.xml</param-value>
</context-param>

However, when I enabled Spring Security in my web application, I got the exception:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Duplicate <http> element detected|Offending resource: ServletContext resource [/WEB-INF/classes/appCtx/applicationContext-security.xml]

The solution is pretty simple – move the security context configuration (e.g. applicationContext-security.xml) to a different directory outside appCtx and load it directly:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath*:appCtx/**/*.xml
        /WEB-INF/applicationContext-security.xml
    </param-value>
</context-param>
Advertisements

Configure TopLink Essentials logging

By default Oracle TopLink uses a TopLink native logger DefaultLogger (oracle.toplink.essentials.logging.DefaultSessionLog). This logger doesn’t offer log level and category settings.

If you try to set a log level, e.g. to get rid of debug output of SQL statement, this setting in persistence.xml won’t have any effect:

&lt;property name=&quot;toplink.logging.level.sql&quot; value=&quot;WARNING&quot;/&gt;

You have to configure explicitly Java logging in persistence.xml:

&lt;property name=&quot;toplink.logging.logger&quot; value=&quot;JavaLogger&quot;/&gt;
&lt;property name=&quot;toplink.logging.level.sql&quot; value=&quot;WARNING&quot;/&gt;

If you are using Spring, you may want to redirect the output to Apache Commons Logging. Spring provides a class org.springframework.orm.toplink.support.CommonsLoggingSessionLog. However, this class works with TopLink full version. To bring it to work with TopLink Essentials, grab the CommonsLoggingSessionLog source and change all imports starting with oracle.toplink to oracle.toplink.essentials.

Finally, register your new SessionLog implementation in persistence.xml:

&lt;property name=&quot;toplink.logging.logger&quot; value=&quot;foo.MyTopLinkEssentialsCommonsLoggingSessionLog&quot;/&gt;

For more information on settings, refer to TopLink Essentials documentation on logging.

Apache CXF JBoss 4.2 deployment – tips and tricks

If you are not able to deploy an application using Apache CXF library in JBoss, you might want to check first Application Server Specific Configuration Guide chapter of CXF user’s guide.

Furthermore, check if the JBossWS framework is already deployed (jbossws.sar directory in the JBoss deployment directory) and try to remove it. It contains already a lot of APIs and implementations that can confict with APIs and implementations provided with CXF.

Concrete example – I was using CXF 2.0 series which implements JAX-WS 2.0 standard. JBossWS 2.0 framework, shipped with JBoss 4.2, implements JAX-WS 2.1 specification. In some situations when a dateTime was parsed I was getting NullPointerException with a message about marshalling error. Removing the jbossws.sar helped.

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.

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

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

&lt;jboss-web&gt;
  &lt;security-domain&gt;java:/jaas/test-realm&lt;/security-domain&gt;
&lt;/jboss-web&gt;

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.

&lt;security-constraint&gt;
    &lt;web-resource-collection&gt;
        &lt;web-resource-name&gt;all&lt;/web-resource-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
    &lt;/web-resource-collection&gt;
    &lt;auth-constraint&gt;
        &lt;role-name&gt;test&lt;/role-name&gt;
    &lt;/auth-constraint&gt;
&lt;/security-constraint&gt;

&lt;security-role&gt;
    &lt;role-name&gt;test&lt;/role-name&gt;
&lt;/security-role&gt;

&lt;login-config&gt;
    &lt;auth-method&gt;BASIC&lt;/auth-method&gt;
    &lt;realm-name&gt;test-realm&lt;/realm-name&gt;
&lt;/login-config&gt;

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(&quot;Login failed&quot;);
        }

        System.out.println(&quot;Login ok, user principal: &quot; + 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(&quot;Logout ok, user principal: &quot; + 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:

&lt;security-constraint&gt;
    &lt;web-resource-colection&gt;
        &lt;web-resource-name&gt;fake&lt;/web-resource-name&gt;
        &lt;url-pattern&gt;/fake/*&lt;/url-pattern&gt;
    &lt;/web-resource-collection&gt;
&lt;/security-constraint&gt;

Links: