Monday, January 2, 2012

CXF and MS CRM 2011

Background
Early last year, Microsoft released a new version of their CRM product, Dynamics CRM 2011. My company has a Java product that integrates with MS CRM and we were successfully able to call the webservice that is included with CRM 2011 using SAML tokens. Everything was working great until we reconfigured CRM for on-premise authentication. In the previous version of MS CRM, the on-premise authentication used transport layer NTLM/Kerberos authentication which Java supports. With CRM 2011, however, Microsoft is using WCF 4.0 which uses message level NTLM/Kerberos based on SPNEGO WS-Trust. (Specification) We searched extensively, but could not find an implementation of this protocol for any open source Java Web Service framework. So I along with a coworker set out to implement this for CXF. After several weeks, we were successful and were able to invoke the CRM web service from Java. We submitted this functionality back to the CXF project. (JIRA) Recently, Colm O hEigeartaigh was kind enough to review the patch and integrate it into the trunk of the CXF codebase. (With some major refactoring to make it fit better) This works out of the box with the latest CXF code, but the configuration of this is far from trivial, so this blog post explains how to configure this new functionality.

CXF and MS CRM 2011
The first step in getting this all to work is to setup Java to authenticate using Kerberos with the Active Directory primary domain controller. This requires you to create a login.conf as follows:
spnego-client {
 com.sun.security.auth.module.Krb5LoginModule required;
};

and a krb5.conf as follows:
[libdefaults]
 default_realm = <NTdomain>
 default_tkt_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
 default_tgs_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
 permitted_enctypes   = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc

[realms]
 <NTdomain>  = {
  kdc = <PrimaryDomainController>
  default_domain = <NTdomain>
}

[domain_realm]
 .<NTdomain> = <NTdomain>

Then, in my Java code, I manually configure the following the system properies so that JAAS will use these files:
System.setProperty("java.security.auth.login.config", "C:\\projects\\login.conf");
   System.setProperty("java.security.krb5.conf", "C:\\projects\\krb5.conf");

CRM 2011 includes a custom policy element in the WSDL that needs to be asserted in CXF. If this is not done, CXF will error out because it doesn't have a policy provider to assert the custom policy. This custom policy can be asserted using the following classes, the first is the PolicyProvider itself:
public class XRMAuthPolicyProvider extends AbstractPolicyInterceptorProvider
{
 public XRMAuthPolicyProvider()
 {
   super(Arrays
     .asList(new QName[]{new QName("http://schemas.microsoft.com/xrm/2011/Contracts/Services",
       "AuthenticationPolicy", "ms-xrm")}));
   getInInterceptors().add(new XRMAuthPolicyInterceptor());
 }
}

and the second is the associated CXF interceptor:
public class XRMAuthPolicyInterceptor extends AbstractSoapInterceptor
{
 public XRMAuthPolicyInterceptor()
 {
   super(Phase.PRE_PROTOCOL);
   addAfter(PolicyBasedWSS4JInInterceptor.class.getName());
   addAfter(PolicyBasedWSS4JOutInterceptor.class.getName());
 }

 public void handleMessage(SoapMessage message) throws Fault
 {
   AssertionInfoMap aim = message.get(AssertionInfoMap.class);
   if (null == aim)
   {
     return;
   }
   QName qname = new QName("http://schemas.microsoft.com/xrm/2011/Contracts/Services",
     "AuthenticationPolicy", "ms-xrm");
   Collection ais = aim.get(qname);
   if (null == ais || ais.size() == 0)
   {
     return;
   }
   for (AssertionInfo ai : ais)
   {
     ai.setAsserted(true);
   }
 }
}

The policy provider can be added to web service client as follows:
   Client client = ClientProxy.getClient(port);
   Bus bus = ((EndpointImpl) client.getEndpoint()).getBus();
   PolicyInterceptorProviderRegistry pipr = bus
     .getExtension(PolicyInterceptorProviderRegistry.class);
   pipr.register(new XRMAuthPolicyProvider());

Once the policy provider is added, CXF needs to be configured to use Kerberos authentication. For my setup, I was using an Active Directory username and password, so I had to create an implementation of SpnegoClientAction that uses GSSName.NT_USER_NAME rather than the default GSSName.NT_HOSTBASED_SERVICE:
public class XRMSpnegoClientAction implements SpnegoClientAction
{
  private org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
    .getLog(DefaultSpnegoClientAction.class);

  protected String serviceName;
  protected GSSContext secContext;
  protected boolean mutualAuth;

  /**
   * Whether to enable mutual authentication or not.
   */
  public void setMutualAuth(boolean mutualAuthentication)
  {
    mutualAuth = mutualAuthentication;
  }

  /**
   * The Service Name
   */
  public void setServiceName(String serviceName)
  {
    this.serviceName = serviceName;
  }

  /**
   * Obtain a service ticket
   */
  public byte[] run()
  {
    try
    {
      GSSManager gssManager = GSSManager.getInstance();
      Oid oid = new Oid("1.3.6.1.5.5.2");

      GSSName gssService = gssManager.createName(serviceName, GSSName.NT_USER_NAME);
      secContext = gssManager.createContext(gssService, oid, null, GSSContext.DEFAULT_LIFETIME);

      secContext.requestMutualAuth(mutualAuth);
      secContext.requestCredDeleg(Boolean.FALSE);

      byte[] token = new byte[0];
      return secContext.initSecContext(token, 0, token.length);
    }
    catch (GSSException e)
    {
      if (log.isDebugEnabled())
      {
        log.debug("Error in obtaining a Kerberos token", e);
      }
    }

    return null;
  }

  /**
   * Get the GSSContext that was created after a service ticket was obtained
   */
  public GSSContext getContext()
  {
    return secContext;
  }
}

Then I added the following code to hook Kerberos into my web service client:
   // Active Directory domain username and password
   final String username = "<username>";
   final String password = "<password>";
   // Kerberos service provider name, e.g. RestrictedKrbHost/<computername>
   String spn = "RestrictedKrbHost/<crm_server>";
   // Kerberos JAAS client as configured in login.conf
   String jaasClient = "spnego-client";
   // Active Directory username and password
   CallbackHandler callbackHandler = new NamePasswordCallbackHandler(username, password);

   client.getRequestContext().put("ws-security.kerberos.jaas.context", jaasClient);
   client.getRequestContext().put("ws-security.kerberos.spn", spn);
   client.getRequestContext().put("ws-security.callback-handler", callbackHandler);
   client.getRequestContext().put("ws-security.spnego.client.action", new XRMSpnegoClientAction());

Once the custom policy provider is added and the Kerberos authentication is setup, the client configuration is complete.

For reference, the complete client code example is below:
   URL wsdlURL = OrganizationService.WSDL_LOCATION;

   System.setProperty("java.security.auth.login.config", "C:\\projects\\login.conf");
   System.setProperty("java.security.krb5.conf", "C:\\projects\\krb5.conf");

   // Active Directory domain username and password
   final String username = "<username>";
   final String password = "<password>";
   // Kerberos service provider name, e.g. RestrictedKrbHost/<computername>
   String spn = "RestrictedKrbHost/<crm_server>";
   // Kerberos JAAS client as configured in login.conf
   String jaasClient = "spnego-client";
   // Active Directory username and password
   CallbackHandler callbackHandler = new NamePasswordCallbackHandler(username, password);

   OrganizationService ss = new OrganizationService(wsdlURL, SERVICE_NAME);
   IOrganizationService port = ss.getCustomBindingIOrganizationService();

   Client client = ClientProxy.getClient(port);
   Bus bus = ((EndpointImpl) client.getEndpoint()).getBus();
   PolicyInterceptorProviderRegistry pipr = bus
     .getExtension(PolicyInterceptorProviderRegistry.class);
   pipr.register(new XRMAuthPolicyProvider());

   client.getRequestContext().put("ws-security.kerberos.jaas.context", jaasClient);
   client.getRequestContext().put("ws-security.kerberos.spn", spn);
   client.getRequestContext().put("ws-security.callback-handler", callbackHandler);
   client.getRequestContext().put("ws-security.spnego.client.action", new XRMSpnegoClientAction());

   // call webservice
   ColumnSet colSet = new ColumnSet();
   colSet.setAllColumns(true);
   colSet.setColumns(new ArrayOfstring());
   QueryByAttribute qba = new QueryByAttribute();
   qba.setEntityName("account");
   qba.setColumnSet(colSet);
   ArrayOfstring aos2 = new ArrayOfstring();
   aos2.getString().add("accountid");
   qba.setAttributes(aos2);
   ArrayOfanyType aoat = new ArrayOfanyType();
   aoat.getAnyType().add("2D08FEC1-9734-E111-9454-000C295D5DEA");
   qba.setValues(aoat);
   EntityCollection entityCol = port.retrieveMultiple(qba);
   List props = entityCol.getEntities().getEntity().get(0)
     .getAttributes().getKeyValuePairOfstringanyType();
   for (KeyValuePairOfstringanyType prop : props)
   {
     if ("name".equals(prop.getKey()))
     {
       System.out.println(prop.getKey() + " = " + prop.getValue());
     }
   }

Since our team spent several weeks working on this example, I hope this walkthrough is helpful for other developers out there. This will not only work for CRM 2011, but any WCF webservice that uses message level NTLM/Kerberos authentication.

**Update (2013-08-26)** With newer versions of CXF (tested against CXF 2.6.9) it is necessary to include a bindings file when generating the client code using wsdl2java:
<jaxb:bindings version="2.1"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jaxb:globalBindings generateElementProperty="false" mapSimpleTypeDef="true"/>
</jaxb:bindings>

93 comments:

  1. Tom, could you provide more information about your IIS configuration. I acquired TGT using AS, and -commit succeeded.
    Then i have such exception:
    org.apache.cxf.interceptor.Fault: General security error (An error occurred in trying to obtain a service ticket)

    Thanks!

    ReplyDelete
    Replies
    1. Hi Dimitry, have you solved this problem? We're facing the same.

      Delete
  2. Sadly, I was not involved in setting up the MS CRM instance. That was handled by our netops team, so I don't have access to those details.

    ReplyDelete
    Replies
    1. Hurray!!! Successfully connected to MS CRM on premise. This is a great article...very helpful. Thanks Tom!

      Delete
  3. Hi tom,
    in your class XRMSpnegoClientAction you implements SpnegoClientAction but in wss4j SpnegoClientaction is a claas

    Can you help me to resolve the problem ?

    Thanks

    ReplyDelete
  4. You need the very latest trunk code for wss4j. If you look at trunk, it is an interface in the latest version:

    http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/spnego/SpnegoClientAction.java?revision=1227128&view=markup

    This is all very bleeding edge, so you'll need the trunk versions of both CXF and wss4j.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. Thank you, Tom!
    Nice work, helpful message.
    But unfortunately I've faced a problem:
    my (ColumnSet) colSet variable has not a method setEntityName(String), but a setEntityName(JAXBElement&<String>) instead.
    It concerns also several analogous setters.
    Wat's wrong?
    I've generated from wsdl using cxf library.
    Thank you.

    ReplyDelete
  7. Ok, I've fixed previous type mismatch problem by creating corresponding JAXBElement<T> type variables instead of T type
    using values of @XmlElementRef notations in corresponding classes of package com.microsoft.schemas.xrm._2011.contracts.
    But when running the sample, I've faced with error at the earliest stages of it.
    Namely, at the line where IOrganizationService port is being obtained (it's just line 47 in my ServiceTest.java):
    IOrganizationService port = ss.getCustomBindingIOrganizationService()
    the exception appears:
    -----------
    java.lang.NoSuchFieldError: QUALIFIED
    at org.apache.cxf.service.model.SchemaInfo.setSchema(SchemaInfo.java:146)
    at org.apache.cxf.wsdl11.SchemaUtil.extractSchema(SchemaUtil.java:136)
    at org.apache.cxf.wsdl11.SchemaUtil.getSchemas(SchemaUtil.java:81)
    at org.apache.cxf.wsdl11.SchemaUtil.getSchemas(SchemaUtil.java:65)
    ............
    at org.apache.cxf.jaxws.ServiceImpl.createPort(ServiceImpl.java:465)
    at org.apache.cxf.jaxws.ServiceImpl.getPort(ServiceImpl.java:332)
    at org.apache.cxf.jaxws.ServiceImpl.getPort(ServiceImpl.java:319)
    at javax.xml.ws.Service.getPort(Service.java:92)
    at com.microsoft.schemas.xrm._2011.contracts.OrganizationService.getCustomBindingIOrganizationService(OrganizationService.java:65)
    at com.mypackage.msdynamics.onpremise.ServiceTest.run(ServiceTest.java:47)
    -----------
    Can anyone help me and explain what goes wrong?
    Thank you.

    ReplyDelete
  8. Double check your JAXB version. The JAXB version used with the latest version of CXF is newer than what comes with the JDK 6. It takes some effort to get it all working because of this. (The JAXB jars have to be 'endorsed' to override what comes with the JDK) If that doesn't resolve the issue, it may help to look at the cxf source at the line in error--it might give you some ideas on what's wrong. This is all very experimental, so you definitely have to get your hands dirty to get it all working.

    ReplyDelete
  9. Tom, thank you.
    At least now I know where to start.

    ReplyDelete
  10. Hi, Tom.
    Thanks to your previous advice, I've solved my problem with type inconsistency and simultaneously have overcome some another problems with inappropriate libraries and cast type errors.
    But I'm stacking now because of null value of the pipr variable: my bus is occurred not to have an extension of type PolicyInterceptorProviderRegistry:

    PolicyInterceptorProviderRegistry pipr = bus
    .getExtension(PolicyInterceptorProviderRegistry.class); // -----> null

    Can you suppose, please, what's wrong?
    Any idea may be helpful.
    Thank you.

    ReplyDelete
  11. Hmm, not sure. I was always able to get the PolicyInterceptorProviderRegistry without issue. It might be a new change with the latest code or something might not be getting initialized properly. You'll have to debug through the code to see where that gets initialized in CXF--I'm not familiar with that part of the code.

    ReplyDelete
  12. Hello Tom,


    I've tried to execute your code, but I've got 2 warnings:

    19.09.2012 15:54:51 org.apache.cxf.ws.policy.AssertionBuilderRegistryImpl handleNoRegisteredBuilder
    WARNING: No assertion builder for type {http://schemas.microsoft.com/xrm/2011/Contracts/Services}AuthenticationPolicy registered.


    19.09.2012 15:54:54 org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
    WARNING: Interceptor for {http://schemas.xmlsoap.org/ws/2005/02/trust/wsdl}SecurityTokenService#{http://schemas.xmlsoap.org/ws/2005/02/trust/wsdl}RequestSecurityToken has thrown exception, unwinding now
    org.apache.cxf.interceptor.Fault: Unexpected element {http://schemas.xmlsoap.org/ws/2005/02/trust}RequestSecurityTokenResponseCollection found. Expected {http://schemas.xmlsoap.org/ws/2005/02/trust}RequestSecurityTokenResponse.

    The programm aborts at the line:

    EntityCollection entityCol = port.retrieveMultiple(qba);

    I've used eclipse juno, jdk 1.6.35 64bit and cxf 2.6.2

    I have no idea, what's wrong with the code and I can't find the error by debugging. I have used the code from the homepage, only the credential and connection-entries are changed.

    Have you any idea?

    Thank you.

    ReplyDelete
  13. Looks like CXF didn't like the response from CRM. What version of CRM are you using? Also, you might want to compare the response to what CXF is expecting. (It wouldn't surprise me is there are valid responses that CXF isn't handling properly)

    ReplyDelete
  14. hi Tom!
    We at our company are looking to integrate the CRM 2011 webservice from a java application. We do not have the on-premise authentication setup because this is not needed.

    Can you give me some more information on how you managed to communicate with the webservice using SAML tokens?
    thank you very much!!

    ReplyDelete
  15. Hi Tom,

    I have the same problem at the same point as jja77 =/

    This is where it goes wrong according to the logs :

    FEIN: Invoking handleMessage on interceptor org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor@6ec44aaf
    11.10.2012 20:40:56 org.apache.cxf.phase.PhaseInterceptorChain doIntercept
    FEIN: Invoking handleMessage on interceptor org.apache.cxf.interceptor.URIMappingInterceptor@2c91e143
    11.10.2012 20:40:56 org.apache.cxf.interceptor.URIMappingInterceptor handleMessage
    FEIN: Invoking HTTP method null
    11.10.2012 20:40:56 org.apache.cxf.interceptor.URIMappingInterceptor handleMessage
    FEIN: URIMappingInterceptor can only handle HTTP GET, not HTTP null
    11.10.2012 20:40:56 org.apache.cxf.phase.PhaseInterceptorChain doIntercept
    FEIN: Invoking handleMessage on interceptor org.apache.cxf.interceptor.DocLiteralInInterceptor@2d83e895
    11.10.2012 20:40:56 org.apache.cxf.phase.PhaseInterceptorChain unwind
    FEIN: Invoking handleFault on interceptor org.apache.cxf.interceptor.DocLiteralInInterceptor@2d83e895
    11.10.2012 20:40:56 org.apache.cxf.phase.PhaseInterceptorChain unwind

    any thoughts on this?

    ReplyDelete
  16. I really have no idea. I don't think we ran into anything like that. I don't have access to the CRM environments anymore, did you look at the request/response in Fiddler? That might give you some idea about what's going on. (Or turning up the logging for CXF to see if there's any clues there)

    ReplyDelete
  17. Hi Tom,

    just FYI the problem seems to be this:

    org.apache.cxf.interceptor.Fault: Unexpected element {http://schemas.xmlsoap.org/ws/2005/02/trust}RequestSecurityTokenResponseCollection found. Expected {http://schemas.xmlsoap.org/ws/2005/02/trust}RequestSecurityTokenResponse.

    now I looked at the schema at http://schemas.xmlsoap.org/ws/2005/02/trust
    for ws-trust.

    There he seems to find this Collection of responses:


    instead of just a singular response.

    Any thoughts on this =/?

    ReplyDelete
  18. Somehow i cannot post the xml here..... =/

    so I´ll put it in words.

    At the http://schemas.xmlsoap.org/ws/2005/02/trust xml he finds a RequestSecurityTokenResponseCollection element instead of a singular RequestSecurityTokenResponse element.

    ReplyDelete
  19. I would take this issue up with the CXF user list. Seems like either CXF isn't doing something correctly or there might be more configuration needed. I haven't looked at the code recently enough to be of any help.

    ReplyDelete
  20. Hi Tom,
    maybe I can get your input on our login.conf file.
    This is what we use:

    spnego-client {
    com.sun.security.auth.module.Krb5LoginModule
    required
    useSubjectCredsOnly=false
    useTicketCache=true
    doNotPrompt=true;
    };

    What´s your take on this?

    ReplyDelete
  21. Here's what I used--you'll have to substitute your values for your windows domain.

    login.conf:
    spnego-client {
    com.sun.security.auth.module.Krb5LoginModule required;
    };

    krb5.conf (if EXAMPLE.COM is the windows domain suffix):
    [libdefaults]
    default_realm = EXAMPLE.COM
    default_tkt_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
    default_tgs_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc
    permitted_enctypes = aes128-cts rc4-hmac des3-cbc-sha1 des-cbc-md5 des-cbc-crc

    [realms]
    EXAMPLE.COM = {
    kdc =
    default_domain = EXAMPLE.COM
    }

    [domain_realm]
    .EXAMPLE.COM = EXAMPLE.COM

    We forced these files to be used by explicitly setting the properties in our client code:
    System.setProperty("java.security.auth.login.config", "C:\\projects\\login.conf");
    System.setProperty("java.security.krb5.conf", "C:\\projects\\krb5.conf");

    ReplyDelete
  22. Sorry the realms section above was mangled by the filters:
    [realms]
    EXAMPLE.COM = {
    kdc = <WINDOWS_DOMAIN_CONTROLLER>
    default_domain = EXAMPLE.COM
    }

    ReplyDelete
  23. Hmm ... we have the same... =/

    Crm 2011 is working with WS-Trust 1.3 right?

    ReplyDelete
  24. I just tried this with the latest CXF (2.7.0) and I get the same exception as you:

    Caused by: org.apache.cxf.interceptor.Fault: Unexpected element {http://schemas.xmlsoap.org/ws/2005/02/trust}RequestSecurityTokenResponseCollection found. Expected {http://schemas.xmlsoap.org/ws/2005/02/trust}RequestSecurityTokenResponse.

    Looks like some of the changes to the STSClient didn't make it in or aren't working correctly. It would be best to submit this as a bug to CXF itself. Here's a link to the original SPNEGO patch:
    https://issues.apache.org/jira/browse/CXF-3635

    ReplyDelete
  25. Hi Tom,

    thanks for the patch info.
    We have implemented it and seem to have gotten a little further, at least as far as my understanding is concerned^^.

    But I cannot find the apache cxf version that you seemed to have been working with.

    I have tried many and always received a different build error.
    I could build it with version 2.3.8 and some own changes to the code.

    What version did you use?

    ReplyDelete
  26. The code seems to work out of the box with cxf 3.5.0

    But I have received following error :

    None of the policy alternatives can be satisfied.
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:146)
    at $Proxy45.execute(Unknown Source)
    at com.example.spnego.Main.main(Main.java:121)

    I assume the SpnegoSTSClient who builds the XML to request the SecurityToken is not able to match crm´s policy?

    ReplyDelete
  27. Where did you get CXF 3.5.0? (typo maybe?) The latest version I see on the download page is 2.7.0: http://cxf.apache.org/download.html

    ReplyDelete
  28. Oh sorry,

    indeed a typo^^.
    I meant cxf 2.3.5

    Does this scenario also work for AD-authentication without sts?


    ReplyDelete
  29. Jair, this is AD-authentication without sts. The STSClient is used to negotiate SPNEGO directly with the endpoint. We're just reusing a lot of the code in the STSClient because the requests/responses are the same as talking to an STS.

    ReplyDelete
  30. OK,

    do you have any idea why I receive the policy exception =/?

    ReplyDelete
  31. Are you sure you have the policty provider registered?

    pipr.register(new XRMAuthPolicyProvider());

    If the policy provider isn't there, I get the same exception.

    ReplyDelete
  32. I was finally able to get this working using CXF 2.7.0. I had to add the following to disable the additional validation that's happening with the new version of CXF. (There might be an easier way to set this property, but this is the only way I found to get it to work)

    STSClient sts = new STSClient(bus);
    sts.setFeatures(Arrays.asList(new Feature()
    {
    @Override
    public void initialize(Server server, Bus bus)
    {
    }
    @Override
    public void initialize(Client client, Bus bus)
    {
    ServiceInfo si = client.getEndpoint().getEndpointInfo().getService();
    si.setProperty("soap.force.doclit.bare", true);
    }
    @Override
    public void initialize(InterceptorProvider interceptorProvider, Bus bus)
    {
    }

    @Override
    public void initialize(Bus bus)
    {
    }
    }));
    client.getRequestContext().put("ws-security.sts.client", sts);

    ReplyDelete
    Replies
    1. You could also do the following instead:

      public void initialize(Client client, Bus bus) {
      bus.getProperties().put("soap.no.validate.parts", true);
      }

      I prefer it because the property name is more explicit in what you are try to achieve.

      Delete
  33. Hi Tom, this indeed solved the issue RSTR Collection in cxf 2.7.0 =)
    does this only return the second leg in spnego ? Or why is the response suddenly not a collection anymore.

    My problems don´t seem to come to an end though. now that I applied your fix for the RSTR-C issue i get this error :

    org.apache.cxf.ws.policy.PolicyException: Cannot encrypt data
    at org.apache.cxf.ws.security.wss4j.policyhandlers.AbstractBindingBuilder.policyNotAsserted(AbstractBindingBuilder.java:290)

    Is this a password encryption problem?

    P.S: Sorry to keep bugging you with my problems.
    I am kind of new to the whole Java to CRM thing and you are the only one who could give me any good answers so far.

    ReplyDelete
  34. Jair, the response is still a RSTR Collection, it just skips the extra validation that is throwing the exception. I truly think this is a bug and it should expect both a RSTR or a RSTR Collection, but it would take more investigation to prove that.

    I don't think it's a password encryption problem. I think you need to install the Java Cryptography Extensions Unlimited Strength Jurisdiction Policy for the JRE/JDK you're using. CRM requires stronger encryption than what the JRE/JDK can do by default.

    ReplyDelete
  35. Hi Tom,

    thanks for the information.

    Regarding the Cryptography library i found the following:

    if i don´t add the Cryptography Extensions i get this error in the log:

    java.lang.ClassNotFoundException: org.bouncycastle.jce.provider.BouncyCastleProvider

    If i copy the Cryptography extensions jar files into my jdk\lib folder the above exception vanishes, but my problem still persists in the same way.

    i use jre6 and the respective Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6

    ReplyDelete
  36. Try removing the bouncy castle jars from your classpath. The newer JDK's come with a JCE provider, so bouncy castle shouldn't be necessary. (And it seems like bouncy castle impl is not unlimited strength which might be why it's still failing for you)

    ReplyDelete
  37. Hi Tom,
    I had aleady removed the bouncy castle jars when I added the Cryptography extensions to my runtime lib folder.

    this is what my class path looks like:
    (I ad to remove the ">" and "<" because of the filters =/)

    xml version="1.0" encoding="UTF-8"
    classpath
    classpathentry kind="src" path=""/
    classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/
    classpathentry kind="con" path="org.eclipse.jst.ws.cxf.core.CXF_CLASSPATH_CONTAINER/Apache CXF/2.7.0"
    attributes
    attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/
    /attributes
    /classpathentry
    classpathentry kind="lib" path="C:/Apps/Dev/apache-cxf-2.7.0/bin"/
    classpathentry kind="output" path=""/
    /classpath"

    is there any way to force cxf to use the cryptography extensions?

    ReplyDelete
  38. Btw,

    does this encryption problem have anything to do with using Using X.509 Certificates?

    Because in our scenario there is no certificate involved. I was reading the
    http://cxf.apache.org/docs/ws-security.html documentation and could only find information on encryption regarding certificates.

    Do I have to set some property in cxf on false so it doesn´t try to use a certificate, or does cxf have a fallback mechanism for this case?

    ReplyDelete
  39. To me the error resembles this one a lot:

    https://jira.talendforge.org/browse/TESB-3768?page=com.atlassian.jira.plugin.system.issuetabpanels%3Achangehistory-tabpanel

    ReplyDelete
  40. Jair, it's hard to say what might be causing it since I can't reproduce this. It's working for me and we've checked all the obvious stuff. Your best bet is to grab the source code for CXF and debug through this issue to see where it's getting hung up. There might be a root cause to the exception or you might find more information about what's going wrong.

    Another thing you might want to try is to create a stand-alone Java program rather than running this within a war project. That's what I typically do to get it working first before I integrate it into a project. It's easier to debug and quicker to try different things.

    ReplyDelete
    Replies
    1. Hi Tom,
      thanks for your answer on a saturday =). I will look into the cxf code and try debug it to find the root cause for my exception.

      I am thinking I might be doing something wrong outside of the cxf code. Can you maybe post an examlple of the OrganizationRequest you sent to your crm server to test the connection?

      Because i just send a WhoAmI request like this:
      URL wsdlURL = OrganizationService.WSDL_LOCATION;
      OrganizationService ss = new OrganizationService(wsdlURL);
      IOrganizationService port = ss.getCustomBindingIOrganizationService();
      OrganizationRequest tmp = new OrganizationRequest();
      tmp.setRequestName("WhoAmI");
      port.execute(tmp);

      Delete
  41. Hi Tom,

    I have tried to get the cxf source code running,
    but many classes are missing in the svn trunk.
    Like org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
    and
    org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;

    Are those classes located elsewhere?

    ReplyDelete
  42. Those are part of wss4j, a separate project:
    http://ws.apache.org/wss4j/

    ReplyDelete
  43. Hi Tom,

    i assume you have already once imported the cxf lib into eclipse. On the cxf website it says, that when you checkout the trunk from svn at
    http://svn.apache.org/repos/asf/cxf/trunk ,
    you can import all the subprojects into eclipse.
    My eclipse doesn´t find any projects inside the whole trunk =/

    Am I missing something here? Because i tried to import the cxf.apache* packages manually, but the load of errors make it practically impossible to get the code running this way.

    ReplyDelete
  44. Hi Tom,

    just ignore my last question. I have solved the encryption issue.

    I now get an unmarshalling error because of

    WARNING: Interceptor for {http://schemas.microsoft.com/xrm/2011/Contracts}OrganizationService#{http://schemas.microsoft.com/xrm/2011/Contracts/Services}Execute has thrown exception, unwinding now
    org.apache.cxf.interceptor.Fault: Unmarshalling Error: unknown typename: {http://schemas.microsoft.com/2003/10/Serialization/}guid

    It seems like I am an unlucky guy :D

    ReplyDelete
    Replies
    1. Hi Jair,

      I too am facing the encryption issue. Are you able to share how you went about solving the problem?

      Thanks (And also thanks to Tom for this very useful article!)

      Delete
    2. Hi Matthew,

      Sorry for my late answer here.
      If you are facing the encryption issue, you will have to install the "Java Cryptographic Extensions unlimited strength" for the JRE you are using.
      In this case installing means replacing the "local_policy.jar" and "US_export_policy.jar" in the security folder of your JRE with the ones delivered with the JCE Unlimited strength package.

      After that you should be aware, that if the problem still persists - although you replaced the JCE with JCE Unl. strength - the organization request that you use is probably faulty.

      Please let me know if this solved your problem

      Delete
  45. When I look at the
    http://schemas.microsoft.com/2003/1/Serialization/
    schema, there is indeed no element called "guid".

    how did you work around this issue?
    Did you bind guid to String somehow?

    ReplyDelete
  46. I have this in my Object factory in the respective schema:

    private final static QName _Guid_QNAME = new QName("http://schemas.microsoft.com/2003/10/Serialization/", "guid");

    ReplyDelete
  47. Here's an example request that's working for me:
    ColumnSet columnSet = new ColumnSet();
    columnSet.setAllColumns(true);
    columnSet.setColumns(new ArrayOfstring());
    Guid guid = new Guid();
    guid.setValue("{GUID_AS_STRING}"); // replace with your guid
    Entity entity = port.retrieve("account", guid, columnSet);

    ReplyDelete
  48. Hi Tom,

    when I generate my classes from the organization wsdl, it doesn´t generate the Class Guid you seem to have. I assume you used a binding file. when u generated the wsdl classes, to bind the jaxb components. Can you maybe post your bindings.txt?

    ReplyDelete
  49. Hi Tom,

    I have found the problem.
    Somehow when i create my java classes from the organization wsdl, Guid and other classes aren´t built. But the unmarshaller can only unmarshall through the object factory of com.microsoft.schemas._2003._10_serialization, which should refer to classes like "Guid" "Duration" etc. But it binds these classes to String =/. Is this a JAXB Binding issue? how does your binding.txt look?

    ReplyDelete
  50. I don't remember doing anything special when generating the java classes from the wsdl. (no binding.txt needed) Are you sure you're using the correct wsdl?

    ReplyDelete
  51. I'm actually having the same problem as Jair, no Guid class was generated. Have you already solved this issue? I generated the classes using this wsdl urls:

    wsdl2java -client -b javabindings.xml http://localhost:5555/Demo/XRMServices/2011/Organization.svc?wsdl

    The "Demo" part in the URL is the name of my CRM-organization.
    I had to use a binding file in order to avoid JAXBElement<String> bindings. The binding file I used is the following:


    <jaxb:bindings version="2.1"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jaxb:globalBindings generateElementProperty="false"/>
    </jaxb:bindings>

    ReplyDelete
  52. I couldn't get the wsdl2java to generate those classes
    either. At the end I just wrote the classes I needed myself, what isn't difficult. Just define your class with the right name and specify a Return method method with the data type you need. You can take a look at the generated Array type classes for a draft

    ReplyDelete
  53. Hello Tom,

    I'm currently building an integration to Microsoft CRM using java, i'm having lots of problems. Can you point me to any documentation about the webservices classes that are generated from the wsdl2java?
    At this point in time, i can not rewrite in java this lines of C#

    Owner owner = new Owner();
    owner.type = EntityName.systemuser.ToString();
    owner.Value = user.UserId;

    Can you help me?

    thx

    ReplyDelete
  54. I have an example CRM call in this very blog, check the 2nd half of the last code block. We didn't do much with owner, our work was more around the Contact, Quote and Opportunity entities.

    ReplyDelete
  55. Hi Miguel,

    to change owner you have to fire an Organization Request with RequestName="Assign" and two Parameters: Assignee and Target, both EntityReferences

    ReplyDelete
  56. Thx Tom,

    I've solved my problem using an entity reference to the "systemuser" entity.

    Do you have any kind of documentation about the java classes generated by the wsdl2java?

    regards

    ReplyDelete
  57. Not really. Microsoft has documentation on their webservices, but it will be generic and not specific to what the jaxb generated classes. That's the closest you'll find, but you have to translate it a bit to get it to work with the wsdl2java generated classes.

    ReplyDelete
  58. Hi Tom,

    thank you for this blog! I am now able to access the webservie without problems. A hint for anybody trying to access the CRM 2011 Webservice with SSL enabled is to use the new CXF Version 2.7.3 as documented here https://issues.apache.org/jira/browse/CXF-4758

    ReplyDelete
  59. Hi Tom and the rest,

    I have been struggling with this for quite some time and have managed to get it working somehow. When I provide a valid request, e.g. a Retrieve with an Id that exists, I do get a valid response. However if I change that retrieve using an id that does not exist I get an error. The service is returning a SOAP Fault as far as I understand, at least it is an HTTP 500 message, but the client fails to handle the SoapFault.

    Here are some of the error messages:
    org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor handleMessage
    WARNING:
    org.apache.ws.security.WSSecurityException: The signature or decryption was invalid
    at org.apache.ws.security.processor.SignatureProcessor.verifyXMLSignature(SignatureProcessor.java:450)

    ...

    Caused by: org.apache.ws.security.WSSecurityException: The signature or decryption was invalid
    at org.apache.ws.security.processor.SignatureProcessor.verifyXMLSignature(SignatureProcessor.java:450)
    at org.apache.ws.security.processor.SignatureProcessor.handleToken(SignatureProcessor.java:231)
    at org.apache.ws.security.WSSecurityEngine.processSecurityHeader(WSSecurityEngine.java:396)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:274)
    ... 19 more
    javax.xml.ws.soap.SOAPFaultException: The signature or decryption was invalid
    at org.apache.cxf.jaxws.DispatchImpl.mapException(DispatchImpl.java:287)
    at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:392)
    at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:243)

    ...

    Caused by: org.apache.cxf.binding.soap.SoapFault: The signature or decryption was invalid
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.createSoapFault(WSS4JInInterceptor.java:760)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:331)
    at org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor.handleMessage(WSS4JInInterceptor.java:93)


    I have Googled this and found a some references to this specifying that it might be a bug in wss4j or xmlsec. I am using wss4j-1.6.9.jar and xmlsec-1.5.4.jar.

    I see that Jair mentions a similar error message above and suggests that providing a correct request will fix it.
    My request is valid, the only difference between a successful response and an unsuccessful is that I provide an Id that does not exist in CRM.
    The client should be able to handle a SoapFault.

    Any ideas?

    Regards
    Ørjan

    ReplyDelete
    Replies
    1. Hi Ørjan,

      i have experienced your problem too. I think the problem is, that CRM does not encrypt its response if it is a fault. My solution was to install a FaultInterceptor which gets the original (unencrypted) SOAP-Message, extracts the fault cause, and creates a new SoapFault containing the real reason of fault.

      This is only a workaround, but at least it returns senseful information.

      public class CRMFaultInterceptor extends AbstractSoapInterceptor {

      public CRMFaultInterceptor() {
      super(Phase.PRE_PROTOCOL);

      addBefore(PolicyBasedWSS4JInInterceptor.class.getName());

      @Override
      public void handleMessage(SoapMessage arg0) throws Fault {

      }

      @Override
      public void handleFault(SoapMessage m) {
      XMLStreamReader reader = m.getContent(XMLStreamReader.class);
      W3CDOMStreamReader w3r = (W3CDOMStreamReader) reader;
      String errorMessage = null;
      if (w3r != null) {
      try {
      while (w3r.hasNext()) {
      w3r.next();
      if (w3r.getCurrentNode().getLocalName().equals("Body")) {
      NodeList l = w3r.getCurrentNode().getChildNodes();
      for (int i = 0; i < l.getLength(); i++) {
      Node n = l.item(i);
      if (n.getLocalName().equals("Fault")) {
      NodeList l1 = n.getChildNodes();
      for (int j = 0; j < l1.getLength(); j++) {
      Node n1 = l1.item(j);
      if (n1.getLocalName().equals("Reason")) {
      NodeList l2 = n1.getChildNodes();
      for (int k = 0; k < l2.getLength(); k++) {
      Node n2 = l2.item(k);
      if (n2.getLocalName()
      .equals("Text")) {
      errorMessage = n2
      .getTextContent();

      }
      }
      }

      }
      }
      }
      }

      }

      if (errorMessage != null) {

      Exception e = m.getContent(Exception.class);

      if (e instanceof SoapFault) {
      SoapFault fault = (SoapFault) e;

      SoapFault newFault = new SoapFault(errorMessage, fault,
      fault.getFaultCode());
      m.setContent(Exception.class, newFault);
      }

      }

      } catch (XMLStreamException e) {
      e.printStackTrace();
      }
      }

      }

      Delete
    2. Sorry, while copying i lost two brackets, one after the constructor and one at the very end.

      Delete
    3. This comment has been removed by the author.

      Delete
  60. The response I get is encrypted. That's why I'm assuming it is a SOAP fault since it is a http 500 and I'm not able to un-encrypt it.

    ReplyDelete
  61. Hi again,

    I've debugged this a bit further by enabling logging in CXF.
    It fails while validating the signature of the body element in the response, below is an excerpt from the log. It doesn't matter what the actual error from CRM is, it fails as long as it is a Fault.

    11.apr.2013 11:02:47 org.apache.jcp.xml.dsig.internal.DigesterOutputStream write
    FINE: <s:Body xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" u:Id="_2"><env:Fault><Code xmlns="http://www.w3.org/2003/05/soap-envelope"><Value>Sender</Value><Subcode><Value>a:DeserializationFailed</Value></Subcode></Code><Reason xmlns="http://www.w3.org/2003/05/soap-envelope"><Text xml:lang="nb-NO">The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://schemas.microsoft.com/xrm/2011/Contracts/Services:id. The InnerException message was 'There was an error deserializing the object of type System.Guid. The value 'F9D6E5AE-2032-E211-88C7-005056004C9X' cannot be parsed as the type 'Guid'.'. Please see InnerException for more details.</Text></Reason></env:Fault></s:Body>
    11.apr.2013 11:02:47 org.apache.jcp.xml.dsig.internal.dom.DOMReference validate
    FINE: Expected digest: UXn4DGytwBUfvXX2naORgG76jvk=
    11.apr.2013 11:02:47 org.apache.jcp.xml.dsig.internal.dom.DOMReference validate
    FINE: Actual digest: NzKaDWYL/OZ7mkGXYLtwVh4KMXk=
    11.apr.2013 11:02:47 org.apache.jcp.xml.dsig.internal.dom.DOMXMLSignature validate
    FINE: Reference[#_2] is valid: false

    I haven't validated that the message/signature from CRM is correct, but I would assume that it is correct and that it is CFX, wss4j or xmlsec which somehow messes this up?
    I have updated my client using the latest CXF (2.7.4), wss4j (1.6.10) and xmlsec (1.5.4).

    Regards
    Ørjan

    ReplyDelete
  62. Hi Tom,

    This is actually brilliant, one question though:

    All these really look liked you are actually using Kerberos auth in the end.

    So my question: is this ok or is there an actual way to enforce NTLM authentication?

    What I don't understand is that at the beginning of your post you talk about NTLM/KERBEROS but then the code seems to use only kerberos auth.

    Thanks in advance

    ReplyDelete
  63. We tried, but were never able to get NTLM working. Only Kerberos is works with this setup.

    ReplyDelete
  64. Hi Tom,

    Thank you for the blog and I appreciate all the comments. The information has helped me immensely. I'm now at the same point as Thomas and Jair were in that I'm receiving an unmarshalling error because wsdl2java did not create the Guid class.

    I'm using the same binding file as Thomas was above to avoid JAXBElement bindings, however it does not generate all of the classes.

    Do you remember what syntax you used with wsdl2java? Also did Jair ever share the sample Guid class? I'm using cxf2.7.6 and CRM 2011 rollup 14 if that makes any difference.

    Thanks,

    Brennan

    ReplyDelete
  65. Brennan,
    I'm having the same issue with CXF 2.6.9 and CRM 2011 rollup 11. The generated JAXB classes are definitely different in the newer version of CXF. (or the MS schemas have changes)
    Tom

    ReplyDelete
  66. Tom,

    Thanks for trying. I've created a new MSCRM 2011 instance without the roll-up's and I will try and earlier version of CXF to see if that makes a difference.

    I did try with xmlbeans binding and that generated all of the classes, but xmlbeans is definitely not as easy to work with as jaxb.

    Thanks,

    Brennan

    ReplyDelete
  67. Tom,

    I tried xmlbeans and I decided to spend more time trouble shooting the jaxb binding issue. I looked at the MSCRM wsdl and noticed that the classes were not being generated for simple types. I found an article that mentions that unless simple types are enumerations, they are not generated into java classes. The article also mentions how to create a binding file with a flag to generate the classes. I tried the flag and all of the classes are now being generated for me and this is against CRM 2011 rollup 14 and cxf 2.7.6.

    Link to generating Java classes for simple types:
    http://fusesource.com/docs/esb/4.2/jaxws/JAXWSCustomTypeMappingSimple.html

    Sample bindings file:




    Hopefully this helps you and others that are reading your blog.

    Thanks,

    Brennan

    ReplyDelete
  68. Its looks like my bindings xml was removed. Basically you need to create a bindings file which has flag mapSimpleTypeDef and that flag needs to be set to "true". Below is the line that I have in my bindings which generates all classes and also addresses the JAXBElement issue.

    jaxb:globalBindings generateElementProperty="false" mapSimpleTypeDef="true"

    Thanks,

    Brennan

    ReplyDelete
  69. Nice work!

    This made it work for me. I've updated the blog post to include the bindings.xml that I used.

    ReplyDelete
  70. Tom,

    Thanks for the update. It looks like there is a unmarshalling issue for picklists (OptionSetValue) possible due to namespaces? Have you been able to retrieve columns on entities that are configured as picklists?

    Thanks,

    Brennan

    ReplyDelete
    Replies
    1. Brennan,

      I am getting the same exception. Did you resolve it? I tried disabling the validation altogether but no luck.

      ((BindingProvider)port).getRequestContext().put("schema-validation-enabled", "false");

      Delete
  71. To be honest, we haven't been doing a lot of active development on CRM lately. It's been several years since I've had to do any significant work with the CRM webservices.

    ReplyDelete
  72. This comment has been removed by the author.

    ReplyDelete
  73. This comment has been removed by the author.

    ReplyDelete
  74. We have to struggle for almost three weeks to make
    the Java Client for CRM Dynamics 2011 work.
    Special Thanks to Groovy Tom for writing such a good Blog.
    Also to all the comments given by Alessandro Nisticò, Jair and Thomas
    Without which the task will never be completed.

    Sardar Saikh.

    ReplyDelete
  75. Hi all,

    i tried the above method and got this error, i am stuck from last two weeks with this issue, not able to go next step at all..

    Do i need to configure the metadata exchange services separately??

    Please help me..


    INFO: Creating Service {http://www.w3.org/2009/09/ws-mex}MetadataExchangeService from class org.apache.cxf.ws.mex.MetadataExchange
    Jan 17, 2014 11:28:11 AM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
    WARNING: Interceptor for {http://www.w3.org/2009/09/ws-mex}MetadataExchangeService#{http://www.w3.org/2009/09/ws-mex}Get2004 has thrown exception, unwinding now
    org.apache.cxf.interceptor.Fault: Response was of unexpected text/html ContentType. Incoming portion of HTML stream: (none)
    at org.apache.cxf.interceptor.StaxInInterceptor.handleMessage(StaxInInterceptor.java:84)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
    at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:835)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1612)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1503)
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1310)
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:628)
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:565)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:474)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:377)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:330)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)
    at $Proxy70.get2004(Unknown Source)
    at org.apache.cxf.ws.security.trust.AbstractSTSClient.configureViaEPR(AbstractSTSClient.java:509)
    at org.apache.cxf.ws.security.trust.STSUtils.getClient(STSUtils.java:115)
    at org.apache.cxf.ws.security.policy.interceptors.IssuedTokenInterceptorProvider$IssuedTokenOutInterceptor.issueToken(IssuedTokenInterceptorProvider.java:447)
    at org.apache.cxf.ws.security.policy.interceptors.IssuedTokenInterceptorProvider$IssuedTokenOutInterceptor.handleMessage(IssuedTokenInterceptorProvider.java:150)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:565)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:474)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:377)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:330)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)
    at $Proxy47.retrieveMultiple(Unknown Source)
    at AuthenticateMe.auth1(AuthenticateMe.java:164)
    at AuthenticateMe.main(AuthenticateMe.java:100)

    ReplyDelete
    Replies





    1. http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey

      256



      http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p

      http://www.w3.org/2001/04/xmlenc#aes256-cbc

      http://www.w3.org/2000/09/xmldsig#hmac-sha1

      http://www.w3.org/2001/10/xml-exc-c14n#

      http://www.w3.org/2001/04/xmlenc#aes256-cbc


      http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue


      https:///XrmServices/2011/Organization.svc?singleWsdl



      tPah/2+jV3Nx+YnbF98JkPm7zKqITBML9zFjyJYktJ4=

      http://docs.oasis-open.org/ws-sx/ws-trust/200512/CK/PSHA1





      This is the soap request it generated to use the metadata exchange.. even after setting the sts client still i get this issue....

      Delete
  76. Hi Tom,

    I am generating java stub using apache CXF apache-cxf-3.0.0-milestone2 and did the process as you said.
    But when i am trying run the client then i get the Exception:

    WARNING: Interceptor for {http://schemas.microsoft.com/xrm/2011/Contracts}OrganizationService#{http://schemas.microsoft.com/xrm/2011/Contracts/Services}RetrieveMultiple has thrown exception, unwinding now
    org.apache.cxf.interceptor.Fault: No message with ID "kerberosLoginError" found in resource bundle "org/apache/xml/security/resource/xmlsecurity"
    at org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.issueToken(SpnegoContextTokenOutInterceptor.java:117)
    at org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.handleMessage(SpnegoContextTokenOutInterceptor.java:74)
    at org.apache.cxf.ws.security.policy.interceptors.SpnegoContextTokenOutInterceptor.handleMessage(SpnegoContextTokenOutInterceptor.java:46)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:502)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:411)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:314)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:267)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
    at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:137)
    at $Proxy53.retrieveMultiple(Unknown Source)
    at test.main(test.java:84)
    Caused by: org.apache.wss4j.common.ext.WSSecurityException: No message with ID "kerberosLoginError" found in resource bundle "org/apache/xml/security/resource/xmlsecurity"
    Original Exception was javax.security.auth.login.LoginException: java.lang.NullPointerException
    at java.io.ByteArrayInputStream.(ByteArrayInputStream.java:89)
    at sun.security.util.DerValue.(DerValue.java:277)
    at sun.security.krb5.KrbAsRep.(KrbAsRep.java:46)
    at sun.security.krb5.KrbAsReq.getReply(KrbAsReq.java:448)
    at sun.security.krb5.Credentials.sendASRequest(Credentials.java:401)
    at sun.security.krb5.Credentials.acquireTGT(Credentials.java:350)
    at com.sun.security.auth.module.Krb5LoginModule.attemptAuthentication(Krb5LoginModule.java:662)
    at com.sun.security.auth.module.Krb5LoginModule.login(Krb5LoginModule.java:542)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    Can someone please help me on this.

    Thanks in Advance.

    Kiran

    ReplyDelete
    Replies
    1. I haven't tried that version of cxf, you might want to try a version that is confirmed working like 2.7.0 or 2.6.9.

      Delete
  77. This comment has been removed by the author.

    ReplyDelete
  78. Anyone have any experience creating SalesOrderDetails through this setup? I pretty much have everything working, and can query and create accounts, contacts, orders and detail lines, as well as code to automatically populate picklists and entityreferences, but I can't for the life of me get it to send a Money value to CRM.

    If i just stick a BigDecimal in the KeyValuePair, it doesn't complain and runs through fine, but the value is zero on CRM. If i intercept the marshaller and create a Money object and set the BigDecimal as the value, I get an unexpected failure on the server message (which digging into appears to be a class cast error). Setting the value as a string yields a generic failure message. I've tried setting the BigDecimal scale to 4 (matching what CRM returns) with a roundingmode of up, but no change.

    ReplyDelete
    Replies
    1. Here's the error message from the server. Looks like BigDecimals create a DecimalAttributeMetadata instead of MoneyAttributeMetadata, but i'm not sure how to override that for the Money fields. Sending the Money class doesn't help, since CXF just maps it as a container with a BigDecimal inside.

      >Crm Exception: Message: An unexpected error occurred., ErrorCode: -2147220970, InnerException: System.InvalidCastException: Unable to cast object of type 'Microsoft.Crm.Metadata.DecimalAttributeMetadata' to type 'Microsoft.Crm.Metadata.MoneyAttributeMetadata'.
      at Microsoft.Crm.ObjectModel.DoubleAttributeValidator.UpdatePrecision(Nullable`1 decimalValue, Nullable`1 floatValue, Money moneyValue, DoubleAttributeMetadata doubleMetadata, Entity entity, String propertyName, ExecutionContext platformContext)
      at Microsoft.Crm.ObjectModel.DoubleAttributeValidator.Validate(Entity entity, KeyValuePair`2 property, AttributeMetadata attributeMetadata, ExecutionContext platformContext)
      at Microsoft.Crm.ObjectModel.AttributeValidationPlugin.ValidateAttributeValue(Entity entity, KeyValuePair`2 property, AttributeMetadata attributeMetadata, ExecutionContext context, Entity parentEntity)
      at Microsoft.Crm.ObjectModel.AttributeValidationPlugin.PerformValidation(Entity entity, EntityMetadata entityMetadata, ExecutionContext platformContext, Entity parentEntity)
      at Microsoft.Crm.ObjectModel.AttributeValidationPlugin.Execute(IServiceProvider serviceProvider)
      at Microsoft.Crm.Extensibility.V5PluginProxyStep.ExecuteInternal(PipelineExecutionContext context)
      at Microsoft.Crm.Extensibility.VersionedPluginProxyStepBase.Execute(PipelineExecutionContext context)

      Delete
  79. • This is a very helpful blog. According the information here I was first able to connect to CRM 2011 On-Premise and invoke CRM web service calls through CXF. After looking into the CXF codebase, I figured out the correct implementation for SOAP message signing and encryption. I have been able to authenticate and send SOAP requests to the 2011/2013 On-Premise server through my standalone Java implementation. Many thanks!

    ReplyDelete
    Replies
    1. Hello,

      would you be able to provide me with your code as I'm in the same situation?

      thanks
      Lawrence

      Delete