From 038c98cfaf04e5730013d1be773d83f531de33e7 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Wed, 11 Jan 2017 21:46:36 -0500 Subject: [PATCH] re-working claims for aspnet core identity integration and backwards compat --- src/Api/Controllers/AccountsController.cs | 8 +++++--- src/Api/Controllers/AliveController.cs | 2 +- src/Api/Startup.cs | 3 +-- .../Identity/{Resources.cs => ApiResources.cs} | 9 +++++---- src/Core/Identity/ProfileService.cs | 2 +- .../Identity/ResourceOwnerPasswordValidator.cs | 15 ++++++++++----- src/Core/Services/IUserService.cs | 1 + src/Core/Services/Implementations/UserService.cs | 11 +++++++++++ 8 files changed, 35 insertions(+), 16 deletions(-) rename src/Core/Identity/{Resources.cs => ApiResources.cs} (66%) diff --git a/src/Api/Controllers/AccountsController.cs b/src/Api/Controllers/AccountsController.cs index 81a5429d1..439213da5 100644 --- a/src/Api/Controllers/AccountsController.cs +++ b/src/Api/Controllers/AccountsController.cs @@ -64,6 +64,7 @@ namespace Bit.Api.Controllers [HttpPost("email-token")] public async Task PostEmailToken([FromBody]EmailTokenRequestModel model) { + _currentContext.User = await _userService.GetUserByIdAsync(_userManager.GetUserId(User)); if(!await _userManager.CheckPasswordAsync(_currentContext.User, model.MasterPasswordHash)) { await Task.Delay(2000); @@ -151,10 +152,11 @@ namespace Bit.Api.Controllers } [HttpGet("profile")] - public Task GetProfile() + public async Task GetProfile() { + _currentContext.User = await _userService.GetUserByIdAsync(_userManager.GetUserId(User)); var response = new ProfileResponseModel(_currentContext.User); - return Task.FromResult(response); + return response; } [HttpPut("profile")] @@ -165,7 +167,7 @@ namespace Bit.Api.Controllers var response = new ProfileResponseModel(_currentContext.User); return response; - } + } [HttpGet("two-factor")] public async Task GetTwoFactor(string masterPasswordHash, TwoFactorProviderType provider) diff --git a/src/Api/Controllers/AliveController.cs b/src/Api/Controllers/AliveController.cs index 32936e658..5dce9f8f8 100644 --- a/src/Api/Controllers/AliveController.cs +++ b/src/Api/Controllers/AliveController.cs @@ -16,7 +16,7 @@ namespace Bit.Api.Controllers [HttpGet("claims")] public IActionResult Claims() { - return new JsonResult(User.Claims.Select(c => new { c.Type, c.Value })); + return new JsonResult(User?.Claims?.Select(c => new { c.Type, c.Value })); } } } diff --git a/src/Api/Startup.cs b/src/Api/Startup.cs index 40e4d5ece..7f954a432 100644 --- a/src/Api/Startup.cs +++ b/src/Api/Startup.cs @@ -28,7 +28,6 @@ using Bit.Api.Middleware; using IdentityServer4.Validation; using IdentityServer4.Services; using IdentityModel.AspNetCore.OAuth2Introspection; -using Microsoft.AspNetCore.Authorization.Infrastructure; namespace Bit.Api { @@ -89,7 +88,7 @@ namespace Bit.Api services.AddIdentityServer() // TODO: Add proper signing creds .AddTemporarySigningCredential() - .AddInMemoryApiResources(Resources.GetApiResources()) + .AddInMemoryApiResources(ApiResources.GetApiResources()) .AddInMemoryClients(Clients.GetClients()); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Core/Identity/Resources.cs b/src/Core/Identity/ApiResources.cs similarity index 66% rename from src/Core/Identity/Resources.cs rename to src/Core/Identity/ApiResources.cs index 01a999e54..bd8d412b1 100644 --- a/src/Core/Identity/Resources.cs +++ b/src/Core/Identity/ApiResources.cs @@ -1,18 +1,19 @@ using IdentityServer4.Models; using System.Collections.Generic; +using System.Security.Claims; namespace Bit.Core.Identity { - public class Resources + public class ApiResources { public static IEnumerable GetApiResources() { return new List { new ApiResource("api", "Vault API", new string[] { - "authmethod", - "nameid", - "email", + ClaimTypes.AuthenticationMethod, + ClaimTypes.NameIdentifier, + ClaimTypes.Email, "securitystamp" }) }; diff --git a/src/Core/Identity/ProfileService.cs b/src/Core/Identity/ProfileService.cs index 0dc9aafe2..b3e2626f8 100644 --- a/src/Core/Identity/ProfileService.cs +++ b/src/Core/Identity/ProfileService.cs @@ -21,7 +21,7 @@ namespace Bit.Core.Identity public Task GetProfileDataAsync(ProfileDataRequestContext context) { - context.AddFilteredClaims(context.IssuedClaims); + context.AddFilteredClaims(context.Subject.Claims); return Task.FromResult(0); } diff --git a/src/Core/Identity/ResourceOwnerPasswordValidator.cs b/src/Core/Identity/ResourceOwnerPasswordValidator.cs index 74f26e246..d1cb1a292 100644 --- a/src/Core/Identity/ResourceOwnerPasswordValidator.cs +++ b/src/Core/Identity/ResourceOwnerPasswordValidator.cs @@ -1,7 +1,9 @@ using Bit.Core.Domains; using IdentityServer4.Models; using IdentityServer4.Validation; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; using System.Security.Claims; using System.Threading.Tasks; @@ -10,11 +12,14 @@ namespace Bit.Core.Identity public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator { private readonly UserManager _userManager; + private readonly IdentityOptions _identityOptions; public ResourceOwnerPasswordValidator( - UserManager userManager) + UserManager userManager, + IOptions optionsAccessor) { _userManager = userManager; + _identityOptions = optionsAccessor?.Value ?? new IdentityOptions(); } public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context) @@ -27,10 +32,10 @@ namespace Bit.Core.Identity context.Result = new GrantValidationResult(user.Id.ToString(), "Application", identityProvider: "bitwarden", claims: new Claim[] { // Deprecated claims for backwards compatability - new Claim("authmethod", "Application"), - new Claim("nameid", user.Id.ToString()), - new Claim("email", user.Email.ToString()), - new Claim("securitystamp", user.SecurityStamp) + new Claim(ClaimTypes.AuthenticationMethod, "Application"), + new Claim(_identityOptions.ClaimsIdentity.UserIdClaimType, user.Id.ToString()), + new Claim(_identityOptions.ClaimsIdentity.UserNameClaimType, user.Email.ToString()), + new Claim(_identityOptions.ClaimsIdentity.SecurityStampClaimType, user.SecurityStamp) }); return; } diff --git a/src/Core/Services/IUserService.cs b/src/Core/Services/IUserService.cs index 52196fda5..9148c9414 100644 --- a/src/Core/Services/IUserService.cs +++ b/src/Core/Services/IUserService.cs @@ -8,6 +8,7 @@ namespace Bit.Core.Services { public interface IUserService { + Task GetUserByIdAsync(string userId); Task GetUserByIdAsync(Guid userId); Task SaveUserAsync(User user); Task RegisterUserAsync(User user, string masterPassword); diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index 549bef4e0..cf7857d06 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -57,6 +57,17 @@ namespace Bit.Core.Services _passwordValidators = passwordValidators; } + public async Task GetUserByIdAsync(string userId) + { + Guid userIdGuid; + if(!Guid.TryParse(userId, out userIdGuid)) + { + return null; + } + + return await _userRepository.GetByIdAsync(userIdGuid); + } + public async Task GetUserByIdAsync(Guid userId) { return await _userRepository.GetByIdAsync(userId);