axis2 + rampart 调用基于ws-trust的.net webservice 碰到的问题总结
郑嘉年
2023-12-01
1. 首先请求是https或者需要证书签名的,需要把证书和private key导入java 的keystore。不过一般.net服务端给的证书是.pfx格式的,我也没找到太好的办法导入,于是就把证书转换成jks的,然后重命名为cacerts,此时你需要把keystore的密码改为"changeit"。
2. 我用的是axis2 1.5.1 和 rampart 1.4 , 如果wsdl如果存在多个endpoint的时候,用wsdl2java工具生成客户端是会抛错: "can not determine the MEP ".
3. 配置sts-config.xml
<wsp:Policy wsu:Id="STS"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding>
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken RequireClientCertificate="false" />
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256 />
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Lax />
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp />
</wsp:Policy>
</sp:TransportBinding>
<sp:SignedSupportingTokens>
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssUsernameToken10 />
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SignedSupportingTokens>
<sp:EndorsingSupportingTokens>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:RequireThumbprintReference />
<sp:WssX509V3Token10 />
</wsp:Policy>
</sp:X509Token>
<sp:SignedParts
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing" />
</sp:SignedParts>
</wsp:Policy>
</sp:EndorsingSupportingTokens>
<sp:Wss11>
<wsp:Policy>
<sp:MustSupportRefKeyIdentifier />
<sp:MustSupportRefIssuerSerial />
<sp:MustSupportRefThumbprint />
<sp:MustSupportRefEncryptedKey />
</wsp:Policy>
</sp:Wss11>
<sp:Trust10>
<wsp:Policy>
<sp:MustSupportIssuedTokens />
<sp:RequireClientEntropy />
<sp:RequireServerEntropy />
</wsp:Policy>
</sp:Trust10>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:user>[color=red]le-8066a9f7-c96a-4c3c-85a8-47121aed3a19[/color]
</ramp:user>
<ramp:passwordCallbackClass>com.mimeo.sandbox.client.sts.PWCBHandler
</ramp:passwordCallbackClass>
<ramp:signatureCrypto>
<ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
<ramp:property
name="org.apache.ws.security.crypto.merlin.keystore.type">PKCS12</ramp:property>
<ramp:property name="org.apache.ws.security.crypto.merlin.file">
./reposity/keys/XXX.pfx</ramp:property>
<ramp:property
name="org.apache.ws.security.crypto.merlin.keystore.alias">[color=red]le-8066a9f7-c96a-4c3c-85a8-47121aed3a19[/color]
</ramp:property>
<ramp:property
name="org.apache.ws.security.crypto.merlin.keystore.password">xxxxxxx</ramp:property>
</ramp:crypto>
</ramp:signatureCrypto>
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
红色部分为证书的别名。
4. .net 支持的saml token 是1.0版本的,rampart 请求sts 服务后解析返回xml时是取不到token id 的,需要修改STSClient.java的源代码,需要从"AssertionID"这个属性中取得token id。
private String findIdentifier(OMElement reqAttRef,
OMElement reqUnattRef,
OMElement token) {
String id;
if (reqAttRef != null) {
//First try the attached ref
id = this.getIdFromSTR(reqAttRef);
} else if (reqUnattRef != null) {
//then try the unattached ref
id = this.getIdFromSTR(reqUnattRef);
} else {
//Return wsu:Id of the token element
id = token.getAttributeValue(new QName(WSConstants.WSU_NS, "Id"));
}
[color=red]if (id == null){
id = "#" + token.getAttributeValue(new QName("AssertionID"));
}[/color]
return id;
}
5. 配置policy.xml (调用服务时的ws policy)
<wsp:Policy
wsu:Id="Scenario_5_IssuedTokenForCertificate_MutualCertificate11_policy"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:ExactlyOne>
<wsp:All>
<sp:TransportBinding
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:TransportToken>
<wsp:Policy>
<sp:HttpsToken
RequireClientCertificate="false"/>
</wsp:Policy>
</sp:TransportToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:Basic256/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Lax/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
</wsp:Policy>
</sp:TransportBinding>
<sp:EndorsingSupportingTokens
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:IssuedToken
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
<Issuer
xmlns="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<Address
xmlns="http://www.w3.org/2005/08/addressing">http://xxxxx/AuthenticationService.svc</Address>
</Issuer>
<sp:RequestSecurityTokenTemplate>
<t:TokenType
xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
<t:KeyType
xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey</t:KeyType>
<t:KeySize
xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">256</t:KeySize>
</sp:RequestSecurityTokenTemplate>
<wsp:Policy>
<sp:RequireInternalReference/>
</wsp:Policy>
</sp:IssuedToken>
<!--<sp:SignedParts>
<sp:Header
Name="To" Namespace="http://www.w3.org/2005/08/addressing"/>
</sp:SignedParts>-->
</wsp:Policy>
</sp:EndorsingSupportingTokens>
<sp:Wss11
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:MustSupportRefKeyIdentifier/>
<sp:MustSupportRefIssuerSerial/>
<sp:MustSupportRefThumbprint />
<sp:MustSupportRefEncryptedKey />
</wsp:Policy>
</sp:Wss11>
<sp:Trust10
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:MustSupportIssuedTokens/>
<sp:RequireClientEntropy/>
<sp:RequireServerEntropy/>
</wsp:Policy>
</sp:Trust10>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
6. 此时调用.net的webservice还是不成功,在对比了.net客户端发出的消息后发现
<KeyInfo>
<o:SecurityTokenReference>
<o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security- 1.1#ThumbprintSHA1">XqQ6CjOEBvBddZtWdSue8LOyUxE=</o:KeyIdentifier>
</o:SecurityTokenReference>
</KeyInfo>
用的是<o:KeyIdentifier>标签,而axis2发出的用的是<wsse:Reference>标签,在ws-trust文档里说明这两种标签都是可以的,不知道为什么调用.net时用<Reference>就不行。如果要使用<keyidentifier>就需要修改WSS4J包中WSSecSignature.java的源代码:
case WSConstants.CUSTOM_SYMM_SIGNING:
// Reference refCust = new Reference(document);
// refCust.setValueType(this.customTokenValueType);
// refCust.setURI("#" + this.customTokenId);
// secRef.setReference(refCust);
[color=darkred] Document doc1 = secRef.getElement().getOwnerDocument();
Element keyId = doc1.createElementNS(WSConstants.WSSE_NS,"wsse:KeyIdentifier");
keyId.setAttributeNS(null, "ValueType", this.customTokenValueType);
keyId.setAttributeNS(null, "EncodingType",BinarySecurity.BASE64_ENCODING);
keyId.appendChild(doc1.createTextNode(this.customTokenId));
Element elem = secRef.getFirstElement();
if (elem != null) {
secRef.getElement().replaceChild(keyId, elem);
} else {
secRef.getElement().appendChild(keyId);
}[/color]
break;
再调用.net的服务,此时就成功了。其中碰到的其他小问题还是挺多的,总之要看axis2 + rampart 的源代码, 加上不断的断点调试。