aspnetcore/src/Microsoft.AspNetCore.Identi.../Claims/ScopesTokenClaimsProvider.cs

87 lines
3.6 KiB
C#

// 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.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Identity.Service.Claims
{
public class ScopesTokenClaimsProvider : ITokenClaimsProvider
{
public int Order => 100;
public Task OnGeneratingClaims(TokenGeneratingContext context)
{
var resource = context.RequestGrants.Scopes.FirstOrDefault(rg => rg.ClientId != null)?.ClientId;
if (context.IsContextForTokenTypes(TokenTypes.AccessToken) && resource != null)
{
// For access tokens we use the scopes from the set of granted scopes, this takes into account the
// fact that a token request can ask for a subset of the scopes granted during authorization, either
// on a code exchange or on a refresh token grant flow.
AddClaimsForAccessToken(context, resource);
return Task.CompletedTask;
}
if (context.IsContextForTokenTypes(TokenTypes.AuthorizationCode))
{
context.AddClaimToCurrentToken(
IdentityServiceClaimTypes.Scope,
GetScopeValue(context.RequestGrants.Scopes, excludeCanonical: false));
if (resource != null)
{
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Resource, resource);
}
return Task.CompletedTask;
}
if (context.IsContextForTokenTypes(TokenTypes.RefreshToken))
{
// For refresh tokens the scope claim never changes as the set of scopes granted for a refresh token
// should not change no matter what scopes are sent on a token request.
var scopeClaim = context
.RequestGrants
.Claims
.Single(c => c.Type.Equals(IdentityServiceClaimTypes.Scope, StringComparison.Ordinal));
var resourceClaim = context
.RequestGrants
.Claims
.SingleOrDefault(c => c.Type.Equals(IdentityServiceClaimTypes.Resource, StringComparison.Ordinal));
context.AddClaimToCurrentToken(scopeClaim);
if (resourceClaim != null)
{
context.AddClaimToCurrentToken(resourceClaim);
}
}
return Task.CompletedTask;
}
private void AddClaimsForAccessToken(TokenGeneratingContext context, string resource)
{
var scopes = context.RequestGrants.Scopes;
var accessTokenScopes = GetAccessTokenScopes(scopes);
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Scope, GetScopeValue(scopes, excludeCanonical: true));
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Audience, resource);
context.AddClaimToCurrentToken(IdentityServiceClaimTypes.AuthorizedParty, context.RequestParameters.ClientId);
}
private IEnumerable<ApplicationScope> GetAccessTokenScopes(IEnumerable<ApplicationScope> applicationScopes) =>
applicationScopes.Where(s => s.ClientId != null);
private string GetScopeValue(IEnumerable<ApplicationScope> scopes, bool excludeCanonical) =>
!excludeCanonical ?
string.Join(" ", scopes.Select(s => s.Scope)) :
string.Join(" ", scopes.Where(s => s.ClientId != null).Select(s => s.Scope));
}
}