Sunday, January 27, 2013

Using Spring Security in OSGi without WAB

This is actually inspired by another post that use Apache CXF in OSGi (but I couldn't find the link now).

Apache CXF D-OSGi, you can add a propety to the OSGi service so that it will use the filter (ServletFilter)

    <osgi:service ref="searchRS" interface="...search.webservice.SearchWS">       
        <osgi:service-properties>
            <entry key="service.exported.interfaces" value="*" />
            <entry key="service.exported.configs" value="org.apache.cxf.rs" />
            <entry key="org.apache.cxf.rs.httpservice.context" value="/search" />
            <entry key="org.apache.cxf.httpservice.requirefilter" value="true" />
               <entry key="org.apache.cxf.rs.provider">
                   <array>
                       <ref bean="jsonProvider" />
                   </array>
               </entry>
        </osgi:service-properties>
    </osgi:service>

and

    <osgi:service ref="customFilterChain" interface="javax.servlet.Filter">
        <osgi:service-properties>
            <entry key="org.apache.cxf.httpservice.filter" value="true" />
            <entry key="servletNames" value="none" />
        </osgi:service-properties>
    </osgi:service>

With this, the customFilterChain will be used everytime when /search has been accessed.

To setup the filter chain,

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:osgi="http://www.eclipse.org/gemini/blueprint/schema/blueprint"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/security           
                        http://www.springframework.org/schema/security/spring-security.xsd
                        http://www.eclipse.org/gemini/blueprint/schema/blueprint
                        http://www.eclipse.org/gemini/blueprint/schema/blueprint/gemini-blueprint.xsd">

    <bean id="customSecurityFilter" class="...security.filter.CustomSecurityFilter"/>

    <bean id="requestContextFilter" class="org.springframework.web.filter.RequestContextFilter"/>
    <!-- disable url rewrite, change session key -->
    <bean id="httpSessionSecurityContextRepository" class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
   
    <bean id="springSecurityFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter" >
        <constructor-arg ref="httpSessionSecurityContextRepository" />
        <property name="forceEagerSessionCreation" value="false" />
    </bean>
   
    <bean id="basicAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter" >
        <constructor-arg ref="customAuthenticationManager" />
    </bean>
   
    <bean id="http403ForbiddenEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
    <bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <constructor-arg ref="http403ForbiddenEntryPoint" /> <!-- can redirect to https here -->
    </bean>
   
    <bean id="sessionManagementFilter" class="org.springframework.security.web.session.SessionManagementFilter">
        <constructor-arg ref="httpSessionSecurityContextRepository"/>
        <constructor-arg ref="sessionFixationProtectionStrategy" />
    </bean>
   
    <bean id="sessionFixationProtectionStrategy" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
        <property name="migrateSessionAttributes" value="true"/>
    </bean>

    <bean id="customFilterChain" class="org.springframework.security.web.FilterChainProxy">
        <security:filter-chain-map request-matcher="ant">
            <security:filter-chain pattern="/osgi/auth/**" filters="springSecurityFilter,requestContextFilter,basicAuthenticationFilter,sessionManagementFilter,exceptionTranslationFilter"/>
            <security:filter-chain pattern="/**" filters="springSecurityFilter,requestContextFilter,customSecurityFilter,exceptionTranslationFilter"/>
        </security:filter-chain-map>
    </bean>
   
</beans>

note that we have our own AuthenticationProvider and only /auth will perform Basic Authentication Filter.

After we've migrated to Resteasy, we're still keeping the filter chain, and instead of registering to OSGi and let Apache CXF handles it, we registered to the WebContainer directly (see my other post about Resteasy & Pax Web).