-
Notifications
You must be signed in to change notification settings - Fork 403
Expand file tree
/
Copy pathAuthenticationResult.cs
More file actions
396 lines (356 loc) · 19.5 KB
/
AuthenticationResult.cs
File metadata and controls
396 lines (356 loc) · 19.5 KB
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Identity.Client.AuthScheme;
using Microsoft.Identity.Client.Cache;
using Microsoft.Identity.Client.Cache.Items;
using Microsoft.Identity.Client.TelemetryCore.Internal.Events;
using Microsoft.Identity.Client.Utils;
using System.Security.Cryptography.X509Certificates;
namespace Microsoft.Identity.Client
{
/// <summary>
/// Contains the results of one token acquisition operation in <see cref="PublicClientApplication"/>
/// or ConfidentialClientApplication. For details see https://aka.ms/msal-net-authenticationresult
/// </summary>
public partial class AuthenticationResult
{
private IAuthenticationOperation _authenticationScheme;
/// <summary>
/// Constructor meant to help application developers test their apps. Allows mocking of authentication flows.
/// App developers should <b>never</b> new-up <see cref="AuthenticationResult"/> in product code.
/// </summary>
/// <param name="accessToken">Access Token that can be used as a bearer token to access protected web APIs</param>
/// <param name="account">Account information</param>
/// <param name="expiresOn">Expiry date-time for the access token</param>
/// <param name="extendedExpiresOn">See <see cref="ExtendedExpiresOn"/></param>
/// <param name="idToken">ID token</param>
/// <param name="isExtendedLifeTimeToken">See <see cref="IsExtendedLifeTimeToken"/></param>
/// <param name="scopes">Granted scope values as returned by the service</param>
/// <param name="tenantId">Identifier for the Azure AD tenant from which the token was acquired. Can be <c>null</c></param>
/// <param name="uniqueId">Unique Id of the account. It can be null. When the <see cref="IdToken"/> is not <c>null</c>, this is its ID, that is its ObjectId claim, or if that claim is <c>null</c>, the Subject claim.</param>
/// <param name="correlationId">The correlation id of the authentication request</param>
/// <param name="tokenType">The token type, defaults to Bearer. Note: this property is experimental and may change in future versions of the library.</param>
/// <param name="authenticationResultMetadata">Contains metadata related to the Authentication Result.</param>
/// <param name="claimsPrincipal">Claims from the ID token</param>
/// <param name="spaAuthCode">Auth Code returned by the Microsoft identity platform when you use AcquireTokenByAuthorizationCode.WithSpaAuthorizationCode(). This auth code is meant to be redeemed by the frontend code. See https://aka.ms/msal-net/spa-auth-code</param>
/// <param name="additionalResponseParameters">Other properties from the token response.</param>
public AuthenticationResult( // for backwards compat with 4.16-
string accessToken,
bool isExtendedLifeTimeToken,
string uniqueId,
DateTimeOffset expiresOn,
DateTimeOffset extendedExpiresOn,
string tenantId,
IAccount account,
string idToken,
IEnumerable<string> scopes,
Guid correlationId,
string tokenType = "Bearer",
AuthenticationResultMetadata authenticationResultMetadata = null,
ClaimsPrincipal claimsPrincipal = null,
string spaAuthCode = null,
IReadOnlyDictionary<string, string> additionalResponseParameters = null)
{
AccessToken = accessToken;
#pragma warning disable CS0618 // Type or member is obsolete
IsExtendedLifeTimeToken = isExtendedLifeTimeToken;
ExtendedExpiresOn = extendedExpiresOn;
#pragma warning restore CS0618 // Type or member is obsolete
UniqueId = uniqueId;
ExpiresOn = expiresOn;
TenantId = tenantId;
Account = account;
IdToken = idToken;
Scopes = scopes;
CorrelationId = correlationId;
TokenType = tokenType;
AuthenticationResultMetadata = authenticationResultMetadata;
ClaimsPrincipal = claimsPrincipal;
SpaAuthCode = spaAuthCode;
AdditionalResponseParameters = additionalResponseParameters;
}
/// <summary>
/// Constructor meant to help application developers test their apps. Allows mocking of authentication flows.
/// App developers should <b>never</b> new-up <see cref="AuthenticationResult"/> in product code.
/// </summary>
/// <param name="accessToken">Access Token that can be used as a bearer token to access protected web APIs</param>
/// <param name="account">Account information</param>
/// <param name="expiresOn">Expiry date-time for the access token</param>
/// <param name="extendedExpiresOn">See <see cref="ExtendedExpiresOn"/></param>
/// <param name="idToken">ID token</param>
/// <param name="isExtendedLifeTimeToken">See <see cref="IsExtendedLifeTimeToken"/></param>
/// <param name="scopes">Granted scope values as returned by the service</param>
/// <param name="tenantId">Identifier for the Azure AD tenant from which the token was acquired. Can be <c>null</c></param>
/// <param name="uniqueId">Unique Id of the account. It can be null. When the <see cref="IdToken"/> is not <c>null</c>, this is its ID, that is its ObjectId claim, or if that claim is <c>null</c>, the Subject claim.</param>
/// <param name="correlationId">The correlation id of the authentication request</param>
/// <param name="authenticationResultMetadata">Contains metadata related to the Authentication Result.</param>
/// <param name="tokenType">The token type, defaults to Bearer. Note: this property is experimental and may change in future versions of the library.</param>
/// <remarks>For backwards compatibility with MSAL 4.17-4.20 </remarks>
public AuthenticationResult(
string accessToken,
bool isExtendedLifeTimeToken,
string uniqueId,
DateTimeOffset expiresOn,
DateTimeOffset extendedExpiresOn,
string tenantId,
IAccount account,
string idToken,
IEnumerable<string> scopes,
Guid correlationId,
AuthenticationResultMetadata authenticationResultMetadata,
string tokenType = "Bearer") :
this(
accessToken,
isExtendedLifeTimeToken,
uniqueId,
expiresOn,
extendedExpiresOn,
tenantId,
account,
idToken,
scopes,
correlationId,
tokenType,
authenticationResultMetadata)
{
}
/// <summary>
/// This method must be used by the product code to create an <see cref="AuthenticationResult"/> instance.
/// It calls IAuthenticationOperation.FormatResult or FormatResultAsync on the authentication scheme
/// </summary>
internal static async Task<AuthenticationResult> CreateAsync(
MsalAccessTokenCacheItem msalAccessTokenCacheItem,
MsalIdTokenCacheItem msalIdTokenCacheItem,
IAuthenticationOperation authenticationScheme,
Guid correlationId,
TokenSource tokenSource,
ApiEvent apiEvent,
Account account,
string spaAuthCode,
IReadOnlyDictionary<string, string> additionalResponseParameters,
CancellationToken cancellationToken = default)
{
if (authenticationScheme == null)
{
throw new ArgumentNullException(nameof(authenticationScheme));
}
// Create the AuthenticationResult without calling FormatResult in constructor
var result = new AuthenticationResult(
msalAccessTokenCacheItem,
msalIdTokenCacheItem,
correlationId,
tokenSource,
apiEvent,
account,
spaAuthCode,
additionalResponseParameters,
authenticationScheme);
// Apply token formatting (async if supported, sync otherwise)
var measuredResultDuration = await StopwatchService.MeasureCodeBlockAsync(async () =>
{
if (authenticationScheme is IAuthenticationOperation2 asyncAuthScheme)
{
await asyncAuthScheme.FormatResultAsync(result, cancellationToken).ConfigureAwait(false);
}
else
{
authenticationScheme.FormatResult(result);
}
}).ConfigureAwait(false);
// Update telemetry metadata
result.AuthenticationResultMetadata.DurationCreatingExtendedTokenInUs = measuredResultDuration.Microseconds;
result.AuthenticationResultMetadata.TelemetryTokenType = authenticationScheme.TelemetryTokenType;
return result;
}
//Default constructor for testing
internal AuthenticationResult() { }
/// <summary>
/// This is to help CreateAsync
/// </summary>
private AuthenticationResult(
MsalAccessTokenCacheItem msalAccessTokenCacheItem,
MsalIdTokenCacheItem msalIdTokenCacheItem,
Guid correlationID,
TokenSource tokenSource,
ApiEvent apiEvent,
Account account,
string spaAuthCode,
IReadOnlyDictionary<string, string> additionalResponseParameters,
IAuthenticationOperation authenticationScheme)
{
string homeAccountId =
msalAccessTokenCacheItem?.HomeAccountId ??
msalIdTokenCacheItem?.HomeAccountId;
string environment = msalAccessTokenCacheItem?.Environment ??
msalIdTokenCacheItem?.Environment;
ClaimsPrincipal = msalIdTokenCacheItem?.IdToken.ClaimsPrincipal;
if (account != null)
{
Account = account;
}
else if (homeAccountId != null)
{
Account = new Account(
homeAccountId,
msalIdTokenCacheItem?.GetUsername(),
environment);
}
UniqueId = msalIdTokenCacheItem?.IdToken?.GetUniqueId();
// For client credentials flow, ID token is not available, so fall back to access token's tenant
// See https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/5743
TenantId = msalIdTokenCacheItem?.IdToken?.TenantId ?? msalAccessTokenCacheItem?.TenantId;
IdToken = msalIdTokenCacheItem?.Secret;
SpaAuthCode = spaAuthCode;
_authenticationScheme = authenticationScheme;
CorrelationId = correlationID;
ApiEvent = apiEvent;
AuthenticationResultMetadata = new AuthenticationResultMetadata(tokenSource);
AdditionalResponseParameters = msalAccessTokenCacheItem?.PersistedCacheParameters?.Count > 0 ?
(IReadOnlyDictionary<string, string>)msalAccessTokenCacheItem.PersistedCacheParameters :
additionalResponseParameters;
if (msalAccessTokenCacheItem != null)
{
ExpiresOn = msalAccessTokenCacheItem.ExpiresOn;
Scopes = msalAccessTokenCacheItem.ScopeSet;
#pragma warning disable CS0618 // Type or member is obsolete
ExtendedExpiresOn = msalAccessTokenCacheItem.ExtendedExpiresOn;
IsExtendedLifeTimeToken = msalAccessTokenCacheItem.IsExtendedLifeTimeToken;
#pragma warning restore CS0618 // Type or member is obsolete
TokenType = msalAccessTokenCacheItem.TokenType;
if (msalAccessTokenCacheItem.RefreshOn.HasValue)
{
AuthenticationResultMetadata.RefreshOn = msalAccessTokenCacheItem.RefreshOn;
}
AccessToken = msalAccessTokenCacheItem.Secret;
}
}
/// <summary>
/// Access Token that can be used as a bearer token to access protected web APIs
/// </summary>
public string AccessToken { get; set; }
/// <summary>
/// In case when Azure AD has an outage, to be more resilient, it can return tokens with
/// an expiration time, and also with an extended expiration time.
/// The tokens are then automatically refreshed by MSAL when the time is more than the
/// expiration time, except when ExtendedLifeTimeEnabled is true and the time is less
/// than the extended expiration time. This goes in pair with Web APIs middleware which,
/// when this extended life time is enabled, can accept slightly expired tokens.
/// Client applications accept extended life time tokens only if
/// the ExtendedLifeTimeEnabled Boolean is set to true on ClientApplicationBase.
/// </summary>
/// <remarks>This feature is not in use</remarks>
[Obsolete("This feature has been deprecated", false)]
[EditorBrowsable(EditorBrowsableState.Never)] // deprecated, this feature is not in use
public bool IsExtendedLifeTimeToken { get; }
/// <summary>
/// Gets the Unique Id of the account in this <see cref="TenantId" />
/// It is set as the oid (ObjectId) claim, or if that claim is <c>null</c>, as the sub (Subject) claim which is guaranteed not-null.
/// </summary>
/// <remarks>
/// The oid claim identifies a user in all apps - Microsoft Identity Providers issue ID tokens with this claim, although it can be null in rare cases.
/// The sub claim is "a locally unique and never reassigned identifier within the Issuer for the End-User" as per https://openid.net/specs/openid-connect-core-1_0.html and it is a
/// mandatory claim with OIDC compliant issuers.
/// Guest AAD accounts have different oid claim values in each tenant. Use <see cref="Account.HomeAccountId"/> to uniquely identify users across tenants.
/// See https://docs.microsoft.com/azure/active-directory/develop/id-tokens#payload-claims
/// </remarks>
public string UniqueId { get; set; }
/// <summary>
/// Gets the point in time in which the Access Token returned in the <see cref="AccessToken"/> property ceases to be valid.
/// This value is calculated based on current UTC time measured locally and the value expiresIn received from the
/// service.
/// </summary>
public DateTimeOffset ExpiresOn { get; set; }
/// <summary>
/// Gets the point in time in which the Access Token returned in the AccessToken property ceases to be valid in MSAL's extended LifeTime.
/// This value is calculated based on current UTC time measured locally and the value ext_expiresIn received from the service.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)] // deprecated, this feature is not in use
[Obsolete("This feature has been deprecated", false)]
public DateTimeOffset ExtendedExpiresOn { get; }
/// <summary>
/// Gets an identifier for the Azure AD tenant from which the token was acquired. This property will be null if tenant information is
/// not returned by the service.
/// </summary>
public string TenantId { get; set; }
/// <summary>
/// Gets the account information. Some elements in <see cref="IAccount"/> might be null if not returned by the
/// service. The account can be passed back in some API overloads to identify which account should be used such
/// as <see cref="IClientApplicationBase.AcquireTokenSilent(IEnumerable{string}, IAccount)"/> or
/// <see cref="IClientApplicationBase.RemoveAsync(IAccount)"/> for instance
/// </summary>
public IAccount Account { get; set; }
/// <summary>
/// Gets the Id Token if returned by the service or null if no Id Token is returned.
/// </summary>
public string IdToken { get; set; }
/// <summary>
/// Gets the granted scope values returned by the service.
/// </summary>
public IEnumerable<string> Scopes { get; set; }
/// <summary>
/// Gets the correlation id used for the request.
/// </summary>
public Guid CorrelationId { get; set; }
/// <summary>
/// Identifies the type of access token. By default tokens returned by Azure Active Directory are Bearer tokens.
/// <seealso cref="CreateAuthorizationHeader"/> for getting an HTTP authorization header from an AuthenticationResult.
/// </summary>
public string TokenType { get; set; }
/// <summary>
/// Gets the SPA Authorization Code, if it was requested using WithSpaAuthorizationCode method on the
/// AcquireTokenByAuthorizationCode builder. See https://aka.ms/msal-net/spa-auth-code for details.
/// </summary>
public string SpaAuthCode { get; set; }
/// <summary>
/// The X509 certificate bound to the access-token when mTLS-PoP was used.
/// </summary>
public X509Certificate2 BindingCertificate { get; set; }
/// <summary>
/// Exposes additional response parameters returned by the token issuer (AAD).
/// </summary>
/// <remarks>
/// Not all parameters are added here, only the ones that MSAL doesn't interpret itself and only scalars.
/// Not supported on mobile frameworks (e.g. net8-android or net8-ios)
/// </remarks>
public IReadOnlyDictionary<string, string> AdditionalResponseParameters { get; set; }
/// <summary>
/// All the claims present in the ID token.
/// </summary>
public ClaimsPrincipal ClaimsPrincipal { get; set; }
/// <summary>
/// The refresh token returned in the authentication response, if any.
/// Access via <see cref="Extensibility.AuthenticationResultExtensions.GetRefreshToken"/>.
/// </summary>
internal string RefreshToken { get; set; }
internal ApiEvent ApiEvent { get; set; }
/// <summary>
/// Contains metadata for the Authentication result.
/// </summary>
public AuthenticationResultMetadata AuthenticationResultMetadata { get; set; }
/// <summary>
/// Creates the content for an HTTP authorization header from this authentication result, so
/// that you can call a protected API
/// </summary>
/// <returns>Created authorization header of the form "Bearer {AccessToken}"</returns>
/// <example>
/// Here is how you can call a protected API from this authentication result (in the <c>result</c>
/// variable):
/// <code>
/// HttpClient client = new HttpClient();
/// client.DefaultRequestHeaders.Add("Authorization", result.CreateAuthorizationHeader());
/// HttpResponseMessage r = await client.GetAsync(urlOfTheProtectedApi);
/// </code>
/// </example>
public string CreateAuthorizationHeader()
{
return $"{_authenticationScheme?.AuthorizationHeaderPrefix ?? TokenType} {AccessToken}";
}
}
}