Skip to content
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

Getting the roles by Id when using client credentials grant type #2743 (Lombiq Technologies: TOTA-2) #2872

Merged
merged 10 commits into from
Jan 10, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -278,18 +278,19 @@ await _applicationManager.GetDisplayNameAsync(application),
OpenIddictConstants.Destinations.AccessToken,
OpenIddictConstants.Destinations.IdentityToken);

// If the role service is available, add all the role claims
// associated with the application roles in the database.
var roleService = HttpContext.RequestServices.GetService<IRoleService>();

foreach (var role in await _applicationManager.GetRolesAsync(application))
{
identity.AddClaim(identity.RoleClaimType, role,
OpenIddictConstants.Destinations.AccessToken,
OpenIddictConstants.Destinations.IdentityToken);

// If the role provider is available, add all the role claims
// associated with the application roles in the database.
var provider = HttpContext.RequestServices.GetService<IRoleProvider>();
if (provider != null)
if (roleService != null)
{
foreach (var claim in await provider.GetRoleClaimsAsync(role))
foreach (var claim in await roleService.GetRoleClaimsAsync(role))
{
identity.AddClaim(claim.SetDestinations(
OpenIdConnectConstants.Destinations.AccessToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class ApplicationController : Controller
private readonly IHtmlLocalizer<ApplicationController> H;
private readonly ISiteService _siteService;
private readonly IShapeFactory _shapeFactory;
private readonly IRoleProvider _roleProvider;
private readonly IRoleService _roleService;
private readonly IOpenIdApplicationManager _applicationManager;
private readonly INotifier _notifier;
private readonly ShellDescriptor _shellDescriptor;
Expand All @@ -42,7 +42,7 @@ public ApplicationController(
ISiteService siteService,
IStringLocalizer<ApplicationController> stringLocalizer,
IAuthorizationService authorizationService,
IRoleProvider roleProvider,
IRoleService roleService,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@domonkosgabor any chance you could also resolve this dependency in an optional way, like you did for the main OpenID controller? Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. What do you think, what should we do if there aren't any service available that implements IRoleService when creating/editing an application?
Just simply show a warning message in this page to the user about there will be no RoleEntrys in the list?

IOpenIdApplicationManager applicationManager,
IHtmlLocalizer<ApplicationController> htmlLocalizer,
INotifier notifier,
Expand All @@ -54,7 +54,7 @@ public ApplicationController(
H = htmlLocalizer;
_authorizationService = authorizationService;
_applicationManager = applicationManager;
_roleProvider = roleProvider;
_roleService = roleService;
_notifier = notifier;
_shellDescriptor = shellDescriptor;
}
Expand Down Expand Up @@ -99,7 +99,7 @@ public async Task<IActionResult> Create(string returnUrl = null)

var model = new CreateOpenIdApplicationViewModel();

foreach (var role in await _roleProvider.GetRoleNamesAsync())
foreach (var role in await _roleService.GetRoleNamesAsync())
{
model.RoleEntries.Add(new CreateOpenIdApplicationViewModel.RoleEntry
{
Expand Down Expand Up @@ -245,7 +245,7 @@ public async Task<IActionResult> Edit(string id, string returnUrl = null)
Type = await _applicationManager.GetClientTypeAsync(application)
};

foreach (var role in await _roleProvider.GetRoleNamesAsync())
foreach (var role in await _roleService.GetRoleNamesAsync())
{
model.RoleEntries.Add(new EditOpenIdApplicationViewModel.RoleEntry
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
Expand Down Expand Up @@ -30,7 +30,7 @@ public class AdminController : Controller
private readonly RoleManager<IRole> _roleManager;
private readonly IEnumerable<IPermissionProvider> _permissionProviders;
private readonly ITypeFeatureProvider _typeFeatureProvider;
private readonly IRoleProvider _roleProvider;
private readonly IRoleService _roleService;
private readonly INotifier _notifier;
private readonly IHtmlLocalizer<AdminController> TH;

Expand All @@ -43,14 +43,14 @@ public AdminController(
ISiteService siteService,
IShapeFactory shapeFactory,
RoleManager<IRole> roleManager,
IRoleProvider roleProvider,
IRoleService roleService,
INotifier notifier,
IEnumerable<IPermissionProvider> permissionProviders
)
{
TH = htmlLocalizer;
_notifier = notifier;
_roleProvider = roleProvider;
_roleService = roleService;
_typeFeatureProvider = typeFeatureProvider;
_permissionProviders = permissionProviders;
_roleManager = roleManager;
Expand All @@ -68,7 +68,7 @@ public async Task<ActionResult> Index()
return Unauthorized();
}

var roles = await _roleProvider.GetRoleNamesAsync();
var roles = await _roleService.GetRoleNamesAsync();

var model = new RolesViewModel
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ namespace OrchardCore.Roles.Deployment
public class AllRolesDeploymentSource : IDeploymentSource
{
private readonly RoleManager<IRole> _roleManager;
private readonly IRoleProvider _roleProvider;
private readonly IRoleService _roleService;

public AllRolesDeploymentSource(RoleManager<IRole> roleManager, IRoleProvider roleProvider)
public AllRolesDeploymentSource(RoleManager<IRole> roleManager, IRoleService roleService)
{
_roleManager = roleManager;
_roleProvider = roleProvider;
_roleService = roleService;
}

public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlanResult result)
Expand All @@ -29,7 +29,7 @@ public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlan
}

// Get all roles
var allRoleNames = await _roleProvider.GetRoleNamesAsync();
var allRoleNames = await _roleService.GetRoleNamesAsync();
var data = new JArray();
var tasks = new List<Task>();

Expand Down
43 changes: 43 additions & 0 deletions src/OrchardCore.Modules/OrchardCore.Roles/Services/RoleService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using OrchardCore.Security;
using OrchardCore.Security.Services;

namespace OrchardCore.Roles.Services
{
public class RoleService : IRoleService
{
private readonly RoleManager<IRole> _roleManager;

public RoleService(RoleManager<IRole> roleManager)
{
_roleManager = roleManager;
}

public async Task<IEnumerable<Claim>> GetRoleClaimsAsync(string role, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(role))
{
throw new ArgumentException("The role name cannot be null or empty.", nameof(role));
}

var entity = await _roleManager.FindByNameAsync(role);
if (entity == null)
{
return Array.Empty<Claim>();
}

return await _roleManager.GetClaimsAsync(entity);
}

public Task<IEnumerable<string>> GetRoleNamesAsync()
{
return Task.FromResult<IEnumerable<string>>(_roleManager.Roles.Select(a => a.RoleName));
}
}
}
28 changes: 4 additions & 24 deletions src/OrchardCore.Modules/OrchardCore.Roles/Services/RoleStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@
using OrchardCore.Modules;
using OrchardCore.Roles.Models;
using OrchardCore.Security;
using OrchardCore.Security.Services;
using YesSql;

namespace OrchardCore.Roles.Services
{
public class RoleStore : IRoleClaimStore<IRole>, IRoleProvider
public class RoleStore : IRoleClaimStore<IRole>, IQueryableRoleStore<IRole>
{
private const string Key = "RolesManager.Roles";

Expand Down Expand Up @@ -50,6 +49,9 @@ public void Dispose()
{
}

public IQueryable<IRole> Roles =>
GetRolesAsync().Result.Roles.AsQueryable();

public Task<RolesDocument> GetRolesAsync()
{
return _memoryCache.GetOrCreateAsync(Key, async (entry) =>
Expand All @@ -75,28 +77,6 @@ public void UpdateRoles(RolesDocument roles)
_memoryCache.Set(Key, roles);
}

public async Task<IEnumerable<string>> GetRoleNamesAsync()
{
var roles = await GetRolesAsync();
return roles.Roles.Select(x => x.RoleName).OrderBy(x => x).ToList();
}

public async Task<IEnumerable<Claim>> GetRoleClaimsAsync(string role, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(role))
{
throw new ArgumentException("The role name cannot be null or empty.", nameof(role));
}

var entity = await FindByNameAsync(role, cancellationToken);
if (entity == null)
{
return Array.Empty<Claim>();
}

return await GetClaimsAsync(entity, cancellationToken);
}

#region IRoleStore<IRole>
public async Task<IdentityResult> CreateAsync(IRole role, CancellationToken cancellationToken)
{
Expand Down
2 changes: 1 addition & 1 deletion src/OrchardCore.Modules/OrchardCore.Roles/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public override void ConfigureServices(IServiceCollection services)
{
services.TryAddScoped<RoleManager<IRole>>();
services.TryAddScoped<IRoleStore<IRole>, RoleStore>();
services.TryAddScoped<IRoleProvider, RoleStore>();
services.TryAddScoped<IRoleService, RoleService>();
services.TryAddScoped<IRoleClaimStore<IRole>, RoleStore>();
services.AddRecipeExecutionStep<RolesStep>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ namespace OrchardCore.Roles.ViewComponents
{
public class SelectRolesViewComponent : ViewComponent
{
private readonly IRoleProvider _roleProvider;
private readonly IRoleService _roleService;

public SelectRolesViewComponent(IRoleProvider roleProvider)
public SelectRolesViewComponent(IRoleService roleService)
{
_roleProvider = roleProvider;
_roleService = roleService;
}

public async Task<IViewComponentResult> InvokeAsync(IEnumerable<string> selectedRoles, string htmlName)
Expand All @@ -35,7 +35,7 @@ public async Task<IViewComponentResult> InvokeAsync(IEnumerable<string> selected

private async Task<IList<Selection<string>>> BuildRoleSelectionsAsync(IEnumerable<string> selectedRoles)
{
var roleNames = await _roleProvider.GetRoleNamesAsync();
var roleNames = await _roleService.GetRoleNamesAsync();
var selections = roleNames.Select(x => new Selection<string>
{
IsSelected = selectedRoles.Contains(x),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class UserDisplayDriver : DisplayDriver<User>
{
private readonly UserManager<IUser> _userManager;
private readonly IUserService _userService;
private readonly IRoleProvider _roleProvider;
private readonly IRoleService _roleService;
private readonly IUserStore<IUser> _userStore;
private readonly IUserEmailStore<IUser> _userEmailStore;
private readonly IUserRoleStore<IUser> _userRoleStore;
Expand All @@ -27,15 +27,15 @@ public class UserDisplayDriver : DisplayDriver<User>
public UserDisplayDriver(
UserManager<IUser> userManager,
IUserService userService,
IRoleProvider roleProvider,
IRoleService roleService,
IUserStore<IUser> userStore,
IUserEmailStore<IUser> userEmailStore,
IUserRoleStore<IUser> userRoleStore,
IStringLocalizer<UserDisplayDriver> stringLocalizer)
{
_userManager = userManager;
_userService = userService;
_roleProvider = roleProvider;
_roleService = roleService;
_userStore = userStore;
_userEmailStore = userEmailStore;
_userRoleStore = userRoleStore;
Expand Down Expand Up @@ -157,7 +157,7 @@ public override async Task<IDisplayResult> UpdateAsync(User user, UpdateEditorCo

private async Task<IEnumerable<string>> GetRoleNamesAsync()
{
var roleNames = await _roleProvider.GetRoleNamesAsync();
var roleNames = await _roleService.GetRoleNamesAsync();
return roleNames.Except(new[] { "Anonymous", "Authenticated" }, StringComparer.OrdinalIgnoreCase);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace OrchardCore.Security.Services
{
public interface IRoleProvider
public interface IRoleService
{
Task<IEnumerable<string>> GetRoleNamesAsync();
Task<IEnumerable<Claim>> GetRoleClaimsAsync(string role, CancellationToken cancellationToken = default);
Expand Down
10 changes: 5 additions & 5 deletions src/OrchardCore/OrchardCore.Users.Core/Services/UserStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ public class UserStore :
IUserLoginStore<IUser>
{
private readonly ISession _session;
private readonly IRoleProvider _roleProvider;
private readonly IRoleService _roleService;
private readonly ILookupNormalizer _keyNormalizer;

public UserStore(ISession session,
IRoleProvider roleProvider,
IRoleService roleService,
ILookupNormalizer keyNormalizer)
{
_session = session;
_roleProvider = roleProvider;
_roleService = roleService;
_keyNormalizer = keyNormalizer;
}

Expand Down Expand Up @@ -308,7 +308,7 @@ public async Task AddToRoleAsync(IUser user, string normalizedRoleName, Cancella
throw new ArgumentNullException(nameof(user));
}

var roleNames = await _roleProvider.GetRoleNamesAsync();
var roleNames = await _roleService.GetRoleNamesAsync();
var roleName = roleNames?.FirstOrDefault(r => NormalizeKey(r) == normalizedRoleName);

if (string.IsNullOrWhiteSpace(roleName))
Expand All @@ -326,7 +326,7 @@ public async Task RemoveFromRoleAsync(IUser user, string normalizedRoleName, Can
throw new ArgumentNullException(nameof(user));
}

var roleNames = await _roleProvider.GetRoleNamesAsync();
var roleNames = await _roleService.GetRoleNamesAsync();
var roleName = roleNames?.FirstOrDefault(r => NormalizeKey(r) == normalizedRoleName);

if (string.IsNullOrWhiteSpace(roleName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public async Task UsersShouldNotBeAbleToCreateIfNotAllowed()
Mock.Of<ISiteService>(),
Mock.Of<IStringLocalizer<ApplicationController>>(),
Mock.Of<IAuthorizationService>(),
Mock.Of<IRoleProvider>(),
Mock.Of<IRoleService>(),
Mock.Of<IOpenIdApplicationManager>(),
Mock.Of<IHtmlLocalizer<ApplicationController>>(),
Mock.Of<INotifier>(),
Expand All @@ -51,7 +51,7 @@ public async Task UsersShouldBeAbleToCreateApplicationIfAllowed()
Mock.Of<ISiteService>(),
Mock.Of<IStringLocalizer<ApplicationController>>(),
MockAuthorizationServiceMock().Object,
Mock.Of<IRoleProvider>(),
Mock.Of<IRoleService>(),
Mock.Of<IOpenIdApplicationManager>(),
Mock.Of<IHtmlLocalizer<ApplicationController>>(),
Mock.Of<INotifier>(),
Expand All @@ -75,7 +75,7 @@ public async Task ConfidentionalClientNeedsSecret(string clientType, string clie
Mock.Of<ISiteService>(),
MockStringLocalizer().Object,
MockAuthorizationServiceMock().Object,
Mock.Of<IRoleProvider>(),
Mock.Of<IRoleService>(),
Mock.Of<IOpenIdApplicationManager>(),
Mock.Of<IHtmlLocalizer<ApplicationController>>(),
Mock.Of<INotifier>(),
Expand Down Expand Up @@ -111,7 +111,7 @@ public async Task RedirectUrisAreValid(string uris, bool expectValidModel)
Mock.Of<ISiteService>(),
MockStringLocalizer().Object,
MockAuthorizationServiceMock().Object,
Mock.Of<IRoleProvider>(),
Mock.Of<IRoleService>(),
Mock.Of<IOpenIdApplicationManager>(),
Mock.Of<IHtmlLocalizer<ApplicationController>>(),
Mock.Of<INotifier>(),
Expand Down