我们正在使用 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:
最佳答案
当然。您可以通过两种替代方式来完成此操作。
- 传递
PromptBehavior.Never
。这将使用不可见的浏览器,使操作 100% 非交互式。这适用于 Kerberos 和任何其他 session 类型(例如 cookie)。 - 使用接受
UserCredential
的AcquireToken
重载。向其传递一个空的UserCredential
,如new UserCredential()
中所示。这将强制使用 Kerberos 身份验证。
关于oauth - Active Directory 身份验证库编程 SSO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35530631/