由证书签名的 Soap 请求。 WS-Security
Soap request signed by certificate. WS-Security
我收到了包含安全策略的 WSDL,至于现在,根据 wsdl 判断,我发现这意味着我需要它来使用证书进行签名。不应使用令牌服务器。
我做了什么:
我使用 cxf wsdl2java 从 wsdl 文件创建 java 类 。到目前为止,我看到 CXF 可以很好地自动处理所有签名,所以我在 java 端添加了带有 ws-security.signature.crypto 和 ws-security.encryption.crypto 的 STSClient 客户端.这基本上什么都不做,我的 Soap 请求只包含 body 而没有任何签名数据。结果什么也没有发生,也没有打印出任何错误,这让我的问题真的很难解决。
问题:
如何在没有任何 username/password 的情况下签署没有令牌服务器的 soap 请求?
所提供的 wsdl 中的地址也是 http,我应该将其覆盖为 https 吗?
收到 wsdl 策略片段:
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="SigOnly">
<wsp:ExactlyOne>
<wsp:All>
<sp:AsymmetricBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Always">
<wsp:Policy>
<sp:WssX509V3Token10/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Always">
<wsp:Policy>
<sp:WssX509V3Token10/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:TripleDesRsa15/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Strict/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
<sp:OnlySignEntireHeadersAndBody/>
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:Wss10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:MustSupportRefKeyIdentifier/>
<sp:MustSupportRefIssuerSerial/>
</wsp:Policy>
</sp:Wss10>
<sp:SignedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<sp:Body/>
</sp:SignedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
收到消息header 示例:
<soap: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"
soap:mustUnderstand="1">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-****">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="soap"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#id-***">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>value=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
signatureValue==
</ds:SignatureValue>
<ds:KeyInfo Id="KI-***">
<wsse:SecurityTokenReference wsu:Id="STR-***">
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>issuer name
</ds:X509IssuerName>
<ds:X509SerialNumber>nmber</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
</soap:Header>
我的 java 片段:
Client client = ClientProxy.getClient(generatedService);
Init.init();
Properties properties = new Properties();
properties.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
properties.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", "jks");
properties.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", keystorePassword);
properties.setProperty("org.apache.ws.security.crypto.merlin.keystore.alias", signedCertificateAliasInTheKeystore);
properties.setProperty("org.apache.ws.security.crypto.merlin.file", new ClassPathResource(keyStore).getPath());
properties.setProperty("org.apache.ws.security.crypto.merlin.keystore.private.password", keystorePassword);
Merlin crypto = null;
try {
crypto = (Merlin) CryptoFactory.getInstance(properties);
}
catch (WSSecurityException e) {
e.printStackTrace();//temp
}
STSClient stsClient = new STSClient(((EndpointImpl) client.getEndpoint()).getBus());
Map<String, Object> stsClientProperties = new HashMap<>();
stsClient.setWsdlLocation(new ClassPathResource("MyWsdl.wsdl").getPath());
stsClientProperties.put("ws-security.signature.crypto", crypto);
stsClientProperties.put("ws-security.encryption.crypto", crypto);
stsClient.setProperties(stsClientProperties);
BindingProvider bindingProvider = (BindingProvider) generatedService;
bindingProvider.getRequestContext().put("ws-security.sts.client", stsClient);
generatedService.callToTheOuterWorld(data);
二次尝试,基本上是copy
link:
org.apache.cxf.endpoint.Client client = ClientProxy.getClient(generatedService);
org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
Map<String,Object> outProps = new HashMap<String,Object>();
outProps.put(WSHandlerConstants.USER, "keystoreAlias");
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
ClientPasswordCallback.class.getName()); //callback has keystore password
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT);
outProps.put(WSHandlerConstants.SIG_PROP_FILE, new ClassPathResource("client_sign.properties").getPath());
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);
generatedService.callToTheOuterWorld(data)
抛出:由以下原因引起:org.apache。wss4j.common.ext.WSSecurityException:EncryptionCrypto 实例化失败
如果我删除 WSHandlerConstants.ENCRYPT 我没有例外,但请求中仍然缺少 header。
我解决了我自己的问题。
基本上我在 SO 示例中找到了如何打印我的请求数据,我用它来查看我的请求,结果它覆盖了 headers 为 null :) 请注意 "getHeaders()" 方法。
Binding binding = bindingProvider.getBinding();
List<Handler> handlerChain = binding.getHandlerChain();
andlerChain.add(new SOAPLoggingHandler());
binding.setHandlerChain(handlerChain);
class SOAPLoggingHandler implements SOAPHandler<SOAPMessageContext> {
public Set<QName> getHeaders() {
return null;
}
public boolean handleMessage(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
public boolean handleFault(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
public void close(MessageContext messageContext) {
}
private void logToSystemOut(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean)
smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
System.out.println("\nOutbound message:");
}
else {
System.out.println("\nInbound message:");
}
SOAPMessage message = smc.getMessage();
try {
message.writeTo(System.out);
System.out.println("");
}
catch (Exception e) {
System.out.println("Exception in handler: " + e);
}
}
}
我收到了包含安全策略的 WSDL,至于现在,根据 wsdl 判断,我发现这意味着我需要它来使用证书进行签名。不应使用令牌服务器。
我做了什么: 我使用 cxf wsdl2java 从 wsdl 文件创建 java 类 。到目前为止,我看到 CXF 可以很好地自动处理所有签名,所以我在 java 端添加了带有 ws-security.signature.crypto 和 ws-security.encryption.crypto 的 STSClient 客户端.这基本上什么都不做,我的 Soap 请求只包含 body 而没有任何签名数据。结果什么也没有发生,也没有打印出任何错误,这让我的问题真的很难解决。
问题: 如何在没有任何 username/password 的情况下签署没有令牌服务器的 soap 请求? 所提供的 wsdl 中的地址也是 http,我应该将其覆盖为 https 吗?
收到 wsdl 策略片段:
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
wsu:Id="SigOnly">
<wsp:ExactlyOne>
<wsp:All>
<sp:AsymmetricBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Always">
<wsp:Policy>
<sp:WssX509V3Token10/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Always">
<wsp:Policy>
<sp:WssX509V3Token10/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:TripleDesRsa15/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Strict/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
<sp:OnlySignEntireHeadersAndBody/>
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:Wss10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:MustSupportRefKeyIdentifier/>
<sp:MustSupportRefIssuerSerial/>
</wsp:Policy>
</sp:Wss10>
<sp:SignedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<sp:Body/>
</sp:SignedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
收到消息header 示例:
<soap: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"
soap:mustUnderstand="1">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-****">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="soap"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#id-***">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>value=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
signatureValue==
</ds:SignatureValue>
<ds:KeyInfo Id="KI-***">
<wsse:SecurityTokenReference wsu:Id="STR-***">
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>issuer name
</ds:X509IssuerName>
<ds:X509SerialNumber>nmber</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
</soap:Header>
我的 java 片段:
Client client = ClientProxy.getClient(generatedService);
Init.init();
Properties properties = new Properties();
properties.setProperty("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
properties.setProperty("org.apache.ws.security.crypto.merlin.keystore.type", "jks");
properties.setProperty("org.apache.ws.security.crypto.merlin.keystore.password", keystorePassword);
properties.setProperty("org.apache.ws.security.crypto.merlin.keystore.alias", signedCertificateAliasInTheKeystore);
properties.setProperty("org.apache.ws.security.crypto.merlin.file", new ClassPathResource(keyStore).getPath());
properties.setProperty("org.apache.ws.security.crypto.merlin.keystore.private.password", keystorePassword);
Merlin crypto = null;
try {
crypto = (Merlin) CryptoFactory.getInstance(properties);
}
catch (WSSecurityException e) {
e.printStackTrace();//temp
}
STSClient stsClient = new STSClient(((EndpointImpl) client.getEndpoint()).getBus());
Map<String, Object> stsClientProperties = new HashMap<>();
stsClient.setWsdlLocation(new ClassPathResource("MyWsdl.wsdl").getPath());
stsClientProperties.put("ws-security.signature.crypto", crypto);
stsClientProperties.put("ws-security.encryption.crypto", crypto);
stsClient.setProperties(stsClientProperties);
BindingProvider bindingProvider = (BindingProvider) generatedService;
bindingProvider.getRequestContext().put("ws-security.sts.client", stsClient);
generatedService.callToTheOuterWorld(data);
二次尝试,基本上是copy link:
org.apache.cxf.endpoint.Client client = ClientProxy.getClient(generatedService);
org.apache.cxf.endpoint.Endpoint cxfEndpoint = client.getEndpoint();
Map<String,Object> outProps = new HashMap<String,Object>();
outProps.put(WSHandlerConstants.USER, "keystoreAlias");
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
ClientPasswordCallback.class.getName()); //callback has keystore password
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.TIMESTAMP + " " + WSHandlerConstants.SIGNATURE + " " + WSHandlerConstants.ENCRYPT);
outProps.put(WSHandlerConstants.SIG_PROP_FILE, new ClassPathResource("client_sign.properties").getPath());
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);
generatedService.callToTheOuterWorld(data)
抛出:由以下原因引起:org.apache。wss4j.common.ext.WSSecurityException:EncryptionCrypto 实例化失败 如果我删除 WSHandlerConstants.ENCRYPT 我没有例外,但请求中仍然缺少 header。
我解决了我自己的问题。 基本上我在 SO 示例中找到了如何打印我的请求数据,我用它来查看我的请求,结果它覆盖了 headers 为 null :) 请注意 "getHeaders()" 方法。
Binding binding = bindingProvider.getBinding();
List<Handler> handlerChain = binding.getHandlerChain();
andlerChain.add(new SOAPLoggingHandler());
binding.setHandlerChain(handlerChain);
class SOAPLoggingHandler implements SOAPHandler<SOAPMessageContext> {
public Set<QName> getHeaders() {
return null;
}
public boolean handleMessage(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
public boolean handleFault(SOAPMessageContext smc) {
logToSystemOut(smc);
return true;
}
public void close(MessageContext messageContext) {
}
private void logToSystemOut(SOAPMessageContext smc) {
Boolean outboundProperty = (Boolean)
smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty.booleanValue()) {
System.out.println("\nOutbound message:");
}
else {
System.out.println("\nInbound message:");
}
SOAPMessage message = smc.getMessage();
try {
message.writeTo(System.out);
System.out.println("");
}
catch (Exception e) {
System.out.println("Exception in handler: " + e);
}
}
}