locked
Who has access to a given Account record? RRS feed

  • Question

  • How can I obtain a list of all systemuser records that have access to a given Account record using SDK?

    Regardless of how access is given, that being through an Access Team Membership, Share or through Security Role(s).

    Monday, January 25, 2016 3:41 PM

Answers

  • Use the CallerId to set the calling context on the ServiceProxy to any user.

    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Client;
    using Microsoft.Xrm.Sdk.Query;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel.Description;
    
    namespace CrmTest
    {
        class CrmAccessTester
        {
            public List<Guid> WhoHasAccess(Guid recordId, string entityName, string serverUrl, string userName, string password, string domain, bool isIfd)
            {
    
                this.ServerUrl = string.Format("{0}/XRMServices/2011/Organization.svc", serverUrl);
                this.ServiceUri = new Uri(this.ServerUrl);
                this.UserName = userName;
                this.Password = password;
                this.Domain = domain;
                if (isIfd)
                {
                    ClientCredentials credentials = new ClientCredentials();
                    credentials.UserName.UserName = userName;
                    credentials.UserName.Password = password;
                    IServiceManagement<IOrganizationService> orgServiceManagement = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(ServerUrl));
                    AuthenticationCredentials authCredentials = new AuthenticationCredentials();
                    authCredentials.ClientCredentials = credentials;
                    AuthenticationCredentials tokenCredentials = orgServiceManagement.Authenticate(authCredentials);
                    ServiceProxy = new OrganizationServiceProxy(orgServiceManagement, tokenCredentials.SecurityTokenResponse);
                }
                else
                {
                    ServiceUser = new ClientCredentials();
                    ServiceUser.Windows.ClientCredential = new System.Net.NetworkCredential(this.UserName, this.Password, this.Domain);
                    ServiceProxy = new OrganizationServiceProxy(new Uri(this.ServerUrl), null, this.ServiceUser, null);
                }
                ServiceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
                ServiceProxy.Timeout = new TimeSpan(0, 15, 0);
    
                QueryByAttribute oQuery = new QueryByAttribute("systemuser");
                oQuery.AddAttributeValue("isdisabled",false);
                List<Guid> oReturnList = new List<Guid>();
                EntityCollection AllUsers = ServiceProxy.RetrieveMultiple(oQuery);
                foreach (Entity oUser in AllUsers.Entities)
                {
                    try
                    {
                        ServiceProxy.CallerId = oUser.Id;
                        Entity oAccessRecord = ServiceProxy.Retrieve(entityName, recordId, new ColumnSet(true));
                        //user has access to record
                        oReturnList.Add(oUser.Id);
                    }
                    catch
                    {
                        //user does not have access to record
                    }
                }
                return oReturnList;
            }
    
            public string ServerUrl { get; set; }
    
            public string UserName { get; set; }
    
            public string Password { get; set; }
    
            public string Domain { get; set; }
    
            public OrganizationServiceProxy ServiceProxy { get; set; }
    
            public ClientCredentials ServiceUser { get; set; }
    
            public Uri ServiceUri { get; set; }
        }
    }
    

    • Proposed as answer by F.Kuyler Tuesday, January 26, 2016 7:15 AM
    • Marked as answer by Allen Campbell Thursday, January 28, 2016 1:02 PM
    Tuesday, January 26, 2016 7:15 AM
  • Hi Allen,

    Below  SQL query can help you.

    Note :  1. Replace MyOrg with your organization name in  "MyOrg_MSCRM". Check this link.

    SELECT  DISTINCT
    CASE WHEN POA.[PrincipalTypeCode] = 8 THEN 'User'
    WHEN POA.[PrincipalTypeCode] = 9 AND TEAM.[TeamType] = 0 THEN 'Owner Team' 
    WHEN POA.[PrincipalTypeCode] = 9 AND TEAM.[TeamType] = 1 THEN 'Access Team' 
    ELSE 'Other' END AS 'PrincipalType',
    COALESCE(USERID.[FirstName],TEAM.[Name]) AS PrincipalName, 
    POA.[ObjectTypeCode],ENTITY.[OriginalLocalizedName], POA.[ObjectId], 
    POA.[AccessRightsMask],POA.[InheritedAccessRightsMask],POA.[ChangedOn], 
    POA.[PrincipalTypeCode],POA.[PrincipalId] 
    FROM [MyOrg_MSCRM].[dbo].[PrincipalObjectAccess] AS POA
    LEFT OUTER JOIN [MyOrg_MSCRM].[dbo].[SystemUserBase] AS USERID 
    ON POA.[PrincipalId] = USERID.[SystemUserId] 
    LEFT OUTER JOIN [MyOrg_MSCRM].[dbo].[TeamBase] AS TEAM 
    ON POA.[PrincipalId] = TEAM.[TeamId] 
    LEFT OUTER JOIN [MyOrg_MSCRM].[MetadataSchema].[Entity] AS ENTITY 
    ON POA.[ObjectTypeCode] = ENTITY.[ObjectTypeCode]
    WHERE POA.[PrincipalTypeCode] IN (8,9) AND POA.[ObjectTypeCode] = 1 AND POA.ObjectId = 'C84FBA58-8CCB-DF11-9176-02BF0AC9DF07'

    Hope this helps


    If you find this post helpful then please "Vote as Helpful" and "Mark As Answer". Thanks and Regards, Mohammad Yusuf Ansari http://microxrm.blogspot.in


    Wednesday, January 27, 2016 1:51 PM
  • Hi Allen,

    You can achieve this with RetrieveSharedPrincipalsAndAccessRequest Class.

    https://msdn.microsoft.com/en-in/library/microsoft.crm.sdk.messages.retrievesharedprincipalsandaccessrequest.aspx

       RetrieveSharedPrincipalsAndAccessRequest accessRequest = new RetrieveSharedPrincipalsAndAccessRequest();
    
                    accessRequest.Target = new EntityReference("account", new Guid("C84FBA58-8CCB-DF11-9176-02BF0AC9DF07"));
    
                    // The RetrieveSharedPrincipalsAndAccessResponse returns an entity reference
                    // that has a LogicalName of "user" when returning access information for a
                    // "team."
                    var accessResponse = (RetrieveSharedPrincipalsAndAccessResponse)                    _orgService.Execute(accessRequest);
                    Console.WriteLine("The following have the specified granted access to the Account.");
                    foreach (var principalAccess in accessResponse.PrincipalAccesses)
                    {
                        Console.WriteLine("\t{0}:\r\n\t\t{1}", GetEntityReferenceString(principalAccess.Principal),  principalAccess.AccessMask);
                    }

    Hope this helps.



    If you find this post helpful then please "Vote as Helpful" and "Mark As Answer". Thanks and Regards, Mohammad Yusuf Ansari http://microxrm.blogspot.in


    Wednesday, January 27, 2016 2:40 PM

All replies

  • Use the CallerId to set the calling context on the ServiceProxy to any user.

    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Client;
    using Microsoft.Xrm.Sdk.Query;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel.Description;
    
    namespace CrmTest
    {
        class CrmAccessTester
        {
            public List<Guid> WhoHasAccess(Guid recordId, string entityName, string serverUrl, string userName, string password, string domain, bool isIfd)
            {
    
                this.ServerUrl = string.Format("{0}/XRMServices/2011/Organization.svc", serverUrl);
                this.ServiceUri = new Uri(this.ServerUrl);
                this.UserName = userName;
                this.Password = password;
                this.Domain = domain;
                if (isIfd)
                {
                    ClientCredentials credentials = new ClientCredentials();
                    credentials.UserName.UserName = userName;
                    credentials.UserName.Password = password;
                    IServiceManagement<IOrganizationService> orgServiceManagement = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(ServerUrl));
                    AuthenticationCredentials authCredentials = new AuthenticationCredentials();
                    authCredentials.ClientCredentials = credentials;
                    AuthenticationCredentials tokenCredentials = orgServiceManagement.Authenticate(authCredentials);
                    ServiceProxy = new OrganizationServiceProxy(orgServiceManagement, tokenCredentials.SecurityTokenResponse);
                }
                else
                {
                    ServiceUser = new ClientCredentials();
                    ServiceUser.Windows.ClientCredential = new System.Net.NetworkCredential(this.UserName, this.Password, this.Domain);
                    ServiceProxy = new OrganizationServiceProxy(new Uri(this.ServerUrl), null, this.ServiceUser, null);
                }
                ServiceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
                ServiceProxy.Timeout = new TimeSpan(0, 15, 0);
    
                QueryByAttribute oQuery = new QueryByAttribute("systemuser");
                oQuery.AddAttributeValue("isdisabled",false);
                List<Guid> oReturnList = new List<Guid>();
                EntityCollection AllUsers = ServiceProxy.RetrieveMultiple(oQuery);
                foreach (Entity oUser in AllUsers.Entities)
                {
                    try
                    {
                        ServiceProxy.CallerId = oUser.Id;
                        Entity oAccessRecord = ServiceProxy.Retrieve(entityName, recordId, new ColumnSet(true));
                        //user has access to record
                        oReturnList.Add(oUser.Id);
                    }
                    catch
                    {
                        //user does not have access to record
                    }
                }
                return oReturnList;
            }
    
            public string ServerUrl { get; set; }
    
            public string UserName { get; set; }
    
            public string Password { get; set; }
    
            public string Domain { get; set; }
    
            public OrganizationServiceProxy ServiceProxy { get; set; }
    
            public ClientCredentials ServiceUser { get; set; }
    
            public Uri ServiceUri { get; set; }
        }
    }
    

    • Proposed as answer by F.Kuyler Tuesday, January 26, 2016 7:15 AM
    • Marked as answer by Allen Campbell Thursday, January 28, 2016 1:02 PM
    Tuesday, January 26, 2016 7:15 AM
  • Hi Allen,

    Below  SQL query can help you.

    Note :  1. Replace MyOrg with your organization name in  "MyOrg_MSCRM". Check this link.

    SELECT  DISTINCT
    CASE WHEN POA.[PrincipalTypeCode] = 8 THEN 'User'
    WHEN POA.[PrincipalTypeCode] = 9 AND TEAM.[TeamType] = 0 THEN 'Owner Team' 
    WHEN POA.[PrincipalTypeCode] = 9 AND TEAM.[TeamType] = 1 THEN 'Access Team' 
    ELSE 'Other' END AS 'PrincipalType',
    COALESCE(USERID.[FirstName],TEAM.[Name]) AS PrincipalName, 
    POA.[ObjectTypeCode],ENTITY.[OriginalLocalizedName], POA.[ObjectId], 
    POA.[AccessRightsMask],POA.[InheritedAccessRightsMask],POA.[ChangedOn], 
    POA.[PrincipalTypeCode],POA.[PrincipalId] 
    FROM [MyOrg_MSCRM].[dbo].[PrincipalObjectAccess] AS POA
    LEFT OUTER JOIN [MyOrg_MSCRM].[dbo].[SystemUserBase] AS USERID 
    ON POA.[PrincipalId] = USERID.[SystemUserId] 
    LEFT OUTER JOIN [MyOrg_MSCRM].[dbo].[TeamBase] AS TEAM 
    ON POA.[PrincipalId] = TEAM.[TeamId] 
    LEFT OUTER JOIN [MyOrg_MSCRM].[MetadataSchema].[Entity] AS ENTITY 
    ON POA.[ObjectTypeCode] = ENTITY.[ObjectTypeCode]
    WHERE POA.[PrincipalTypeCode] IN (8,9) AND POA.[ObjectTypeCode] = 1 AND POA.ObjectId = 'C84FBA58-8CCB-DF11-9176-02BF0AC9DF07'

    Hope this helps


    If you find this post helpful then please "Vote as Helpful" and "Mark As Answer". Thanks and Regards, Mohammad Yusuf Ansari http://microxrm.blogspot.in


    Wednesday, January 27, 2016 1:51 PM
  • Hi Allen,

    You can achieve this with RetrieveSharedPrincipalsAndAccessRequest Class.

    https://msdn.microsoft.com/en-in/library/microsoft.crm.sdk.messages.retrievesharedprincipalsandaccessrequest.aspx

       RetrieveSharedPrincipalsAndAccessRequest accessRequest = new RetrieveSharedPrincipalsAndAccessRequest();
    
                    accessRequest.Target = new EntityReference("account", new Guid("C84FBA58-8CCB-DF11-9176-02BF0AC9DF07"));
    
                    // The RetrieveSharedPrincipalsAndAccessResponse returns an entity reference
                    // that has a LogicalName of "user" when returning access information for a
                    // "team."
                    var accessResponse = (RetrieveSharedPrincipalsAndAccessResponse)                    _orgService.Execute(accessRequest);
                    Console.WriteLine("The following have the specified granted access to the Account.");
                    foreach (var principalAccess in accessResponse.PrincipalAccesses)
                    {
                        Console.WriteLine("\t{0}:\r\n\t\t{1}", GetEntityReferenceString(principalAccess.Principal),  principalAccess.AccessMask);
                    }

    Hope this helps.



    If you find this post helpful then please "Vote as Helpful" and "Mark As Answer". Thanks and Regards, Mohammad Yusuf Ansari http://microxrm.blogspot.in


    Wednesday, January 27, 2016 2:40 PM