我试图将当前的应用程序升级到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正在改变它的生活方式。它已经从&#34; org.apache.ws.security&#34; to&#34; org.apache.wss4j.common.ext&#34;。我还将所有常量更新为&#34; org.apache.wss4j.dom.WSConstants&#34; &安培; &#34; org.apache.wss4j.dom.handler.WSHandlerConstants&#34;把事情编译好。这也彻底改变了旧的&#34; org.apache.ws.security.validate.Validator&#34; class in&#34; org.apache.commons.validator.Validator&#34;。这些课程现在完全不同了。也许&#34; org.apache.wss4j.dom.validate.KerberosTokenValidator&#34;是新的替代品?再说一遍,我找不到这个事实的文件。
请注意:这是所有正在运行的代码,直到转移到新的CXF和WSS4J版本!
答案 0 :(得分:5)
由于我在这个问题上花了很多时间,所以我想确保提供了解决方案。这可能不适合所有人,但如果您的代码看起来像我的问题,这应该让您走上正确的轨道。
首先,什么是Validator类现在是CXF 3之后的接口。我工作的是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;
}
}
备注:强>
答案 1 :(得分:1)
听起来您正在从使用WSS4J 1.5.x的旧版CXF升级。从WSS4J 1.6.x开始,CallbackHandler不再提供密码,而是必须在Callback上设置密码。见这里:
http://coheigea.blogspot.ie/2011/02/usernametoken-processing-changes-in.html
科尔姆。