Skip to content

validate if user hasRoleToBypassScopeValidation to skip client scope … #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 6, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static async Task<Client> FindEnabledClientByIdAsync(this IClientStore st

if (clientUserRoleService != null && !string.IsNullOrEmpty(userID))
{
var userHasLoginByPassRoleInClient = await clientUserRoleService.UserHasLoginByPassRoleInClient(userID, client);
var userHasLoginByPassRoleInClient = await clientUserRoleService.UserHasLoginByPassRoleInClient(userID, client, null);

if (userHasLoginByPassRoleInClient)
{
Expand Down
7 changes: 7 additions & 0 deletions Bornlogic.IdentityServer/Models/ClientRoleOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Bornlogic.IdentityServer.Models
{
public class ClientRoleOptions
{
public string[] ValidUserRolesToBypassClientScopeValidation { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Bornlogic.IdentityServer.Services.Default
{
public class DefaultClientUserRoleService : IClientUserRoleService
{
public Task<bool> UserHasLoginByPassRoleInClient(string userID, Client client)
public Task<bool> UserHasLoginByPassRoleInClient(string userID, Client client, string[] validRoles)
{
return Task.FromResult(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ namespace Bornlogic.IdentityServer.Services
{
public interface IClientUserRoleService
{
Task<bool> UserHasLoginByPassRoleInClient(string userID, Client client);
Task<bool> UserHasLoginByPassRoleInClient(string userID, Client client, string[] validRoles);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,8 @@ private async Task<AuthorizeRequestValidationResult> ValidateScopeAsync(Validate
{
Client = request.Client,
Scopes = request.RequestedScopes,
RequiredRequestScopes = request.Raw.Get("required_scope")?.Split(' ') ?? Array.Empty<string>()
RequiredRequestScopes = request.Raw.Get("required_scope")?.Split(' ') ?? Array.Empty<string>(),
Subject = request.Subject
});

if (!validatedResources.Succeeded)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@


using Bornlogic.IdentityServer.Extensions;
using Bornlogic.IdentityServer.Models;
using Bornlogic.IdentityServer.Services;
using Bornlogic.IdentityServer.Storage.Models;
using Bornlogic.IdentityServer.Storage.Stores;
using Bornlogic.IdentityServer.Validation.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Bornlogic.IdentityServer.Validation.Default
{
Expand All @@ -16,6 +19,8 @@ namespace Bornlogic.IdentityServer.Validation.Default
public class DefaultResourceValidator : IResourceValidator
{
private readonly ILogger _logger;
private readonly IClientUserRoleService _clientUserRoleService;
private readonly IOptions<ClientRoleOptions> _clientRoleOptions;
private readonly IScopeParser _scopeParser;
private readonly IResourceStore _store;

Expand All @@ -25,9 +30,11 @@ public class DefaultResourceValidator : IResourceValidator
/// <param name="store">The store.</param>
/// <param name="scopeParser"></param>
/// <param name="logger">The logger.</param>
public DefaultResourceValidator(IResourceStore store, IScopeParser scopeParser, ILogger<DefaultResourceValidator> logger)
public DefaultResourceValidator(IResourceStore store, IScopeParser scopeParser, ILogger<DefaultResourceValidator> logger, IClientUserRoleService clientUserRoleService, IOptions<ClientRoleOptions> clientRoleOptions)
{
_logger = logger;
_clientUserRoleService = clientUserRoleService;
_clientRoleOptions = clientRoleOptions;
_scopeParser = scopeParser;
_store = store;
}
Expand Down Expand Up @@ -65,20 +72,30 @@ public virtual async Task<ResourceValidationResult> ValidateRequestedResourcesAs
return result;
}

var scopeNames = parsedScopesResult.ParsedScopes.Select(x => x.ParsedName).Distinct().ToArray();
var resourcesFromStore = await _store.FindEnabledResourcesByScopeAsync(scopeNames);
var subjectIdOrDefault = request.Subject?.GetSubjectIdOrDefault();

foreach (var scope in parsedScopesResult.ParsedScopes)
if (!string.IsNullOrEmpty(subjectIdOrDefault))
{
await ValidateScopeAsync(request.Client, resourcesFromStore, scope, result, request.RequiredRequestScopes.Any(a => a == scope.ParsedName));
}
var hasRoleToBypassScopeValidation = await _clientUserRoleService.UserHasLoginByPassRoleInClient(subjectIdOrDefault, request.Client, _clientRoleOptions?.Value?.ValidUserRolesToBypassClientScopeValidation);

var requiredRequestScopeNames = parsedRequiredRequestScopesResult.ParsedScopes.Select(x => x.ParsedName).Distinct().ToArray();
var requiredRequestResourcesFromStore = await _store.FindEnabledResourcesByScopeAsync(requiredRequestScopeNames);
if (!hasRoleToBypassScopeValidation)
{
var scopeNames = parsedScopesResult.ParsedScopes.Select(x => x.ParsedName).Distinct().ToArray();
var resourcesFromStore = await _store.FindEnabledResourcesByScopeAsync(scopeNames);

foreach (var scope in parsedRequiredRequestScopesResult.ParsedScopes)
{
await ValidateRequestRequiredScopeAsync(request.Client, requiredRequestResourcesFromStore, scope, result);
foreach (var scope in parsedScopesResult.ParsedScopes)
{
await ValidateScopeAsync(request.Client, resourcesFromStore, scope, result, request.RequiredRequestScopes.Any(a => a == scope.ParsedName));
}

var requiredRequestScopeNames = parsedRequiredRequestScopesResult.ParsedScopes.Select(x => x.ParsedName).Distinct().ToArray();
var requiredRequestResourcesFromStore = await _store.FindEnabledResourcesByScopeAsync(requiredRequestScopeNames);

foreach (var scope in parsedRequiredRequestScopesResult.ParsedScopes)
{
await ValidateRequestRequiredScopeAsync(request.Client, requiredRequestResourcesFromStore, scope, result);
}
}
}

if (result.InvalidScopes.Count > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ private async Task<DeviceAuthorizationRequestValidationResult> ValidateScopeAsyn
//////////////////////////////////////////////////////////
var validatedResources = await _resourceValidator.ValidateRequestedResourcesAsync(new ResourceValidationRequest{
Client = request.Client,
Scopes = request.RequestedScopes
Scopes = request.RequestedScopes,
Subject = request.Subject
});

if (!validatedResources.Succeeded)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,8 @@ private async Task<bool> ValidateRequestedScopesAsync(NameValueCollection parame

var resourceValidationResult = await _resourceValidator.ValidateRequestedResourcesAsync(new ResourceValidationRequest {
Client = _validatedRequest.Client,
Scopes = requestedScopes
Scopes = requestedScopes,
Subject = _validatedRequest.Subject
});

if (!resourceValidationResult.Succeeded)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.


using System.Security.Claims;
using Bornlogic.IdentityServer.Storage.Models;

namespace Bornlogic.IdentityServer.Validation.Models
Expand All @@ -16,6 +17,8 @@ public class ResourceValidationRequest
/// </summary>
public Client Client { get; set; }

public ClaimsPrincipal Subject { get; set; }

/// <summary>
/// The requested scope values.
/// </summary>
Expand Down