The POST /identity/users response serialized the plain-text password (including one the caller supplied), the password hash, and the salt. The response now carries only id, name, roles, tenantId and a nullable generatedPassword that is populated once, and only when Core generated the password because none was supplied. - CreateUserResult gains IsPasswordGenerated so the endpoint can tell a generated password from a supplied one without re-deriving it. - Response.FromResult centralises the mapping and omits credential material. - Expose Elsa.Identity internals to Elsa.Identity.UnitTests and add contract tests covering the response shape, the no-echo rule, the serialized JSON, and UserManager's generated-password flag. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
56 lines
1.9 KiB
C#
56 lines
1.9 KiB
C#
using Elsa.Identity.Contracts;
|
|
using Elsa.Identity.Entities;
|
|
using Elsa.Identity.Services;
|
|
using Elsa.Testing.Shared.Multitenancy;
|
|
using Elsa.Workflows;
|
|
using NSubstitute;
|
|
|
|
namespace Elsa.Identity.UnitTests.Services;
|
|
|
|
public class UserManagerTests
|
|
{
|
|
private readonly ISecretGenerator _secretGenerator = Substitute.For<ISecretGenerator>();
|
|
private readonly IUserStore _userStore = Substitute.For<IUserStore>();
|
|
private readonly UserManager _manager;
|
|
|
|
public UserManagerTests()
|
|
{
|
|
var identityGenerator = Substitute.For<IIdentityGenerator>();
|
|
identityGenerator.GenerateId().Returns("user-1");
|
|
_secretGenerator.Generate(Arg.Any<int>()).Returns("generated-secret");
|
|
_manager = new(identityGenerator, _secretGenerator, new DefaultSecretHasher(), _userStore, new TestTenantAccessor("tenant-a"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task CreateUserAsyncWithSuppliedPasswordMarksItAsNotGenerated()
|
|
{
|
|
var result = await _manager.CreateUserAsync("alice", " supplied-secret ", ["admin"]);
|
|
|
|
Assert.False(result.IsPasswordGenerated);
|
|
Assert.Equal("supplied-secret", result.Password);
|
|
_secretGenerator.DidNotReceive().Generate(Arg.Any<int>());
|
|
AssertStoredCredentials(result.User);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public async Task CreateUserAsyncWithoutPasswordGeneratesOneAndMarksIt(string? password)
|
|
{
|
|
var result = await _manager.CreateUserAsync("alice", password);
|
|
|
|
Assert.True(result.IsPasswordGenerated);
|
|
Assert.Equal("generated-secret", result.Password);
|
|
AssertStoredCredentials(result.User);
|
|
}
|
|
|
|
private static void AssertStoredCredentials(User user)
|
|
{
|
|
Assert.Equal("user-1", user.Id);
|
|
Assert.Equal("tenant-a", user.TenantId);
|
|
Assert.False(string.IsNullOrEmpty(user.HashedPassword));
|
|
Assert.False(string.IsNullOrEmpty(user.HashedPasswordSalt));
|
|
}
|
|
}
|