即使在 onBehalfOf 中有 SAML 令牌,CXF STSClient 仍要求输入用户名和密码

CXF STSClient asks for user+password even though there is a SAML token in onBehalfOf

我正在使用 CXF 的 STSClient 代表用户请求 JWT 令牌,这样我就可以调用 REST 服务。

我有一个有效的 SAML 令牌并尝试像这样配置 STSClient

stsClient.setTokenType("urn:ietf:params:oauth:token-type:jwt");
stsClient.setKeyType("http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer");
stsClient.setOnBehalfOf(samlToken.getToken());
stsClient.setEnableAppliesTo(true);

// Not sure about these.
stsClient.setSendRenewing(false);
stsClient.setKeySize(0);
stsClient.setRequiresEntropy(false);

final Map<String, Object> requestContext = Preconditions.checkNotNull(stsClient.getRequestContext());
requestContext.put(SecurityConstants.USERNAME, name); // Without this, I get "No username available"

SecurityToken result = stsClient.requestSecurityToken(appliesTo);

但是当方法失败时:

Caused by: org.apache.cxf.interceptor.Fault: No callback handler and no password available
    at org.apache.cxf.ws.security.wss4j.policyhandlers.TransportBindingHandler.handleBinding(TransportBindingHandler.java:182)
    at org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor$PolicyBasedWSS4JOutInterceptorInternal.handleMessageInternal(PolicyBasedWSS4JOutInterceptor.java:180)
    at org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor$PolicyBasedWSS4JOutInterceptorInternal.handleMessage(PolicyBasedWSS4JOutInterceptor.java:110)
    at org.apache.cxf.ws.security.wss4j.PolicyBasedWSS4JOutInterceptor$PolicyBasedWSS4JOutInterceptorInternal.handleMessage(PolicyBasedWSS4JOutInterceptor.java:97)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:530)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:441)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:356)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:314)
    at org.apache.cxf.ws.security.trust.AbstractSTSClient.issue(AbstractSTSClient.java:874)
    at org.apache.cxf.ws.security.trust.STSClient.requestSecurityToken(STSClient.java:71)
    at org.apache.cxf.ws.security.trust.STSClient.requestSecurityToken(STSClient.java:65)
    at org.apache.cxf.ws.security.trust.STSClient.requestSecurityToken(STSClient.java:61)
Caused by: org.apache.cxf.ws.policy.PolicyException: No callback handler and no password available
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AbstractCommonBindingHandler.unassertPolicy(AbstractCommonBindingHandler.java:93)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AbstractBindingBuilder.getPassword(AbstractBindingBuilder.java:1042)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AbstractBindingBuilder.addUsernameToken(AbstractBindingBuilder.java:839)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.TransportBindingHandler.addSignedSupportingTokens(TransportBindingHandler.java:115)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.TransportBindingHandler.handleNonEndorsingSupportingTokens(TransportBindingHandler.java:208)
    at org.apache.cxf.ws.security.wss4j.policyhandlers.TransportBindingHandler.handleBinding(TransportBindingHandler.java:167)
    ... 16 common frames omitted

因为我有 SAML 令牌,所以我希望 STSClient 不再需要用户名或密码。

如何告诉 CXF / STSClient 跳过 addUsernameToken() 方法调用?

问题出在服务的 WSDL 定义中。

WSDL 中的每个端口都附加到一个 URL 和一个绑定。绑定有一个策略。这种情况下的策略要求用户名和密码。在 WSDL 中查找 UsernameToken

你需要的是一个不需要这个的端口。我不是这方面的专家,但从我见过的例子来看,政策中不能有 SignedSupportingTokens 元素,只有 Wss11Trust13 元素。

如果没有这个元素,CXF 将在代码中采用不同的路径,错误就会消失。