简体   繁体   English

Apache CXF和WS-Security - 密码回调

[英]Apache CXF and WS-Security - Password Callback

I have followed a mash up of a couple tutorials and neither too succesfully! 我已经完成了几个教程的混搭,也没有太成功!

I am trying to get Apache CXF and WS-Security to call back to my Spring Security authenticator. 我试图让Apache CXF和WS-Security回调我的Spring Security身份验证器。 All is close to working but at tne moment I have a problem getting the password to give Spring security out of the WS-call back. 一切都接近工作但是在某个时刻,我在获取密码以使Spring安全性退出WS-call时遇到问题。

The Handler below gets galled but pc.getPassword() is null. 下面的处理程序变得很难,但pc.getPassword()为空。 I want this to be the password sent in Soap so I can pass it to spring 我希望这是在Soap中发送的密码,所以我可以把它传递给spring

public class ServerPasswordCallback implements CallbackHandler {

public void handle(Callback[] callbacks) throws IOException, 
    UnsupportedCallbackException {

    WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

    pc.setPassword( pc.getPassword() );
}

My interceptor is set up as so 我的拦截器设置如此

 <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>

And the soap request I am sending out of SoapUI is 我从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>

Version wise it is Spring 3.1 and CXF 2.7.0 版本明智的是Spring 3.1和CXF 2.7.0

What do I need to do to see "passwordxx" in the ServerPasswordCallback class? 在ServerPasswordCallback类中查看“passwordxx”需要做什么? Is it the Soap request, the config or just wrong?! 是Soap请求,配置还是错误?!

Cheers, Rob 干杯,罗布

It appears from the documentation on org.apache.ws.security.handler.WSHandlerConstants.PW_CALLBACK_CLASS that the method should instead call pc.setPassword with the stored password to compare the user provided password against as argument, instead of the user provided password itself: org.apache.ws.security.handler.WSHandlerConstants.PW_CALLBACK_CLASS上的文档中可以看出,该方法应该使用存储的密码调用pc.setPassword来比较用户提供的密码作为参数,而不是用户提供的密码本身:

This tag refers to the CallbackHandler implementation class used to obtain passwords. 此标记引用用于获取密码的CallbackHandler实现类。 The value of this tag must be the class name of a javax.security.auth.callback.CallbackHandler instance. 此标记的值必须是javax.security.auth.callback.CallbackHandler实例的类名。 The callback function 回调函数

javax.security.auth.callback.CallbackHandler.handle(javax.security.auth.callback.Callback[])

gets an array of org.apache.ws.security.WSPasswordCallback objects. 获取org.apache.ws.security.WSPasswordCallback对象的数组。 Only the first entry of the array is used. 仅使用数组的第一个条目。 This object contains the username/keyname as identifier. 该对象包含用户名/密钥名称作为标识符。 The callback handler must set the password or key associated with this identifier before it returns. 回调处理程序必须在返回之前设置与此标识符关联的密码或密钥。 The application may set this parameter using the following method: 应用程序可以使用以下方法设置此参数:

call.setProperty(WSHandlerConstants.PW_CALLBACK_CLASS, "PWCallbackClass");


I'm using a org.apache.ws.security.validate.Validator to check the validity of the supplied password, and setting the Spring security context there: 我正在使用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;
}

I'm not sure whether that approach is any better or worse (I'd appreciate some feedback on this), but perhaps it's useful for the next person to come across this issue. 我不确定这种方法是好还是坏(我很感激对此的一些反馈),但也许这对下一个人遇到这个问题很有用。 There appears to be a lack of decent up to date documentation on how to integrate Spring security and CXF. 似乎缺乏关于如何集成Spring安全性和CXF的最新文档。

Ok so this is not the ideal solution and hopefully a better answer will come along a bit later down the line, most likely when I have some more time to look at this. 好的,所以这不是理想的解决方案,希望更好的答案会在稍后的时候出现,最有可能的是,当我有更多时间来看这个时。

I use a regex to inspect the full packet and pull out the password field. 我使用正则表达式检查完整数据包并拔出密码字段。 Code is below. 代码如下。 Will update later when I work out the right way to do this as this is defintley not it! 稍后当我找到正确的方法来执行此操作时会更新,因为这不是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) );
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM