Replace JObject with JsonDocument in Authentication (#7105)
This commit is contained in:
parent
d630a20d1a
commit
67037a0039
|
|
@ -21,7 +21,7 @@ namespace MusicStore.Mocks.Facebook
|
||||||
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value == "Id", "");
|
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value == "Id", "");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst("urn:facebook:link")?.Value == "https://www.facebook.com/myLink", "");
|
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst("urn:facebook:link")?.Value == "https://www.facebook.com/myLink", "");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.Name)?.Value == "AspnetvnextTest AspnetvnextTest", "");
|
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.Name)?.Value == "AspnetvnextTest AspnetvnextTest", "");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.User.SelectToken("id").ToString() == context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value, "");
|
Helpers.ThrowIfConditionFailed(() => context.User.GetString("id") == context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value, "");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.ExpiresIn.Value == TimeSpan.FromSeconds(100), "");
|
Helpers.ThrowIfConditionFailed(() => context.ExpiresIn.Value == TimeSpan.FromSeconds(100), "");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.AccessToken == "ValidAccessToken", "");
|
Helpers.ThrowIfConditionFailed(() => context.AccessToken == "ValidAccessToken", "");
|
||||||
context.Principal.Identities.First().AddClaim(new Claim("ManageStore", "false"));
|
context.Principal.Identities.First().AddClaim(new Claim("ManageStore", "false"));
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ namespace MusicStore.Mocks.Google
|
||||||
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.Surname)?.Value == "AspnetvnextTest", "FamilyName is not valid");
|
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.Surname)?.Value == "AspnetvnextTest", "FamilyName is not valid");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.Name)?.Value == "AspnetvnextTest AspnetvnextTest", "Name is not valid");
|
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.Name)?.Value == "AspnetvnextTest AspnetvnextTest", "Name is not valid");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.ExpiresIn.Value == TimeSpan.FromSeconds(1200), "ExpiresIn is not valid");
|
Helpers.ThrowIfConditionFailed(() => context.ExpiresIn.Value == TimeSpan.FromSeconds(1200), "ExpiresIn is not valid");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.User != null, "User object is not valid");
|
|
||||||
context.Principal.Identities.First().AddClaim(new Claim("ManageStore", "false"));
|
context.Principal.Identities.First().AddClaim(new Claim("ManageStore", "false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,7 @@ namespace MusicStore.Mocks.MicrosoftAccount
|
||||||
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value == "fccf9a24999f4f4f", "Id is not valid");
|
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value == "fccf9a24999f4f4f", "Id is not valid");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.Name)?.Value == "AspnetvnextTest AspnetvnextTest", "Name is not valid");
|
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.Name)?.Value == "AspnetvnextTest AspnetvnextTest", "Name is not valid");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.ExpiresIn.Value == TimeSpan.FromSeconds(3600), "ExpiresIn is not valid");
|
Helpers.ThrowIfConditionFailed(() => context.ExpiresIn.Value == TimeSpan.FromSeconds(3600), "ExpiresIn is not valid");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.User != null, "User object is not valid");
|
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value == context.User.GetString("id"), "User id is not valid");
|
||||||
Helpers.ThrowIfConditionFailed(() => context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value == context.User.SelectToken("id").ToString(), "User id is not valid");
|
|
||||||
context.Principal.Identities.First().AddClaim(new Claim("ManageStore", "false"));
|
context.Principal.Identities.First().AddClaim(new Claim("ManageStore", "false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
#launchSettings.json files are required for the auth samples. The ports must not change.
|
||||||
|
!launchSettings.json
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:1780/",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CookieSample": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:1782/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:1771/",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"CookieSessionSample": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "http://localhost:1776/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Authentication
|
||||||
|
{
|
||||||
|
public static class JsonDocumentAuthExtensions
|
||||||
|
{
|
||||||
|
public static string GetString(this JsonElement element, string key) =>
|
||||||
|
element.TryGetProperty(key, out var property)
|
||||||
|
? property.ToString() : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,12 +8,12 @@ using System.Security.Claims;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.Facebook
|
namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
{
|
{
|
||||||
|
|
@ -41,15 +41,13 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
throw new HttpRequestException($"An error occurred when retrieving Facebook user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Facebook Graph API is enabled.");
|
throw new HttpRequestException($"An error occurred when retrieving Facebook user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Facebook Graph API is enabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
|
using (var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync()))
|
||||||
|
{
|
||||||
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload);
|
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
|
||||||
context.RunClaimActions();
|
context.RunClaimActions();
|
||||||
|
await Events.CreatingTicket(context);
|
||||||
await Events.CreatingTicket(context);
|
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
||||||
|
}
|
||||||
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GenerateAppSecretProof(string accessToken)
|
private string GenerateAppSecretProof(string accessToken)
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@ using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.Google
|
namespace Microsoft.AspNetCore.Authentication.Google
|
||||||
{
|
{
|
||||||
|
|
@ -37,13 +37,13 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
||||||
throw new HttpRequestException($"An error occurred when retrieving Google user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Google+ API is enabled.");
|
throw new HttpRequestException($"An error occurred when retrieving Google user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Google+ API is enabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
|
using (var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync()))
|
||||||
|
{
|
||||||
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload);
|
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
|
||||||
context.RunClaimActions();
|
context.RunClaimActions();
|
||||||
|
await Events.CreatingTicket(context);
|
||||||
await Events.CreatingTicket(context);
|
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
||||||
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Abstract this properties override pattern into the base class?
|
// TODO: Abstract this properties override pattern into the base class?
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "https://localhost:44318/",
|
||||||
|
"sslPort": 44318
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SocialSample": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://localhost:44318/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.IO.Pipelines;
|
||||||
using System.Runtime.ExceptionServices;
|
using System.Runtime.ExceptionServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
|
@ -10,7 +14,6 @@ using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace JwtBearerSample
|
namespace JwtBearerSample
|
||||||
{
|
{
|
||||||
|
|
@ -93,19 +96,37 @@ namespace JwtBearerSample
|
||||||
{
|
{
|
||||||
var reader = new StreamReader(context.Request.Body);
|
var reader = new StreamReader(context.Request.Body);
|
||||||
var body = await reader.ReadToEndAsync();
|
var body = await reader.ReadToEndAsync();
|
||||||
var obj = JObject.Parse(body);
|
using (var json = JsonDocument.Parse(body))
|
||||||
var todo = new Todo() { Description = obj["Description"].Value<string>(), Owner = context.User.Identity.Name };
|
{
|
||||||
Todos.Add(todo);
|
var obj = json.RootElement;
|
||||||
|
var todo = new Todo() { Description = obj.GetProperty("Description").GetString(), Owner = context.User.Identity.Name };
|
||||||
|
Todos.Add(todo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
response.ContentType = "application/json";
|
response.ContentType = "application/json";
|
||||||
response.Headers[HeaderNames.CacheControl] = "no-cache";
|
response.Headers[HeaderNames.CacheControl] = "no-cache";
|
||||||
var json = JToken.FromObject(Todos);
|
Serialize(Todos, response.BodyPipe);
|
||||||
await response.WriteAsync(json.ToString());
|
await response.BodyPipe.FlushAsync();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Serialize(IList<Todo> todos, IBufferWriter<byte> output)
|
||||||
|
{
|
||||||
|
var writer = new Utf8JsonWriter(output);
|
||||||
|
writer.WriteStartArray();
|
||||||
|
foreach (var todo in todos)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
writer.WriteString("Description", todo.Description);
|
||||||
|
writer.WriteString("Owner", todo.Owner);
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
writer.WriteEndArray();
|
||||||
|
writer.Flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
||||||
{
|
{
|
||||||
|
|
@ -30,13 +30,13 @@ namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
||||||
throw new HttpRequestException($"An error occurred when retrieving Microsoft user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Microsoft Account API is enabled.");
|
throw new HttpRequestException($"An error occurred when retrieving Microsoft user information ({response.StatusCode}). Please check if the authentication information is correct and the corresponding Microsoft Account API is enabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
|
using (var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync()))
|
||||||
|
{
|
||||||
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload);
|
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload.RootElement);
|
||||||
context.RunClaimActions();
|
context.RunClaimActions();
|
||||||
|
await Events.CreatingTicket(context);
|
||||||
await Events.CreatingTicket(context);
|
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
||||||
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,8 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
|
||||||
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
||||||
{
|
{
|
||||||
|
|
@ -29,7 +27,7 @@ namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
||||||
ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName");
|
ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName");
|
||||||
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "givenName");
|
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "givenName");
|
||||||
ClaimActions.MapJsonKey(ClaimTypes.Surname, "surname");
|
ClaimActions.MapJsonKey(ClaimTypes.Surname, "surname");
|
||||||
ClaimActions.MapCustomJson(ClaimTypes.Email, user => user.Value<string>("mail") ?? user.Value<string>("userPrincipalName"));
|
ClaimActions.MapCustomJson(ClaimTypes.Email, user => user.GetString("mail") ?? user.GetString("userPrincipalName"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Newtonsoft.Json.Linq;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
{
|
{
|
||||||
|
|
@ -37,6 +37,6 @@ namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
/// <param name="userData">The source data to examine. This value may be null.</param>
|
/// <param name="userData">The source data to examine. This value may be null.</param>
|
||||||
/// <param name="identity">The identity to add Claims to.</param>
|
/// <param name="identity">The identity to add Claims to.</param>
|
||||||
/// <param name="issuer">The value to use for Claim.Issuer when creating a Claim.</param>
|
/// <param name="issuer">The value to use for Claim.Issuer when creating a Claim.</param>
|
||||||
public abstract void Run(JObject userData, ClaimsIdentity identity, string issuer);
|
public abstract void Run(JsonElement userData, ClaimsIdentity identity, string issuer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication
|
namespace Microsoft.AspNetCore.Authentication
|
||||||
{
|
{
|
||||||
|
|
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
/// <param name="collection"></param>
|
/// <param name="collection"></param>
|
||||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||||
/// <param name="resolver">The Func that will be called to select value from the given json user data.</param>
|
/// <param name="resolver">The Func that will be called to select value from the given json user data.</param>
|
||||||
public static void MapCustomJson(this ClaimActionCollection collection, string claimType, Func<JObject, string> resolver)
|
public static void MapCustomJson(this ClaimActionCollection collection, string claimType, Func<JsonElement, string> resolver)
|
||||||
{
|
{
|
||||||
collection.MapCustomJson(claimType, ClaimValueTypes.String, resolver);
|
collection.MapCustomJson(claimType, ClaimValueTypes.String, resolver);
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,7 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||||
/// <param name="valueType">The value to use for Claim.ValueType when creating a Claim.</param>
|
/// <param name="valueType">The value to use for Claim.ValueType when creating a Claim.</param>
|
||||||
/// <param name="resolver">The Func that will be called to select value from the given json user data.</param>
|
/// <param name="resolver">The Func that will be called to select value from the given json user data.</param>
|
||||||
public static void MapCustomJson(this ClaimActionCollection collection, string claimType, string valueType, Func<JObject, string> resolver)
|
public static void MapCustomJson(this ClaimActionCollection collection, string claimType, string valueType, Func<JsonElement, string> resolver)
|
||||||
{
|
{
|
||||||
collection.Add(new CustomJsonClaimAction(claimType, valueType, resolver));
|
collection.Add(new CustomJsonClaimAction(claimType, valueType, resolver));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Newtonsoft.Json.Linq;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
{
|
{
|
||||||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||||
/// <param name="valueType">The value to use for Claim.ValueType when creating a Claim.</param>
|
/// <param name="valueType">The value to use for Claim.ValueType when creating a Claim.</param>
|
||||||
/// <param name="resolver">The Func that will be called to select value from the given json user data.</param>
|
/// <param name="resolver">The Func that will be called to select value from the given json user data.</param>
|
||||||
public CustomJsonClaimAction(string claimType, string valueType, Func<JObject, string> resolver)
|
public CustomJsonClaimAction(string claimType, string valueType, Func<JsonElement, string> resolver)
|
||||||
: base(claimType, valueType)
|
: base(claimType, valueType)
|
||||||
{
|
{
|
||||||
Resolver = resolver;
|
Resolver = resolver;
|
||||||
|
|
@ -27,15 +27,11 @@ namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Func that will be called to select value from the given json user data.
|
/// The Func that will be called to select value from the given json user data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Func<JObject, string> Resolver { get; }
|
public Func<JsonElement, string> Resolver { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
|
||||||
{
|
{
|
||||||
if (userData == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var value = Resolver(userData);
|
var value = Resolver(userData);
|
||||||
if (!string.IsNullOrEmpty(value))
|
if (!string.IsNullOrEmpty(value))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Newtonsoft.Json.Linq;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
{
|
{
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
|
||||||
{
|
{
|
||||||
foreach (var claim in identity.FindAll(ClaimType).ToList())
|
foreach (var claim in identity.FindAll(ClaimType).ToList())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@ using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth
|
namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
{
|
{
|
||||||
|
|
@ -15,27 +15,6 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OAuthCreatingTicketContext : ResultContext<OAuthOptions>
|
public class OAuthCreatingTicketContext : ResultContext<OAuthOptions>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new <see cref="OAuthCreatingTicketContext"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="principal">The <see cref="ClaimsPrincipal"/>.</param>
|
|
||||||
/// <param name="properties">The <see cref="AuthenticationProperties"/>.</param>
|
|
||||||
/// <param name="context">The HTTP environment.</param>
|
|
||||||
/// <param name="scheme">The authentication scheme.</param>
|
|
||||||
/// <param name="options">The options used by the authentication middleware.</param>
|
|
||||||
/// <param name="backchannel">The HTTP client used by the authentication middleware</param>
|
|
||||||
/// <param name="tokens">The tokens returned from the token endpoint.</param>
|
|
||||||
public OAuthCreatingTicketContext(
|
|
||||||
ClaimsPrincipal principal,
|
|
||||||
AuthenticationProperties properties,
|
|
||||||
HttpContext context,
|
|
||||||
AuthenticationScheme scheme,
|
|
||||||
OAuthOptions options,
|
|
||||||
HttpClient backchannel,
|
|
||||||
OAuthTokenResponse tokens)
|
|
||||||
: this(principal, properties, context, scheme, options, backchannel, tokens, user: new JObject())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new <see cref="OAuthCreatingTicketContext"/>.
|
/// Initializes a new <see cref="OAuthCreatingTicketContext"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -55,7 +34,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
OAuthOptions options,
|
OAuthOptions options,
|
||||||
HttpClient backchannel,
|
HttpClient backchannel,
|
||||||
OAuthTokenResponse tokens,
|
OAuthTokenResponse tokens,
|
||||||
JObject user)
|
JsonElement user)
|
||||||
: base(context, scheme, options)
|
: base(context, scheme, options)
|
||||||
{
|
{
|
||||||
if (backchannel == null)
|
if (backchannel == null)
|
||||||
|
|
@ -68,11 +47,6 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
throw new ArgumentNullException(nameof(tokens));
|
throw new ArgumentNullException(nameof(tokens));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
TokenResponse = tokens;
|
TokenResponse = tokens;
|
||||||
Backchannel = backchannel;
|
Backchannel = backchannel;
|
||||||
User = user;
|
User = user;
|
||||||
|
|
@ -82,9 +56,9 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the JSON-serialized user or an empty
|
/// Gets the JSON-serialized user or an empty
|
||||||
/// <see cref="JObject"/> if it is not available.
|
/// <see cref="JsonElement"/> if it is not available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public JObject User { get; }
|
public JsonElement User { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the token response returned by the authentication service.
|
/// Gets the token response returned by the authentication service.
|
||||||
|
|
@ -136,17 +110,12 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
|
|
||||||
public void RunClaimActions() => RunClaimActions(User);
|
public void RunClaimActions() => RunClaimActions(User);
|
||||||
|
|
||||||
public void RunClaimActions(JObject userData)
|
public void RunClaimActions(JsonElement userData)
|
||||||
{
|
{
|
||||||
if (userData == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(userData));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var action in Options.ClaimActions)
|
foreach (var action in Options.ClaimActions)
|
||||||
{
|
{
|
||||||
action.Run(userData, Identity, Options.ClaimsIssuer ?? Scheme.Name);
|
action.Run(userData, Identity, Options.ClaimsIssuer ?? Scheme.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Newtonsoft.Json.Linq;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
{
|
{
|
||||||
|
|
@ -30,20 +30,27 @@ namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
public string JsonKey { get; }
|
public string JsonKey { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
|
||||||
{
|
{
|
||||||
var value = userData?[JsonKey];
|
if (!userData.TryGetProperty(JsonKey, out var value))
|
||||||
if (value is JValue)
|
|
||||||
{
|
{
|
||||||
AddClaim(value?.ToString(), identity, issuer);
|
return;
|
||||||
}
|
}
|
||||||
else if (value is JArray)
|
if (value.Type == JsonValueType.Array)
|
||||||
{
|
{
|
||||||
foreach (var v in value)
|
foreach (var v in value.EnumerateArray())
|
||||||
{
|
{
|
||||||
AddClaim(v?.ToString(), identity, issuer);
|
AddClaim(v.ToString(), identity, issuer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (value.Type == JsonValueType.Object || value.Type == JsonValueType.Undefined)
|
||||||
|
{
|
||||||
|
// Skip, because they were previously skipped
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddClaim(value.ToString(), identity, issuer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddClaim(string value, ClaimsIdentity identity, string issuer)
|
private void AddClaim(string value, ClaimsIdentity identity, string issuer)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
{
|
{
|
||||||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
public string SubKey { get; }
|
public string SubKey { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
|
||||||
{
|
{
|
||||||
var value = GetValue(userData, JsonKey, SubKey);
|
var value = GetValue(userData, JsonKey, SubKey);
|
||||||
if (!string.IsNullOrEmpty(value))
|
if (!string.IsNullOrEmpty(value))
|
||||||
|
|
@ -42,15 +42,12 @@ namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the given subProperty from a property.
|
// Get the given subProperty from a property.
|
||||||
private static string GetValue(JObject userData, string propertyName, string subProperty)
|
private static string GetValue(JsonElement userData, string propertyName, string subProperty)
|
||||||
{
|
{
|
||||||
if (userData != null && userData.TryGetValue(propertyName, out var value))
|
if (userData.TryGetProperty(propertyName, out var value)
|
||||||
|
&& value.Type == JsonValueType.Object && value.TryGetProperty(subProperty, out value))
|
||||||
{
|
{
|
||||||
var subObject = JObject.Parse(value.ToString());
|
return value.ToString();
|
||||||
if (subObject != null && subObject.TryGetValue(subProperty, out value))
|
|
||||||
{
|
|
||||||
return value.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Newtonsoft.Json.Linq;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
{
|
{
|
||||||
|
|
@ -17,24 +17,20 @@ namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
|
||||||
{
|
{
|
||||||
if (userData == null)
|
foreach (var pair in userData.EnumerateObject())
|
||||||
{
|
{
|
||||||
return;
|
var claimValue = pair.Value.ToString();
|
||||||
}
|
|
||||||
foreach (var pair in userData)
|
|
||||||
{
|
|
||||||
var claimValue = userData.TryGetValue(pair.Key, out var value) ? value.ToString() : null;
|
|
||||||
|
|
||||||
// Avoid adding a claim if there's a duplicate name and value. This often happens in OIDC when claims are
|
// Avoid adding a claim if there's a duplicate name and value. This often happens in OIDC when claims are
|
||||||
// retrieved both from the id_token and from the user-info endpoint.
|
// retrieved both from the id_token and from the user-info endpoint.
|
||||||
var duplicate = identity.FindFirst(c => string.Equals(c.Type, pair.Key, StringComparison.OrdinalIgnoreCase)
|
var duplicate = identity.FindFirst(c => string.Equals(c.Type, pair.Name, StringComparison.OrdinalIgnoreCase)
|
||||||
&& string.Equals(c.Value, claimValue, StringComparison.Ordinal)) != null;
|
&& string.Equals(c.Value, claimValue, StringComparison.Ordinal)) != null;
|
||||||
|
|
||||||
if (!duplicate)
|
if (!duplicate)
|
||||||
{
|
{
|
||||||
identity.AddClaim(new Claim(pair.Key, claimValue, ClaimValueTypes.String, issuer));
|
identity.AddClaim(new Claim(pair.Name, claimValue, ClaimValueTypes.String, issuer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>ASP.NET Core middleware that enables an application to support any standard OAuth 2.0 authentication workflow.</Description>
|
<Description>ASP.NET Core middleware that enables an application to support any standard OAuth 2.0 authentication workflow.</Description>
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Microsoft.AspNetCore.Authentication" />
|
<Reference Include="Microsoft.AspNetCore.Authentication" />
|
||||||
<Reference Include="Newtonsoft.Json" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ using System.Net.Http.Headers;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth
|
namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
{
|
{
|
||||||
|
|
@ -99,62 +99,63 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
return HandleRequestResult.Fail("Code was not found.", properties);
|
return HandleRequestResult.Fail("Code was not found.", properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokens = await ExchangeCodeAsync(code, BuildRedirectUri(Options.CallbackPath));
|
using (var tokens = await ExchangeCodeAsync(code, BuildRedirectUri(Options.CallbackPath)))
|
||||||
|
|
||||||
if (tokens.Error != null)
|
|
||||||
{
|
{
|
||||||
return HandleRequestResult.Fail(tokens.Error, properties);
|
if (tokens.Error != null)
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(tokens.AccessToken))
|
|
||||||
{
|
|
||||||
return HandleRequestResult.Fail("Failed to retrieve access token.", properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
var identity = new ClaimsIdentity(ClaimsIssuer);
|
|
||||||
|
|
||||||
if (Options.SaveTokens)
|
|
||||||
{
|
|
||||||
var authTokens = new List<AuthenticationToken>();
|
|
||||||
|
|
||||||
authTokens.Add(new AuthenticationToken { Name = "access_token", Value = tokens.AccessToken });
|
|
||||||
if (!string.IsNullOrEmpty(tokens.RefreshToken))
|
|
||||||
{
|
{
|
||||||
authTokens.Add(new AuthenticationToken { Name = "refresh_token", Value = tokens.RefreshToken });
|
return HandleRequestResult.Fail(tokens.Error, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tokens.TokenType))
|
if (string.IsNullOrEmpty(tokens.AccessToken))
|
||||||
{
|
{
|
||||||
authTokens.Add(new AuthenticationToken { Name = "token_type", Value = tokens.TokenType });
|
return HandleRequestResult.Fail("Failed to retrieve access token.", properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(tokens.ExpiresIn))
|
var identity = new ClaimsIdentity(ClaimsIssuer);
|
||||||
|
|
||||||
|
if (Options.SaveTokens)
|
||||||
{
|
{
|
||||||
int value;
|
var authTokens = new List<AuthenticationToken>();
|
||||||
if (int.TryParse(tokens.ExpiresIn, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
|
|
||||||
|
authTokens.Add(new AuthenticationToken { Name = "access_token", Value = tokens.AccessToken });
|
||||||
|
if (!string.IsNullOrEmpty(tokens.RefreshToken))
|
||||||
{
|
{
|
||||||
// https://www.w3.org/TR/xmlschema-2/#dateTime
|
authTokens.Add(new AuthenticationToken { Name = "refresh_token", Value = tokens.RefreshToken });
|
||||||
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx
|
|
||||||
var expiresAt = Clock.UtcNow + TimeSpan.FromSeconds(value);
|
|
||||||
authTokens.Add(new AuthenticationToken
|
|
||||||
{
|
|
||||||
Name = "expires_at",
|
|
||||||
Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(tokens.TokenType))
|
||||||
|
{
|
||||||
|
authTokens.Add(new AuthenticationToken { Name = "token_type", Value = tokens.TokenType });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(tokens.ExpiresIn))
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
if (int.TryParse(tokens.ExpiresIn, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
|
||||||
|
{
|
||||||
|
// https://www.w3.org/TR/xmlschema-2/#dateTime
|
||||||
|
// https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx
|
||||||
|
var expiresAt = Clock.UtcNow + TimeSpan.FromSeconds(value);
|
||||||
|
authTokens.Add(new AuthenticationToken
|
||||||
|
{
|
||||||
|
Name = "expires_at",
|
||||||
|
Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.StoreTokens(authTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
properties.StoreTokens(authTokens);
|
var ticket = await CreateTicketAsync(identity, properties, tokens);
|
||||||
}
|
if (ticket != null)
|
||||||
|
{
|
||||||
var ticket = await CreateTicketAsync(identity, properties, tokens);
|
return HandleRequestResult.Success(ticket);
|
||||||
if (ticket != null)
|
}
|
||||||
{
|
else
|
||||||
return HandleRequestResult.Success(ticket);
|
{
|
||||||
}
|
return HandleRequestResult.Fail("Failed to retrieve user information from remote server.", properties);
|
||||||
else
|
}
|
||||||
{
|
|
||||||
return HandleRequestResult.Fail("Failed to retrieve user information from remote server.", properties);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +178,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
|
var response = await Backchannel.SendAsync(requestMessage, Context.RequestAborted);
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync());
|
var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
|
||||||
return OAuthTokenResponse.Success(payload);
|
return OAuthTokenResponse.Success(payload);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -198,9 +199,12 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
|
|
||||||
protected virtual async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
|
protected virtual async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
|
||||||
{
|
{
|
||||||
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens);
|
using (var user = JsonDocument.Parse("{}"))
|
||||||
await Events.CreatingTicket(context);
|
{
|
||||||
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, user.RootElement);
|
||||||
|
await Events.CreatingTicket(context);
|
||||||
|
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,20 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Newtonsoft.Json.Linq;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OAuth
|
namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
{
|
{
|
||||||
public class OAuthTokenResponse
|
public class OAuthTokenResponse : IDisposable
|
||||||
{
|
{
|
||||||
private OAuthTokenResponse(JObject response)
|
private OAuthTokenResponse(JsonDocument response)
|
||||||
{
|
{
|
||||||
Response = response;
|
Response = response;
|
||||||
AccessToken = response.Value<string>("access_token");
|
var root = response.RootElement;
|
||||||
TokenType = response.Value<string>("token_type");
|
AccessToken = root.GetString("access_token");
|
||||||
RefreshToken = response.Value<string>("refresh_token");
|
TokenType = root.GetString("token_type");
|
||||||
ExpiresIn = response.Value<string>("expires_in");
|
RefreshToken = root.GetString("refresh_token");
|
||||||
|
ExpiresIn = root.GetString("expires_in");
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuthTokenResponse(Exception error)
|
private OAuthTokenResponse(Exception error)
|
||||||
|
|
@ -22,7 +23,7 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
Error = error;
|
Error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static OAuthTokenResponse Success(JObject response)
|
public static OAuthTokenResponse Success(JsonDocument response)
|
||||||
{
|
{
|
||||||
return new OAuthTokenResponse(response);
|
return new OAuthTokenResponse(response);
|
||||||
}
|
}
|
||||||
|
|
@ -32,11 +33,16 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||||
return new OAuthTokenResponse(error);
|
return new OAuthTokenResponse(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JObject Response { get; set; }
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Response?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonDocument Response { get; set; }
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
public string TokenType { get; set; }
|
public string TokenType { get; set; }
|
||||||
public string RefreshToken { get; set; }
|
public string RefreshToken { get; set; }
|
||||||
public string ExpiresIn { get; set; }
|
public string ExpiresIn { get; set; }
|
||||||
public Exception Error { get; set; }
|
public Exception Error { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "https://localhost:44318/",
|
||||||
|
"sslPort": 44318
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SocialSample": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://localhost:44318/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "https://localhost:44318/",
|
||||||
|
"sslPort": 44318
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SocialSample": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://localhost:44318/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
|
@ -16,7 +17,6 @@ using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace OpenIdConnectSample
|
namespace OpenIdConnectSample
|
||||||
{
|
{
|
||||||
|
|
@ -208,30 +208,31 @@ namespace OpenIdConnectSample
|
||||||
var tokenResponse = await options.Backchannel.PostAsync(metadata.TokenEndpoint, content, context.RequestAborted);
|
var tokenResponse = await options.Backchannel.PostAsync(metadata.TokenEndpoint, content, context.RequestAborted);
|
||||||
tokenResponse.EnsureSuccessStatusCode();
|
tokenResponse.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
var payload = JObject.Parse(await tokenResponse.Content.ReadAsStringAsync());
|
using (var payload = JsonDocument.Parse(await tokenResponse.Content.ReadAsStringAsync()))
|
||||||
|
|
||||||
// Persist the new acess token
|
|
||||||
props.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
|
|
||||||
props.UpdateTokenValue("refresh_token", payload.Value<string>("refresh_token"));
|
|
||||||
if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
|
|
||||||
{
|
{
|
||||||
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
// Persist the new acess token
|
||||||
props.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
props.UpdateTokenValue("access_token", payload.RootElement.GetString("access_token"));
|
||||||
|
props.UpdateTokenValue("refresh_token", payload.RootElement.GetString("refresh_token"));
|
||||||
|
if (payload.RootElement.TryGetProperty("expires_in", out var property) && property.TryGetInt32(out var seconds))
|
||||||
|
{
|
||||||
|
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
||||||
|
props.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
await context.SignInAsync(user, props);
|
||||||
|
|
||||||
|
await WriteHtmlAsync(response, async res =>
|
||||||
|
{
|
||||||
|
await res.WriteAsync($"<h1>Refreshed.</h1>");
|
||||||
|
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/refresh\">Refresh tokens</a>");
|
||||||
|
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
|
||||||
|
|
||||||
|
await res.WriteAsync("<h2>Tokens:</h2>");
|
||||||
|
await WriteTableHeader(res, new string[] { "Token Type", "Value" }, props.GetTokens().Select(token => new string[] { token.Name, token.Value }));
|
||||||
|
|
||||||
|
await res.WriteAsync("<h2>Payload:</h2>");
|
||||||
|
await res.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",<br>") + "<br>");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
await context.SignInAsync(user, props);
|
|
||||||
|
|
||||||
await WriteHtmlAsync(response, async res =>
|
|
||||||
{
|
|
||||||
await res.WriteAsync($"<h1>Refreshed.</h1>");
|
|
||||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/refresh\">Refresh tokens</a>");
|
|
||||||
await res.WriteAsync("<a class=\"btn btn-default\" href=\"/\">Home</a>");
|
|
||||||
|
|
||||||
await res.WriteAsync("<h2>Tokens:</h2>");
|
|
||||||
await WriteTableHeader(res, new string[] { "Token Type", "Value" }, props.GetTokens().Select(token => new string[] { token.Name, token.Value }));
|
|
||||||
|
|
||||||
await res.WriteAsync("<h2>Payload:</h2>");
|
|
||||||
await res.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",<br>") + "<br>");
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||||
{
|
{
|
||||||
|
|
@ -16,6 +16,6 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||||
|
|
||||||
public OpenIdConnectMessage ProtocolMessage { get; set; }
|
public OpenIdConnectMessage ProtocolMessage { get; set; }
|
||||||
|
|
||||||
public JObject User { get; set; }
|
public JsonDocument User { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using System.Security.Claims;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
@ -20,7 +21,6 @@ using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||||
{
|
{
|
||||||
|
|
@ -712,10 +712,13 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var identity = (ClaimsIdentity)user.Identity;
|
using (var payload = JsonDocument.Parse("{}"))
|
||||||
foreach (var action in Options.ClaimActions)
|
|
||||||
{
|
{
|
||||||
action.Run(null, identity, ClaimsIssuer);
|
var identity = (ClaimsIdentity)user.Identity;
|
||||||
|
foreach (var action in Options.ClaimActions)
|
||||||
|
{
|
||||||
|
action.Run(payload.RootElement, identity, ClaimsIssuer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -853,42 +856,46 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||||
responseMessage.EnsureSuccessStatusCode();
|
responseMessage.EnsureSuccessStatusCode();
|
||||||
var userInfoResponse = await responseMessage.Content.ReadAsStringAsync();
|
var userInfoResponse = await responseMessage.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
JObject user;
|
JsonDocument user;
|
||||||
var contentType = responseMessage.Content.Headers.ContentType;
|
var contentType = responseMessage.Content.Headers.ContentType;
|
||||||
if (contentType.MediaType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
|
if (contentType.MediaType.Equals("application/json", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
user = JObject.Parse(userInfoResponse);
|
user = JsonDocument.Parse(userInfoResponse);
|
||||||
}
|
}
|
||||||
else if (contentType.MediaType.Equals("application/jwt", StringComparison.OrdinalIgnoreCase))
|
else if (contentType.MediaType.Equals("application/jwt", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var userInfoEndpointJwt = new JwtSecurityToken(userInfoResponse);
|
var userInfoEndpointJwt = new JwtSecurityToken(userInfoResponse);
|
||||||
user = JObject.FromObject(userInfoEndpointJwt.Payload);
|
user = JsonDocument.Parse(userInfoEndpointJwt.Payload.SerializeToJson());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return HandleRequestResult.Fail("Unknown response type: " + contentType.MediaType, properties);
|
return HandleRequestResult.Fail("Unknown response type: " + contentType.MediaType, properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(principal, properties, message, user);
|
using (user)
|
||||||
if (userInformationReceivedContext.Result != null)
|
|
||||||
{
|
{
|
||||||
return userInformationReceivedContext.Result;
|
var userInformationReceivedContext = await RunUserInformationReceivedEventAsync(principal, properties, message, user);
|
||||||
}
|
if (userInformationReceivedContext.Result != null)
|
||||||
principal = userInformationReceivedContext.Principal;
|
{
|
||||||
properties = userInformationReceivedContext.Properties;
|
return userInformationReceivedContext.Result;
|
||||||
user = userInformationReceivedContext.User;
|
}
|
||||||
|
principal = userInformationReceivedContext.Principal;
|
||||||
|
properties = userInformationReceivedContext.Properties;
|
||||||
|
using (var updatedUser = userInformationReceivedContext.User)
|
||||||
|
{
|
||||||
|
Options.ProtocolValidator.ValidateUserInfoResponse(new OpenIdConnectProtocolValidationContext()
|
||||||
|
{
|
||||||
|
UserInfoEndpointResponse = userInfoResponse,
|
||||||
|
ValidatedIdToken = jwt,
|
||||||
|
});
|
||||||
|
|
||||||
Options.ProtocolValidator.ValidateUserInfoResponse(new OpenIdConnectProtocolValidationContext()
|
var identity = (ClaimsIdentity)principal.Identity;
|
||||||
{
|
|
||||||
UserInfoEndpointResponse = userInfoResponse,
|
|
||||||
ValidatedIdToken = jwt,
|
|
||||||
});
|
|
||||||
|
|
||||||
var identity = (ClaimsIdentity)principal.Identity;
|
foreach (var action in Options.ClaimActions)
|
||||||
|
{
|
||||||
foreach (var action in Options.ClaimActions)
|
action.Run(user.RootElement, identity, ClaimsIssuer);
|
||||||
{
|
}
|
||||||
action.Run(user, identity, ClaimsIssuer);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HandleRequestResult.Success(new AuthenticationTicket(principal, properties, Scheme.Name));
|
return HandleRequestResult.Success(new AuthenticationTicket(principal, properties, Scheme.Name));
|
||||||
|
|
@ -1144,7 +1151,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<UserInformationReceivedContext> RunUserInformationReceivedEventAsync(ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectMessage message, JObject user)
|
private async Task<UserInformationReceivedContext> RunUserInformationReceivedEventAsync(ClaimsPrincipal principal, AuthenticationProperties properties, OpenIdConnectMessage message, JsonDocument user)
|
||||||
{
|
{
|
||||||
Logger.UserInformationReceived(user.ToString());
|
Logger.UserInformationReceived(user.ToString());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect.Claims
|
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect.Claims
|
||||||
{
|
{
|
||||||
|
|
@ -27,9 +27,9 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect.Claims
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
public override void Run(JsonElement userData, ClaimsIdentity identity, string issuer)
|
||||||
{
|
{
|
||||||
var value = userData?.Value<string>(JsonKey);
|
var value = userData.GetString(JsonKey);
|
||||||
if (string.IsNullOrEmpty(value))
|
if (string.IsNullOrEmpty(value))
|
||||||
{
|
{
|
||||||
// Not found
|
// Not found
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.Twitter
|
namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
{
|
{
|
||||||
|
|
@ -36,14 +35,14 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
string screenName,
|
string screenName,
|
||||||
string accessToken,
|
string accessToken,
|
||||||
string accessTokenSecret,
|
string accessTokenSecret,
|
||||||
JObject user)
|
JsonElement user)
|
||||||
: base(context, scheme, options)
|
: base(context, scheme, options)
|
||||||
{
|
{
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
ScreenName = screenName;
|
ScreenName = screenName;
|
||||||
AccessToken = accessToken;
|
AccessToken = accessToken;
|
||||||
AccessTokenSecret = accessTokenSecret;
|
AccessTokenSecret = accessTokenSecret;
|
||||||
User = user ?? new JObject();
|
User = user;
|
||||||
Principal = principal;
|
Principal = principal;
|
||||||
Properties = properties;
|
Properties = properties;
|
||||||
}
|
}
|
||||||
|
|
@ -70,8 +69,8 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the JSON-serialized user or an empty
|
/// Gets the JSON-serialized user or an empty
|
||||||
/// <see cref="JObject"/> if it is not available.
|
/// <see cref="JsonElement"/> if it is not available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public JObject User { get; }
|
public JsonElement User { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ using System.Security.Claims;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication.Twitter
|
namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
{
|
{
|
||||||
|
|
@ -99,25 +99,33 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
},
|
},
|
||||||
ClaimsIssuer);
|
ClaimsIssuer);
|
||||||
|
|
||||||
JObject user = null;
|
JsonDocument user;
|
||||||
if (Options.RetrieveUserDetails)
|
if (Options.RetrieveUserDetails)
|
||||||
{
|
{
|
||||||
user = await RetrieveUserDetailsAsync(accessToken, identity);
|
user = await RetrieveUserDetailsAsync(accessToken, identity);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (Options.SaveTokens)
|
|
||||||
{
|
{
|
||||||
properties.StoreTokens(new [] {
|
user = JsonDocument.Parse("{}");
|
||||||
new AuthenticationToken { Name = "access_token", Value = accessToken.Token },
|
|
||||||
new AuthenticationToken { Name = "access_token_secret", Value = accessToken.TokenSecret }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return HandleRequestResult.Success(await CreateTicketAsync(identity, properties, accessToken, user));
|
using (user)
|
||||||
|
{
|
||||||
|
if (Options.SaveTokens)
|
||||||
|
{
|
||||||
|
properties.StoreTokens(new[] {
|
||||||
|
new AuthenticationToken { Name = "access_token", Value = accessToken.Token },
|
||||||
|
new AuthenticationToken { Name = "access_token_secret", Value = accessToken.TokenSecret }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var ticket = await CreateTicketAsync(identity, properties, accessToken, user.RootElement);
|
||||||
|
return HandleRequestResult.Success(ticket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task<AuthenticationTicket> CreateTicketAsync(
|
protected virtual async Task<AuthenticationTicket> CreateTicketAsync(
|
||||||
ClaimsIdentity identity, AuthenticationProperties properties, AccessToken token, JObject user)
|
ClaimsIdentity identity, AuthenticationProperties properties, AccessToken token, JsonElement user)
|
||||||
{
|
{
|
||||||
foreach (var action in Options.ClaimActions)
|
foreach (var action in Options.ClaimActions)
|
||||||
{
|
{
|
||||||
|
|
@ -275,7 +283,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dev.twitter.com/rest/reference/get/account/verify_credentials
|
// https://dev.twitter.com/rest/reference/get/account/verify_credentials
|
||||||
private async Task<JObject> RetrieveUserDetailsAsync(AccessToken accessToken, ClaimsIdentity identity)
|
private async Task<JsonDocument> RetrieveUserDetailsAsync(AccessToken accessToken, ClaimsIdentity identity)
|
||||||
{
|
{
|
||||||
Logger.RetrieveUserDetails();
|
Logger.RetrieveUserDetails();
|
||||||
|
|
||||||
|
|
@ -288,7 +296,7 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
||||||
}
|
}
|
||||||
var responseText = await response.Content.ReadAsStringAsync();
|
var responseText = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
var result = JObject.Parse(responseText);
|
var result = JsonDocument.Parse(responseText);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "https://localhost:44318/",
|
||||||
|
"sslPort": 44318
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SocialSample": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://localhost:44318/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "https://localhost:44318/",
|
||||||
|
"sslPort": 44318
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"SocialSample": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://localhost:44318/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
|
@ -21,7 +22,6 @@ using Microsoft.AspNetCore.Http.Extensions;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace SocialSample
|
namespace SocialSample
|
||||||
{
|
{
|
||||||
|
|
@ -207,9 +207,10 @@ namespace SocialSample
|
||||||
var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
|
var response = await context.Backchannel.SendAsync(request, context.HttpContext.RequestAborted);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
|
using (var user = JsonDocument.Parse(await response.Content.ReadAsStringAsync()))
|
||||||
|
{
|
||||||
context.RunClaimActions(user);
|
context.RunClaimActions(user.RootElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
@ -332,24 +333,25 @@ namespace SocialSample
|
||||||
var refreshResponse = await options.Backchannel.PostAsync(options.TokenEndpoint, content, context.RequestAborted);
|
var refreshResponse = await options.Backchannel.PostAsync(options.TokenEndpoint, content, context.RequestAborted);
|
||||||
refreshResponse.EnsureSuccessStatusCode();
|
refreshResponse.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
var payload = JObject.Parse(await refreshResponse.Content.ReadAsStringAsync());
|
using (var payload = JsonDocument.Parse(await refreshResponse.Content.ReadAsStringAsync()))
|
||||||
|
|
||||||
// Persist the new acess token
|
|
||||||
authProperties.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
|
|
||||||
refreshToken = payload.Value<string>("refresh_token");
|
|
||||||
if (!string.IsNullOrEmpty(refreshToken))
|
|
||||||
{
|
{
|
||||||
authProperties.UpdateTokenValue("refresh_token", refreshToken);
|
|
||||||
}
|
|
||||||
if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
|
|
||||||
{
|
|
||||||
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
|
||||||
authProperties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
|
||||||
}
|
|
||||||
await context.SignInAsync(user, authProperties);
|
|
||||||
|
|
||||||
await PrintRefreshedTokensAsync(response, payload, authProperties);
|
// Persist the new acess token
|
||||||
|
authProperties.UpdateTokenValue("access_token", payload.RootElement.GetString("access_token"));
|
||||||
|
refreshToken = payload.RootElement.GetString("refresh_token");
|
||||||
|
if (!string.IsNullOrEmpty(refreshToken))
|
||||||
|
{
|
||||||
|
authProperties.UpdateTokenValue("refresh_token", refreshToken);
|
||||||
|
}
|
||||||
|
if (payload.RootElement.TryGetProperty("expires_in", out var property) && property.TryGetInt32(out var seconds))
|
||||||
|
{
|
||||||
|
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
||||||
|
authProperties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
await context.SignInAsync(user, authProperties);
|
||||||
|
|
||||||
|
await PrintRefreshedTokensAsync(response, payload, authProperties);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// https://developers.facebook.com/docs/facebook-login/access-tokens/expiration-and-extension
|
// https://developers.facebook.com/docs/facebook-login/access-tokens/expiration-and-extension
|
||||||
|
|
@ -368,18 +370,18 @@ namespace SocialSample
|
||||||
}.ToQueryString();
|
}.ToQueryString();
|
||||||
|
|
||||||
var refreshResponse = await options.Backchannel.GetStringAsync(options.TokenEndpoint + query);
|
var refreshResponse = await options.Backchannel.GetStringAsync(options.TokenEndpoint + query);
|
||||||
var payload = JObject.Parse(refreshResponse);
|
using (var payload = JsonDocument.Parse(refreshResponse))
|
||||||
|
|
||||||
authProperties.UpdateTokenValue("access_token", payload.Value<string>("access_token"));
|
|
||||||
if (int.TryParse(payload.Value<string>("expires_in"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var seconds))
|
|
||||||
{
|
{
|
||||||
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
authProperties.UpdateTokenValue("access_token", payload.RootElement.GetString("access_token"));
|
||||||
authProperties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
if (payload.RootElement.TryGetProperty("expires_in", out var property) && property.TryGetInt32(out var seconds))
|
||||||
|
{
|
||||||
|
var expiresAt = DateTimeOffset.UtcNow + TimeSpan.FromSeconds(seconds);
|
||||||
|
authProperties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
await context.SignInAsync(user, authProperties);
|
||||||
|
|
||||||
|
await PrintRefreshedTokensAsync(response, payload, authProperties);
|
||||||
}
|
}
|
||||||
await context.SignInAsync(user, authProperties);
|
|
||||||
|
|
||||||
await PrintRefreshedTokensAsync(response, payload, authProperties);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -485,12 +487,12 @@ namespace SocialSample
|
||||||
throw new NotImplementedException(currentAuthType);
|
throw new NotImplementedException(currentAuthType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PrintRefreshedTokensAsync(HttpResponse response, JObject payload, AuthenticationProperties authProperties)
|
private async Task PrintRefreshedTokensAsync(HttpResponse response, JsonDocument payload, AuthenticationProperties authProperties)
|
||||||
{
|
{
|
||||||
response.ContentType = "text/html";
|
response.ContentType = "text/html";
|
||||||
await response.WriteAsync("<html><body>");
|
await response.WriteAsync("<html><body>");
|
||||||
await response.WriteAsync("Refreshed.<br>");
|
await response.WriteAsync("Refreshed.<br>");
|
||||||
await response.WriteAsync(HtmlEncoder.Default.Encode(payload.ToString()).Replace(",", ",<br>") + "<br>");
|
await response.WriteAsync(HtmlEncoder.Default.Encode(payload.RootElement.ToString()).Replace(",", ",<br>") + "<br>");
|
||||||
|
|
||||||
await response.WriteAsync("<br>Tokens:<br>");
|
await response.WriteAsync("<br>Tokens:<br>");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
<handlers>
|
<handlers>
|
||||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
|
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
|
||||||
</handlers>
|
</handlers>
|
||||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false" />
|
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false">
|
||||||
|
<environmentVariables />
|
||||||
|
</aspNetCore>
|
||||||
</system.webServer>
|
</system.webServer>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using System.Text.Json;
|
||||||
using Xunit;
|
|
||||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||||
using Newtonsoft.Json.Linq;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Authentication
|
namespace Microsoft.AspNetCore.Authentication
|
||||||
{
|
{
|
||||||
|
|
@ -17,15 +14,12 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CanMapSingleValueUserDataToClaim()
|
public void CanMapSingleValueUserDataToClaim()
|
||||||
{
|
{
|
||||||
var userData = new JObject
|
var userData = JsonDocument.Parse("{ \"name\": \"test\" }");
|
||||||
{
|
|
||||||
["name"] = "test"
|
|
||||||
};
|
|
||||||
|
|
||||||
var identity = new ClaimsIdentity();
|
var identity = new ClaimsIdentity();
|
||||||
|
|
||||||
var action = new JsonKeyClaimAction("name", "name", "name");
|
var action = new JsonKeyClaimAction("name", "name", "name");
|
||||||
action.Run(userData, identity, "iss");
|
action.Run(userData.RootElement, identity, "iss");
|
||||||
|
|
||||||
Assert.Equal("name", identity.FindFirst("name").Type);
|
Assert.Equal("name", identity.FindFirst("name").Type);
|
||||||
Assert.Equal("test", identity.FindFirst("name").Value);
|
Assert.Equal("test", identity.FindFirst("name").Value);
|
||||||
|
|
@ -34,15 +28,12 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CanMapArrayValueUserDataToClaims()
|
public void CanMapArrayValueUserDataToClaims()
|
||||||
{
|
{
|
||||||
var userData = new JObject
|
var userData = JsonDocument.Parse("{ \"role\": [ \"role1\", null, \"role2\" ] }");
|
||||||
{
|
|
||||||
["role"] = new JArray { "role1", "role2" }
|
|
||||||
};
|
|
||||||
|
|
||||||
var identity = new ClaimsIdentity();
|
var identity = new ClaimsIdentity();
|
||||||
|
|
||||||
var action = new JsonKeyClaimAction("role", "role", "role");
|
var action = new JsonKeyClaimAction("role", "role", "role");
|
||||||
action.Run(userData, identity, "iss");
|
action.Run(userData.RootElement, identity, "iss");
|
||||||
|
|
||||||
var roleClaims = identity.FindAll("role").ToList();
|
var roleClaims = identity.FindAll("role").ToList();
|
||||||
Assert.Equal(2, roleClaims.Count);
|
Assert.Equal(2, roleClaims.Count);
|
||||||
|
|
@ -55,15 +46,11 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MapAllSucceeds()
|
public void MapAllSucceeds()
|
||||||
{
|
{
|
||||||
var userData = new JObject
|
var userData = JsonDocument.Parse("{ \"name0\": \"value0\", \"name1\": \"value1\" }");
|
||||||
{
|
|
||||||
["name0"] = "value0",
|
|
||||||
["name1"] = "value1",
|
|
||||||
};
|
|
||||||
|
|
||||||
var identity = new ClaimsIdentity();
|
var identity = new ClaimsIdentity();
|
||||||
var action = new MapAllClaimsAction();
|
var action = new MapAllClaimsAction();
|
||||||
action.Run(userData, identity, "iss");
|
action.Run(userData.RootElement, identity, "iss");
|
||||||
|
|
||||||
Assert.Equal("name0", identity.FindFirst("name0").Type);
|
Assert.Equal("name0", identity.FindFirst("name0").Type);
|
||||||
Assert.Equal("value0", identity.FindFirst("name0").Value);
|
Assert.Equal("value0", identity.FindFirst("name0").Value);
|
||||||
|
|
@ -74,17 +61,13 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MapAllAllowesDulicateKeysWithUniqueValues()
|
public void MapAllAllowesDulicateKeysWithUniqueValues()
|
||||||
{
|
{
|
||||||
var userData = new JObject
|
var userData = JsonDocument.Parse("{ \"name0\": \"value0\", \"name1\": \"value1\" }");
|
||||||
{
|
|
||||||
["name0"] = "value0",
|
|
||||||
["name1"] = "value1",
|
|
||||||
};
|
|
||||||
|
|
||||||
var identity = new ClaimsIdentity();
|
var identity = new ClaimsIdentity();
|
||||||
identity.AddClaim(new Claim("name0", "value2"));
|
identity.AddClaim(new Claim("name0", "value2"));
|
||||||
identity.AddClaim(new Claim("name1", "value3"));
|
identity.AddClaim(new Claim("name1", "value3"));
|
||||||
var action = new MapAllClaimsAction();
|
var action = new MapAllClaimsAction();
|
||||||
action.Run(userData, identity, "iss");
|
action.Run(userData.RootElement, identity, "iss");
|
||||||
|
|
||||||
Assert.Equal(2, identity.FindAll("name0").Count());
|
Assert.Equal(2, identity.FindAll("name0").Count());
|
||||||
Assert.Equal(2, identity.FindAll("name1").Count());
|
Assert.Equal(2, identity.FindAll("name1").Count());
|
||||||
|
|
@ -93,17 +76,13 @@ namespace Microsoft.AspNetCore.Authentication
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MapAllSkipsDuplicateValues()
|
public void MapAllSkipsDuplicateValues()
|
||||||
{
|
{
|
||||||
var userData = new JObject
|
var userData = JsonDocument.Parse("{ \"name0\": \"value0\", \"name1\": \"value1\" }");
|
||||||
{
|
|
||||||
["name0"] = "value0",
|
|
||||||
["name1"] = "value1",
|
|
||||||
};
|
|
||||||
|
|
||||||
var identity = new ClaimsIdentity();
|
var identity = new ClaimsIdentity();
|
||||||
identity.AddClaim(new Claim("name0", "value0"));
|
identity.AddClaim(new Claim("name0", "value0"));
|
||||||
identity.AddClaim(new Claim("name1", "value1"));
|
identity.AddClaim(new Claim("name1", "value1"));
|
||||||
var action = new MapAllClaimsAction();
|
var action = new MapAllClaimsAction();
|
||||||
action.Run(userData, identity, "iss");
|
action.Run(userData.RootElement, identity, "iss");
|
||||||
|
|
||||||
Assert.Single(identity.FindAll("name0"));
|
Assert.Single(identity.FindAll("name0"));
|
||||||
Assert.Single(identity.FindAll("name1"));
|
Assert.Single(identity.FindAll("name1"));
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.TestHost;
|
using Microsoft.AspNetCore.TestHost;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
@ -325,10 +324,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == FacebookDefaults.TokenEndpoint)
|
if (req.RequestUri.GetComponents(UriComponents.SchemeAndServer | UriComponents.Path, UriFormat.UriEscaped) == FacebookDefaults.TokenEndpoint)
|
||||||
{
|
{
|
||||||
var res = new HttpResponseMessage(HttpStatusCode.OK);
|
var res = new HttpResponseMessage(HttpStatusCode.OK);
|
||||||
var graphResponse = JsonConvert.SerializeObject(new
|
var graphResponse = "{ \"access_token\": \"TestAuthToken\" }";
|
||||||
{
|
|
||||||
access_token = "TestAuthToken"
|
|
||||||
});
|
|
||||||
res.Content = new StringContent(graphResponse, Encoding.UTF8);
|
res.Content = new StringContent(graphResponse, Encoding.UTF8);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -337,11 +333,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||||
{
|
{
|
||||||
finalUserInfoEndpoint = req.RequestUri.ToString();
|
finalUserInfoEndpoint = req.RequestUri.ToString();
|
||||||
var res = new HttpResponseMessage(HttpStatusCode.OK);
|
var res = new HttpResponseMessage(HttpStatusCode.OK);
|
||||||
var graphResponse = JsonConvert.SerializeObject(new
|
var graphResponse = "{ \"id\": \"TestProfileId\", \"name\": \"TestName\" }";
|
||||||
{
|
|
||||||
id = "TestProfileId",
|
|
||||||
name = "TestName"
|
|
||||||
});
|
|
||||||
res.Content = new StringContent(graphResponse, Encoding.UTF8);
|
res.Content = new StringContent(graphResponse, Encoding.UTF8);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using Microsoft.AspNetCore.TestHost;
|
||||||
using Microsoft.AspNetCore.WebUtilities;
|
using Microsoft.AspNetCore.WebUtilities;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -704,7 +703,6 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
||||||
{
|
{
|
||||||
OnCreatingTicket = context =>
|
OnCreatingTicket = context =>
|
||||||
{
|
{
|
||||||
Assert.NotNull(context.User);
|
|
||||||
Assert.Equal("Test Access Token", context.AccessToken);
|
Assert.Equal("Test Access Token", context.AccessToken);
|
||||||
Assert.Equal("Test Refresh Token", context.RefreshToken);
|
Assert.Equal("Test Refresh Token", context.RefreshToken);
|
||||||
Assert.Equal(TimeSpan.FromSeconds(3600), context.ExpiresIn);
|
Assert.Equal(TimeSpan.FromSeconds(3600), context.ExpiresIn);
|
||||||
|
|
@ -972,7 +970,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
||||||
private static HttpResponseMessage ReturnJsonResponse(object content, HttpStatusCode code = HttpStatusCode.OK)
|
private static HttpResponseMessage ReturnJsonResponse(object content, HttpStatusCode code = HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
var res = new HttpResponseMessage(code);
|
var res = new HttpResponseMessage(code);
|
||||||
var text = JsonConvert.SerializeObject(content);
|
var text = Newtonsoft.Json.JsonConvert.SerializeObject(content);
|
||||||
res.Content = new StringContent(text, Encoding.UTF8, "application/json");
|
res.Content = new StringContent(text, Encoding.UTF8, "application/json");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.TestHost;
|
using Microsoft.AspNetCore.TestHost;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
@ -302,7 +301,7 @@ namespace Microsoft.AspNetCore.Authentication.Tests.MicrosoftAccount
|
||||||
private static HttpResponseMessage ReturnJsonResponse(object content)
|
private static HttpResponseMessage ReturnJsonResponse(object content)
|
||||||
{
|
{
|
||||||
var res = new HttpResponseMessage(HttpStatusCode.OK);
|
var res = new HttpResponseMessage(HttpStatusCode.OK);
|
||||||
var text = JsonConvert.SerializeObject(content);
|
var text = Newtonsoft.Json.JsonConvert.SerializeObject(content);
|
||||||
res.Content = new StringContent(text, Encoding.UTF8, "application/json");
|
res.Content = new StringContent(text, Encoding.UTF8, "application/json");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue