我们正在Spring Boot中构建CXF客户端。用于针对SOAP服务器进行身份验证/授权的SAML令牌在每个请求中都从外部身份验证代理以自定义HTTP头提供给我们的应用程序。因此,我需要一种方法将提供的令牌添加到每个传出的CXF请求中。
我知道我可以为此注册一个定制的CXF拦截器。然而,
目前,Spring配置如下所示:
@Configuration
public class MyConfig {
@Bean
public PartnerServicePortType partnerServicePortType() {
PartnerServicePortType partnerServicePortType = new PartnerServiceV0().getPartnerService();
(PartnerServiceV0
是使用Maven从服务的WSDL生成的。)
在上面的配置类中,我们目前没有声明/配置CXF总线bean。
一种可能的解决方案是:
@Configuration
public class MyConfig {
@Bean
public PartnerServicePortType partnerServicePortType() {
PartnerServicePortType service = new PartnerServiceV0().getPartnerService();
configure(service, path, baseUrl);
return service;
}
private void configureService(BindingProvider bindingProvider, String path, String baseUrl) {
// maybe try the approach outlined at https://github
// .com/kprasad99/kp-soap-ws-client/blob/master/src/main/java/com/kp/swasthik/soap/CxfConfig.java#L24
// as an alternative
bindingProvider.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, baseUrl + path);
Endpoint cxfEndpoint = ClientProxy.getClient(bindingProvider).getEndpoint();
cxfEndpoint.getInInterceptors().add(cxfLoggingInInterceptor);
cxfEndpoint.getInFaultInterceptors().add(cxfLoggingInInterceptor);
cxfEndpoint.getOutInterceptors().add(addSamlAssertionInterceptor);
}
}
还有拦截器
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.binding.soap.SoapHeader;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.Phase;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.core.xml.XMLObjectBuilder;
import org.opensaml.core.xml.XMLObjectBuilderFactory;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.core.xml.io.Marshaller;
import org.opensaml.core.xml.io.MarshallingException;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.soap.wssecurity.Created;
import org.opensaml.soap.wssecurity.Expires;
import org.opensaml.soap.wssecurity.Security;
import org.opensaml.soap.wssecurity.Timestamp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.w3c.dom.Element;
import javax.xml.namespace.QName;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* Adding SOAP header with SAML assertion to request.
*/
@Slf4j
@Component
public class AddSamlAssertionInterceptor extends AbstractSoapInterceptor {
private final SamlAssertionExtractor samlAssertionExtractor;
@Autowired
public AddSamlAssertionInterceptor(SamlAssertionExtractor samlAssertionExtractor) {
super(Phase.POST_LOGICAL);
this.samlAssertionExtractor = samlAssertionExtractor;
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
String decodedToken = SamlTokenHolder.getDecodedToken();
if (StringUtils.isBlank(decodedToken)) {
log.trace("Not adding SOAP header with SAML assertion because SAML token is blank.");
} else {
log.trace("Got decoded SAML token: {}", decodedToken);
log.trace("Adding SOAP header with SAML assertion to request.");
SoapHeader header = createSoapHeaderWithSamlAssertionFrom(decodedToken);
message.getHeaders().add(header);
}
}
private SoapHeader createSoapHeaderWithSamlAssertionFrom(String decodedToken) {
Assertion assertion = samlAssertionExtractor.extractAssertion(decodedToken);
Security security = createNewSecurityObject();
security.getUnknownXMLObjects().add(createTimestampElementFrom(assertion));
security.getUnknownXMLObjects().add(assertion);
log.trace("Creating new SOAP header with WS-Security element for '{}'.",
assertion.getSubject().getNameID().getValue());
SoapHeader header = new SoapHeader(security.getElementQName(), marshallToDom(security));
header.setMustUnderstand(config.isMustUnderstandHeader());
return header;
}
@SneakyThrows(MarshallingException.class)
private Element marshallToDom(Security security) {
Marshaller marshaller = XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(security);
return marshaller.marshall(security);
}
/*
* SAML requirements documented at https://docs.oasis-open.org/wss/v1.1/wss-v1.1-spec-errata-os-SOAPMessageSecurity
* .htm#_Toc118717167. Both timestamps must be in UTC and formatted to comply with xsd:dateTime.
*/
private Timestamp createTimestampElementFrom(Assertion assertion) {
Timestamp timestamp = (Timestamp) createOpenSamlXmlObject(Timestamp.ELEMENT_NAME);
Created created = (Created) createOpenSamlXmlObject(Created.ELEMENT_NAME);
Expires expires = (Expires) createOpenSamlXmlObject(Expires.ELEMENT_NAME);
// alternative would be to use timestamp from assertion like so assertion.getConditions().getNotBefore()
created.setValue(ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT));
// security semantics should ensure that the expiry date here is the same as the expiry of the SAML assertion
expires.setValue(assertion.getConditions().getNotOnOrAfter().toString());
timestamp.setCreated(created);
timestamp.setExpires(expires);
return timestamp;
}
private Security createNewSecurityObject() {
return (Security) createOpenSamlXmlObject(Security.ELEMENT_NAME);
}
private XMLObject createOpenSamlXmlObject(QName elementName) {
XMLObjectBuilderFactory builderFactory = XMLObjectProviderRegistrySupport.getBuilderFactory();
XMLObjectBuilder<Security> builder = (XMLObjectBuilder<Security>) builderFactory.getBuilder(elementName);
return builder.buildObject(elementName);
}
}
我了解如何简单地将“标准”ws-addressing头添加到cxf客户端调用: 但是我不明白如何添加wsa引用参数,以便消息的肥皂剧头如下所示: 如何在cxf客户端调用中添加此标头? 你好,soilworker
我想允许用户重置他们的密码。为了做到这一点,我首先检查他们的电子邮件是否存在于数据库中,如果存在,我向他们发送一封电子邮件,其中包含指向重置密码页面的链接。为了确保链接是安全的,后者是用jwt令牌制作的,该令牌仅对15mn有效。 但是,无法访问该url,因为有“.”在jwt中: < code > http://www . myapp . com/reset-password/eyjhbgcioin
我有一个wsdl,它定义了一个在调用Web服务时需要传递的肥皂头。 示例SOAP头是: CXF的wsdl2java生成了一个“身份验证信息”java类,我可以创建这个类并用用户名和密码填充它,但是我不知道在调用网络服务时如何将它传递给CXF客户端。
问题内容: 我有一个wsdl,它定义了在调用Web服务时需要传递的soap标头。 样本SOAP标头是: CXF的wsdl2java生成了一个“ AuthenticationInfo” java类,我可以使用用户名和密码来创建和填充该类,但是我不知道在调用Web服务时将其传递给CXF客户端的正确方法。 问题答案: 那么,最简单的方式做这将是创建的对象,并添加所有的参数或并添加所有的标头, 最后获取您
我是SOA开发环境中CXF的用户。 我想知道我的问题是否有CXF的解决方案。这是我的需要。我们开发了一个服务于JAXWSendpoint的webapp,endpoint实现包括通过拦截器分析请求,将请求中的数据存储到Java服务层的数据库中,并通过CXF客户端将原始请求重新发送到另一台服务器。关键是我们的一些请求包含DSIG签名(https://www.w3.org/TR/xmldsig-core
问题内容: 到目前为止,我的代码: 我想发送with 方法的内容,但是我不知道如何将它们添加到请求的正文中。我需要帮助,因为在网络上,我只能找到如何添加args。 提前致谢。 问题答案: 您始终可以在Java SE中使用java.net API: