-
Notifications
You must be signed in to change notification settings - Fork 340
/
WebUI.cs
121 lines (106 loc) · 4.96 KB
/
WebUI.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client.Core;
using Microsoft.Identity.Client.Http;
using Microsoft.Identity.Client.Internal;
using Microsoft.Identity.Client.Platforms.Features.DesktopOs;
using Microsoft.Identity.Client.UI;
using Microsoft.Identity.Client.Utils;
namespace Microsoft.Identity.Client.Platforms.Features.WinFormsLegacyWebUi
{
internal abstract class WebUI : IWebUI
{
protected Uri RequestUri { get; private set; }
protected Uri CallbackUri { get; private set; }
public object OwnerWindow { get; set; }
protected SynchronizationContext SynchronizationContext { get; set; }
public RequestContext RequestContext { get; set; }
public async Task<AuthorizationResult> AcquireAuthorizationAsync(
Uri authorizationUri,
Uri redirectUri,
RequestContext requestContext,
CancellationToken cancellationToken)
{
AuthorizationResult authorizationResult = null;
var authUriBuilder = new UriBuilder(authorizationUri);
authUriBuilder.AppendOrReplaceQueryParameter("response_mode", "form_post");
authorizationUri = authUriBuilder.Uri;
var sendAuthorizeRequest = new Action(() =>
{
authorizationResult = Authenticate(authorizationUri, redirectUri, cancellationToken);
});
var sendAuthorizeRequestWithTcs = new Action<object>((tcs) =>
{
try
{
authorizationResult = Authenticate(authorizationUri, redirectUri, cancellationToken);
((TaskCompletionSource<object>)tcs).TrySetResult(null);
}
catch (Exception e)
{
// Need to catch the exception here and put on the TCS which is the task we are waiting on so that
// the exception coming out of Authenticate is correctly thrown.
((TaskCompletionSource<object>)tcs).TrySetException(e);
}
});
// If the thread is MTA, it cannot create or communicate with WebBrowser which is a COM control.
// In this case, we have to create the browser in an STA thread via StaTaskScheduler object.
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA)
{
if (SynchronizationContext != null)
{
var tcs = new TaskCompletionSource<object>();
SynchronizationContext.Post(new SendOrPostCallback(sendAuthorizeRequestWithTcs), tcs);
await tcs.Task.ConfigureAwait(false);
}
else
{
using (var staTaskScheduler = new StaTaskScheduler(1))
{
try
{
Task.Factory.StartNew(
sendAuthorizeRequest,
cancellationToken,
TaskCreationOptions.None,
staTaskScheduler).Wait(cancellationToken);
}
catch (AggregateException ae)
{
requestContext.Logger.ErrorPii(ae.InnerException);
// Any exception thrown as a result of running task will cause AggregateException to be thrown with
// actual exception as inner.
Exception innerException = ae.InnerExceptions[0];
// In MTA case, AggregateException is two layer deep, so checking the InnerException for that.
if (innerException is AggregateException innerAggregateException)
{
innerException = innerAggregateException.InnerExceptions[0];
}
throw innerException;
}
}
}
}
else
{
sendAuthorizeRequest();
}
return await Task.Factory.StartNew(() => authorizationResult, cancellationToken).ConfigureAwait(false);
}
internal AuthorizationResult Authenticate(Uri requestUri, Uri callbackUri, CancellationToken cancellationToken)
{
RequestUri = requestUri;
CallbackUri = callbackUri;
return OnAuthenticate(cancellationToken);
}
protected abstract AuthorizationResult OnAuthenticate(CancellationToken cancellationToken);
public Uri UpdateRedirectUri(Uri redirectUri)
{
RedirectUriHelper.Validate(redirectUri, usesSystemBrowser: false);
return redirectUri;
}
}
}