用于声明模式xRM(Microsoft Dynamics CRM 2011)的Apache CXF客户端?

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(格式化后)包含Addresshttp://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身份验证?

Mar*_*ica 5

我们终于得到了它的工作,不仅我在这个问题中提到的Groovy Tom博客上使用了"CXF和MS CRM 2011",而且还使用Jan-Hendrik Ku​​perus在JH上使用"使用Apache CXF连接到Microsoft Dynamics"在Java博客上,另外纠正(?)AD FS 2.0 WSDL.

遗憾的是,出于许可原因,我无法直接发布任何代码,但这里概述了我们所做的工作.


Jan-Hendrik Ku​​perus解决方案的关键部分是我们创建自己的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.


希望这有助于其他人; 如果你没有让它工作,请随时提问.