Add endpoint to create users
This commit is contained in:
parent
63c104d428
commit
bf810e7d7a
|
|
@ -27,7 +27,7 @@
|
|||
"Id": "a2323f46-42db-4e15-af8b-94238717d817",
|
||||
"Name": "admin",
|
||||
"HashedPassword": "TfKzh9RLix6FPcCNeHLkGrysFu3bYxqzGqduNdi8v1U=",
|
||||
"HashedSalt": "JEy9kBlhHCNsencitRHlGxmErmSgY+FVyMJulCH27Ds=",
|
||||
"HashedPasswordSalt": "JEy9kBlhHCNsencitRHlGxmErmSgY+FVyMJulCH27Ds=",
|
||||
"Roles": ["admin"]
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Elsa.Identity.Contracts;
|
||||
using Elsa.Identity.Entities;
|
||||
using Elsa.Identity.Models;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using FastEndpoints;
|
||||
using JetBrains.Annotations;
|
||||
|
|
@ -70,7 +69,16 @@ internal class Create : Endpoint<Request, Response>
|
|||
|
||||
await _applicationStore.SaveAsync(application, cancellationToken);
|
||||
|
||||
var response = new Response(apiKey);
|
||||
var response = new Response(
|
||||
id,
|
||||
application.Name,
|
||||
application.Roles,
|
||||
clientId,
|
||||
clientSecret,
|
||||
apiKey,
|
||||
hashedApiKey,
|
||||
hashedClientSecret);
|
||||
|
||||
await SendOkAsync(response, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
using Elsa.Identity.Models;
|
||||
|
||||
namespace Elsa.Identity.Endpoints.Applications.Create;
|
||||
|
||||
internal class Request
|
||||
|
|
@ -6,4 +8,13 @@ internal class Request
|
|||
public ICollection<string>? Roles { get; set; }
|
||||
}
|
||||
|
||||
internal record Response(string ApiKey);
|
||||
internal record Response(
|
||||
string Id,
|
||||
string Name,
|
||||
ICollection<string> Roles,
|
||||
string ClientId,
|
||||
string ClientSecret,
|
||||
string ApiKey,
|
||||
HashedSecret HashedApiKey,
|
||||
HashedSecret HashedClientSecret
|
||||
);
|
||||
69
src/modules/Elsa.Identity/Endpoints/Users/Create/Endpoint.cs
Normal file
69
src/modules/Elsa.Identity/Endpoints/Users/Create/Endpoint.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
using Elsa.Abstractions;
|
||||
using Elsa.Identity.Contracts;
|
||||
using Elsa.Identity.Entities;
|
||||
using Elsa.Workflows.Core.Contracts;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Elsa.Identity.Endpoints.Users.Create;
|
||||
|
||||
/// <summary>
|
||||
/// An endpoint that creates a new user. Requires the <code>SecurityRoot</code> policy.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
internal class Create : ElsaEndpoint<Request, Response>
|
||||
{
|
||||
private readonly IIdentityGenerator _identityGenerator;
|
||||
private readonly ISecretGenerator _secretGenerator;
|
||||
private readonly ISecretHasher _secretHasher;
|
||||
private readonly IUserStore _userStore;
|
||||
private readonly IRoleStore _roleStore;
|
||||
|
||||
public Create(
|
||||
IIdentityGenerator identityGenerator,
|
||||
ISecretGenerator secretGenerator,
|
||||
ISecretHasher secretHasher,
|
||||
IUserStore userStore,
|
||||
IRoleStore roleStore)
|
||||
{
|
||||
_identityGenerator = identityGenerator;
|
||||
_secretGenerator = secretGenerator;
|
||||
_secretHasher = secretHasher;
|
||||
_userStore = userStore;
|
||||
_roleStore = roleStore;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/identity/users");
|
||||
ConfigurePermissions("create:user");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var id = _identityGenerator.GenerateId();
|
||||
var password = string.IsNullOrWhiteSpace(request.Password) ? _secretGenerator.Generate() : request.Password.Trim();
|
||||
var hashedPassword = _secretHasher.HashSecret(password);
|
||||
|
||||
var user = new User
|
||||
{
|
||||
Id = id,
|
||||
Name = request.Name,
|
||||
Roles = request.Roles ?? new List<string>(),
|
||||
HashedPassword = hashedPassword.EncodeSecret(),
|
||||
HashedPasswordSalt = hashedPassword.EncodeSalt()
|
||||
};
|
||||
|
||||
await _userStore.SaveAsync(user, cancellationToken);
|
||||
|
||||
var response = new Response(
|
||||
id,
|
||||
user.Name,
|
||||
password,
|
||||
user.Roles,
|
||||
hashedPassword);
|
||||
|
||||
await SendOkAsync(response, cancellationToken);
|
||||
}
|
||||
}
|
||||
18
src/modules/Elsa.Identity/Endpoints/Users/Create/Models.cs
Normal file
18
src/modules/Elsa.Identity/Endpoints/Users/Create/Models.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using Elsa.Identity.Models;
|
||||
|
||||
namespace Elsa.Identity.Endpoints.Users.Create;
|
||||
|
||||
internal class Request
|
||||
{
|
||||
public string Name { get; set; } = default!;
|
||||
public string? Password { get; set; }
|
||||
public ICollection<string>? Roles { get; set; }
|
||||
}
|
||||
|
||||
internal record Response(
|
||||
string Id,
|
||||
string Name,
|
||||
string Password,
|
||||
ICollection<string> Roles,
|
||||
HashedSecret HashedPassword
|
||||
);
|
||||
|
|
@ -3,9 +3,9 @@ namespace Elsa.Identity.Models;
|
|||
/// <summary>
|
||||
/// Represents a hashed secret.
|
||||
/// </summary>
|
||||
/// <param name="Password">A base64 encoded string representing the hashed secret.</param>
|
||||
/// <param name="Secret">A base64 encoded string representing the hashed secret.</param>
|
||||
/// <param name="Salt">A base64 encoded string representing the salt.</param>
|
||||
public record HashedSecret(byte[] Password, byte[] Salt)
|
||||
public record HashedSecret(byte[] Secret, byte[] Salt)
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="HashedSecret"/> from a byte array representing the hashed secret and the salt.
|
||||
|
|
@ -27,7 +27,7 @@ public record HashedSecret(byte[] Password, byte[] Salt)
|
|||
/// Encodes the secret using base64.
|
||||
/// </summary>
|
||||
/// <returns>The base64-encoded secret.</returns>
|
||||
public string EncodeSecret() => Encode(Password);
|
||||
public string EncodeSecret() => Encode(Secret);
|
||||
|
||||
/// <summary>
|
||||
/// Encodes the salt using base64.
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ public class DefaultSecretHasher : ISecretHasher
|
|||
/// <inheritdoc />
|
||||
public bool VerifySecret(string clearTextSecret, HashedSecret hashedSecret)
|
||||
{
|
||||
var password = hashedSecret.Password;
|
||||
var password = hashedSecret.Secret;
|
||||
var salt = hashedSecret.Salt;
|
||||
var providedHashedPassword = HashSecret(clearTextSecret, salt);
|
||||
return providedHashedPassword.Password.SequenceEqual(password);
|
||||
return providedHashedPassword.Secret.SequenceEqual(password);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
Loading…
Reference in a new issue