在 Karaf 中的 JAX-RS 包上使用 Spring Security
我有一个 OSGi 包,它使用 JAX-RS 来处理一些 REST 服务。该捆绑包在 Karaf 中与 Apache CXF 一起运行。我需要将基本的 http 身份验证应用于某些路径/方法组合。我一直在修改 Spring Security,似乎新的 3.1 版本可以让你做到这一点,但是我在让它在 OSGi 中工作时遇到了很多麻烦。
作为测试,我创建了一个非常简单的 beans.xml 文件:
<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>
现在,有趣的部分来了...根据我一直在做的所有阅读,我需要一个 web.xml 才能使这些工作正常进行。比如我尝试使用的这个示例:
<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>
使用这两个文件的组合不起作用。我所说的“不起作用”是指什么也没发生。没有错误消息,没有例外,该包的功能就像我尝试添加 Spring Security 之前一样。我假设问题是捆绑包需要是 WAR 或 WAB 才能加载 web.xml。这是正确的吗?
更重要的是,有没有办法让 spring 在没有 web.xml 的情况下工作?
我正在假设我需要将捆绑包保留为 CXF 加载它的捆绑包,因此我无法将其转换为 WAR 或 WAB,但我不完全确定情况是这样。
感谢您提供的任何帮助!
更新: 经过一系列额外的谷歌搜索后,我发现了 论坛帖子提到将 Web-FilterMappings: springSecurityFilterChain;url-patterns:="/*"
添加到清单中,而不是使用 web.xml。但是,您仍然需要使用 WAB 而不是普通的捆绑包。我已将该行添加到我的清单中以防万一,但它没有效果。看来我的问题变成了:如何将 WAB 与 CXF 结合使用?
更新2: 因为这个问题不够长...我决定尝试使用Spring Security注释而不是intercept-url只是为了看看会发生什么。当我尝试访问安全路径时,我得到了这个有趣的堆栈跟踪:
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]
spring 网站说,当您第一次尝试匿名连接到安全服务时,会发生这种情况,并且不会再发生第二次。嗯,这对我来说每次都会发生。从异常情况来看,我在清单中的条目似乎正在被拾取,也许问题与我想象的不同。有人对为什么会发生这种情况有任何想法吗?我是否缺少 beans.xml 中的某些条目来使基本的 http 身份验证工作?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先你需要清楚地了解 spring 和 web.xml 的作用。
如果你想在没有容器的情况下使用 servlet 进行 Http,我想你必须注册一个 HttpService,请参阅: http://karaf.apache.org/manual/latest-2.2.x/users-guide/http.html
你的异常发生,因为当它达到映射的方法,SecurityContext 中没有 Authentication bean。您尚未在映射中定义任何匿名访问,也许这就是它失败的原因。
基本上,要么定义 AnonymousAuthenticationFilter,要么在 http 配置中定义带有 PermitAll 的 URL 模式。否则,当您第一次尝试匿名连接同一会话时,您将不断收到该异常。
First of all you need a clear understanding of what spring and web.xml do.
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.