From da56901d17c6e95fce0e9b75c0ebab4eb477d6db Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Sat, 6 Aug 2016 15:15:11 -0400 Subject: [PATCH] Revert device id in jwt token and moved to reading from header. Added clear token by identifier API/repo/sproc so that token can be cleared after logout. --- src/Api/Controllers/DevicesController.cs | 16 +++------------- .../Identity/JwtBearerEventImplementations.cs | 6 ++---- src/Core/Identity/JwtBearerSignInManager.cs | 17 ++++++----------- src/Core/Repositories/IDeviceRepository.cs | 1 + .../Repositories/SqlServer/DeviceRepository.cs | 14 ++++++++++++++ src/Sql/Sql.sqlproj | 1 + .../Device_ClearPushTokenByIdentifier.sql | 13 +++++++++++++ 7 files changed, 40 insertions(+), 28 deletions(-) create mode 100644 src/Sql/dbo/Stored Procedures/Device_ClearPushTokenByIdentifier.sql diff --git a/src/Api/Controllers/DevicesController.cs b/src/Api/Controllers/DevicesController.cs index 6fd0d89dd..c0e2ee30e 100644 --- a/src/Api/Controllers/DevicesController.cs +++ b/src/Api/Controllers/DevicesController.cs @@ -107,22 +107,12 @@ namespace Bit.Api.Controllers return response; } + [AllowAnonymous] [HttpPut("identifier/{identifier}/clear-token")] [HttpPost("identifier/{identifier}/clear-token")] - public async Task PutClearToken(string identifier) + public async Task PutClearToken(string identifier) { - var device = await _deviceRepository.GetByIdentifierAsync(identifier, new Guid(_userManager.GetUserId(User))); - if(device == null) - { - await Task.Delay(2000); - throw new NotFoundException(); - } - - device.PushToken = null; - await _deviceService.SaveAsync(device); - - var response = new DeviceResponseModel(device); - return response; + await _deviceRepository.ClearPushTokenByIdentifierAsync(identifier); } [HttpDelete("{id}")] diff --git a/src/Core/Identity/JwtBearerEventImplementations.cs b/src/Core/Identity/JwtBearerEventImplementations.cs index f57e14c67..4c36af7e6 100644 --- a/src/Core/Identity/JwtBearerEventImplementations.cs +++ b/src/Core/Identity/JwtBearerEventImplementations.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Http.Authentication; using Microsoft.IdentityModel.Tokens; using Microsoft.AspNetCore.Identity; using Bit.Core.Domains; -using System.Linq; namespace Bit.Core.Identity { @@ -38,10 +37,9 @@ namespace Bit.Core.Identity // register the current context user var currentContext = context.HttpContext.RequestServices.GetRequiredService(); currentContext.User = user; - var deviceIdentifierClaim = context.Ticket.Principal.Claims.SingleOrDefault(c => c.Type == "DeviceIdentifier"); - if(deviceIdentifierClaim != null) + if(context.HttpContext.Request.Headers.ContainsKey("Device-Identifier")) { - currentContext.DeviceIdentifier = deviceIdentifierClaim.Value; + currentContext.DeviceIdentifier = context.HttpContext.Request.Headers["Device-Identifier"]; } } diff --git a/src/Core/Identity/JwtBearerSignInManager.cs b/src/Core/Identity/JwtBearerSignInManager.cs index 15490262f..0e86717c4 100644 --- a/src/Core/Identity/JwtBearerSignInManager.cs +++ b/src/Core/Identity/JwtBearerSignInManager.cs @@ -68,7 +68,7 @@ namespace Bit.Core.Identity if(await UserManager.CheckPasswordAsync(user, password)) { - var result = await SignInOrTwoFactorAsync(user, device); + var result = await SignInOrTwoFactorAsync(user); if(result.Succeeded && device != null) { var existingDevice = await _deviceRepository.GetByIdentifierAsync(device.Identifier, user.Id); @@ -105,7 +105,7 @@ namespace Bit.Core.Identity if(await UserManager.VerifyTwoFactorTokenAsync(user, provider, code)) { - var token = await SignInAsync(user, false, device); + var token = await SignInAsync(user, false); var success = JwtBearerSignInResult.Success; success.Token = token; @@ -127,7 +127,7 @@ namespace Bit.Core.Identity return JwtBearerSignInResult.Failed; } - private async Task SignInAsync(User user, bool twoFactor, Device device) + private async Task SignInAsync(User user, bool twoFactor) { var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler(); @@ -150,11 +150,6 @@ namespace Bit.Core.Identity } } - if(device != null && !string.IsNullOrWhiteSpace(device.Identifier)) - { - userPrincipal.Identities.First().AddClaim(new Claim("DeviceIdentifier", device.Identifier)); - } - var descriptor = new SecurityTokenDescriptor { Issuer = JwtIdentityOptions.Issuer, @@ -169,13 +164,13 @@ namespace Bit.Core.Identity return handler.WriteToken(securityToken); } - private async Task SignInOrTwoFactorAsync(User user, Device device) + private async Task SignInOrTwoFactorAsync(User user) { if(UserManager.SupportsUserTwoFactor && await UserManager.GetTwoFactorEnabledAsync(user) && (await UserManager.GetValidTwoFactorProvidersAsync(user)).Count > 0) { - var twoFactorToken = await SignInAsync(user, true, device); + var twoFactorToken = await SignInAsync(user, true); var twoFactorResult = JwtBearerSignInResult.TwoFactorRequired; twoFactorResult.Token = twoFactorToken; @@ -184,7 +179,7 @@ namespace Bit.Core.Identity return twoFactorResult; } - var token = await SignInAsync(user, false, device); + var token = await SignInAsync(user, false); var result = JwtBearerSignInResult.Success; result.Token = token; diff --git a/src/Core/Repositories/IDeviceRepository.cs b/src/Core/Repositories/IDeviceRepository.cs index 0f379be0d..86db7aacf 100644 --- a/src/Core/Repositories/IDeviceRepository.cs +++ b/src/Core/Repositories/IDeviceRepository.cs @@ -10,5 +10,6 @@ namespace Bit.Core.Repositories Task GetByIdAsync(Guid id, Guid userId); Task GetByIdentifierAsync(string identifier, Guid userId); Task> GetManyByUserIdAsync(Guid userId); + Task ClearPushTokenByIdentifierAsync(string identifier); } } diff --git a/src/Core/Repositories/SqlServer/DeviceRepository.cs b/src/Core/Repositories/SqlServer/DeviceRepository.cs index ea3263035..9b7638b03 100644 --- a/src/Core/Repositories/SqlServer/DeviceRepository.cs +++ b/src/Core/Repositories/SqlServer/DeviceRepository.cs @@ -59,5 +59,19 @@ namespace Bit.Core.Repositories.SqlServer return results.ToList(); } } + + public async Task ClearPushTokenByIdentifierAsync(string identifier) + { + using(var connection = new SqlConnection(ConnectionString)) + { + await connection.ExecuteAsync( + $"[{Schema}].[{Table}_ClearPushTokenByIdentifier]", + new + { + Identifier = identifier + }, + commandType: CommandType.StoredProcedure); + } + } } } diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index bfd0b0a53..91ad02949 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -93,5 +93,6 @@ + \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/Device_ClearPushTokenByIdentifier.sql b/src/Sql/dbo/Stored Procedures/Device_ClearPushTokenByIdentifier.sql new file mode 100644 index 000000000..928d30d51 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/Device_ClearPushTokenByIdentifier.sql @@ -0,0 +1,13 @@ +CREATE PROCEDURE [dbo].[Device_ClearPushTokenByIdentifier] + @Identifier NVARCHAR(50) +AS +BEGIN + SET NOCOUNT ON + + UPDATE + [dbo].[Device] + SET + [Identifier] = NULL + WHERE + [Identifier] = @Identifier +END