Merge branch 'release/2.1' into dev

This commit is contained in:
Chris Ross (ASP.NET) 2018-03-22 09:42:44 -07:00
commit ce278eba92
4 changed files with 145 additions and 0 deletions

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Text.Encodings.Web;
@ -44,6 +45,8 @@ namespace OpenIdConnectSample
public void ConfigureServices(IServiceCollection services)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
@ -56,9 +59,13 @@ namespace OpenIdConnectSample
o.ClientId = Configuration["oidc:clientid"];
o.ClientSecret = Configuration["oidc:clientsecret"]; // for code flow
o.Authority = Configuration["oidc:authority"];
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
o.SaveTokens = true;
o.GetClaimsFromUserInfoEndpoint = true;
o.ClaimActions.MapAllExcept("aud", "iss", "iat", "nbf", "exp", "aio", "c_hash", "uti", "nonce");
o.Events = new OpenIdConnectEvents()
{
OnAuthenticationFailed = c =>

View File

@ -87,6 +87,27 @@ namespace Microsoft.AspNetCore.Authentication
collection.Add(new CustomJsonClaimAction(claimType, valueType, resolver));
}
/// <summary>
/// Clears any current ClaimsActions and maps all values from the json user data as claims, excluding duplicates.
/// </summary>
/// <param name="collection"></param>
public static void MapAll(this ClaimActionCollection collection)
{
collection.Clear();
collection.Add(new MapAllClaimsAction());
}
/// <summary>
/// Clears any current ClaimsActions and maps all values from the json user data as claims, excluding the specified types.
/// </summary>
/// <param name="collection"></param>
/// <param name="exclusions"></param>
public static void MapAllExcept(this ClaimActionCollection collection, params string[] exclusions)
{
collection.MapAll();
collection.DeleteClaims(exclusions);
}
/// <summary>
/// Delete all claims from the given ClaimsIdentity with the given ClaimType.
/// </summary>
@ -96,5 +117,23 @@ namespace Microsoft.AspNetCore.Authentication
{
collection.Add(new DeleteClaimAction(claimType));
}
/// <summary>
/// Delete all claims from the ClaimsIdentity with the given claimTypes.
/// </summary>
/// <param name="collection"></param>
/// <param name="claimTypes"></param>
public static void DeleteClaims(this ClaimActionCollection collection, params string[] claimTypes)
{
if (claimTypes == null)
{
throw new ArgumentNullException(nameof(claimTypes));
}
foreach (var claimType in claimTypes)
{
collection.Add(new DeleteClaimAction(claimType));
}
}
}
}

View File

@ -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;
using System.Security.Claims;
using Newtonsoft.Json.Linq;
namespace Microsoft.AspNetCore.Authentication.OAuth.Claims
{
/// <summary>
/// A ClaimAction that selects all top level values from the json user data and adds them as Claims.
/// This excludes duplicate sets of names and values.
/// </summary>
public class MapAllClaimsAction : ClaimAction
{
public MapAllClaimsAction() : base("All", ClaimValueTypes.String)
{
}
public override void Run(JObject userData, ClaimsIdentity identity, string issuer)
{
if (userData == null)
{
return;
}
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
// 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)
&& string.Equals(c.Value, claimValue, StringComparison.Ordinal)) != null;
if (!duplicate)
{
identity.AddClaim(new Claim(pair.Key, claimValue, ClaimValueTypes.String, issuer));
}
}
}
}
}

View File

@ -51,5 +51,62 @@ namespace Microsoft.AspNetCore.Authentication
Assert.Equal("role", roleClaims[1].Type);
Assert.Equal("role2", roleClaims[1].Value);
}
[Fact]
public void MapAllSucceeds()
{
var userData = new JObject
{
["name0"] = "value0",
["name1"] = "value1",
};
var identity = new ClaimsIdentity();
var action = new MapAllClaimsAction();
action.Run(userData, identity, "iss");
Assert.Equal("name0", identity.FindFirst("name0").Type);
Assert.Equal("value0", identity.FindFirst("name0").Value);
Assert.Equal("name1", identity.FindFirst("name1").Type);
Assert.Equal("value1", identity.FindFirst("name1").Value);
}
[Fact]
public void MapAllAllowesDulicateKeysWithUniqueValues()
{
var userData = new JObject
{
["name0"] = "value0",
["name1"] = "value1",
};
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim("name0", "value2"));
identity.AddClaim(new Claim("name1", "value3"));
var action = new MapAllClaimsAction();
action.Run(userData, identity, "iss");
Assert.Equal(2, identity.FindAll("name0").Count());
Assert.Equal(2, identity.FindAll("name1").Count());
}
[Fact]
public void MapAllSkipsDuplicateValues()
{
var userData = new JObject
{
["name0"] = "value0",
["name1"] = "value1",
};
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim("name0", "value0"));
identity.AddClaim(new Claim("name1", "value1"));
var action = new MapAllClaimsAction();
action.Run(userData, identity, "iss");
Assert.Single(identity.FindAll("name0"));
Assert.Single(identity.FindAll("name1"));
}
}
}