我已经完成了几个教程的混搭,但也没有太成功!
我正在尝试让Apache CXF和WS-Security回调我的Spring Security身份验证器。一切都接近于工作但是在某个时刻,我在获取密码以使Spring安全性退出WS-call时遇到问题。
下面的处理程序变得很难,但pc.getPassword()为空。我希望这是在Soap中发送的密码,所以我可以将它传递给spring
public class ServerPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword( pc.getPassword() );
}
我的拦截器设置如此
<bean id="wsAuthenticationInterceptor" class="com.olympus.viewtheworld.server.security.auth.WSAuthenticationInInterceptor">
<constructor-arg index="0">
<map key-type="java.lang.String" value-type="java.lang.Object">
<entry key="action" value="UsernameToken" />
<entry key="passwordType" value="PasswordText" />
<entry key="passwordCallbackClass" value="com.olympus.viewtheworld.server.security.auth.ServerPasswordCallback" />
</map>
</constructor-arg>
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<jaxws:endpoint id="secureHelloService"
implementor="#secureHelloServiceImpl"
implementorClass="com.olympus.viewtheworld.server.service.Impl.SecureHelloServiceImpl"
address="/SoapService/secure/hello">
<jaxws:serviceFactory>
<ref bean="jaxws-and-aegis-service-factory" />
</jaxws:serviceFactory>
<jaxws:inInterceptors>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
<ref bean="wsAuthenticationInterceptor" />
</jaxws:inInterceptors>
</jaxws:endpoint>
我从SoapUI发出的soap请求是
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:test="http://test/">
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>rob2</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">passwordxx</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
<test:hello>
<!--Optional:-->
<hello>asdf</hello>
</test:hello>
</soapenv:Body>
</soapenv:Envelope>
版本明智的是Spring 3.1和CXF 2.7.0
在ServerPasswordCallback类中查看“passwordxx”需要做什么?是Soap请求,配置还是错误?!
干杯, 罗布
答案 0 :(得分:1)
从org.apache.ws.security.handler.WSHandlerConstants.PW_CALLBACK_CLASS
的文档中可以看出,该方法应该使用存储的密码调用pc.setPassword
来比较用户提供的密码作为参数,而不是用户提供的密码本身:
此标记指的是用于的CallbackHandler实现类 获取密码。此标记的值必须是a的类名 javax.security.auth.callback.CallbackHandler实例。回调函数
javax.security.auth.callback.CallbackHandler.handle(javax.security.auth.callback.Callback[])
获取org.apache.ws.security.WSPasswordCallback对象的数组。 仅使用数组的第一个条目。该对象包含 username / keyname作为标识符。回调处理程序必须设置 返回之前与此标识符关联的密码或密钥。该 应用程序可以使用以下方法设置此参数:
call.setProperty(WSHandlerConstants.PW_CALLBACK_CLASS, "PWCallbackClass");
我使用org.apache.ws.security.validate.Validator
检查所提供密码的有效性,并在那里设置Spring安全上下文:
@Bean(name = "wssforjInInterceptor")
public WSS4JInInterceptor wssforjInInterceptor() {
// Configure how we ask for username and password
Map<String, Object> props = new HashMap<>();
props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
props.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
// Password callback
props.put(WSHandlerConstants.PW_CALLBACK_REF, passwordCallbackHandler());
// Validator registration
Map<QName, Object> validators = new HashMap<>();
String WSS_WSSECURITY_SECEXT_1_0_XSD = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
QName qName = new QName(WSS_WSSECURITY_SECEXT_1_0_XSD, WSHandlerConstants.USERNAME_TOKEN, "");
validators.put(qName, usernameTokenValidator());
props.put(WSS4JInInterceptor.VALIDATOR_MAP, validators);
WSS4JInInterceptor wss4jInInterceptor = new WSS4JInInterceptor(props);
return wss4jInInterceptor;
}
我不确定这种方法是更好还是更糟(我对这方面的反馈很感激),但也许这对下一个遇到这个问题的人有用。似乎缺乏关于如何集成Spring安全性和CXF的最新文档。
答案 1 :(得分:0)
好的,所以这不是理想的解决方案,希望稍后会有更好的答案,最有可能的是我有更多时间来看这个。
我使用正则表达式检查完整数据包并拔出密码字段。代码如下。当我找到正确的方法来做这件事时会更新,因为这不是defintley!
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
String mydata= pc.getRequestData().getMsgContext().toString();
Pattern pattern = Pattern.compile("<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">(.*?)<");
Matcher matcher = pattern.matcher(mydata);
if (matcher.find())
{
pc.setPassword( matcher.group(1) );
}