ADFS 错误 - MSIS9605:不允许客户端访问请求的资源

Dav*_*rux 3 crm adfs node.js microsoft-dynamics-crm

我有一个 Dynamics CRM 2016 的本地安装,它使用 ADFS 4.0 (Server 2016) 实例配置了基于声明的身份验证。通过 ADFS 登录 CRM 工作正常。我有一个单独的 Node.js 应用程序尝试使用 Microsoft 提供的 ADAL 库访问 CRM Web API 以执行身份验证。我已经使用 PowerShell 为这个具有客户端 ID 和密钥的 Node 应用程序创建了一个 ADFS 客户端。当节点代码执行以从 ADFS 获取令牌以用于调用 CRM Web API 时,我收到错误MSIS9605: The client is not allowed to access the requested resource。显然调用到达 ADFS,但我似乎找不到配置 ADFS 以允许客户端访问受 ADFS 保护的其他资源的方法。

这是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
                                       }
Run Code Online (Sandbox Code Playgroud)

这是使用 ADAL 的 Node.js 函数(https://github.com/AzureAD/azure-activedirectory-library-for-nodejs)。我意识到它的标题中有 Azure,但它正在与 ADFS 成功通信,并且问题日志中有评论指出我正在做的事情是可能的。

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);
        }
    });
};
Run Code Online (Sandbox Code Playgroud)

此外,来自 ADFS 事件日志:

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()
Run Code Online (Sandbox Code Playgroud)

任何见解都会很棒,因为我对 ADFS 还很陌生,并且该消息似乎表明 ADFS 中的某些内容不正确。

小智 6

在 Windows Server 2016 上,您需要明确授予客户端对资源的权限,即使访问策略设置为“允许所有人”。

试试这个命令:

Grant-AdfsApplicationPermission -ClientRoleIdentifier "clientName" -ServerRoleIdentifier "https://service.url"
Run Code Online (Sandbox Code Playgroud)