mirror of
https://github.com/bitwarden/server
synced 2025-12-30 15:14:02 +00:00
initial commit of source
This commit is contained in:
43
src/Core/Identity/AuthenticatorTokenProvider.cs
Normal file
43
src/Core/Identity/AuthenticatorTokenProvider.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Base32;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Bit.Core.Domains;
|
||||
using Bit.Core.Enums;
|
||||
using OtpSharp;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public class AuthenticatorTokenProvider : IUserTokenProvider<User>
|
||||
{
|
||||
public Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
|
||||
{
|
||||
var canGenerate = user.TwoFactorEnabled
|
||||
&& user.TwoFactorProvider.HasValue
|
||||
&& user.TwoFactorProvider.Value == TwoFactorProvider.Authenticator
|
||||
&& !string.IsNullOrWhiteSpace(user.AuthenticatorKey);
|
||||
|
||||
return Task.FromResult(canGenerate);
|
||||
}
|
||||
|
||||
public Task<string> GetUserModifierAsync(string purpose, UserManager<User> manager, User user)
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
public Task<string> GenerateAsync(string purpose, UserManager<User> manager, User user)
|
||||
{
|
||||
return Task.FromResult<string>(null);
|
||||
}
|
||||
|
||||
public Task<bool> ValidateAsync(string purpose, string token, UserManager<User> manager, User user)
|
||||
{
|
||||
var otp = new Totp(Base32Encoder.Decode(user.AuthenticatorKey));
|
||||
|
||||
long timeStepMatched;
|
||||
var valid = otp.VerifyTotp(token, out timeStepMatched, new VerificationWindow(2, 2));
|
||||
|
||||
return Task.FromResult(valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
src/Core/Identity/JwtBearerBuilderExtensions.cs
Normal file
62
src/Core/Identity/JwtBearerBuilderExtensions.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using Bit.Core.Domains;
|
||||
using Microsoft.AspNet.Authentication.JwtBearer;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public static class JwtBearerBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseJwtBearerIdentity(this IApplicationBuilder app)
|
||||
{
|
||||
if(app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
var marker = app.ApplicationServices.GetService<IdentityMarkerService>();
|
||||
if(marker == null)
|
||||
{
|
||||
throw new InvalidOperationException("Must Call AddJwtBearerIdentity");
|
||||
}
|
||||
|
||||
var jwtOptions = app.ApplicationServices.GetRequiredService<IOptions<JwtBearerIdentityOptions>>().Value;
|
||||
var jwtSignInManager = app.ApplicationServices.GetRequiredService<JwtBearerSignInManager>();
|
||||
app.UseJwtBearerAuthentication(options =>
|
||||
{
|
||||
// Basic settings - signing key to validate with, audience and issuer.
|
||||
//options.TokenValidationParameters.IssuerSigningKey = key;
|
||||
options.TokenValidationParameters.ValidAudience = jwtOptions.Audience;
|
||||
options.TokenValidationParameters.ValidIssuer = jwtOptions.Issuer;
|
||||
|
||||
options.TokenValidationParameters.RequireExpirationTime = true;
|
||||
options.TokenValidationParameters.RequireSignedTokens = false;
|
||||
|
||||
// When receiving a token, check that we've signed it.
|
||||
options.TokenValidationParameters.ValidateSignature = false;
|
||||
|
||||
//// When receiving a token, check that it is still valid.
|
||||
options.TokenValidationParameters.ValidateLifetime = true;
|
||||
|
||||
// This defines the maximum allowable clock skew - i.e. provides a tolerance on the token expiry time
|
||||
// when validating the lifetime. As we're creating the tokens locally and validating them on the same
|
||||
// machines which should have synchronised time, this can be set to zero. Where external tokens are
|
||||
// used, some leeway here could be useful.
|
||||
options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(0);
|
||||
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnValidatedToken = JwtBearerEventImplementations.ValidatedTokenAsync,
|
||||
OnAuthenticationFailed = JwtBearerEventImplementations.AuthenticationFailedAsync
|
||||
};
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/Core/Identity/JwtBearerEventImplementations.cs
Normal file
50
src/Core/Identity/JwtBearerEventImplementations.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Authentication.JwtBearer;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.IdentityModel.Tokens;
|
||||
using Bit.Core.Repositories;
|
||||
using Microsoft.AspNet.Authentication;
|
||||
using Microsoft.AspNet.Http.Authentication;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public static class JwtBearerEventImplementations
|
||||
{
|
||||
public async static Task ValidatedTokenAsync(ValidatedTokenContext context)
|
||||
{
|
||||
if(context.HttpContext.RequestServices == null)
|
||||
{
|
||||
throw new InvalidOperationException("RequestServices is null");
|
||||
}
|
||||
|
||||
var userRepository = context.HttpContext.RequestServices.GetRequiredService<IUserRepository>();
|
||||
var manager = context.HttpContext.RequestServices.GetRequiredService<JwtBearerSignInManager>();
|
||||
|
||||
var userId = context.AuthenticationTicket.Principal.GetUserId();
|
||||
var user = await userRepository.GetByIdAsync(userId);
|
||||
|
||||
// validate security token
|
||||
if(!await manager.ValidateSecurityStampAsync(user, context.AuthenticationTicket.Principal))
|
||||
{
|
||||
throw new SecurityTokenValidationException("Bad security stamp.");
|
||||
}
|
||||
|
||||
// register the current context user
|
||||
var currentContext = context.HttpContext.RequestServices.GetRequiredService<CurrentContext>();
|
||||
currentContext.User = user;
|
||||
}
|
||||
|
||||
public static Task AuthenticationFailedAsync(AuthenticationFailedContext context)
|
||||
{
|
||||
if(!context.HttpContext.User.Identity.IsAuthenticated)
|
||||
{
|
||||
context.State = EventResultState.HandledResponse;
|
||||
context.AuthenticationTicket = new AuthenticationTicket(context.HttpContext.User, new AuthenticationProperties(), context.Options.AuthenticationScheme);
|
||||
}
|
||||
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Core/Identity/JwtBearerIdentityOptions.cs
Normal file
16
src/Core/Identity/JwtBearerIdentityOptions.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.IdentityModel.Tokens;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public class JwtBearerIdentityOptions
|
||||
{
|
||||
public string Audience { get; set; }
|
||||
public string Issuer { get; set; }
|
||||
public SigningCredentials SigningCredentials { get; set; }
|
||||
public TimeSpan? TokenLifetime { get; set; }
|
||||
public TimeSpan? TwoFactorTokenLifetime { get; set; }
|
||||
public string AuthenticationMethod { get; set; } = "Application";
|
||||
public string TwoFactorAuthenticationMethod { get; set; } = "TwoFactor";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Bit.Core.Domains;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public static class JwtBearerIdentityServiceCollectionExtensions
|
||||
{
|
||||
public static IdentityBuilder AddJwtBearerIdentit(
|
||||
this IServiceCollection services)
|
||||
{
|
||||
return services.AddJwtBearerIdentity(setupAction: null, jwtBearerSetupAction: null);
|
||||
}
|
||||
|
||||
public static IdentityBuilder AddJwtBearerIdentity(
|
||||
this IServiceCollection services,
|
||||
Action<IdentityOptions> setupAction,
|
||||
Action<JwtBearerIdentityOptions> jwtBearerSetupAction)
|
||||
{
|
||||
// Services used by identity
|
||||
services.AddOptions();
|
||||
services.AddAuthentication();
|
||||
|
||||
// Identity services
|
||||
services.TryAddSingleton<IdentityMarkerService>();
|
||||
services.TryAddScoped<IUserValidator<User>, UserValidator<User>>();
|
||||
services.TryAddScoped<IPasswordValidator<User>, PasswordValidator<User>>();
|
||||
services.TryAddScoped<IPasswordHasher<User>, PasswordHasher<User>>();
|
||||
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
|
||||
services.TryAddScoped<IRoleValidator<Role>, RoleValidator<Role>>();
|
||||
// No interface for the error describer so we can add errors without rev'ing the interface
|
||||
services.TryAddScoped<IdentityErrorDescriber>();
|
||||
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<User>>();
|
||||
services.TryAddScoped<IUserClaimsPrincipalFactory<User>, UserClaimsPrincipalFactory<User, Role>>();
|
||||
services.TryAddScoped<UserManager<User>, UserManager<User>>();
|
||||
services.TryAddScoped<JwtBearerSignInManager, JwtBearerSignInManager>();
|
||||
services.TryAddScoped<RoleManager<Role>, RoleManager<Role>>();
|
||||
|
||||
if(setupAction != null)
|
||||
{
|
||||
services.Configure(setupAction);
|
||||
}
|
||||
|
||||
if(jwtBearerSetupAction != null)
|
||||
{
|
||||
services.Configure(jwtBearerSetupAction);
|
||||
}
|
||||
|
||||
return new IdentityBuilder(typeof(User), typeof(Role), services);
|
||||
}
|
||||
}
|
||||
}
|
||||
160
src/Core/Identity/JwtBearerSignInManager.cs
Normal file
160
src/Core/Identity/JwtBearerSignInManager.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Authentication.JwtBearer;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.OptionsModel;
|
||||
using Bit.Core.Domains;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public class JwtBearerSignInManager
|
||||
{
|
||||
public JwtBearerSignInManager(
|
||||
UserManager<User> userManager,
|
||||
IHttpContextAccessor contextAccessor,
|
||||
IUserClaimsPrincipalFactory<User> claimsFactory,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
IOptions<JwtBearerIdentityOptions> jwtIdentityOptionsAccessor,
|
||||
IOptions<JwtBearerOptions> jwtOptionsAccessor,
|
||||
ILogger<JwtBearerSignInManager> logger)
|
||||
{
|
||||
UserManager = userManager;
|
||||
Context = contextAccessor.HttpContext;
|
||||
ClaimsFactory = claimsFactory;
|
||||
IdentityOptions = optionsAccessor?.Value ?? new IdentityOptions();
|
||||
JwtIdentityOptions = jwtIdentityOptionsAccessor?.Value ?? new JwtBearerIdentityOptions();
|
||||
JwtBearerOptions = jwtOptionsAccessor?.Value ?? new JwtBearerOptions();
|
||||
}
|
||||
|
||||
internal UserManager<User> UserManager { get; set; }
|
||||
internal HttpContext Context { get; set; }
|
||||
internal IUserClaimsPrincipalFactory<User> ClaimsFactory { get; set; }
|
||||
internal IdentityOptions IdentityOptions { get; set; }
|
||||
internal JwtBearerIdentityOptions JwtIdentityOptions { get; set; }
|
||||
internal JwtBearerOptions JwtBearerOptions { get; set; }
|
||||
|
||||
public async Task<ClaimsPrincipal> CreateUserPrincipalAsync(User user) => await ClaimsFactory.CreateAsync(user);
|
||||
|
||||
public Task<bool> ValidateSecurityStampAsync(User user, ClaimsPrincipal principal)
|
||||
{
|
||||
if(user != null && UserManager.SupportsUserSecurityStamp)
|
||||
{
|
||||
var securityStamp = principal.FindFirstValue(IdentityOptions.ClaimsIdentity.SecurityStampClaimType);
|
||||
if(securityStamp == user.SecurityStamp)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
public async Task<JwtBearerSignInResult> PasswordSignInAsync(User user, string password)
|
||||
{
|
||||
if(user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
if(await UserManager.CheckPasswordAsync(user, password))
|
||||
{
|
||||
return await SignInOrTwoFactorAsync(user);
|
||||
}
|
||||
|
||||
return JwtBearerSignInResult.Failed;
|
||||
}
|
||||
|
||||
public async Task<JwtBearerSignInResult> PasswordSignInAsync(string userName, string password)
|
||||
{
|
||||
var user = await UserManager.FindByNameAsync(userName);
|
||||
if(user == null)
|
||||
{
|
||||
return JwtBearerSignInResult.Failed;
|
||||
}
|
||||
|
||||
return await PasswordSignInAsync(user, password);
|
||||
}
|
||||
|
||||
public async Task<JwtBearerSignInResult> TwoFactorSignInAsync(User user, string provider, string code)
|
||||
{
|
||||
if(user == null)
|
||||
{
|
||||
return JwtBearerSignInResult.Failed;
|
||||
}
|
||||
|
||||
if(await UserManager.VerifyTwoFactorTokenAsync(user, provider, code))
|
||||
{
|
||||
var token = await SignInAsync(user, false);
|
||||
|
||||
var success = JwtBearerSignInResult.Success;
|
||||
success.Token = token;
|
||||
success.User = user;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
return JwtBearerSignInResult.Failed;
|
||||
}
|
||||
|
||||
private async Task<string> SignInAsync(User user, bool twoFactor)
|
||||
{
|
||||
var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
|
||||
|
||||
DateTime? tokenExpiration = null;
|
||||
var userPrincipal = await CreateUserPrincipalAsync(user);
|
||||
if(twoFactor)
|
||||
{
|
||||
userPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.AuthenticationMethod, JwtIdentityOptions.TwoFactorAuthenticationMethod));
|
||||
if(JwtIdentityOptions.TwoFactorTokenLifetime.HasValue)
|
||||
{
|
||||
tokenExpiration = DateTime.UtcNow.Add(JwtIdentityOptions.TwoFactorTokenLifetime.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
userPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.AuthenticationMethod, JwtIdentityOptions.AuthenticationMethod));
|
||||
if(JwtIdentityOptions.TokenLifetime.HasValue)
|
||||
{
|
||||
tokenExpiration = DateTime.UtcNow.Add(JwtIdentityOptions.TokenLifetime.Value);
|
||||
}
|
||||
}
|
||||
|
||||
var securityToken = handler.CreateToken(
|
||||
issuer: JwtIdentityOptions.Issuer,
|
||||
audience: JwtIdentityOptions.Audience,
|
||||
signingCredentials: JwtIdentityOptions.SigningCredentials,
|
||||
subject: userPrincipal.Identities.First(),
|
||||
expires: tokenExpiration);
|
||||
|
||||
return handler.WriteToken(securityToken);
|
||||
}
|
||||
|
||||
private async Task<JwtBearerSignInResult> SignInOrTwoFactorAsync(User user)
|
||||
{
|
||||
if(UserManager.SupportsUserTwoFactor &&
|
||||
await UserManager.GetTwoFactorEnabledAsync(user) &&
|
||||
(await UserManager.GetValidTwoFactorProvidersAsync(user)).Count > 0)
|
||||
{
|
||||
var twoFactorToken = await SignInAsync(user, true);
|
||||
|
||||
var twoFactorResult = JwtBearerSignInResult.TwoFactorRequired;
|
||||
twoFactorResult.Token = twoFactorToken;
|
||||
twoFactorResult.User = user;
|
||||
|
||||
return twoFactorResult;
|
||||
}
|
||||
|
||||
var token = await SignInAsync(user, false);
|
||||
|
||||
var result = JwtBearerSignInResult.Success;
|
||||
result.Token = token;
|
||||
result.User = user;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/Core/Identity/JwtBearerSignInResult.cs
Normal file
34
src/Core/Identity/JwtBearerSignInResult.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Bit.Core.Domains;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public class JwtBearerSignInResult
|
||||
{
|
||||
private static readonly JwtBearerSignInResult _success = new JwtBearerSignInResult { Succeeded = true };
|
||||
private static readonly JwtBearerSignInResult _failed = new JwtBearerSignInResult();
|
||||
private static readonly JwtBearerSignInResult _lockedOut = new JwtBearerSignInResult { IsLockedOut = true };
|
||||
private static readonly JwtBearerSignInResult _notAllowed = new JwtBearerSignInResult { IsNotAllowed = true };
|
||||
private static readonly JwtBearerSignInResult _twoFactorRequired = new JwtBearerSignInResult { RequiresTwoFactor = true };
|
||||
|
||||
public bool Succeeded { get; protected set; }
|
||||
public bool IsLockedOut { get; protected set; }
|
||||
public bool IsNotAllowed { get; protected set; }
|
||||
public bool RequiresTwoFactor { get; protected set; }
|
||||
public string Token { get; set; }
|
||||
public User User { get; set; }
|
||||
|
||||
public static JwtBearerSignInResult Success => _success;
|
||||
public static JwtBearerSignInResult Failed => _failed;
|
||||
public static JwtBearerSignInResult LockedOut => _lockedOut;
|
||||
public static JwtBearerSignInResult NotAllowed => _notAllowed;
|
||||
public static JwtBearerSignInResult TwoFactorRequired => _twoFactorRequired;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return IsLockedOut ? "Lockedout" :
|
||||
IsNotAllowed ? "NotAllowed" :
|
||||
RequiresTwoFactor ? "RequiresTwoFactor" :
|
||||
Succeeded ? "Succeeded" : "Failed";
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/Core/Identity/LowerInvariantLookupNormalizer.cs
Normal file
12
src/Core/Identity/LowerInvariantLookupNormalizer.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNet.Identity;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public class LowerInvariantLookupNormalizer : ILookupNormalizer
|
||||
{
|
||||
public string Normalize(string key)
|
||||
{
|
||||
return key?.Normalize().ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/Core/Identity/RoleStore.cs
Normal file
64
src/Core/Identity/RoleStore.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Bit.Core.Domains;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public class RoleStore : IRoleStore<Role>
|
||||
{
|
||||
public void Dispose() { }
|
||||
|
||||
public Task<IdentityResult> CreateAsync(Role role, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<IdentityResult> DeleteAsync(Role role, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Role> FindByIdAsync(string roleId, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<Role> FindByNameAsync(string normalizedRoleName, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetNormalizedRoleNameAsync(Role role, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(role.Name);
|
||||
}
|
||||
|
||||
public Task<string> GetRoleIdAsync(Role role, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task<string> GetRoleNameAsync(Role role, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(role.Name);
|
||||
}
|
||||
|
||||
public Task SetNormalizedRoleNameAsync(Role role, string normalizedName, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task SetRoleNameAsync(Role role, string roleName, CancellationToken cancellationToken)
|
||||
{
|
||||
role.Name = roleName;
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task<IdentityResult> UpdateAsync(Role role, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
160
src/Core/Identity/UserStore.cs
Normal file
160
src/Core/Identity/UserStore.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Bit.Core.Domains;
|
||||
using Bit.Core.Repositories;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public class UserStore :
|
||||
IUserStore<User>,
|
||||
IUserPasswordStore<User>,
|
||||
IUserEmailStore<User>,
|
||||
IUserTwoFactorStore<User>,
|
||||
IUserSecurityStampStore<User>
|
||||
{
|
||||
private readonly IUserRepository _userRepository;
|
||||
|
||||
public UserStore(IUserRepository userRepository)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public async Task<IdentityResult> CreateAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
await _userRepository.CreateAsync(user);
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
public async Task<IdentityResult> DeleteAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
await _userRepository.DeleteAsync(user);
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
public async Task<User> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return await _userRepository.GetByEmailAsync(normalizedEmail);
|
||||
}
|
||||
|
||||
public async Task<User> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return await _userRepository.GetByIdAsync(userId);
|
||||
}
|
||||
|
||||
public async Task<User> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return await _userRepository.GetByEmailAsync(normalizedUserName);
|
||||
}
|
||||
|
||||
public Task<string> GetEmailAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(user.Email);
|
||||
}
|
||||
|
||||
public Task<bool> GetEmailConfirmedAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(true); // all emails are confirmed
|
||||
}
|
||||
|
||||
public Task<string> GetNormalizedEmailAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(user.Email);
|
||||
}
|
||||
|
||||
public Task<string> GetNormalizedUserNameAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(user.Email);
|
||||
}
|
||||
|
||||
public Task<string> GetPasswordHashAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(user.MasterPassword);
|
||||
}
|
||||
|
||||
public Task<string> GetUserIdAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(user.Id);
|
||||
}
|
||||
|
||||
public Task<string> GetUserNameAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(user.Email);
|
||||
}
|
||||
|
||||
public Task<bool> HasPasswordAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
return Task.FromResult(!string.IsNullOrWhiteSpace(user.MasterPassword));
|
||||
}
|
||||
|
||||
public Task SetEmailAsync(User user, string email, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
user.Email = email;
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task SetEmailConfirmedAsync(User user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// do nothing
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task SetNormalizedEmailAsync(User user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
user.Email = normalizedEmail;
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task SetNormalizedUserNameAsync(User user, string normalizedName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
user.Email = normalizedName;
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task SetPasswordHashAsync(User user, string passwordHash, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
user.MasterPassword = passwordHash;
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task SetUserNameAsync(User user, string userName, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
user.Email = userName;
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public async Task<IdentityResult> UpdateAsync(User user, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
await _userRepository.ReplaceAsync(user);
|
||||
return IdentityResult.Success;
|
||||
}
|
||||
|
||||
public Task SetTwoFactorEnabledAsync(User user, bool enabled, CancellationToken cancellationToken)
|
||||
{
|
||||
user.TwoFactorEnabled = enabled;
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task<bool> GetTwoFactorEnabledAsync(User user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.TwoFactorEnabled && user.TwoFactorProvider.HasValue);
|
||||
}
|
||||
|
||||
public Task SetSecurityStampAsync(User user, string stamp, CancellationToken cancellationToken)
|
||||
{
|
||||
user.SecurityStamp = stamp;
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
public Task<string> GetSecurityStampAsync(User user, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(user.SecurityStamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user