如何通过odata冒充用户

时间:2017-09-14 22:30:03

标签: c# dynamics-crm azure-service-fabric dynamics-crm-2016 dynamics-crm-webapi

我们在2016年使用odata v8.1端点成功impersonate a user.

请注意,预期的请求流程为:邮递员 - > LocalHost微服务 - > CRM

来自 Postman - > CRM 的工作请求示例(直接,无需通过微服务)

Accept:application/json
Content-Type:application/json; charset=utf-8
OData-MaxVersion:4.0
OData-Version:4.0
MSCRMCallerID:d994d6ff-5531-e711-9422-00155dc0d345
Cache-Control:no-cache

反对odata终点:..../api/data/v8.1/leads

请注意,仅当通过postman直接针对odata v8.1端点发出时,此操作才会成功。

当尝试执行相同操作时,让本地服务(邮递员 - > LocalHost服务 - > CRM),这会失败,并且只是忽略??? MSCRMCallerID标头。

检查从Postman传递给LocalHost微服务的标头时,请求,由VS 2017中的调试器检查:

{Method: POST, RequestUri: 'https://.../api/data/v8.1/leads', Version: 1.1, Content: System.Net.Http.StringContent, Headers:
{
  OData-Version: 4.0
  OData-MaxVersion: 4.0
  MSCRMCallerID: D994D6FF-5531-E711-9422-00155DC0D345
  Cache-Control: no-cache
  Accept: application/json
  Content-Type: application/json; charset=utf-8
}}

记录是成功创建的,但是在CreatedBy字段上是服务用户名而不是MSCRMCallerID用户名(d994d6ff-5531-e711-9422-00155dc0d345),并且CreatedOnBehalf字段为空。

我们做错了什么?

我们如何通过我们的服务进行此模拟?

编辑+更多信息

请注意,我相信我已经包含了所有相关信息,但如果我没有,请告诉我在这个问题上我应该提供哪些其他输入。

我尝试了什么?

  1. 更改了标题的顺序
  2. 使用标题
  3. 的情况
  4. 确保guid对用户进行冒充是正确的
  5. 确保用户具有委托和sys管理员角色(尽管这是无关紧要的,因为这在直接执行针对crm odata端点的请求时起作用,而不是我们的服务公开的端点
  6. 尝试针对https AND http
  7. 执行请求
  8. fiddler trace如下图所示
  9. 请注意,此小提琴曲线是显示 Postman - >的曲线。微服务请求。 它没有显示从localhost微服务到CRM的通信。(我不知道为什么,也许是因为它是加密的)

    POST https://localhost:19081/.....Leads/API/leads HTTP/1.1
    Host: localhost:19081
    Connection: keep-alive
    Content-Length: 84
    Cache-Control: no-cache
    Origin: chrome-extension://aicmkgpgakddgnaphhhpliifpcfhicfo
    MSCRMCallerID: D994D6FF-5531-E711-9422-00155DC0D345
    X-Postman-Interceptor-Id: d79b1d2e-2155-f2ec-4ad7-e9b63e7fb90d
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
    Content-Type: application/json; charset=UTF-8
    Accept: */*
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-US,en;q=0.8
    Cookie: ai_user=Ka2Xn|2017-05-25T17:30:57.941Z
    
    {
        "subject": "created by mscrmcaller user2: d994d6ff-5531-e711-9422-00155dc0d345"
    }
    

    @Ram建议我们使用组织服务进行身份验证,这是一个选项,考虑到我们是针对Web API执行的吗?请求的令牌是否仍然有效。 (请注意,这可能是一个愚蠢的问题,原因是因为我不了解身份验证的工作原理。)

    以下是我们如何在每次通话上对当前进行身份验证时的代码段:

    //check headers to see if we got a redirect to the new location
                var shouldAuthenticate = redirectUri.AbsoluteUri.Contains("adfs/ls");
    
                if (!shouldAuthenticate)
                {
                    return;
                }
    
                var adfsServerName = redirectUri.Authority;
                var queryParams = HttpUtility.ParseQueryString(redirectUri.Query);
    
                ServicePointManager.ServerCertificateValidationCallback +=
                    (sender, cert, chain, sslPolicyErrors) => true;
    
                WSTrustChannelFactory factory = null;
                try
                {
                    // use a UserName Trust Binding for username authentication
                    factory = new WSTrustChannelFactory(
                        new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
                        $"https://{adfsServerName}/adfs/services/trust/13/usernamemixed")
                    {
                        Credentials =
                        {
                            UserName =
                            {
                                UserName = $"{credential.Domain}\\{credential.UserName}",
                                Password = credential.Password
                            }
                        },
                        TrustVersion = TrustVersion.WSTrust13
                    };
    
                    var rst = new RequestSecurityToken
                    {
                        RequestType = RequestTypes.Issue,
                        AppliesTo = new EndpointReference(_client.BaseAddress.AbsoluteUri),
                        TokenType = "urn:oasis:names:tc:SAML:1.0:assertion",
                        KeyType = KeyTypes.Bearer
                    };
    
                    var channel = factory.CreateChannel();
                    channel.Issue(rst, out RequestSecurityTokenResponse rstr);
    
                    var fedSerializer = new WSFederationSerializer();
                    var rstrContent = fedSerializer.GetResponseAsString(rstr, new WSTrustSerializationContext());
    
                    // construct a authentication form
                    var crmauthenticaionPostDictionary = new Dictionary<string, string>
                    {
                        {"wa", queryParams["wa"]},
                        {"wresult", rstrContent},
                        {"wctx", queryParams["wctx"]}
                    };
    
                    // post the authentication form to the website. 
                    var crmAuthorizationPostResponse = _client.PostAsync(_client.BaseAddress.AbsoluteUri, new FormUrlEncodedContent(crmauthenticaionPostDictionary)).Result;
    
                    var crmAuthorizationPostResponseString = crmAuthorizationPostResponse.Content.ReadAsStringAsync().Result;
                    //we  should be authenticated here
                    if (
                        !(
                            // we are correctly authorized if we got redirected to the correct address that we
                            // were trying to reach in the first place.
                            crmAuthorizationPostResponse.StatusCode == HttpStatusCode.Redirect
                            && crmAuthorizationPostResponse.Headers.Location == authenticationTestUri
                        )
                    )
                    {
                        throw new Exception("ADFS Authentication to CRM failed.");
                    }
    

2 个答案:

答案 0 :(得分:3)

当你做Postman to CRM请求时,它的直接电话&amp; CRM以预期的方式处理它。

但是在Postman中 - &gt;微服务 - &gt; CRM,微软服务与CRM之间的标头迷失了。

在您的微服务中,您必须手动将标头处理到CRM SDK调用。

HttpWebRequest myHttpWebRequest1= (HttpWebRequest)WebRequest.Create(uri);
myHttpWebRequest1.Headers.Add("MSCRMCallerID", "D994D6FF-5531-E711-9422-00155DC0D345");

HTTP Header Forwarding(抱歉,我找不到Azure / C#)

enter image description here

更新

假设您正在关注此MSDN samples在c#microservice中进行CRM Web api调用。我已经包含了我们需要的标头 - MSCRMCallerID。看看它是否对你有帮助。

public async Task BasicCreateAndUpdatesAsync()
{
   Console.WriteLine("--Section 1 started--");
   string queryOptions;  //select, expand and filter clauses
                         //First create a new contact instance,  then add additional property values and update 
                         // several properties.
                         //Local representation of CRM Contact instance
   contact1.Add("firstname", "Peter");
   contact1.Add("lastname", "Cambel");

   HttpRequestMessage createRequest1 =
       new HttpRequestMessage(HttpMethod.Post, getVersionedWebAPIPath() + "contacts");
   createRequest1.Content = new StringContent(contact1.ToString(),
       Encoding.UTF8, "application/json");

createRequest1.Headers.Add("MSCRMCallerID", "D994D6FF-5531-E711-9422-00155DC0D345");

   HttpResponseMessage createResponse1 =
       await httpClient.SendAsync(createRequest1);

   if (createResponse1.StatusCode == HttpStatusCode.NoContent)  //204
   {
    Console.WriteLine("Contact '{0} {1}' created.",
        contact1.GetValue("firstname"), contact1.GetValue("lastname"));
    contact1Uri = createResponse1.Headers.
        GetValues("OData-EntityId").FirstOrDefault();
    entityUris.Add(contact1Uri);
    Console.WriteLine("Contact URI: {0}", contact1Uri);
   }
   else
   {
    Console.WriteLine("Failed to create contact for reason: {0}",
        createResponse1.ReasonPhrase);
    throw new CrmHttpResponseException(createResponse1.Content);
   }
}

答案 1 :(得分:2)

在冒充

时,你必须小心谨慎

<强> 1。要模拟用户,请在实例上设置Call​​erId属性     在调用服务的Web方法之前的OrganizationServiceProxy。

<强> 2。用户(模仿者)必须具有ActOnBehalfOf权限,或者是Active Directory中PrivUserGroup组的成员

代码示例

 SystemUser user = null;
 user = new SystemUser(systemUser);
 OrganizationServiceProxy service = CrmService.Proxy;
 service.CallerID = user.Id;

由于您的代码不可用,请确保正确设置上述所有字段

有关详细信息,请使用链接 https://crmbusiness.wordpress.com/2015/07/21/crm-2015-understanding-impersonation-in-plugins-and-knowing-when-to-use-it/