Skip to content
This repository has been archived by the owner on Jul 31, 2024. It is now read-only.

Move the IsActive call from the custom token validator to the core token validatator #1718

Merged
merged 4 commits into from
Dec 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 4 additions & 78 deletions src/IdentityServer4/Validation/DefaultCustomTokenValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,9 @@
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using IdentityModel;
using IdentityServer4.Extensions;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace IdentityServer4.Validation
Expand Down Expand Up @@ -54,57 +49,9 @@ public DefaultCustomTokenValidator(IProfileService profile, IClientStore clients
/// <returns>
/// The validation result
/// </returns>
public virtual async Task<TokenValidationResult> ValidateAccessTokenAsync(TokenValidationResult result)
public virtual Task<TokenValidationResult> ValidateAccessTokenAsync(TokenValidationResult result)
{
if (result.IsError)
{
return result;
}

// make sure user is still active (if sub claim is present)
var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject);
if (subClaim != null)
{
var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

if (result.ReferenceTokenId.IsPresent())
{
principal.Identities.First().AddClaim(new Claim(JwtClaimTypes.ReferenceTokenId, result.ReferenceTokenId));
}

var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.AccessTokenValidation);
await Profile.IsActiveAsync(isActiveCtx);

if (isActiveCtx.IsActive == false)
{
Logger.LogError("User marked as not active: {subject}", subClaim.Value);

result.IsError = true;
result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken;
result.Claims = null;

return result;
}
}

// make sure client is still active (if client_id claim is present)
var clientClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.ClientId);
if (clientClaim != null)
{
var client = await Clients.FindEnabledClientByIdAsync(clientClaim.Value);
if (client == null)
{
Logger.LogError("Client deleted or disabled: {clientId}", clientClaim.Value);

result.IsError = true;
result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken;
result.Claims = null;

return result;
}
}

return result;
return Task.FromResult(result);
}

/// <summary>
Expand All @@ -114,30 +61,9 @@ public virtual async Task<TokenValidationResult> ValidateAccessTokenAsync(TokenV
/// <returns>
/// The validation result
/// </returns>
public virtual async Task<TokenValidationResult> ValidateIdentityTokenAsync(TokenValidationResult result)
public virtual Task<TokenValidationResult> ValidateIdentityTokenAsync(TokenValidationResult result)
{
// make sure user is still active (if sub claim is present)
var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject);
if (subClaim != null)
{
var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.IdentityTokenValidation);
await Profile.IsActiveAsync(isActiveCtx);

if (isActiveCtx.IsActive == false)
{
Logger.LogError("User marked as not active: {subject}", subClaim.Value);

result.IsError = true;
result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken;
result.Claims = null;

return result;
}
}

return result;
return Task.FromResult(result);
}
}
}
74 changes: 70 additions & 4 deletions src/IdentityServer4/Validation/TokenValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,27 @@ public async Task<TokenValidationResult> ValidateIdentityTokenAsync(string token

_log.Claims = result.Claims.ToClaimsDictionary();

// make sure user is still active (if sub claim is present)
var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject);
if (subClaim != null)
{
var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.IdentityTokenValidation);
await _profile.IsActiveAsync(isActiveCtx);

if (isActiveCtx.IsActive == false)
{
_logger.LogError("User marked as not active: {subject}", subClaim.Value);

result.IsError = true;
result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken;
result.Claims = null;

return result;
}
}

_logger.LogDebug("Calling into custom token validator: {type}", _customValidator.GetType().FullName);
var customResult = await _customValidator.ValidateIdentityTokenAsync(result);

Expand Down Expand Up @@ -178,6 +199,50 @@ public async Task<TokenValidationResult> ValidateAccessTokenAsync(string token,
return result;
}

// make sure client is still active (if client_id claim is present)
var clientClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.ClientId);
if (clientClaim != null)
{
var client = await _clients.FindEnabledClientByIdAsync(clientClaim.Value);
if (client == null)
{
_logger.LogError("Client deleted or disabled: {clientId}", clientClaim.Value);

result.IsError = true;
result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken;
result.Claims = null;

return result;
}
}

// make sure user is still active (if sub claim is present)
var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject);
if (subClaim != null)
{
var principal = Principal.Create("tokenvalidator", result.Claims.ToArray());

if (result.ReferenceTokenId.IsPresent())
{
principal.Identities.First().AddClaim(new Claim(JwtClaimTypes.ReferenceTokenId, result.ReferenceTokenId));
}

var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.AccessTokenValidation);
await _profile.IsActiveAsync(isActiveCtx);

if (isActiveCtx.IsActive == false)
{
_logger.LogError("User marked as not active: {subject}", subClaim.Value);

result.IsError = true;
result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken;
result.Claims = null;

return result;
}
}

// check expected scope(s)
if (expectedScope.IsPresent())
{
var scope = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Scope && c.Value == expectedScope);
Expand All @@ -188,6 +253,7 @@ public async Task<TokenValidationResult> ValidateAccessTokenAsync(string token,
}
}

_logger.LogDebug("Calling into custom token validator: {type}", _customValidator.GetType().FullName);
var customResult = await _customValidator.ValidateAccessTokenAsync(result);

if (customResult.IsError)
Expand Down Expand Up @@ -301,7 +367,7 @@ private async Task<TokenValidationResult> ValidateReferenceAccessTokenAsync(stri
public async Task<TokenValidationResult> ValidateRefreshTokenAsync(string tokenHandle, Client client = null)
{
_logger.LogTrace("Start refresh token validation");

/////////////////////////////////////////////
// check if refresh token is valid
/////////////////////////////////////////////
Expand Down Expand Up @@ -351,8 +417,8 @@ public async Task<TokenValidationResult> ValidateRefreshTokenAsync(string tokenH
// make sure user is enabled
/////////////////////////////////////////////
var isActiveCtx = new IsActiveContext(
refreshToken.Subject,
client,
refreshToken.Subject,
client,
IdentityServerConstants.ProfileIsActiveCallers.RefreshTokenValidation);
await _profile.IsActiveAsync(isActiveCtx);

Expand All @@ -365,7 +431,7 @@ public async Task<TokenValidationResult> ValidateRefreshTokenAsync(string tokenH
_log.Claims = refreshToken.Subject.Claims.ToClaimsDictionary();

LogSuccess();

return new TokenValidationResult
{
IsError = false,
Expand Down