Mar*_*ica 5 wcf cxf adfs claims-based-identity dynamics-crm-2011
我正在尝试为Microsoft Dynamics CRM 2011("xRM")Web服务(我理解为基于WCF 4)创建Apache CXF(2.7.5)客户端,其中CRM处于声明模式,因此WSDL这个Web服务指向STS(在我的情况下是AD FS 2.0).
我的主要问题:是否有任何教程,建议,博客文章可以帮助我(描述如何发送声明,或如何避免它们,而是使用Windows身份验证)?
以下是我到目前为止所做的事情的描述.
我已经拥有相同Web服务的工作代码,当CRM处于Windows身份验证模式时,该服务可以正常运行.该代码基于Groovy Tom博客上的"CXF和MS CRM 2011".
为了支持声明模式,我还需要包含org.apache.cxf:cxf-rt-ws-mex,以便CXF可以解析xRM WSDL.然后我需要让CXF内置的STS客户端使用SOAP 1.2:
client.getRequestContext().put("ws-security.sts.client-soap12-binding", "true");
Run Code Online (Sandbox Code Playgroud)
避免来自AD FS 2.0的错误500.(显然AD FS 2.0期望使用SOAP 1.2调用/ adfs/services/trust/mex端点,而CXF默认使用SOAP 1.1.我必须从AD FS的WCF跟踪中找到它,
System.ServiceModel.ProtocolException:Content Type text/xml; charset = UTF-8被发送到期望application/soap + xml的服务; 字符集= UTF-8.客户端和服务绑定可能不匹配.
当Apache CXF使用SOAP 1.1时.)
然后还有另一个问题:AD FS的/ adfs/services/trust/mex端点返回的WSDL似乎不完整,因为它包含
<wsdl:types>
<xsd:schema
targetNamespace="http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice/Imports">
<xsd:import namespace="http://schemas.microsoft.com/Message" />
<xsd:import namespace="http://schemas.xmlsoap.org/ws/2005/02/trust" />
<xsd:import namespace="http://docs.oasis-open.org/ws-sx/ws-trust/200512" />
</xsd:schema>
</wsdl:types>
Run Code Online (Sandbox Code Playgroud)
所以没有import
一个人有schemaLocation
.这让CXF抱怨道
org.apache.cxf.wsdl11.WSDLRuntimeException:部件请求定义为元素{ http://docs.oasis-open.org/ws-sx/ws-trust/200512 } RequestSecurityToken,它不在架构中.
我发现是什么原因造成的:含有模式RequestSecurityToken
等等都在MEX SOAP调用的结果,但在不同的<wsx:MetadataSection Dialect="http://www.w3.org/2001/XMLSchema">
部分,这些代码AbstractSTSClient
完全忽略.
所以我放置了我自己的WSDLFactory + WSDLReader(使用属性{{javax.wsdl.factory.WSDLFactory}}),它只是将三个命名空间的模式插入到它读取的任何WSDL中.
现在我挡在旁边点:XRM WSDL(格式化后)包含Address
的http://www.w3.org/2005/08/addressing/anonymous
(见下文),这在某种程度上导致CXF来查找AD FS的元数据端点.但是,这样的终点当然不存在:它包含,例如,https://...:.../adfs/services/trust/2005/usernamemixed
.
<wsdl:definitions
targetNamespace="http://schemas.microsoft.com/xrm/2011/Contracts/Services"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
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"
snipped="other xmlns attributes">
<wsp:Policy wsu:Id="CustomBinding_IOrganizationService_policy">
<wsp:ExactlyOne>
<wsp:All>
<!-- snip -->
<sp:EndorsingSupportingTokens
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:IssuedToken
sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<Issuer
xmlns="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<Address xmlns="http://www.w3.org/2005/08/addressing">
http://www.w3.org/2005/08/addressing/anonymous
</Address>
Run Code Online (Sandbox Code Playgroud)
那我现在该怎么办?
更一般地说,我现在的问题是:我是否正在为xRM-in-claims-mode构建Java客户端? 其他人如何让这个工作?或者是否有办法避免使用声明,而是使用xRM-in-claims-mode的Windows身份验证?
我们终于得到了它的工作,不仅在我在这个问题中提到的Groovy Tom博客上使用了"CXF和MS CRM 2011",而且还使用Jan-Hendrik Kuperus在JH上使用"使用Apache CXF连接到Microsoft Dynamics"在Java博客上,另外纠正(?)AD FS 2.0 WSDL.
遗憾的是,出于许可原因,我无法直接发布任何代码,但这里概述了我们所做的工作.
Jan-Hendrik Kuperus解决方案的关键部分是我们创建自己的STSClient,而不是让CXF创建一个.这解决了忽略<wsx:MetadataSection Dialect="http://www.w3.org/2001/XMLSchema">
部分的问题.它也解决了我的问题中的寻址问题,因为已经在CXF中继中修复了.(不幸的是,我们无法切换到最新的CXF版本:所有这些都是使用CXF 2.7.5完成的.)
在该自定义STS客户端中,我们指向特定的AD FS端点,确保我们使用SOAP 1.2(防止HTTP错误500,请参阅问题),并关闭"续订":
STSClient stsClient = new STSClient(bus);
stsClient.setSoap12();
stsClient.setWsdlLocation(wsdlLocation.toExternalForm());
stsClient.setServiceQName(new QName("http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice", "SecurityTokenService"));
stsClient.setEndpointQName(new QName("http://schemas.microsoft.com/ws/2008/06/identity/securitytokenservice", "UserNameWSTrustBinding_IWSTrust13Async"));
stsClient.setSendRenewing(false);
Run Code Online (Sandbox Code Playgroud)
(如果"更新"未关闭,则AD FS 2.0将返回SOAP错误"ID3035:请求无效或格式错误."AD FS跟踪显示"Microsoft.IdentityModel.SecurityTokenService.InvalidRequestException:MSIS3137:RequestSecurityTokenElement包含一个不受支持的WS-Trust参数:'Renewing'.")
现在stsClient
在property SecurityConstants.STS_CLIENT
("ws-security.sts.client"
)下面的请求上下文中注册,设置请求上下文属性SecurityConstants.USERNAME
,并在属性SecurityConstants.CALLBACK_HANDLER
寄存器中注册一个CallbackHandler
处理结果WSPasswordCallback
并设置密码,并且您正在营业.除了.
除此之外,我们在AD FS的WSDL上发现CXF 2.7.5扼流圈:java.lang.IllegalArgumentException: sp:KeyValueToken/wsp:Policy must have a value
在KeyValueTokenBuilder#build()中.事实证明,WSDL包含许多带属性的安全策略wsp:Optional="true"
,并且对于每个CXF都需要一个嵌套<wsp:Policy>
元素.所以我们所做的是预处理AD FS WSDL,并<wsp:Policy/>
在这些地方添加了空元素.
(我们不知道CXF 2.7.5在这里是否过于严格,或者AD FS 2.0的WSDL是否不符合标准.)
此外,我们通过查看xRM WSDL安全策略中的元素,实现了在Windows模式xRM和声明模式xRM系统之间动态切换<ms-xrm:AuthenticationPolicy>
,并检查是否<ms-xrm:Authentication>
包含ActiveDirectory或Federation.我们通过创建扩展XmlPrimitiveAssertion
和注册相应自定义构建器的自定义策略扩展来完成此操作bus.getExtension(AssertionBuilderRegistry.class)
.然后我们在自定义'out interceptor'中创建自定义STSClient:
private static class XRMAuthSecurityModeInterceptor extends AbstractSoapInterceptor {
public XRMAuthSecurityModeInterceptor() {
super(Phase.PREPARE_SEND);
addBefore("IssuedTokenOutInterceptor");
}
public void handleMessage(SoapMessage message) throws Fault {
// if the custom assertion with security mode Federation is present, then create STSClient and...
message.setContextualProperty(SecurityConstants.STS_CLIENT, stsClient);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,由于我们不想使用下载版本的AD FS的WSDL,我们通过获取SP12Constants.ISSUED_TOKEN
断言,获取它.getIssuerEpr().getMetadata().getAny()
以及从中获取该断言,在同一个"out interceptor"中"修复"该WSDL {http://www.w3.org/2005/08/addressing}Address
.结果类似于http://example.com:12345/adfs/services/trust/mex.我们检索该URL,解析XML,<wsp:Policy/>
如上所述添加元素,将结果保存到文件,并将该文件的URL用作STSClient的wsdlLocation.
希望这有助于其他人; 如果你没有让它工作,请随时提问.
归档时间: |
|
查看次数: |
2677 次 |
最近记录: |