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?