apache - CXF 3.X 和 WSS4J 2.X 中的回调处理程序

标签 apache web-services cxf ws-security wss4j

我正在尝试将我们当前的应用程序升级到 CXF 3 和 WSS4J 2。这让我很头疼。

客户端当前应用代码:

private void secureWebService( Client client, final Credentials credentials ) {

  // set some WS-Security information
  Map<String,Object> outProps = new HashMap<String,Object>();
  outProps.put( WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN );
  outProps.put( WSHandlerConstants.USER, credentials.getUsername() );
  outProps.put( WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT );

  // Callback used to retrieve password for given user.
  outProps.put( WSHandlerConstants.PW_CALLBACK_REF, new CallbackHandler() {
     @Override
     public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
        pc.setPassword( credentials.getPassword() );
     }
  });

  WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor( outProps );
  client.getOutInterceptors().clear();
  client.getOutInterceptors().add( wssOut );
}

在服务器端...

public class ServerPasswordCallback implements CallbackHandler {
    public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback)callbacks[0];
        boolean result = false;
        try {
            LoginContext lc = new LoginContext( container, new CallbackHandler() {
                public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
                    NameCallback nc = (NameCallback)callbacks[0];
                    nc.setName( myGetName() );

                    PasswordCallback pc2 = (PasswordCallback)callbacks[1];
                    String clientPasssword = pc.getPassword(); //Used to contain the password but is now NULL
                    pc2.setPassword( clientPasssword.toCharArray() );
                }
            } );
            lc.login();
            result = true;
        } catch( LoginException le ) {
            le.printStackTrace(); //current stack trace is a NULLPointerException since "clientPassword" is NULL
            // We haven't authenticated, so false will be returned
        } catch( SecurityException se ) {
            throw new IOException( "Cannot create LoginContext. " + se.getMessage() );
        }
        return result;
    }
}

我的 JAX-WS 端点配置:

<bean id="wss4jPasswordCallback" class="com.mycompany.webservice.security.ServerPasswordCallback"/>

<jaxws:endpoint id="customerEndpoint" implementor="#customerWebService" address="/Customer">
    <jaxws:inInterceptors>
        <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
            <constructor-arg>
                <map>
                    <entry key="action" value="UsernameToken"/>
                    <entry key="passwordType" value="PlainText"/>
                    <entry key="passwordCallbackRef">
                        <ref bean="wss4jPasswordCallback"/>
                    </entry>
                </map>
            </constructor-arg>
        </bean>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalInjectorInterceptor"/>
    </jaxws:inInterceptors>
    <jaxws:outInterceptors>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalRemoverInterceptor"/>
    </jaxws:outInterceptors>    
    <jaxws:outFaultInterceptors>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalRemoverInterceptor"/>
    </jaxws:outFaultInterceptors>   
</jaxws:endpoint>

具体来说,WSPasswordCallback 对象现在传递 NULL 而不是像过去那样传递密码。根据我的阅读,CXF 只是选择停止执行此操作,因为关于我将为升级路径执行的操作的文档不足。这个的升级路径是什么?

另外,我注意到 WSS4J 正在改变它所在的位置。它已从“org.apache.ws.security”移动到“org.apache.wss4j.common.ext”。我还将我的所有常量更新为“org.apache.wss4j.dom.WSConstants”和“org.apache.wss4j.dom.handler.WSHandlerConstants”,以便编译。这也彻底改变了“org.apache.commons.validator.Validator”中旧的“org.apache.ws.security.validate.Validator”类。现在的类(class)大不相同。也许“org.apache.wss4j.dom.validate.KerberosTokenValidator”是新的替代品?同样,我找不到关于这个事实的文档。

请注意:在迁移到新的 CXF 和 WSS4J 版本之前,这是所有工作代码!

最佳答案

由于我在这个问题上花费了大量时间,所以我想确保提供我的解决方案。这可能并不适合所有人,但如果您的代码看起来像我的问题,这应该会让您走上正轨。

首先,Validator 类现在是 CXF 3 之后的一个接口(interface)。我正在工作的是 org.apache.wss4j.dom.validate.UsernameTokenValidator 代替了 org.apache.ws.security.validate。验证器。我的搜索中没有这条关键信息。

因此,如果您使用 CallbackHandler 进行自定义身份验证,则需要切换到 UsernameTokenValidator。这是我的代码现在的样子。

JAX-WS 配置:

<!-- Bean for custom authentication of web service -->
<bean id="UsernameTokenLDAPValidator" class="com.mycompany.webservice.security.UsernameTokenLDAPValidator"/>

<jaxws:endpoint id="customerEndpoint" implementor="#customerWebService" address="/Customer">
    <jaxws:inInterceptors>
        <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
            <constructor-arg>
                <map>
                    <entry key="action" value="UsernameToken"/>
                    <entry key="passwordType" value="PasswordText"/>
                </map>
            </constructor-arg>
        </bean>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalInjectorInterceptor"/>
    </jaxws:inInterceptors>
    <jaxws:outInterceptors>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalRemoverInterceptor"/>
    </jaxws:outInterceptors>    
    <jaxws:outFaultInterceptors>
        <bean class="com.mycompany.webservice.security.Wss4jPrincipalRemoverInterceptor"/>
    </jaxws:outFaultInterceptors>   
    <jaxws:properties>
        <entry key="ws-security.enable.nonce.cache" value="false" />
        <entry key="ws-security.enable.timestamp.cache" value="false" />
        <entry key="ws-security.ut.validator" value-ref="UsernameTokenLDAPValidator"/>
    </jaxws:properties>
</jaxws:endpoint>

新的 UsernameTokenLDAPValidator 类

public class UsernameTokenLDAPValidator extends UsernameTokenValidator {


    public Credential validate( Credential credential, RequestData request ) throws WSSecurityException {
        UsernameToken userToken = credential.getUsernametoken();
        final String userId = userToken.getName();
        final String password = userToken.getPassword();
        String securityDomainName = "SecurityDomainNameNameOfJBOSSConfig"; //<login-module>

        LoginContext lc;
        try {
            lc = new LoginContext( securityDomainName, new CallbackHandler() {
                public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException {
                    NameCallback nc = (NameCallback)callbacks[0];
                    nc.setName( userId );

                    PasswordCallback pc2 = (PasswordCallback)callbacks[1];
                    pc2.setPassword( password.toCharArray() );
                }
            } );
            lc.login();
        } catch( LoginException e ) {
            throw new WSSecurityException( ErrorCode.FAILED_AUTHENTICATION, e );
        }

        return credential;
    }

}

注意事项:

  • 我删除了旧的 CallbackHandler 类 (ServerPasswordCallback)(有问题)
  • 我没有对客户端(有问题)的应用程序代码进行任何更改

关于apache - CXF 3.X 和 WSS4J 2.X 中的回调处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26638905/

相关文章:

PHP 错误 : Access denied for user 'jobportal' @'localhost' (using password: YES)

java - HttpResponseProxy HTTP/1.0 401 未经授权

c++ - gSOAP 在请求完成后删除对象中的引用值

java - 动态添加新过滤器

web-services - CXF - 如何声明一个必需且非原始的属性?

java - Apache StrTokenizer 如何转义字符串文字中的引号和逗号

javascript - joomla 3.2后端javascript错误

Java Web 服务 REST 正确设计最佳实践

html - 如何根据用户所在的国家/地区提供不同的 HTML 页面?

cxf - 在 "in Interceptor"中注入(inject) CXF JAXRS MessageContext