适用于声明模式xRM的Apache CXF客户端(Microsoft Dynamics CRM 2011)? [英] Apache CXF client for claims-mode xRM (Microsoft Dynamics CRM 2011)?

查看:152
本文介绍了适用于声明模式xRM的Apache CXF客户端(Microsoft Dynamics CRM 2011)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为CRM处于声明模式的Microsoft Dynamics CRM 2011( xRM)Web服务(我理解为基于WCF 4)创建Apache CXF(2.7.5)客户端。该Web服务的WSDL指向STS(在我的情况下为AD FS 2.0)。

I'm trying to create an Apache CXF (2.7.5) client for the Microsoft Dynamics CRM 2011 ("xRM") web services (which I understood to be based on WCF 4) where CRM is in claims mode, so that the WSDL for this web service points to an STS (in my case AD FS 2.0).

我的主要问题:是否有任何教程,建议和博客可以帮助我解决问题的帖子(描述如何发送声明,或者如何避免声明,而是使用Windows身份验证)?

以下是对内容的描述我到目前为止已经做完了。

Below is a description of what I've done until now.

我已经有相同Web服务的工作代码,当CRM处于 Windows身份验证模式。该代码基于 CXF和MS CRM 2011在Groovy Tom的博客上

I already had working code for the same web service, which works when CRM is in Windows authentication mode. That code is based on "CXF and MS CRM 2011" on Groovy Tom's Blog.

要支持声明模式,我还需要添加 org.apache.cxf:cxf-rt-ws-mex ,以便可以通过以下方式解析xRM WSDL: CXF。然后,我需要使CXF内置STS客户端使用SOAP 1.2:

To support claims mode, I additionally needed to include org.apache.cxf:cxf-rt-ws-mex, so that the xRM WSDL can be parsed by CXF. Then I needed to make the CXF built-in STS client use SOAP 1.2:

client.getRequestContext().put("ws-security.sts.client-soap12-binding", "true");

以避免AD FS 2.0出现错误500。 (显然,AD FS 2.0期望使用SOAP 1.2来调用/ adfs / services / trust / mex终结点,而CXF默认为SOAP 1.1。我必须从 AD FS的WCF跟踪,其中报告了

to avoid an error 500 from AD FS 2.0. (Apparently AD FS 2.0 expects the /adfs/services/trust/mex endpoint to be called using SOAP 1.2, and CXF defaults to SOAP 1.1. I had to find this out from AD FS's WCF trace, which reported


System.ServiceModel.ProtocolException:内容类型text / xml; charset = UTF-8已发送到期望应用程序/ soap + xml的服务; charset = utf-8。客户端和服务绑定可能不匹配。

System.ServiceModel.ProtocolException: Content Type text/xml; charset=UTF-8 was sent to a service expecting application/soap+xml; charset=utf-8. The client and service bindings may be mismatched.

当Apache CXF使用SOAP 1.1时。)

when Apache CXF used SOAP 1.1.)

另一个问题:AD FS的/ adfs / services / trust / mex端点返回的WSDL似乎不完整,因为其中包含

Then there was another problem: the WSDL returned by AD FS's /adfs/services/trust/mex endpoint seemed incomplete, in that it contains

<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>

所以导入都没有 schemaLocation 。这使CXF抱怨

so none of the imports has a schemaLocation. This makes CXF complain that


org.apache.cxf.wsdl11.WSDLRuntimeException:零件请求定义为元素{ http://docs.oasis-open.org/ws-sx/ws-trust/200512 } RequestSecurityToken不在架构中。

org.apache.cxf.wsdl11.WSDLRuntimeException: Part request defined as element {http://docs.oasis-open.org/ws-sx/ws-trust/200512}RequestSecurityToken which is not in the schema.

我发现了造成此问题的原因:包含 RequestSecurityToken的架构等。,但在单独的< wsx:MetadataSection Dialect = http://www.w3.org / 2001 / XMLSchema> 部分, AbstractSTSClient 中的代码将完全忽略。

I found out what caused this: the schemas containing RequestSecurityToken etc. are in the mex SOAP call result, but in separate <wsx:MetadataSection Dialect="http://www.w3.org/2001/XMLSchema"> sections, which the code in AbstractSTSClient completely ignores.

因此,我放置了自己的WSDLFactory + WSDLReader(使用属性{{javax.wsdl.factory.WSDLFactory}}),它只是将三个名称空间的模式插入到它读取的任何WSDL中。

So I put in place my own WSDLFactory+WSDLReader (using property {{javax.wsdl.factory.WSDLFactory}}), which just inserts the schemas for the three namespaces into any WSDL it reads.

现在我在下一点被阻止:xRM WSDL(格式化后)包含地址 http ://www.w3.org/2005/08/addressing/anonymous (请参见下文),这会导致CXF在AD FS的元数据中查找该终结点。但是,这样的终结点当然不存在:它包含例如 https:// ...:... / adfs / services / trust / 2005 / usernamemixed

Now I'm blocked at the next point: the xRM WSDL (after formatting) contains an Address of http://www.w3.org/2005/08/addressing/anonymous (see below), which somehow causes CXF to look up that endpoint in AD FS's metadata. However, such an endpoint of course does not exist: it contains, e.g., 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>

那我现在该怎么办?

一般来说,我的问题是:我是否在为xRM-in-claims-mode构建Java客户端的正确道路上?得到这个工作?还是有办法避免使用声明,而是使用Windows身份验证和xRM-in-claims-mode?

More generally, my question is now: Am I on the right path for building a Java client for xRM-in-claims-mode? How have others gotten this to work? Or is there perhaps a way to avoid using claims, and instead use Windows authentication with xRM-in-claims-mode?

推荐答案

我们终于使用了它,不仅使用了 CXF和MS CRM 2011 ,还包括使用Apache CXF连接到Microsoft 动态,由Jan-Hendrik Ku​​perus在Java博客上的JH上(archive.org缓存副本),此外还纠正了(?)AD FS 2.0 WSDL。

We've finally gotten it to work, using not only "CXF and MS CRM 2011" on Groovy Tom's Blog which I mentioned in this question, but also "Using Apache CXF to connect to Microsoft Dynamics" by Jan-Hendrik Kuperus on the JH on Java blog (archive.org cached copy), and in addition correcting (?) the AD FS 2.0 WSDL.

不幸的是,出于许可原因,我无法直接发布任何代码,但这是我们所做工作的概述。

Unfortunately I cannot directly post any code for licensing reasons, but here is an overview of what we did.

Jan-Hendrik Ku​​perus解决方案的关键部分是我们创建自己的STSCl定向,而不是让CXF创建一个。可以解决被忽略的< wsx:MetadataSection Dialect = http://www.w3.org/2001/XMLSchema> 部分的问题。它也解决了我的问题,因为该问题已在CXF干线中修复。 (不幸的是,我们无法切换到最新的CXF版本:所有这些操作都是使用CXF 2.7.5完成的。)

The key part of Jan-Hendrik Kuperus's solution is that we create our own STSClient, instead of letting CXF create one. That works around the issue of the ignored <wsx:MetadataSection Dialect="http://www.w3.org/2001/XMLSchema"> sections. It also works around the addressing issue from my question, that since has been fixed in CXF trunk. (We cannot switch to the latest CXF version, unfortunately: all of this was done with CXF 2.7.5.)

在该自定义STS客户端中,我们指向一个特定的AD FS端点,请确保我们使用SOAP 1.2(防止HTTP错误500,请参阅问题),然后关闭续订:

In that custom STS client, we point to a specific AD FS endpoint, make sure we use SOAP 1.2 (prevent HTTP error 500, see question), and switch off 'renewing':

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);

(如果未关闭续订,则AD FS 2.0返回SOAP错误 ID3035:该请求无效或格式错误。 AD FS跟踪显示, Microsoft.IdentityModel.SecurityTokenService.InvalidRequestException:MSIS3137:RequestSecurityTokenElement包含不受支持的WS-Trust参数:续订。)

(If 'renewing' is not switched off, then AD FS 2.0 returns a SOAP fault "ID3035: The request was not valid or is malformed." The AD FS trace says, "Microsoft.IdentityModel.SecurityTokenService.InvalidRequestException: MSIS3137: The RequestSecurityTokenElement contained an unsupported WS-Trust parameter: 'Renewing'.")

现在在请求上下文中的属性 SecurityConstants.STS_CLIENT (<$ c中的 stsClient 中注册$ c> ws-security.sts.client ),设置请求上下文属性 SecurityConstants.USERNAME ,并在属性 SecurityConstants.CALLBACK_HANDLER 注册一个 CallbackHandler 来处理生成的 WSPasswordCallback 并设置密码,并且您在做生意。

Now register stsClient in the request context under property SecurityConstants.STS_CLIENT ("ws-security.sts.client"), set request context property SecurityConstants.USERNAME, and in property SecurityConstants.CALLBACK_HANDLER register a CallbackHandler that handles the resulting WSPasswordCallback and sets the password, and you're in business. Except.

除了那时我们发现AD FS的WSDL上的CXF 2.7.5阻塞: java.lang.IllegalArgumentException:sp:KeyValueToken / wsp:政策在KeyValueTokenBuilder#build()中必须有一个值。事实证明,WSDL包含许多属性为 wsp:Optional = true 的安全策略,对于每个CXF,都期望嵌套的 < wsp:Policy> 元素。因此,我们要做的是预处理AD FS WSDL,然后在这些位置添加空的< wsp:Policy /> 元素。

Except that at that point we found that CXF 2.7.5 chokes on AD FS's WSDL: java.lang.IllegalArgumentException: sp:KeyValueToken/wsp:Policy must have a value in KeyValueTokenBuilder#build(). It turns out that the WSDL contains a number of security policies with attribute wsp:Optional="true", and for each of these CXF expects a nested <wsp:Policy> element. So what we did is pre-process the AD FS WSDL, and just added empty <wsp:Policy/> elements in these places.

(我们不知道CXF 2.7.5是否在此过于严格,或者AD FS 2.0的WSDL是否未遵循标准。)

(We have no idea whether CXF 2.7.5 is too strict here, or whether AD FS 2.0's WSDL does not follow the standards.)

另外,通过查看切换 xRM WSDL的安全策略中的>< ms-xrm:AuthenticationPolicy> 元素,并检查< ms-xrm:Authentication> 是否包含ActiveDirectory或联合。为此,我们创建了一个扩展 XmlPrimitiveAssertion 的自定义策略扩展,并在 bus.getExtension(AssertionBuilderRegistry.class)。然后,我们在自定义输出拦截器中创建自定义STSClient:

Also, we achieved to dynamically switch between a Windows-mode xRM and claims-mode xRM system, by looking at the <ms-xrm:AuthenticationPolicy> element in the xRM WSDL's security policy, and check whether <ms-xrm:Authentication> contains either ActiveDirectory or Federation. We did this by creating a custom policy extension extending XmlPrimitiveAssertion and registering the corresponding custom builder in bus.getExtension(AssertionBuilderRegistry.class). Then we create the custom STSClient in a custom 'out interceptor':

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);
    }
}

最后,因为我们不想使用下载AD FS WSDL的版本,我们通过获取 SP12Constants.ISSUED_TOKEN 断言,获取其<$ c,在相同的输出拦截器中对该WSDL进行了修复。 $ c> .getIssuerEpr()。getMetadata()。getAny(),然后从 {http://www.w3.org/2005/08/addressing}地址。结果类似于 http://example.com:12345/adfs/services/trust / mex 。我们检索该URL,解析XML,如上所述添加< wsp:Policy /> 元素,将结果保存到文件中,然后将该文件的URL用作

Finally, since we did not want to work with a downloaded version of AD FS's WSDL, we did the 'fixing' of that WSDL in the same 'out interceptor', by getting the SP12Constants.ISSUED_TOKEN assertion , getting its .getIssuerEpr().getMetadata().getAny(), and from that the {http://www.w3.org/2005/08/addressing}Address. The result is something like http://example.com:12345/adfs/services/trust/mex. We retrieve that URL, parse the XML, add the <wsp:Policy/> elements as described above, save the result to a file, and use that file's URL as the STSClient's wsdlLocation.

希望这对其他人有帮助;如果您没有解决这个问题,请随时提出问题。

Hopefully this helps others; feel free to ask questions if you don't get this to work.

这篇关于适用于声明模式xRM的Apache CXF客户端(Microsoft Dynamics CRM 2011)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆