使用 Apache CXF 验证 SOAP usernameToken 时出现问题
Problem authenticating SOAP usernameToken with Apache CXF
我正在尝试在 Apache CXF 3.0.4
下开发一个 SOAP 网络服务,但我在使用 [=39= 验证每个 SOAP 消息 header 中包含的 UsernameToken
时遇到了问题].
根据 documentation,如果 cxf-rt-ws-policy
和 cxf-rt-ws-security
模块在 classpath
上可用,WS-SecurityPolicy 将自动启用。经过适当的处理后,它会做必要的工作来处理安全问题
配置。
我通过 Endpoint 属性 Annotations 进行配置,在
以下方式:
@WebService(targetNamespace = "http://tempuri.org/", name = "MyService")
@EndpointProperties(value = {
@EndpointProperty(key = "ws-security.callback-handler", value = "org.tempuri.ServerPasswordCallback")
//@EndpointProperty(key = "ws-security.validate.token", value = "false")
}
)
public interface MyService {
...
}
ServerPasswordCallback 是:
public class ServerPasswordCallback implements CallbackHandler {
public ServerPasswordCallback() {
System.out.println("Instantiating ServerPasswordCallback");
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
System.out.println("Validating on ServerPasswordCallback");
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if (pc.getIdentifier().equals("joe")) {
// set the password on the callback. This will be compared to the
// password which was sent from the client.
pc.setPassword("password");
}
}
}
问题是我遇到以下异常:
Caused by: org.apache.wss4j.common.ext.WSSecurityException: The security token could not be authenticated or authorized
at org.apache.wss4j.dom.validate.UsernameTokenValidator.verifyDigestPassword(UsernameTokenValidator.java:176)
at org.apache.wss4j.dom.validate.UsernameTokenValidator.verifyPlaintextPassword(UsernameTokenValidator.java:136)
at org.apache.wss4j.dom.validate.UsernameTokenValidator.validate(UsernameTokenValidator.java:94)
已发送消息的header是:
<?xml version="1.0"?>
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-3B91E43693FA4F34C61536922750459149">
<wsse:Username>joe</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">ey+3J+OKoHlhfqREn7Q8jw==</wsse:Nonce>
<wsu:Created>2018-09-14T10:59:10.459Z</wsu:Created>
</wsse:UsernameToken>
<wsu:Timestamp wsu:Id="TS-3B91E43693FA4F34C61536922750459148">
<wsu:Created>2018-09-14T10:59:10.459Z</wsu:Created>
<wsu:Expires>2018-09-14T10:59:15.459Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soapenv:Header>
奇怪的是,似乎 ServerPasswordCallback
从未实例化,并且 handle()
从未被调用。
如果在端点属性注释中我将 ws-security.validate.token
设置为 false
,则抛出前一个异常,即使这
属性 应该阻止令牌验证。
这个事实让我认为注释不起作用,但我不明白为什么。
这是验证 UsernameToken
的正确方法吗?
端点属性注释是否正确?
N.B。我无法像 documentation because I have not access to Endpoint instance. A sample project is available here
中建议的那样设置端点属性
最后我想出了一个解决办法:
@WebService(targetNamespace = "http://tempuri.org/", name = "MyService")
@EndpointProperties(value = {
@EndpointProperty(key = "webservice.security.authMethod", value = "WS-SECURITY")
@EndpointProperty(key = "ws-security.callback-handler", value = "org.tempuri.ServerPasswordCallback")
}
)
public interface MyService {
...
}
为了使注释起作用,有必要在 EndpointProperties 中包含以下注释:
@EndpointProperty(key = "webservice.security.authMethod", value = "WS-SECURITY")
我正在尝试在 Apache CXF 3.0.4
下开发一个 SOAP 网络服务,但我在使用 [=39= 验证每个 SOAP 消息 header 中包含的 UsernameToken
时遇到了问题].
根据 documentation,如果 cxf-rt-ws-policy
和 cxf-rt-ws-security
模块在 classpath
上可用,WS-SecurityPolicy 将自动启用。经过适当的处理后,它会做必要的工作来处理安全问题
配置。
我通过 Endpoint 属性 Annotations 进行配置,在
以下方式:
@WebService(targetNamespace = "http://tempuri.org/", name = "MyService")
@EndpointProperties(value = {
@EndpointProperty(key = "ws-security.callback-handler", value = "org.tempuri.ServerPasswordCallback")
//@EndpointProperty(key = "ws-security.validate.token", value = "false")
}
)
public interface MyService {
...
}
ServerPasswordCallback 是:
public class ServerPasswordCallback implements CallbackHandler {
public ServerPasswordCallback() {
System.out.println("Instantiating ServerPasswordCallback");
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
System.out.println("Validating on ServerPasswordCallback");
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if (pc.getIdentifier().equals("joe")) {
// set the password on the callback. This will be compared to the
// password which was sent from the client.
pc.setPassword("password");
}
}
}
问题是我遇到以下异常:
Caused by: org.apache.wss4j.common.ext.WSSecurityException: The security token could not be authenticated or authorized
at org.apache.wss4j.dom.validate.UsernameTokenValidator.verifyDigestPassword(UsernameTokenValidator.java:176)
at org.apache.wss4j.dom.validate.UsernameTokenValidator.verifyPlaintextPassword(UsernameTokenValidator.java:136)
at org.apache.wss4j.dom.validate.UsernameTokenValidator.validate(UsernameTokenValidator.java:94)
已发送消息的header是:
<?xml version="1.0"?>
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-3B91E43693FA4F34C61536922750459149">
<wsse:Username>joe</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">ey+3J+OKoHlhfqREn7Q8jw==</wsse:Nonce>
<wsu:Created>2018-09-14T10:59:10.459Z</wsu:Created>
</wsse:UsernameToken>
<wsu:Timestamp wsu:Id="TS-3B91E43693FA4F34C61536922750459148">
<wsu:Created>2018-09-14T10:59:10.459Z</wsu:Created>
<wsu:Expires>2018-09-14T10:59:15.459Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soapenv:Header>
奇怪的是,似乎 ServerPasswordCallback
从未实例化,并且 handle()
从未被调用。
如果在端点属性注释中我将 ws-security.validate.token
设置为 false
,则抛出前一个异常,即使这
属性 应该阻止令牌验证。
这个事实让我认为注释不起作用,但我不明白为什么。
这是验证 UsernameToken
的正确方法吗?
端点属性注释是否正确?
N.B。我无法像 documentation because I have not access to Endpoint instance. A sample project is available here
中建议的那样设置端点属性最后我想出了一个解决办法:
@WebService(targetNamespace = "http://tempuri.org/", name = "MyService")
@EndpointProperties(value = {
@EndpointProperty(key = "webservice.security.authMethod", value = "WS-SECURITY")
@EndpointProperty(key = "ws-security.callback-handler", value = "org.tempuri.ServerPasswordCallback")
}
)
public interface MyService {
...
}
为了使注释起作用,有必要在 EndpointProperties 中包含以下注释:
@EndpointProperty(key = "webservice.security.authMethod", value = "WS-SECURITY")