2

I have an on-premise installation of Dynamics CRM 2016 which has claims-based authentication configured using an ADFS 4.0 (Server 2016) instance. Logging into CRM works fine via ADFS. I have a separate Node.js application trying to access the CRM Web API using the ADAL library provided by Microsoft to perform authentication. I have created an ADFS client using PowerShell for this Node app that has a Client ID and Secret. When the Node code executes to acquire a token from ADFS to use for calling the CRM Web API, I get the error MSIS9605: The client is not allowed to access the requested resource. Clearly the call is reaching ADFS, but I cannot seem to find a way to configure ADFS to allow the client to access the other resource protected by ADFS.

Here is the output of Get-ADFSRelyingPartyTrust:

AllowedAuthenticationClassReferences : {}
EncryptionCertificateRevocationCheck : CheckChainExcludeRoot
PublishedThroughProxy                : False
SigningCertificateRevocationCheck    : CheckChainExcludeRoot
WSFedEndpoint                        : https://crm.mysite.com/
AdditionalWSFedEndpoint              : {}
ClaimsProviderName                   : {}
ClaimsAccepted                       : {, , }
EncryptClaims                        : True
Enabled                              : True
EncryptionCertificate                : [Subject]
                                         CN=*.mysite.com, OU=Domain Control Validated

                                       [Issuer]
                                         CN=Go Daddy Secure Certificate Authority - G2, 
                                       OU=http://certs.godaddy.com/repository/, O="GoDaddy.com, Inc.", L=Scottsdale, 
                                       S=Arizona, C=US

                                       [Serial Number]
                                         2DC..............91

                                       [Not Before]
                                         11/23/2016 9:41:00 PM

                                       [Not After]
                                         1/19/2018 3:51:41 PM

                                       [Thumbprint]
                                         2FC..................AADD

Identifier                           : {https://demo.mysite.com/, https://crm.mysite.com/}
NotBeforeSkew                        : 0
EnableJWT                            : True
AlwaysRequireAuthentication          : False
Notes                                : 
OrganizationInfo                     : 
ObjectIdentifier                     : 8e869c1e-..........8b5a
ProxyEndpointMappings                : {}
ProxyTrustedEndpoints                : {}
ProtocolProfile                      : WsFed-SAML
RequestSigningCertificate            : {}
EncryptedNameIdRequired              : False
SignedSamlRequestsRequired           : False
SamlEndpoints                        : {}
SamlResponseSignature                : AssertionOnly
SignatureAlgorithm                   : http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
TokenLifetime                        : 0
AllowedClientTypes                   : Public, Confidential
IssueOAuthRefreshTokensTo            : AllDevices
RefreshTokenProtectionEnabled        : True
RequestMFAFromClaimsProviders        : False
ScopeGroupId                         : 
Name                                 : crm.mysite.com
AutoUpdateEnabled                    : True
MonitoringEnabled                    : True
MetadataUrl                          : https://crm.mysite.com/federationmetadata/2007-06/federationmetadata.xml
ConflictWithPublishedPolicy          : False
IssuanceAuthorizationRules           : 
IssuanceTransformRules               : @RuleTemplate = "PassThroughClaims"
                                       @RuleName = "Pass Through UPN"
                                       c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"]
                                        => issue(claim = c);

                                       @RuleTemplate = "PassThroughClaims"
                                       @RuleName = "Pass Through Primary SID"
                                       c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"]
                                        => issue(claim = c);

                                       @RuleTemplate = "MapClaims"
                                       @RuleName = "Transform Windows Account Name to Name"
                                       c:[Type == 
                                       "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"]
                                        => issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", 
                                       Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, 
                                       ValueType = c.ValueType);

                                       @RuleTemplate = "PassThroughClaims"
                                       @RuleName = "App Claim"
                                       c:[Type == "http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-clie
                                       nt-application"]
                                        => issue(claim = c);


DelegationAuthorizationRules         : 
LastPublishedPolicyCheckSuccessful   : True
LastUpdateTime                       : 1/4/2017 8:24:16 PM
LastMonitoredTime                    : 1/5/2017 8:02:07 PM
ImpersonationAuthorizationRules      : 
AdditionalAuthenticationRules        : 
AccessControlPolicyName              : Permit everyone
AccessControlPolicyParameters        : 
ResultantPolicy                      : RequireFreshAuthentication:False
                                       IssuanceAuthorizationRules:
                                       {
                                         Permit everyone
                                       }

Here is the Node.js function using ADAL (https://github.com/AzureAD/azure-activedirectory-library-for-nodejs). I realize it has Azure in the title but it is successfully communicating with ADFS and there are comments in the issues log stating that what I am doing is possible.

let ADAuthenticationContext = require('adal-node').AuthenticationContext;

const authorityHostUrl = 'https://sso.mysite.com';
const tenant = 'adfs';
let authorityUrl = authorityHostUrl + '/' + tenant;
const clientId = 'c43002e2-............67c';
const clientSecret = 'lT..................jjh';

const resource = 'https://crm.mysite.com/';


let crm = module.exports = {};

let context = new ADAuthenticationContext(authorityUrl, false);

crm.test = function() {
    context.acquireTokenWithClientCredentials(resource, clientId, clientSecret, function(err, tokenResponse) {
        if (err) {
            console.log('well that didn\'t work: ' + err.stack);
        } else {
            console.log(tokenResponse);
        }
    });
};

Also, from the ADFS Event Log:

Encountered error during OAuth token request. 

Additional Data 

Exception details: 
Microsoft.IdentityServer.Web.Protocols.OAuth.Exceptions.OAuthUnauthorizedClientException: MSIS9321: Received invalid OAuth request. The client 'c43002e2-f1a6-4786-9234-f71e971c167c' is forbidden to access the resource 'https://demo.mysite.com/'.
   at Microsoft.IdentityServer.Web.Protocols.OAuth.OAuthProtocolContext.ValidateScopes(String scopeParameter, String clientId, String relyingPartyId)
   at Microsoft.IdentityServer.Web.Protocols.OAuth.OAuthToken.OAuthClientCredentialsContext.ValidateCore()

Any insight would be great as I am pretty new to ADFS and the message seems to indicate something in ADFS is not correct.

4

On Windows Server 2016 you need to explicitly grant clients permission to a resource, even when the access policy is set to "Permit everyone".

Try this command:

Grant-AdfsApplicationPermission -ClientRoleIdentifier "clientName" -ServerRoleIdentifier "https://service.url"
1

You need to create a rule to permit or deny users based on an incoming claim.

In Windows Server 2016, you can use an Access Control Policy to create a rule that will permit or deny users based on an incoming claim. Also, you can permit all users to access the relying party, use the Permit Everyone Access Control Policy or the Permit All Users rule template

You can refer to the article below for creating the rule by using the AD FS Management.

https://technet.microsoft.com/en-us/windows-server-docs/identity/ad-fs/operations/create-a-rule-to-permit-or-deny-users-based-on-an-incoming-claim?f=255&MSPPError=-2147217396

Or you also can use the following command with related parameters running in PowerShell.

Add-ADFSRelyingPartyTrust -Name "Fabrikam" -MetadataURL "https://fabrikam.com/federationmetadata/2007-06/federationmetadata.xml" -IssuanceAuthorizationRules '=> issue(Type ="http://schemas.microsoft.com/authorization/claims/permit", value="true");'
  • The existing relying party trust already was already using the Permit Everyone rule template. Do I need to create another relying party trust for the Node app? – DaveTrux Jan 6 '17 at 15:56
  • I recommend to create relying party trust by using command in PowerShell, and please make sure add the following in the command. -IssuanceAuthorizationRules '=> issue(Type ="schemas.microsoft.com/authorization/claims/permit", value="true");' – Andy Liu - MSFT Jan 9 '17 at 1:58
  • I deleted the relying party trust and recreated it using PowerShell following your template. No change, error still persists. – DaveTrux Jan 9 '17 at 14:54
  • How did you register the Node App with ADFS by using PowerShell? Did you set the client type as Public or Confidential? You may refer to the article AD FS Scenarios for Developers for the scenarios in Windows Server 2016. – Andy Liu - MSFT Jan 11 '17 at 5:22
  • 1
    BTW, in answer to Andy's question it was set to public. Via a support call with Microsoft they told me CRM with ADFS 4.0 is unsupported as of this date. – DaveTrux Jan 24 '17 at 18:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.