Now implementing IUserAuthenticationTokenStore to work with TFA.
This commit is contained in:
@@ -0,0 +1,73 @@
|
|||||||
|
using Raven.Client.Documents;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Raven.Identity
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A two-factor authentication authorization token.
|
||||||
|
/// </summary>
|
||||||
|
public class IdentityUserAuthToken
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the auth token.
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the <see cref="IdentityUser"/> this auth token is for.
|
||||||
|
/// </summary>
|
||||||
|
public string UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The login provider.
|
||||||
|
/// </summary>
|
||||||
|
public string LoginProvider { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the token.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The value of the token.
|
||||||
|
/// </summary>
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the well-known ID for a IdentityuserAuthToken.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="db"></param>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="loginProvider"></param>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetWellKnownId(IDocumentStore db, string userId, string loginProvider, string name)
|
||||||
|
{
|
||||||
|
var vals = new[] { userId, loginProvider, name }
|
||||||
|
.Select(v => v ?? "[null]");
|
||||||
|
var collection = db.Conventions.GetCollectionName(typeof(IdentityUserAuthToken));
|
||||||
|
var separator = db.Conventions.IdentityPartsSeparator;
|
||||||
|
var valsHash = CalculateHash(string.Join("-", vals));
|
||||||
|
return collection + separator + valsHash.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int CalculateHash(string input)
|
||||||
|
{
|
||||||
|
// We can't use input.GetHashCode in .NET Core, as it can (and does!) return different values each time the app is run.
|
||||||
|
// See https://github.com/dotnet/corefx/issues/19703
|
||||||
|
// Instead, we've implemented the following deterministic string hash algorithm: https://stackoverflow.com/a/5155015/536
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
int hash = 23;
|
||||||
|
foreach (char c in input)
|
||||||
|
{
|
||||||
|
hash = hash * 31 + c;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,14 +12,16 @@
|
|||||||
<PackageProjectUrl>https://github.com/JudahGabriel/RavenDB.Identity</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/JudahGabriel/RavenDB.Identity</PackageProjectUrl>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<RepositoryUrl>https://github.com/JudahGabriel/RavenDB.Identity</RepositoryUrl>
|
<RepositoryUrl>https://github.com/JudahGabriel/RavenDB.Identity</RepositoryUrl>
|
||||||
|
<ReleaseNotes>Added support for Two Factor auth.</ReleaseNotes>
|
||||||
<PackageLicenseUrl>https://github.com/JudahGabriel/RavenDB.Identity/blob/master/LICENSE.md</PackageLicenseUrl>
|
<PackageLicenseUrl>https://github.com/JudahGabriel/RavenDB.Identity/blob/master/LICENSE.md</PackageLicenseUrl>
|
||||||
<PackageIconUrl>https://github.com/JudahGabriel/RavenDB.Identity/blob/master/RavenDB.Identity/nuget-icon.png?raw=true</PackageIconUrl>
|
<PackageIconUrl>https://github.com/JudahGabriel/RavenDB.Identity/blob/master/RavenDB.Identity/nuget-icon.png?raw=true</PackageIconUrl>
|
||||||
<copyright>Copyright 2018 BitShuva</copyright>
|
<copyright>Copyright 2018 BitShuva</copyright>
|
||||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
||||||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
|
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
|
||||||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
|
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
|
||||||
<Version>4.1.1</Version>
|
<Version>4.2.0</Version>
|
||||||
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
|
||||||
|
<RootNamespace>Raven.Identity</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ namespace Raven.Identity
|
|||||||
IUserLockoutStore<TUser>,
|
IUserLockoutStore<TUser>,
|
||||||
IUserTwoFactorStore<TUser>,
|
IUserTwoFactorStore<TUser>,
|
||||||
IUserPhoneNumberStore<TUser>,
|
IUserPhoneNumberStore<TUser>,
|
||||||
IUserAuthenticatorKeyStore<TUser>
|
IUserAuthenticatorKeyStore<TUser>,
|
||||||
|
IUserAuthenticationTokenStore<TUser>
|
||||||
where TUser : IdentityUser
|
where TUser : IdentityUser
|
||||||
{
|
{
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
@@ -652,6 +653,55 @@ namespace Raven.Identity
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region IUserAuthenticationTokenStore
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task SetTokenAsync(TUser user, string loginProvider, string name, string value, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var id = IdentityUserAuthToken.GetWellKnownId(DbSession.Advanced.DocumentStore, user.Id, loginProvider, name);
|
||||||
|
ThrowIfDisposedOrCancelled(cancellationToken);
|
||||||
|
|
||||||
|
var existingOrNull = await DbSession.LoadAsync<IdentityUserAuthToken>(id);
|
||||||
|
if (existingOrNull == null)
|
||||||
|
{
|
||||||
|
existingOrNull = new IdentityUserAuthToken
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
LoginProvider = loginProvider,
|
||||||
|
Name = name,
|
||||||
|
UserId = user.Id,
|
||||||
|
Value = value
|
||||||
|
};
|
||||||
|
await DbSession.StoreAsync(existingOrNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
existingOrNull.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Task RemoveTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var id = IdentityUserAuthToken.GetWellKnownId(DbSession.Advanced.DocumentStore, user.Id, loginProvider, name);
|
||||||
|
DbSession.Delete(id);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<string> GetTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var id = IdentityUserAuthToken.GetWellKnownId(DbSession.Advanced.DocumentStore, user.Id, loginProvider, name);
|
||||||
|
var tokenOrNull = await DbSession.LoadAsync<IdentityUserAuthToken>(id);
|
||||||
|
if (tokenOrNull == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenOrNull.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private IAsyncDocumentSession DbSession
|
private IAsyncDocumentSession DbSession
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|||||||
Reference in New Issue
Block a user