-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathCreateUserUseCase.cs
More file actions
75 lines (67 loc) · 2.85 KB
/
Copy pathCreateUserUseCase.cs
File metadata and controls
75 lines (67 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Search;
using Dfe.SignIn.Core.Contracts.Users;
using Dfe.SignIn.Core.Entities.Directories;
using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
/// <summary>
/// An interactor for creating a new user account.
/// </summary>
/// <remarks>
/// <para>Only to be used after an account has been created in Entra.
/// For "classic" account creation a different use-case should be created,
/// as this will require creating a user password policy, determining
/// which policy is currently configured, and implementing that, along
/// with a supporting salt etc. Likely to require configuration access
/// for activePasswordPolicyCode, passwordHistoryLimit.
/// Review login.dfe.directories for implementation details.</para>
/// </remarks>
public sealed class CreateUserUseCase(
DbDirectoriesContext unitOfWork,
IInteractionDispatcher interaction,
TimeProvider timeProvider
) : Interactor<CreateUserRequest, CreateUserResponse>
{
/// <inheritdoc/>
public override async Task<CreateUserResponse> InvokeAsync(
InteractionContext<CreateUserRequest> context,
CancellationToken cancellationToken = default)
{
context.ThrowIfHasValidationErrors();
var user = await unitOfWork.Users
.Where(x =>
x.Email == context.Request.EmailAddress ||
x.EntraOid == context.Request.EntraUserId)
.Select(x => new { x.Email })
.SingleOrDefaultAsync(cancellationToken);
if (user is not null) {
throw user.Email.Equals(context.Request.EmailAddress, StringComparison.OrdinalIgnoreCase)
? CannotCreateNewUserException.FromEmailAddress(context.Request.EmailAddress)
: throw CannotCreateNewUserException.FromEntraUserId(context.Request.EntraUserId);
}
// Creates a new user only compatible with Entra i.e. no password, salt etc.
var newUser = new UserEntity {
Email = context.Request.EmailAddress,
EntraLinked = timeProvider.GetUtcNow().DateTime,
EntraOid = context.Request.EntraUserId,
FirstName = context.Request.FirstName,
IsEntra = true,
LastName = context.Request.LastName,
Password = "none",
Salt = string.Empty,
Status = (int)AccountStatus.Active,
Sub = Guid.NewGuid(),
};
await unitOfWork.AddAsync(newUser, cancellationToken);
await unitOfWork.SaveChangesAsync(cancellationToken);
await interaction.DispatchAsync(
new UpdateUserInSearchIndexRequest {
UserId = newUser.Sub
}
);
return new CreateUserResponse {
UserId = newUser.Sub
};
}
}