#969 Make social auth claims mapping more configurable
#1024 Remove OIDC protocol claims
This commit is contained in:
parent
7637f2ea44
commit
ad425163b2
|
|
@ -112,7 +112,7 @@ namespace SocialSample
|
|||
|
||||
// You must first create an app with GitHub and add its ID and Secret to your user-secrets.
|
||||
// https://console.developers.google.com/project
|
||||
app.UseGoogleAuthentication(new GoogleOptions
|
||||
var googleOptions = new GoogleOptions
|
||||
{
|
||||
ClientId = Configuration["google:clientid"],
|
||||
ClientSecret = Configuration["google:clientsecret"],
|
||||
|
|
@ -126,11 +126,14 @@ namespace SocialSample
|
|||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
googleOptions.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url");
|
||||
googleOptions.ClaimActions.Remove(ClaimTypes.GivenName);
|
||||
app.UseGoogleAuthentication(googleOptions);
|
||||
|
||||
// You must first create an app with Twitter and add its key and Secret to your user-secrets.
|
||||
// https://apps.twitter.com/
|
||||
app.UseTwitterAuthentication(new TwitterOptions
|
||||
var twitterOptions = new TwitterOptions
|
||||
{
|
||||
ConsumerKey = Configuration["twitter:consumerkey"],
|
||||
ConsumerSecret = Configuration["twitter:consumersecret"],
|
||||
|
|
@ -140,12 +143,6 @@ namespace SocialSample
|
|||
SaveTokens = true,
|
||||
Events = new TwitterEvents()
|
||||
{
|
||||
OnCreatingTicket = ctx =>
|
||||
{
|
||||
var profilePic = ctx.User.Value<string>("profile_image_url");
|
||||
ctx.Principal.Identities.First().AddClaim(new Claim("urn:twitter:profilepicture", profilePic, ClaimTypes.Uri, ctx.Options.ClaimsIssuer));
|
||||
return Task.FromResult(0);
|
||||
},
|
||||
OnRemoteFailure = ctx =>
|
||||
{
|
||||
ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message));
|
||||
|
|
@ -153,7 +150,9 @@ namespace SocialSample
|
|||
return Task.FromResult(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
twitterOptions.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri);
|
||||
app.UseTwitterAuthentication(twitterOptions);
|
||||
|
||||
/* Azure AD app model v2 has restrictions that prevent the use of plain HTTP for redirect URLs.
|
||||
Therefore, to authenticate through microsoft accounts, tryout the sample using the following URL:
|
||||
|
|
@ -200,7 +199,7 @@ namespace SocialSample
|
|||
|
||||
// You must first create an app with GitHub and add its ID and Secret to your user-secrets.
|
||||
// https://github.com/settings/applications/
|
||||
app.UseOAuthAuthentication(new OAuthOptions
|
||||
var githubOptions = new OAuthOptions
|
||||
{
|
||||
AuthenticationScheme = "GitHub",
|
||||
DisplayName = "Github",
|
||||
|
|
@ -227,48 +226,16 @@ namespace SocialSample
|
|||
|
||||
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
|
||||
|
||||
var identifier = user.Value<string>("id");
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
context.Identity.AddClaim(new Claim(
|
||||
ClaimTypes.NameIdentifier, identifier,
|
||||
ClaimValueTypes.String, context.Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var userName = user.Value<string>("login");
|
||||
if (!string.IsNullOrEmpty(userName))
|
||||
{
|
||||
context.Identity.AddClaim(new Claim(
|
||||
ClaimsIdentity.DefaultNameClaimType, userName,
|
||||
ClaimValueTypes.String, context.Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var name = user.Value<string>("name");
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
context.Identity.AddClaim(new Claim(
|
||||
"urn:github:name", name,
|
||||
ClaimValueTypes.String, context.Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var email = user.Value<string>("email");
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
{
|
||||
context.Identity.AddClaim(new Claim(
|
||||
ClaimTypes.Email, email,
|
||||
ClaimValueTypes.Email, context.Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var link = user.Value<string>("url");
|
||||
if (!string.IsNullOrEmpty(link))
|
||||
{
|
||||
context.Identity.AddClaim(new Claim(
|
||||
"urn:github:url", link,
|
||||
ClaimValueTypes.String, context.Options.ClaimsIssuer));
|
||||
}
|
||||
context.RunClaimActions(user);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
githubOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
|
||||
githubOptions.ClaimActions.MapJsonKey(ClaimTypes.Name, "login");
|
||||
githubOptions.ClaimActions.MapJsonKey("urn:github:name", "name");
|
||||
githubOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email);
|
||||
githubOptions.ClaimActions.MapJsonKey("urn:github:url", "url");
|
||||
app.UseOAuthAuthentication(githubOptions);
|
||||
|
||||
// Choose an authentication type
|
||||
app.Map("/login", signoutApp =>
|
||||
|
|
@ -357,7 +324,7 @@ namespace SocialSample
|
|||
}
|
||||
|
||||
await context.Response.WriteAsync("Tokens:<br>");
|
||||
|
||||
|
||||
await context.Response.WriteAsync("Access Token: " + await context.Authentication.GetTokenAsync("access_token") + "<br>");
|
||||
await context.Response.WriteAsync("Refresh Token: " + await context.Authentication.GetTokenAsync("refresh_token") + "<br>");
|
||||
await context.Response.WriteAsync("Token Type: " + await context.Authentication.GetTokenAsync("token_type") + "<br>");
|
||||
|
|
|
|||
|
|
@ -45,90 +45,7 @@ namespace Microsoft.AspNetCore.Authentication.Facebook
|
|||
|
||||
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme);
|
||||
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload);
|
||||
|
||||
var identifier = FacebookHelper.GetId(payload);
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var ageRangeMin = FacebookHelper.GetAgeRangeMin(payload);
|
||||
if (!string.IsNullOrEmpty(ageRangeMin))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:facebook:age_range_min", ageRangeMin, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var ageRangeMax = FacebookHelper.GetAgeRangeMax(payload);
|
||||
if (!string.IsNullOrEmpty(ageRangeMax))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:facebook:age_range_max", ageRangeMax, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var birthday = FacebookHelper.GetBirthday(payload);
|
||||
if (!string.IsNullOrEmpty(birthday))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.DateOfBirth, birthday, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var email = FacebookHelper.GetEmail(payload);
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var firstName = FacebookHelper.GetFirstName(payload);
|
||||
if (!string.IsNullOrEmpty(firstName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.GivenName, firstName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var gender = FacebookHelper.GetGender(payload);
|
||||
if (!string.IsNullOrEmpty(gender))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Gender, gender, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var lastName = FacebookHelper.GetLastName(payload);
|
||||
if (!string.IsNullOrEmpty(lastName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Surname, lastName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var link = FacebookHelper.GetLink(payload);
|
||||
if (!string.IsNullOrEmpty(link))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:facebook:link", link, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var location = FacebookHelper.GetLocation(payload);
|
||||
if (!string.IsNullOrEmpty(location))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:facebook:location", location, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var locale = FacebookHelper.GetLocale(payload);
|
||||
if (!string.IsNullOrEmpty(locale))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Locality, locale, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var middleName = FacebookHelper.GetMiddleName(payload);
|
||||
if (!string.IsNullOrEmpty(middleName))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:facebook:middle_name", middleName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var name = FacebookHelper.GetName(payload);
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var timeZone = FacebookHelper.GetTimeZone(payload);
|
||||
if (!string.IsNullOrEmpty(timeZone))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:facebook:timezone", timeZone, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
context.RunClaimActions();
|
||||
|
||||
await Options.Events.CreatingTicket(context);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,206 +0,0 @@
|
|||
// 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;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.Facebook
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains static methods that allow to extract user's information from a <see cref="JObject"/>
|
||||
/// instance retrieved from Facebook after a successful authentication process.
|
||||
/// </summary>
|
||||
public static class FacebookHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Facebook user ID.
|
||||
/// </summary>
|
||||
public static string GetId(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("id");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's min age.
|
||||
/// </summary>
|
||||
public static string GetAgeRangeMin(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
return TryGetValue(user, "age_range", "min");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's max age.
|
||||
/// </summary>
|
||||
public static string GetAgeRangeMax(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return TryGetValue(user, "age_range", "max");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's birthday.
|
||||
/// </summary>
|
||||
public static string GetBirthday(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
return user.Value<string>("birthday");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Facebook email.
|
||||
/// </summary>
|
||||
public static string GetEmail(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("email");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's first name.
|
||||
/// </summary>
|
||||
public static string GetFirstName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("first_name");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's gender.
|
||||
/// </summary>
|
||||
public static string GetGender(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
return user.Value<string>("gender");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's family name.
|
||||
/// </summary>
|
||||
public static string GetLastName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("last_name");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's link.
|
||||
/// </summary>
|
||||
public static string GetLink(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
return user.Value<string>("link");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's location.
|
||||
/// </summary>
|
||||
public static string GetLocation(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
return TryGetValue(user, "location", "name");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's locale.
|
||||
/// </summary>
|
||||
public static string GetLocale(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
return user.Value<string>("locale");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's middle name.
|
||||
/// </summary>
|
||||
public static string GetMiddleName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("middle_name");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's name.
|
||||
/// </summary>
|
||||
public static string GetName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("name");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's timezone.
|
||||
/// </summary>
|
||||
public static string GetTimeZone(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
return user.Value<string>("timezone");
|
||||
}
|
||||
|
||||
// Get the given subProperty from a property.
|
||||
private static string TryGetValue(JObject user, string propertyName, string subProperty)
|
||||
{
|
||||
JToken value;
|
||||
if (user.TryGetValue(propertyName, out value))
|
||||
{
|
||||
var subObject = JObject.Parse(value.ToString());
|
||||
if (subObject != null && subObject.TryGetValue(subProperty, out value))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Facebook;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
|
@ -30,6 +32,21 @@ namespace Microsoft.AspNetCore.Builder
|
|||
Fields.Add("email");
|
||||
Fields.Add("first_name");
|
||||
Fields.Add("last_name");
|
||||
|
||||
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
|
||||
ClaimActions.MapJsonSubKey("urn:facebook:age_range_min", "age_range", "min");
|
||||
ClaimActions.MapJsonSubKey("urn:facebook:age_range_max", "age_range", "max");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.DateOfBirth, "birthday");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "first_name");
|
||||
ClaimActions.MapJsonKey("urn:facebook:middle_name", "middle_name");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Surname, "last_name");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Gender, "gender");
|
||||
ClaimActions.MapJsonKey("urn:facebook:link", "link");
|
||||
ClaimActions.MapJsonSubKey("urn:facebook:location", "location", "name");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Locality, "locale");
|
||||
ClaimActions.MapJsonKey("urn:facebook:timezone", "timezone");
|
||||
}
|
||||
|
||||
// Facebook uses a non-standard term for this field.
|
||||
|
|
|
|||
|
|
@ -42,42 +42,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
|||
var principal = new ClaimsPrincipal(identity);
|
||||
var ticket = new AuthenticationTicket(principal, properties, Options.AuthenticationScheme);
|
||||
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload);
|
||||
|
||||
var identifier = GoogleHelper.GetId(payload);
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var givenName = GoogleHelper.GetGivenName(payload);
|
||||
if (!string.IsNullOrEmpty(givenName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.GivenName, givenName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var familyName = GoogleHelper.GetFamilyName(payload);
|
||||
if (!string.IsNullOrEmpty(familyName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Surname, familyName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var name = GoogleHelper.GetName(payload);
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var email = GoogleHelper.GetEmail(payload);
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var profile = GoogleHelper.GetProfile(payload);
|
||||
if (!string.IsNullOrEmpty(profile))
|
||||
{
|
||||
identity.AddClaim(new Claim("urn:google:profile", profile, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
context.RunClaimActions();
|
||||
|
||||
await Options.Events.CreatingTicket(context);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,71 +12,6 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
|||
/// </summary>
|
||||
public static class GoogleHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Google user ID.
|
||||
/// </summary>
|
||||
public static string GetId(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("id");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's name.
|
||||
/// </summary>
|
||||
public static string GetName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("displayName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's given name.
|
||||
/// </summary>
|
||||
public static string GetGivenName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return TryGetValue(user, "name", "givenName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's family name.
|
||||
/// </summary>
|
||||
public static string GetFamilyName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return TryGetValue(user, "name", "familyName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's profile link.
|
||||
/// </summary>
|
||||
public static string GetProfile(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("url");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's email.
|
||||
/// </summary>
|
||||
|
|
@ -90,21 +25,6 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
|||
return TryGetFirstValue(user, "emails", "value");
|
||||
}
|
||||
|
||||
// Get the given subProperty from a property.
|
||||
private static string TryGetValue(JObject user, string propertyName, string subProperty)
|
||||
{
|
||||
JToken value;
|
||||
if (user.TryGetValue(propertyName, out value))
|
||||
{
|
||||
var subObject = JObject.Parse(value.ToString());
|
||||
if (subObject != null && subObject.TryGetValue(subProperty, out value))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the given subProperty from a list property.
|
||||
private static string TryGetFirstValue(JObject user, string propertyName, string subProperty)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
// 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.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Google;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
|
@ -25,6 +27,13 @@ namespace Microsoft.AspNetCore.Builder
|
|||
Scope.Add("openid");
|
||||
Scope.Add("profile");
|
||||
Scope.Add("email");
|
||||
|
||||
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName");
|
||||
ClaimActions.MapJsonSubKey(ClaimTypes.GivenName, "name", "givenName");
|
||||
ClaimActions.MapJsonSubKey(ClaimTypes.Surname, "name", "familyName");
|
||||
ClaimActions.MapJsonKey("urn:google:profile", "url");
|
||||
ClaimActions.MapCustomJson(ClaimTypes.Email, GoogleHelper.GetEmail);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -35,39 +35,7 @@ namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
|||
|
||||
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme);
|
||||
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload);
|
||||
var identifier = MicrosoftAccountHelper.GetId(payload);
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
identity.AddClaim(new Claim("urn:microsoftaccount:id", identifier, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var name = MicrosoftAccountHelper.GetDisplayName(payload);
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
identity.AddClaim(new Claim("urn:microsoftaccount:name", name, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var givenName = MicrosoftAccountHelper.GetGivenName(payload);
|
||||
if (!string.IsNullOrEmpty(givenName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.GivenName, givenName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
identity.AddClaim(new Claim("urn:microsoftaccount:givenname", givenName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var surname = MicrosoftAccountHelper.GetSurname(payload);
|
||||
if (!string.IsNullOrEmpty(surname))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Surname, surname, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
identity.AddClaim(new Claim("urn:microsoftaccount:surname", surname, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var email = MicrosoftAccountHelper.GetEmail(payload);
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
context.RunClaimActions();
|
||||
|
||||
await Options.Events.CreatingTicket(context);
|
||||
return context.Ticket;
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
// 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;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.MicrosoftAccount
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains static methods that allow to extract user's information from a <see cref="JObject"/>
|
||||
/// instance retrieved from Microsoft after a successful authentication process.
|
||||
/// http://graph.microsoft.io/en-us/docs/api-reference/v1.0/resources/user
|
||||
/// </summary>
|
||||
public static class MicrosoftAccountHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Microsoft Account user ID.
|
||||
/// </summary>
|
||||
public static string GetId(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("id");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's name.
|
||||
/// </summary>
|
||||
public static string GetDisplayName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("displayName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's given name.
|
||||
/// </summary>
|
||||
public static string GetGivenName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("givenName");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's surname.
|
||||
/// </summary>
|
||||
public static string GetSurname(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("surname");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user's email address.
|
||||
/// </summary>
|
||||
public static string GetEmail(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("mail") ?? user.Value<string>("userPrincipalName");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
{
|
||||
|
|
@ -23,6 +25,12 @@ namespace Microsoft.AspNetCore.Builder
|
|||
TokenEndpoint = MicrosoftAccountDefaults.TokenEndpoint;
|
||||
UserInformationEndpoint = MicrosoftAccountDefaults.UserInformationEndpoint;
|
||||
Scope.Add("https://graph.microsoft.com/user.read");
|
||||
|
||||
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Name, "displayName");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.GivenName, "givenName");
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Surname, "surname");
|
||||
ClaimActions.MapCustomJson(ClaimTypes.Email, user => user.Value<string>("mail") ?? user.Value<string>("userPrincipalName"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
// 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.Security.Claims;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||
{
|
||||
/// <summary>
|
||||
/// Infrastructure for mapping user data from a json structure to claims on the ClaimsIdentity.
|
||||
/// </summary>
|
||||
public abstract class ClaimAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new claim manipulation action.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public ClaimAction(string claimType, string valueType)
|
||||
{
|
||||
ClaimType = claimType;
|
||||
ValueType = valueType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The value to use for Claim.Type when creating a Claim.
|
||||
/// </summary>
|
||||
public string ClaimType { get; }
|
||||
|
||||
// The value to use for Claim.ValueType when creating a Claim.
|
||||
public string ValueType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Exhamine the given userData json, determine if the requisite data is present, and optionally add it
|
||||
/// as a new Claim on the ClaimsIdentity.
|
||||
/// </summary>
|
||||
/// <param name="userData">The source data to exhamine. This value may be null.</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>
|
||||
public abstract void Run(JObject userData, ClaimsIdentity identity, string issuer);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// 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;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection of ClaimActions used when mapping user data to Claims.
|
||||
/// </summary>
|
||||
public class ClaimActionCollection : IEnumerable<ClaimAction>
|
||||
{
|
||||
private IList<ClaimAction> Actions { get; } = new List<ClaimAction>();
|
||||
|
||||
/// <summary>
|
||||
/// Remove all claim actions.
|
||||
/// </summary>
|
||||
public void Clear() => Actions.Clear();
|
||||
|
||||
/// <summary>
|
||||
/// Remove all claim actions for the given ClaimType.
|
||||
/// </summary>
|
||||
/// <param name="claimType">The ClaimType of maps to remove.</param>
|
||||
public void Remove(string claimType)
|
||||
{
|
||||
var itemsToRemove = Actions.Where(map => string.Equals(claimType, map.ClaimType, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
itemsToRemove.ForEach(map => Actions.Remove(map));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a claim action to the collection.
|
||||
/// </summary>
|
||||
/// <param name="action">The claim action to add.</param>
|
||||
public void Add(ClaimAction action)
|
||||
{
|
||||
Actions.Add(action);
|
||||
}
|
||||
|
||||
public IEnumerator<ClaimAction> GetEnumerator()
|
||||
{
|
||||
return Actions.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return Actions.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
// 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;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication
|
||||
{
|
||||
public static class ClaimActionCollectionMapExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Select a top level value from the json user data with the given key name and add it as a Claim.
|
||||
/// This no-ops if the key is not found or the value is empty.
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||
/// <param name="jsonKey">The top level key to look for in the json user data.</param>
|
||||
public static void MapJsonKey(this ClaimActionCollection collection, string claimType, string jsonKey)
|
||||
{
|
||||
collection.MapJsonKey(claimType, jsonKey, ClaimValueTypes.String);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select a top level value from the json user data with the given key name and add it as a Claim.
|
||||
/// This no-ops if the key is not found or the value is empty.
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||
/// <param name="jsonKey">The top level key to look for in the json user data.</param>
|
||||
/// <param name="valueType">The value to use for Claim.ValueType when creating a Claim.</param>
|
||||
public static void MapJsonKey(this ClaimActionCollection collection, string claimType, string jsonKey, string valueType)
|
||||
{
|
||||
collection.Add(new JsonKeyClaimAction(claimType, valueType, jsonKey));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select a second level value from the json user data with the given top level key name and second level sub key name and add it as a Claim.
|
||||
/// This no-ops if the keys are not found or the value is empty.
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||
/// <param name="jsonKey">The top level key to look for in the json user data.</param>
|
||||
/// <param name="subKey">The second level key to look for in the json user data.</param>
|
||||
public static void MapJsonSubKey(this ClaimActionCollection collection, string claimType, string jsonKey, string subKey)
|
||||
{
|
||||
collection.MapJsonSubKey(claimType, jsonKey, subKey, ClaimValueTypes.String);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select a second level value from the json user data with the given top level key name and second level sub key name and add it as a Claim.
|
||||
/// This no-ops if the keys are not found or the value is empty.
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||
/// <param name="jsonKey">The top level key to look for in the json user data.</param>
|
||||
/// <param name="subKey">The second level key to look for in the json user data.</param>
|
||||
/// <param name="valueType">The value to use for Claim.ValueType when creating a Claim.</param>
|
||||
public static void MapJsonSubKey(this ClaimActionCollection collection, string claimType, string jsonKey, string subKey, string valueType)
|
||||
{
|
||||
collection.Add(new JsonSubKeyClaimAction(claimType, valueType, jsonKey, subKey));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the given resolver to select a value from the json user data to add as a claim.
|
||||
/// This no-ops if the returned value is empty.
|
||||
/// </summary>
|
||||
/// <param name="collection"></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>
|
||||
public static void MapCustomJson(this ClaimActionCollection collection, string claimType, Func<JObject, string> resolver)
|
||||
{
|
||||
collection.MapCustomJson(claimType, ClaimValueTypes.String, resolver);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run the given resolver to select a value from the json user data to add as a claim.
|
||||
/// This no-ops if the returned value is empty.
|
||||
/// </summary>
|
||||
/// <param name="collection"></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="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)
|
||||
{
|
||||
collection.Add(new CustomJsonClaimAction(claimType, valueType, resolver));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete all claims from the given ClaimsIdentity with the given ClaimType.
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="claimType"></param>
|
||||
public static void DeleteClaim(this ClaimActionCollection collection, string claimType)
|
||||
{
|
||||
collection.Add(new DeleteClaimAction(claimType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// 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;
|
||||
using System.Security.Claims;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||
{
|
||||
/// <summary>
|
||||
/// A ClaimAction that selects the value from the json user data by running the given Func resolver.
|
||||
/// </summary>
|
||||
public class CustomJsonClaimAction : ClaimAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new CustomJsonClaimAction.
|
||||
/// </summary>
|
||||
/// <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="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)
|
||||
: base(claimType, valueType)
|
||||
{
|
||||
Resolver = resolver;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Func that will be called to select value from the given json user data.
|
||||
/// </summary>
|
||||
public Func<JObject, string> Resolver { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
||||
{
|
||||
if (userData == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var value = Resolver(userData);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimType, value, ValueType, issuer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// 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.Linq;
|
||||
using System.Security.Claims;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||
{
|
||||
/// <summary>
|
||||
/// A ClaimAction that deletes all claims from the given ClaimsIdentity with the given ClaimType.
|
||||
/// </summary>
|
||||
public class DeleteClaimAction : ClaimAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new DeleteClaimAction.
|
||||
/// </summary>
|
||||
/// <param name="claimType">The ClaimType of Claims to delete.</param>
|
||||
public DeleteClaimAction(string claimType)
|
||||
: base(claimType, ClaimValueTypes.String)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
||||
{
|
||||
foreach (var claim in identity.FindAll(ClaimType).ToList())
|
||||
{
|
||||
identity.TryRemoveClaim(claim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// 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.Security.Claims;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||
{
|
||||
/// <summary>
|
||||
/// A ClaimAction that selects a top level value from the json user data with the given key name and adds it as a Claim.
|
||||
/// This no-ops if the key is not found or the value is empty.
|
||||
/// </summary>
|
||||
public class JsonKeyClaimAction : ClaimAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new JsonKeyClaimAction.
|
||||
/// </summary>
|
||||
/// <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="jsonKey">The top level key to look for in the json user data.</param>
|
||||
public JsonKeyClaimAction(string claimType, string valueType, string jsonKey)
|
||||
: base(claimType, valueType)
|
||||
{
|
||||
JsonKey = jsonKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The top level key to look for in the json user data.
|
||||
/// </summary>
|
||||
public string JsonKey { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
||||
{
|
||||
var value = userData?.Value<string>(JsonKey);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimType, value, ValueType, issuer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
// 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 Newtonsoft.Json.Linq;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
|
||||
{
|
||||
/// <summary>
|
||||
/// A ClaimAction that selects a second level value from the json user data with the given top level key
|
||||
/// name and second level sub key name and add it as a Claim.
|
||||
/// This no-ops if the keys are not found or the value is empty.
|
||||
/// </summary>
|
||||
public class JsonSubKeyClaimAction : JsonKeyClaimAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new JsonSubKeyClaimAction.
|
||||
/// </summary>
|
||||
/// <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="jsonKey">The top level key to look for in the json user data.</param>
|
||||
/// <param name="subKey">The second level key to look for in the json user data.</param>
|
||||
public JsonSubKeyClaimAction(string claimType, string valueType, string jsonKey, string subKey)
|
||||
: base(claimType, valueType, jsonKey)
|
||||
{
|
||||
SubKey = subKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The second level key to look for in the json user data.
|
||||
/// </summary>
|
||||
public string SubKey { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
||||
{
|
||||
var value = GetValue(userData, JsonKey, SubKey);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimType, value, ValueType, issuer));
|
||||
}
|
||||
}
|
||||
|
||||
// Get the given subProperty from a property.
|
||||
private static string GetValue(JObject userData, string propertyName, string subProperty)
|
||||
{
|
||||
if (userData != null && userData.TryGetValue(propertyName, out var value))
|
||||
{
|
||||
var subObject = JObject.Parse(value.ToString());
|
||||
if (subObject != null && subObject.TryGetValue(subProperty, out value))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -144,5 +144,23 @@ namespace Microsoft.AspNetCore.Authentication.OAuth
|
|||
/// This property returns <c>null</c> when <see cref="Ticket"/> is <c>null</c>.
|
||||
/// </summary>
|
||||
public ClaimsIdentity Identity => Ticket?.Principal.Identity as ClaimsIdentity;
|
||||
|
||||
public void RunClaimActions()
|
||||
{
|
||||
RunClaimActions(User);
|
||||
}
|
||||
|
||||
public void RunClaimActions(JObject userData)
|
||||
{
|
||||
if (userData == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(userData));
|
||||
}
|
||||
|
||||
foreach (var action in Options.ClaimActions)
|
||||
{
|
||||
action.Run(userData, Identity, Options.ClaimsIssuer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,11 +11,10 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http.Authentication;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.AspNetCore.Http.Features.Authentication;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OAuth
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||
using Microsoft.AspNetCore.Http.Authentication;
|
||||
|
||||
namespace Microsoft.AspNetCore.Builder
|
||||
|
|
@ -55,6 +55,11 @@ namespace Microsoft.AspNetCore.Builder
|
|||
set { base.Events = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A collection of claim actions used to select values from the json user data and create Claims.
|
||||
/// </summary>
|
||||
public ClaimActionCollection ClaimActions { get; } = new ClaimActionCollection();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of permissions to request.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
// 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.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect.Claims;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication
|
||||
{
|
||||
public static class ClaimActionCollectionUniqueExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Selects a top level value from the json user data with the given key name and adds it as a Claim.
|
||||
/// This no-ops if the ClaimsIdentity already contains a Claim with the given ClaimType.
|
||||
/// This no-ops if the key is not found or the value is empty.
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||
/// <param name="jsonKey">The top level key to look for in the json user data.</param>
|
||||
public static void MapUniqueJsonKey(this ClaimActionCollection collection, string claimType, string jsonKey)
|
||||
{
|
||||
collection.MapUniqueJsonKey(claimType, jsonKey, ClaimValueTypes.String);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects a top level value from the json user data with the given key name and adds it as a Claim.
|
||||
/// This no-ops if the ClaimsIdentity already contains a Claim with the given ClaimType.
|
||||
/// This no-ops if the key is not found or the value is empty.
|
||||
/// </summary>
|
||||
/// <param name="collection"></param>
|
||||
/// <param name="claimType">The value to use for Claim.Type when creating a Claim.</param>
|
||||
/// <param name="jsonKey">The top level key to look for in the json user data.</param>
|
||||
/// <param name="valueType">The value to use for Claim.ValueType when creating a Claim.</param>
|
||||
public static void MapUniqueJsonKey(this ClaimActionCollection collection, string claimType, string jsonKey, string valueType)
|
||||
{
|
||||
collection.Add(new UniqueJsonKeyClaimAction(claimType, valueType, jsonKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// 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.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect.Claims
|
||||
{
|
||||
/// <summary>
|
||||
/// A ClaimAction that selects a top level value from the json user data with the given key name and adds it as a Claim.
|
||||
/// This no-ops if the ClaimsIdentity already contains a Claim with the given ClaimType.
|
||||
/// This no-ops if the key is not found or the value is empty.
|
||||
/// </summary>
|
||||
public class UniqueJsonKeyClaimAction : JsonKeyClaimAction
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new UniqueJsonKeyClaimAction.
|
||||
/// </summary>
|
||||
/// <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="jsonKey">The top level key to look for in the json user data.</param>
|
||||
public UniqueJsonKeyClaimAction(string claimType, string valueType, string jsonKey)
|
||||
: base(claimType, valueType, jsonKey)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
|
||||
{
|
||||
var value = userData?.Value<string>(JsonKey);
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
// Not found
|
||||
return;
|
||||
}
|
||||
|
||||
var claim = identity.FindFirst(c => string.Equals(c.Type, JsonKey, System.StringComparison.OrdinalIgnoreCase));
|
||||
if (claim != null && string.Equals(claim.Value, value, System.StringComparison.Ordinal))
|
||||
{
|
||||
// Duplicate
|
||||
return;
|
||||
}
|
||||
|
||||
claim = identity.FindFirst(c =>
|
||||
{
|
||||
// If this claimType is mapped by the JwtSeurityTokenHandler, then this property will be set
|
||||
return c.Properties.TryGetValue(JwtSecurityTokenHandler.ShortClaimTypeProperty, out var shortType)
|
||||
&& string.Equals(shortType, JsonKey, System.StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
if (claim != null && string.Equals(claim.Value, value, System.StringComparison.Ordinal))
|
||||
{
|
||||
// Duplicate with an alternate name.
|
||||
return;
|
||||
}
|
||||
|
||||
identity.AddClaim(new Claim(ClaimType, value, ValueType, issuer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
<PackageTags>aspnetcore;authentication;security</PackageTags>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
|
||||
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="1.2.0-*" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="2.1.3-*" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -661,6 +661,14 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
{
|
||||
return await GetUserInformationAsync(tokenEndpointResponse ?? authorizationResponse, jwt, ticket);
|
||||
}
|
||||
else
|
||||
{
|
||||
var identity = (ClaimsIdentity)ticket.Principal.Identity;
|
||||
foreach (var action in Options.ClaimActions)
|
||||
{
|
||||
action.Run(null, identity, Options.ClaimsIssuer);
|
||||
}
|
||||
}
|
||||
|
||||
return AuthenticateResult.Success(ticket);
|
||||
}
|
||||
|
|
@ -727,7 +735,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
|
||||
// Error handling:
|
||||
// 1. If the response body can't be parsed as json, throws.
|
||||
// 2. If the response's status code is not in 2XX range, throw OpenIdConnectProtocolException. If the body is correct parsed,
|
||||
// 2. If the response's status code is not in 2XX range, throw OpenIdConnectProtocolException. If the body is correct parsed,
|
||||
// pass the error information from body to the exception.
|
||||
OpenIdConnectMessage message;
|
||||
try
|
||||
|
|
@ -809,29 +817,11 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
|
||||
var identity = (ClaimsIdentity)ticket.Principal.Identity;
|
||||
|
||||
foreach (var claim in identity.Claims)
|
||||
foreach (var action in Options.ClaimActions)
|
||||
{
|
||||
// If this claimType is mapped by the JwtSeurityTokenHandler, then this property will be set
|
||||
var shortClaimTypeName = claim.Properties.ContainsKey(JwtSecurityTokenHandler.ShortClaimTypeProperty) ?
|
||||
claim.Properties[JwtSecurityTokenHandler.ShortClaimTypeProperty] : string.Empty;
|
||||
|
||||
// checking if claim in the identity (generated from id_token) has the same type as a claim retrieved from userinfo endpoint
|
||||
JToken value;
|
||||
var isClaimIncluded = user.TryGetValue(claim.Type, out value) || user.TryGetValue(shortClaimTypeName, out value);
|
||||
|
||||
// if a same claim exists (matching both type and value) both in id_token identity and userinfo response, remove the json entry from the userinfo response
|
||||
if (isClaimIncluded && claim.Value.Equals(value.ToString(), StringComparison.Ordinal))
|
||||
{
|
||||
if (!user.Remove(claim.Type))
|
||||
{
|
||||
user.Remove(shortClaimTypeName);
|
||||
}
|
||||
}
|
||||
action.Run(user, identity, Options.ClaimsIssuer);
|
||||
}
|
||||
|
||||
// adding remaining unique claims from userinfo endpoint to the identity
|
||||
ClaimsHelper.AddClaimsToIdentity(user, identity, jwt.Issuer);
|
||||
|
||||
return AuthenticateResult.Success(ticket);
|
||||
}
|
||||
|
||||
|
|
@ -908,7 +898,7 @@ namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
|||
/// </summary>
|
||||
/// <param name="nonce">the nonce that we are looking for.</param>
|
||||
/// <returns>echos 'nonce' if a cookie is found that matches, null otherwise.</returns>
|
||||
/// <remarks>Examine <see cref="IRequestCookieCollection.Keys"/> of <see cref="HttpRequest.Cookies"/> that start with the prefix: 'OpenIdConnectAuthenticationDefaults.Nonce'.
|
||||
/// <remarks>Examine <see cref="IRequestCookieCollection.Keys"/> of <see cref="HttpRequest.Cookies"/> that start with the prefix: 'OpenIdConnectAuthenticationDefaults.Nonce'.
|
||||
/// <see cref="M:ISecureDataFormat{TData}.Unprotect"/> of <see cref="OpenIdConnectOptions.StringDataFormat"/> is used to obtain the actual 'nonce'. If the nonce is found, then <see cref="M:IResponseCookies.Delete"/> of <see cref="HttpResponse.Cookies"/> is called.</remarks>
|
||||
private string ReadNonceCookie(string nonce)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Authentication;
|
||||
|
|
@ -55,6 +57,30 @@ namespace Microsoft.AspNetCore.Builder
|
|||
Events = new OpenIdConnectEvents();
|
||||
Scope.Add("openid");
|
||||
Scope.Add("profile");
|
||||
|
||||
ClaimActions.DeleteClaim("nonce");
|
||||
ClaimActions.DeleteClaim("aud");
|
||||
ClaimActions.DeleteClaim("azp");
|
||||
ClaimActions.DeleteClaim("acr");
|
||||
ClaimActions.DeleteClaim("amr");
|
||||
ClaimActions.DeleteClaim("iss");
|
||||
ClaimActions.DeleteClaim("iat");
|
||||
ClaimActions.DeleteClaim("nbf");
|
||||
ClaimActions.DeleteClaim("exp");
|
||||
ClaimActions.DeleteClaim("at_hash");
|
||||
ClaimActions.DeleteClaim("c_hash");
|
||||
ClaimActions.DeleteClaim("auth_time");
|
||||
ClaimActions.DeleteClaim("ipaddr");
|
||||
ClaimActions.DeleteClaim("platf");
|
||||
ClaimActions.DeleteClaim("ver");
|
||||
|
||||
// http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
|
||||
ClaimActions.MapUniqueJsonKey("sub", "sub");
|
||||
ClaimActions.MapUniqueJsonKey("name", "name");
|
||||
ClaimActions.MapUniqueJsonKey("given_name", "given_name");
|
||||
ClaimActions.MapUniqueJsonKey("family_name", "family_name");
|
||||
ClaimActions.MapUniqueJsonKey("profile", "profile");
|
||||
ClaimActions.MapUniqueJsonKey("email", "email");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -90,6 +116,11 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// </summary>
|
||||
public bool GetClaimsFromUserInfoEndpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A collection of claim actions used to select values from the json user data and create Claims.
|
||||
/// </summary>
|
||||
public ClaimActionCollection ClaimActions { get; } = new ClaimActionCollection();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if HTTPS is required for the metadata address or authority.
|
||||
/// The default is true. This should be disabled only in development environments.
|
||||
|
|
@ -112,7 +143,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="OpenIdConnectProtocolValidator"/> that is used to ensure that the 'id_token' received
|
||||
/// is valid per: http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||
/// is valid per: http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentNullException">if 'value' is null.</exception>
|
||||
public OpenIdConnectProtocolValidator ProtocolValidator { get; set; } = new OpenIdConnectProtocolValidator()
|
||||
|
|
|
|||
|
|
@ -1,81 +0,0 @@
|
|||
// 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.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Microsoft.AspNetCore.Authentication.OpenIdConnect
|
||||
{
|
||||
internal static class ClaimsHelper
|
||||
{
|
||||
public static void AddClaimsToIdentity(
|
||||
JObject userInformationPayload,
|
||||
ClaimsIdentity identity,
|
||||
string issuer)
|
||||
{
|
||||
foreach (var pair in userInformationPayload)
|
||||
{
|
||||
var array = pair.Value as JArray;
|
||||
if (array != null)
|
||||
{
|
||||
foreach (var item in array)
|
||||
{
|
||||
AddClaimsToIdentity(item, identity, pair.Key, issuer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddClaimsToIdentity(pair.Value, identity, pair.Key, issuer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddClaimsToIdentity(JToken item, ClaimsIdentity identity, string key, string issuer)
|
||||
=> identity.AddClaim(new Claim(key, item?.ToString() ?? string.Empty, GetClaimValueType(item), issuer));
|
||||
|
||||
private static string GetClaimValueType(JToken token)
|
||||
{
|
||||
if (token == null)
|
||||
{
|
||||
return JsonClaimValueTypes.JsonNull;
|
||||
}
|
||||
|
||||
switch (token.Type)
|
||||
{
|
||||
case JTokenType.Array:
|
||||
return JsonClaimValueTypes.JsonArray;
|
||||
|
||||
case JTokenType.Boolean:
|
||||
return ClaimValueTypes.Boolean;
|
||||
|
||||
case JTokenType.Date:
|
||||
return ClaimValueTypes.DateTime;
|
||||
|
||||
case JTokenType.Float:
|
||||
return ClaimValueTypes.Double;
|
||||
|
||||
case JTokenType.Integer:
|
||||
{
|
||||
var value = (long) token;
|
||||
if (value >= int.MinValue && value <= int.MaxValue)
|
||||
{
|
||||
return ClaimValueTypes.Integer;
|
||||
}
|
||||
|
||||
return ClaimValueTypes.Integer64;
|
||||
}
|
||||
|
||||
case JTokenType.Object:
|
||||
return JsonClaimValueTypes.Json;
|
||||
|
||||
case JTokenType.String:
|
||||
return ClaimValueTypes.String;
|
||||
}
|
||||
|
||||
// Fall back to ClaimValueTypes.String when no appropriate
|
||||
// claim value type can be inferred from the claim value.
|
||||
return ClaimValueTypes.String;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// 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;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication\Microsoft.AspNetCore.Authentication.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.Authentication.OAuth\Microsoft.AspNetCore.Authentication.OAuth.csproj" />
|
||||
<PackageReference Include="Microsoft.Extensions.TaskCache.Sources" Version="1.2.0-*" PrivateAssets="All" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -108,6 +108,11 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
protected virtual async Task<AuthenticationTicket> CreateTicketAsync(
|
||||
ClaimsIdentity identity, AuthenticationProperties properties, AccessToken token, JObject user)
|
||||
{
|
||||
foreach (var action in Options.ClaimActions)
|
||||
{
|
||||
action.Run(user, identity, Options.ClaimsIssuer);
|
||||
}
|
||||
|
||||
var context = new TwitterCreatingTicketContext(Context, Options, token.UserId, token.ScreenName, token.Token, token.TokenSecret, user)
|
||||
{
|
||||
Principal = new ClaimsPrincipal(identity),
|
||||
|
|
@ -355,12 +360,6 @@ namespace Microsoft.AspNetCore.Authentication.Twitter
|
|||
|
||||
var result = JObject.Parse(responseText);
|
||||
|
||||
var email = result.Value<string>("email");
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.Email, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
|
||||
using Microsoft.AspNetCore.Authentication.Twitter;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
|
@ -24,6 +25,8 @@ namespace Microsoft.AspNetCore.Builder
|
|||
CallbackPath = new PathString("/signin-twitter");
|
||||
BackchannelTimeout = TimeSpan.FromSeconds(60);
|
||||
Events = new TwitterEvents();
|
||||
|
||||
ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -46,6 +49,11 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// </summary>
|
||||
public bool RetrieveUserDetails { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A collection of claim actions used to select values from the json user data and create Claims.
|
||||
/// </summary>
|
||||
public ClaimActionCollection ClaimActions { get; } = new ClaimActionCollection();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type used to secure data handled by the middleware.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -653,11 +653,11 @@ namespace Microsoft.AspNetCore.Authentication.Google
|
|||
Assert.Equal(context.AccessToken, "Test Access Token");
|
||||
Assert.Equal(context.RefreshToken, "Test Refresh Token");
|
||||
Assert.Equal(context.ExpiresIn, TimeSpan.FromSeconds(3600));
|
||||
Assert.Equal(GoogleHelper.GetEmail(context.User), "Test email");
|
||||
Assert.Equal(GoogleHelper.GetId(context.User), "Test User ID");
|
||||
Assert.Equal(GoogleHelper.GetName(context.User), "Test Name");
|
||||
Assert.Equal(GoogleHelper.GetFamilyName(context.User), "Test Family Name");
|
||||
Assert.Equal(GoogleHelper.GetGivenName(context.User), "Test Given Name");
|
||||
Assert.Equal(context.Identity.FindFirst(ClaimTypes.Email)?.Value, "Test email");
|
||||
Assert.Equal(context.Identity.FindFirst(ClaimTypes.NameIdentifier)?.Value, "Test User ID");
|
||||
Assert.Equal(context.Identity.FindFirst(ClaimTypes.Name)?.Value, "Test Name");
|
||||
Assert.Equal(context.Identity.FindFirst(ClaimTypes.Surname)?.Value, "Test Family Name");
|
||||
Assert.Equal(context.Identity.FindFirst(ClaimTypes.GivenName)?.Value, "Test Given Name");
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -22,4 +22,8 @@
|
|||
<PackageReference Include="xunit" Version="2.2.0-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@
|
|||
<PackageReference Include="xunit" Version="2.2.0-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -18,4 +18,8 @@
|
|||
<PackageReference Include="xunit" Version="2.2.0-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@
|
|||
<PackageReference Include="xunit" Version="2.2.0-*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
Loading…
Reference in New Issue