首页 > 解决方案 > 即使 onBehalfOf 中有 SAML 令牌,CXF STSClient 也会要求提供用户+密码

问题描述

我正在使用 CXFSTSClient代表用户请求 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()方法调用?

标签: jwtcxfsaml-2.0

解决方案


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

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

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

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


推荐阅读