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