oauth - Active Directory 身份验证库编程 SSO

标签 oauth azure-active-directory adfs azure-ad-graph-api

我们正在使用 ADAL C# 库获取 Azure AD 应用程序(包括图形 API)的 token 。

我们使用本地 ADFS 3.0 服务器通过 Azure AD 设置了 AD Connect。因此,当 native 客户端应用程序调用时......

var ourDomain = "abc.com";
var authority = "https://login.microsoftonline.com/" + ourDomain;
var authenticationContext = new AuthenticationContext(authority);

var graphResourceUri = "https://graph.windows.net";
var azureADApplicationClientId = "7718c738-0000-0000-0000-4382476f1c65";

var result = authenticationContext.AcquireToken(
   graphResourceUri, 
   azureADApplicationClientId, new Uri("https://localhost"),
   PromptBehavior.RefreshSession, 
   new UserIdentifier($"jdoe@{ourDomain}", UserIdentifierType.RequiredDisplayableId), 
   $"domain_hint={ourDomain}");

弹出 MSOnline 登录窗口,立即重定向到我们的 ADFS 服务器

https://ouradfs.abc.com/adfs/ls/wia?username=.......................

然后由于 NTLM(Windows 集成)身份验证发生并成功而立即关闭...并且 result包含登录 Windows 用户在我们的 abc.com 上的有效访问 token 域名。

尽管此过程不需要任何点击...但它仍然是“交互式”的。我希望能够利用 Windows 集成身份验证以编程方式在非交互式环境(例如 Windows 服务或计划任务)中获取此类访问 token 。这样我就不必将客户端 secret 嵌入到我们的 Windows 服务或计划任务中。

这可能吗?

更新: 这是代码行

var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/mycorpdev.onmicrosoft.com");

AuthenticationResult result = authenticationContext.AcquireToken(
  "https://graph.windows.net", 
  nativeApplicationClientId, 
  new Uri("https://localhost"),
  PromptBehavior.Never, 
  new UserIdentifier("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6f051c02061b072f02160c001d1f410c0002" rel="noreferrer noopener nofollow">[email protected]</a>"), UserIdentifierType.RequiredDisplayableId), $"domain_hint=mycorp.com");

以及确切的错误:

Microsoft.IdentityModel.Clients.ActiveDirectory.AdalException occurred
  ErrorCode=user_interaction_required
  HResult=-2146233088
  Message=user_interaction_required: One of two conditions was encountered: 1. The PromptBehavior.Never flag was passed, but the constraint could not be honored, because user interaction was required. 2. An error occurred during a silent web authentication that prevented the http authentication flow from completing in a short enough time frame
  Source=Microsoft.IdentityModel.Clients.ActiveDirectory
  StackTrace:
       at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.RunAsyncTask[T](Task`1 task)

另一个更新:

这有效(其中客户端 ID 和租户与用户的主租户相同)

varauthenticationContext = new AuthenticationContext("https://login.microsoftonline.com/mycorp.onmicrosoft.com ");

AuthenticationResult result = authenticationContext.AcquireToken(
  "https://graph.windows.net", 
  nativeApplicationClientIdFromHomeTenantNotOtherTenant, 
  new Uri("https://localhost"),
  PromptBehavior.Never, 
  new UserIdentifier("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7e140d13170a163e13071d110c0e501d1113" rel="noreferrer noopener nofollow">[email protected]</a>"), UserIdentifierType.RequiredDisplayableId), $"domain_hint=mycorp.com");

更新 - 这是 Fiddler 的捕获

GET https://login.microsoftonline.com/mycorpdev.onmicrosoft.com/oauth2/authorize?resource=https%3A%2F%2Fgraph.windows.net&client_id=78ebfdee-8144-48f8-9a96-1bd5418c0492&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%2F&login_hint=jsmith%40mycorp.COM&client-request-id=7a8878d4-2762-4784-9d29-6f49b147d474&prompt=attempt_none&x-client-SKU=.NET&x-client-Ver=2.19.0.0&x-client-CPU=x64&x-client-OS=Microsoft+Windows+NT+6.1.7601+Service+Pack+1&domain_hint=mycorpdev.onmicrosoft.com HTTP/1.1
Accept: */*
Accept-Language: en-US
UA-CPU: AMD64
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/7.0; .NET CLR 2.0.50727; SLCC2; Media Center PC 6.0; Tablet PC 2.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E)
Host: login.microsoftonline.com
Connection: Keep-Alive
Cookie: ESTSAUTHPERSISTENT=AAABAAEAiL9Kn2Z27UubvWFPbm0gLfZQz8hXb5bXR-iThmkV-FLuLx102LOLAWrogj3rvf40Xl0xjZntMo0Kzvbo0x38Z2CpfCjtOwyyVpp1DWlxyyRPBbl4Z4da5pFuYjfCLPqExGUvo5gBoMdeQ-0MobfbSV2GQCHgbL1CFRjOu6YJZUEgnk7Vyls4rOlHGaqEGpzm5OeFQj3acldcvD9C4PX1gGsV-2g5GU8Frx3co4YzqYHMbhp6fgzf18sfgWaaG9caWj756P2oDvqe9qAlehXk51cA2AUacM2h-k2rtN8F341p7tnOFkNBzCj_E4z3bTnwHodimoXLiDlDWjFWkzAANyAA


HTTP/1.1 302 Found
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Expires: -1
Location: https://localhost/?error=login_required&error_description=AADSTS50058%3a+User+account+identifier+is+not+provided.%0d%0aTrace+ID%3a+133f0405-eb3d-452d-a8b6-b6ba6267af7c%0d%0aCorrelation+ID%3a+7a8878d4-2762-4784-9d29-6f49b147d474%0d%0aTimestamp%3a+2016-02-21+04%3a54%3a07Z
Vary: Accept-Encoding
Server: Microsoft-IIS/8.5
x-ms-request-id: 133f0405-eb3d-452d-a8b6-b6ba6267af7c
client-request-id: 7a8878d4-2762-4784-9d29-6f49b147d474
x-ms-gateway-service-instanceid: ESTSFE_IN_420
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000; includeSubDomains
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"
Set-Cookie: flight-uxoptin=true; path=/; secure; HttpOnly
Set-Cookie: x-ms-gateway-slice=productionb; path=/; secure; HttpOnly
Set-Cookie: stsservicecookie=ests; path=/; secure; HttpOnly
X-Powered-By: ASP.NET
Date: Sun, 21 Feb 2016 04:54:05 GMT
Content-Length: 0

还有一个更新...

如果我尝试使用集成身份验证(请注意,它确实尝试正确重定向到我们的 ADFS...):

var authenticationContext = new AuthenticationContext(""https://login.microsoftonline.com/" + UserPrincipal.Current.UserPrincipalName.Split('@')[1]), false);
var nativeClientId = "00000000-0f32-4c38-bdb9-4ea5bd732c69";
var token = authenticationContext.AcquireTokenAsync(Constants.ReportingApplicationUri, nativeClientId, new UserCredential()).Result;

System.AggregateException occurred
  HResult=-2146233088
  Message=One or more errors occurred.
  Source=mscorlib
  StackTrace:
       at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
:line 68
  InnerException: 
       ErrorCode=federated_service_returned_error
       HResult=-2146233088
       Message=Federated service at https://ds1.mycorp.com/adfs/services/trust/2005/windowstransport returned error: The message with Action 'http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver.  Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
       Source=Microsoft.IdentityModel.Clients.ActiveDirectory
       StatusCode=500
       StackTrace:
            at Microsoft.IdentityModel.Clients.ActiveDirectory.WsTrustRequest.<SendRequestAsync>d__1.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenNonInteractiveHandler.<PreTokenRequest>d__4.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase.<RunAsync>d__0.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.<AcquireTokenCommonAsync>d__0.MoveNext()
         --- End of stack trace from previous location where exception was thrown ---
            at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
            at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
            at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.<AcquireTokenAsync>d__14.MoveNext()
       InnerException: 
            HResult=-2146233079
            Message=The remote server returned an error: (500) Internal Server Error.
            Source=System
            StackTrace:
                 at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
                 at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
              --- End of stack trace from previous location where exception was thrown ---
                 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
                 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
                 at Microsoft.IdentityModel.Clients.ActiveDirectory.HttpWebRequestWrapper.<GetResponseSyncOrAsync>d__2.MoveNext()
              --- End of stack trace from previous location where exception was thrown ---
                 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
                 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
                 at Microsoft.IdentityModel.Clients.ActiveDirectory.WsTrustRequest.<SendRequestAsync>d__1.MoveNext()
            InnerException: 

最佳答案

当然。您可以通过两种替代方式来完成此操作。

  1. 传递PromptBehavior.Never。这将使用不可见的浏览器,使操作 100% 非交互式。这适用于 Kerberos 和任何其他 session 类型(例如 cookie)。
  2. 使用接受 UserCredentialAcquireToken 重载。向其传递一个空的 UserCredential,如 new UserCredential() 中所示。这将强制使用 Kerberos 身份验证。

关于oauth - Active Directory 身份验证库编程 SSO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35530631/

相关文章:

python - 寻找使用 OAuth 的 Netsuite API 的示例 Python 代码?

azure-active-directory - Azure AD 发布声明安全组名称

azure - 尝试在 Azure US Gov 中获取授权码时出现 "AADSTS650057: Invalid resource"错误

azure - 为什么 MSAL loginPopup 响应“应用程序客户端要求资源上不存在的范围”?

ruby-on-rails - 使用 OAuth-Ruby 和 Tumblr API 获取访问 token (Rails 3)

c# - 使用 WebAuthenticationBroker 进行 oAuth

objective-c - 检测 Twitter 的 iOS 版本?

java - Spring Security SAML 与标准 java 应用程序

authentication - Blazor 服务器 - 如何配置本地 ADFS 安全性?

azure - 使用客户的 Active Directory(Azure 或 ADFS)对 UWP 客户端和 .Net Core Web 应用程序进行身份验证