Posts Tagged Apache Karaf

Authentication and authorization of a web application in Apache ServiceMix using JAAS

Why Apache ServiceMix?

First I had to answer myself why to deploy a web application on the Apache ServiceMix? Simply – because we had it in place. We use it as a runtime container for web services  (many popular ESB’s are based on the ServiceMix, such as Fuse ESB, Talend ESB, ..). I find the Apache ServiceMix very lightweight, having small footprint even under workload. So when creating a web application accessing exposed services (Web Services or OSGi based), it makes sense to deploy the web app directly in the ServiceMix instead of spinning up an extra web server just for one or two simple apps.

There’s a great resource by David Valeri about deploying a spring-mvc web application in the OSGi environment (and much more..).  http://davidvaleri.wordpress.com/2011/08/17/deploying-spring-mvc-based-web-applications-to-osgi-using-apache-servicemix/

In this exercise Talend ESB 5.2.0 based on Apache Karaf 2.2.9 is used. And lot of web searching and trying.

Configuring the authentication and authorization

Once I had my web app running, from the J2EE world I am used to set up the role based security using built in JAAS. It proved to be not so straightforward with the default Apache ServiceMix setup. The ServiceMix already uses JAAS realm 'karaf' by default users and groups defined in the ./etc/user.properties file. for start I am happy with that. There are ways to set up JDBC or LDAP based realms, but it is not the goal and all I wanted is at least a simple basic role based security around my web app without weight of the whole spring-security configuration.

1. enable jetty.xml configuration in the etc/org.ops4j.pax.url.mvn.cfg

org.ops4j.pax.web.config.file=./etc/jetty.xml

2. define users and groups

in the ./etc/user.properties file I defined a user with its role user (e.g. webuser=<password>,user)

3. define spring configuration for the web app in the META-INF/spring/jetty-security.xml This configuration duplicates the web.xml security constraint definition, but it was the only way I found working. This configuration works with Jetty 7.6 shipped within Talend ESB. Note that other Jetty versions may a little bit other packaging of the classes.

<?xml version="1.0" encoding="UTF-8"?>
<beans    xmlns="http://www.springframework.org/schema/beans"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="loginService" class="org.eclipse.jetty.plus.jaas.JAASLoginService">       
    <property name="name" value="karaf" />
    <property name="loginModuleName" value="karaf" />    
 </bean>    
 <bean id="constraint" class="org.eclipse.jetty.util.security.Constraint">        
   <property name="name" value="BASIC"/>       
   <property name="roles" value="user"/>        
   <property name="authenticate" value="true"/>   
</bean>    
<bean id="constraintMapping" class="org.eclipse.jetty.security.ConstraintMapping">        
  <property name="constraint" ref="constraint"/>        
  <property name="pathSpec" value="/*"/>    
</bean>
 <bean id="securityHandler" class="org.eclipse.jetty.security.ConstraintSecurityHandler">       
   <property name="authenticator">          
     <bean class="org.eclipse.jetty.security.authentication.BasicAuthenticator"/>     
   </property>        
   <property name="constraintMappings">          
    <list>           
     <ref bean="constraintMapping"/>     
   </list>   
   </property>        
  <property name="loginService" ref="loginService" />      
  <property name="strict" value="false" />   
 </bean>
</beans>

3. I set up a default web.xml configuration

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>example_application</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
    <security-constraint>
        <display-name>authenticated</display-name>
        <web-resource-collection>
            <web-resource-name>All files</web-resource-name>
            <description/>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>user</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>karaf</realm-name>
    </login-config>
    <security-role>
        <description/>
        <role-name>user</role-name>
    </security-role>
</web-app>

4. update pom.xml to import the configured packages

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <archive>
                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
                    </archive>
                </configuration>
            </plugin>
            <!--
                Enable support for non-bundle packaging types
                See: http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html
            -->
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>2.3.7</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                    </execution>
                    <execution>
                        <id>bundle-manifest</id>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>manifest</goal>
                        </goals>
                        <configuration>
                            <instructions>
                                <Bundle-SymbolicName>gmap1</Bundle-SymbolicName>
                                <Export-Package/>
                                <Import-Package>
                                    javax.servlet,
                                    javax.servlet.http,
                                    javax.servlet.*,javax.servlet.jsp.*,
                                    javax.servlet.jsp.jstl.*,
                                    javax.security.auth,
                                    javax.security.auth.callback,
                                    javax.security.auth.login,
                                    javax.security.auth.spi,
                                    org.apache.karaf.jaas.modules,
                                    org.eclipse.jetty.plus.jaas,
                                    org.eclipse.jetty.security,
                                    org.eclipse.jetty.util.security,
                                    org.eclipse.jetty.security.authentication,
                                    *
                                </Import-Package>
                                <DynamicImport-Package>javax.*, org.xml.sax, org.xml.sax.*, org.w3c.*</DynamicImport-Package>
                                <Bundle-ClassPath>.,WEB-INF/classes</Bundle-ClassPath>
                                WEB-INF/lib</Embed-Directory>
                                *;scope=compile|runtime</Embed-Dependency>
                                true</Embed-Transitive>
                                <Web-ContextPath>/gmap1</Web-ContextPath>
                                <Webapp-Context>/gmap1</Webapp-Context>
                            </instructions>
                        </configuration>
                    </execution>
                </executions>
                <configuration>
                    <supportedProjectTypes>
                        <supportedProjectType>jar</supportedProjectType>
                        <supportedProjectType>bundle</supportedProjectType>
                        <supportedProjectType>war</supportedProjectType>
                    </supportedProjectTypes>
                    <instructions>
                    </instructions>
                </configuration>
            </plugin>     
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-security</artifactId>
            <version>7.5.3.v20111011</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

5. this is an optional step. Well.. depends. Seems Jetty shipped with the ServiceMix has a bug manifesting on the Windows OS not releasing resources when using NIO transport, so having a look into the ./etc/jetty.xml file you can find there are blocking channels used by default (org.eclipse.jetty.server.nio.BlockingChannelConnector).

I believe on the *NIX environment we can happily set up the NIO transport channel instead of the blocking connectors.

<Call name="addConnector">
        <Arg>
            <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
                <Set name="host">
                    <SystemProperty name="jetty.host" />
                </Set>
                <Set name="port">
                    <SystemProperty name="jetty.port" default="8040"/>
                </Set>
                <Set name="maxIdleTime">30000</Set>
                <Set name="Acceptors">2</Set>
                <Set name="statsOn">false</Set>
                <Set name="confidentialPort">8443</Set>
                <Set name="lowResourcesConnections">5000</Set>
                <Set name="lowResourcesMaxIdleTime">5000</Set>
                <Set name="requestHeaderSize">8192</Set>
                <Set name="responseHeaderSize">8192</Set>
                <Set name="useDirectBuffers">false</Set>
            </New>
        </Arg>
    </Call

6. deploy the web app. I’m shipping the bundles as features or KAR archive. But to simply test I use direct mvn deploy from the command line

features:install war
install -s war:mvn:<group-id>/<artifact-id>/<version>/war

, ,

1 Comment