Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Spring Security on a JAX-RS bundle in Karaf

Tags:

I have an OSGi bundle that uses JAX-RS to handle some REST services. This bundle is running in Karaf with Apache CXF. I need to apply basic http authentication to certain path/method combinations. I've been tinkering with Spring Security and it appears that the new 3.1 version lets you do exactly this, however I've been having a lot of trouble getting it working in OSGi.

Just as a test, I've created a very simple beans.xml file:

<beans>
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-extension-http.xml"/>
    <import resource="classpath:META-INF/cxf/osgi/cxf-extension-osgi.xml"/>

    <jaxrs:server id="serverTest" address="/test">
        <jaxrs:serviceBeans>
            <ref bean="tstSvr"/>
        </jaxrs:serviceBeans>
    </jaxrs:server>

    <bean id="tstSvr" class="com.demo.Test"/>

    <security:http auto-config="true">
        <security:intercept-url pattern="/admin/**" access="ROLE_ADMIN" method="PUT" />
        <security:intercept-url pattern="/**" access="ROLE_USER" />
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <security:user name="user" password="pass" authorities="ROLE_USER"/>
                <security:user name="admin" password="pass" authorities="ROLE_ADMIN"/>
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

Now, here comes the fun part... From all of the reading that I've been doing, I need a web.xml for any of this to work. Such as this sample one that I tried to use:

<web-app>
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

Using the combination of those two files didn't work. And by "didn't work," I mean nothing happened. No error messages, no exceptions, the bundle functioned like before I tried adding spring security. I'm assuming that the problem is that the bundle needs to be a WAR or WAB for the web.xml to be loaded. Is this correct?

And more importantly, is there a way to get spring working without a web.xml?

I'm working on the assumption that I need to keep the bundle as a bundle for CXF to load it, so I can't convert it to a WAR or WAB, but I'm not totally certain that's the case.

Thanks for any help you can provide!

UPDATE: After doing a bunch of additional googling, I found a forum post that mentioned adding Web-FilterMappings: springSecurityFilterChain;url-patterns:="/*" to your manifest instead of using a web.xml. However, it still appears that you need to use a WAB instead of a normal bundle. I've added the line to my manifest in case, but it has no effect. It appears that my question is turning into: How do I use a WAB with CXF?

UPDATE 2: Because this question isn't long enough... I decided to try to use Spring Security annotations instead of intercept-url just to see what would happen. When I try to hit a secured path, I get this fun stack trace:

Caused by: org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.credentialsNotFound(AbstractSecurityInterceptor.java:323)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:196)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)[46:org.springframework.aop:3.0.5.RELEASE]

The spring website says that this happens the first time you try to anonymously connect to a secured service and it won't happen a second time. Well, it happens every time for me. From the exception, it looks like my entry in the manifest is being picked up and maybe the problem is different than I thought. Anyone have any thoughts on why this is happening? Am I missing some entry in the beans.xml to make basic http auth work?

like image 543
Jon7 Avatar asked Jul 13 '11 16:07

Jon7


1 Answers

First of all you need a clear understanding of what spring and web.xml do.

  • Web.xml is the standard file for configuring your servlet container, which usually is an application server like Jboss, Glassifsh, Jetty, Tomcat...
  • Your beans.xml is a configuration file for spring application context, seeing as you're not using any namespace for it, it means that Karaf uses spring oob.

If you want to do Http using servlets, without a container, I guess you'd have to register an HttpService, see : http://karaf.apache.org/manual/latest-2.2.x/users-guide/http.html

Your exception happens, because when it reaches the mapped method, there is no Authentication bean in the SecurityContext. You have not defined any anonymous access in your mappings, maybe that's why it fails.

Basically, either define an AnonymousAuthenticationFilter, or a URL pattern with permitAll in your http config. Otherwise you'll keep getting that exception, the first time you try to connect with the same session anonymously.

like image 119
Gepsens Avatar answered Sep 28 '22 04:09

Gepsens