-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented One-Time Passwords. (#40)
* Implementing One-Time Passwords. * Created a repository interface and added the TenantId property. * Implemented OTP persistence and unit tests. * Fixed typos. * Implemented unit tests. * Implemented unit tests. * Refactored demo project. * Refactored password management. * NuGet Upgrade. * Completed password management. * Fixed namespaces. * Removed the PasswordMock.
- Loading branch information
Showing
64 changed files
with
3,242 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Logitar.Identity.Demo.Constants; | ||
|
||
internal static class Api | ||
{ | ||
public const string Title = "Identity API"; | ||
public static readonly Version Version = new(1, 0, 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using Logitar.Identity.Demo.Models.Index; | ||
using Microsoft.AspNetCore.Mvc; | ||
|
||
namespace Logitar.Identity.Demo.Controllers; | ||
|
||
[ApiController] | ||
[ApiExplorerSettings(IgnoreApi = true)] | ||
[Route("")] | ||
public class IndexController : ControllerBase | ||
{ | ||
[HttpGet] | ||
public ActionResult<ApiVersion> Get() => Ok(new ApiVersion()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using Logitar.Identity.Demo.Constants; | ||
|
||
namespace Logitar.Identity.Demo.Models.Index; | ||
|
||
public record ApiVersion | ||
{ | ||
public string Title { get; set; } | ||
public string Version { get; set; } | ||
|
||
public ApiVersion() : this(Api.Title, Api.Version) | ||
{ | ||
} | ||
|
||
public ApiVersion(string title, Version version) : this(title, version.ToString()) | ||
{ | ||
} | ||
|
||
public ApiVersion(string title, string version) | ||
{ | ||
Title = title; | ||
Version = version; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
{ | ||
"EnableMigrations": true, | ||
"EnableOpenApi": true, | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
47 changes: 47 additions & 0 deletions
47
src/Logitar.Identity.Domain/Passwords/Events/OneTimePasswordCreatedEvent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using Logitar.EventSourcing; | ||
using Logitar.Identity.Domain.Shared; | ||
using MediatR; | ||
|
||
namespace Logitar.Identity.Domain.Passwords.Events; | ||
|
||
/// <summary> | ||
/// The event raised when a new One-Time Password (OTP) is created. | ||
/// </summary> | ||
public record OneTimePasswordCreatedEvent : DomainEvent, INotification | ||
{ | ||
/// <summary> | ||
/// Gets the tenant identifier of the One-Time Password (OTP). | ||
/// </summary> | ||
public TenantId? TenantId { get; } | ||
|
||
/// <summary> | ||
/// Gets the encoded value of the One-Time Password (OTP). | ||
/// </summary> | ||
public Password Password { get; } | ||
|
||
/// <summary> | ||
/// Gets the expiration date and time of the One-Time Password (OTP). | ||
/// </summary> | ||
public DateTime? ExpiresOn { get; } | ||
/// <summary> | ||
/// Gets the maximum number of attempts of the One-Time Password (OTP). | ||
/// </summary> | ||
public int? MaximumAttempts { get; } | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="OneTimePasswordCreatedEvent"/> class. | ||
/// </summary> | ||
/// <param name="actorId">The actor identifier.</param> | ||
/// <param name="expiresOn">The expiration date and time of the One-Time Password (OTP).</param> | ||
/// <param name="maximumAttempts">The maximum number of attempts of the One-Time Password (OTP).</param> | ||
/// <param name="password">The encoded value of the One-Time Password (OTP).</param> | ||
/// <param name="tenantId">The tenant identifier of the One-Time Password (OTP).</param> | ||
public OneTimePasswordCreatedEvent(ActorId actorId, DateTime? expiresOn, int? maximumAttempts, Password password, TenantId? tenantId) | ||
{ | ||
ActorId = actorId; | ||
ExpiresOn = expiresOn; | ||
MaximumAttempts = maximumAttempts; | ||
Password = password; | ||
TenantId = tenantId; | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/Logitar.Identity.Domain/Passwords/Events/OneTimePasswordDeletedEvent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using Logitar.EventSourcing; | ||
using MediatR; | ||
|
||
namespace Logitar.Identity.Domain.Passwords.Events; | ||
|
||
/// <summary> | ||
/// The event raised when a One-Time Password (OTP) is deleted. | ||
/// </summary> | ||
public record OneTimePasswordDeletedEvent : DomainEvent, INotification | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="OneTimePasswordDeletedEvent"/> class. | ||
/// </summary> | ||
/// <param name="actorId">The actor identifier.</param> | ||
public OneTimePasswordDeletedEvent(ActorId actorId) | ||
{ | ||
ActorId = actorId; | ||
IsDeleted = true; | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/Logitar.Identity.Domain/Passwords/Events/OneTimePasswordUpdatedEvent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using Logitar.EventSourcing; | ||
using MediatR; | ||
|
||
namespace Logitar.Identity.Domain.Passwords.Events; | ||
|
||
/// <summary> | ||
/// The event raised when an existing One-Time Password (OTP) is modified. | ||
/// </summary> | ||
public record OneTimePasswordUpdatedEvent : DomainEvent, INotification | ||
{ | ||
/// <summary> | ||
/// Gets or sets the custom attribute modifications of the One-Time Password (OTP). | ||
/// </summary> | ||
public Dictionary<string, string?> CustomAttributes { get; } = []; | ||
|
||
/// <summary> | ||
/// Gets a value indicating whether or not the One-Time Password (OTP) is being modified. | ||
/// </summary> | ||
public bool HasChanges => CustomAttributes.Count > 0; | ||
} |
19 changes: 19 additions & 0 deletions
19
src/Logitar.Identity.Domain/Passwords/Events/OneTimePasswordValidationFailedEvent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using Logitar.EventSourcing; | ||
using MediatR; | ||
|
||
namespace Logitar.Identity.Domain.Passwords.Events; | ||
|
||
/// <summary> | ||
/// The event raised when a One-Time Password (OTP) validation failed. | ||
/// </summary> | ||
public record OneTimePasswordValidationFailedEvent : DomainEvent, INotification | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="OneTimePasswordValidationFailedEvent"/> class. | ||
/// </summary> | ||
/// <param name="actorId">The actor identifier.</param> | ||
public OneTimePasswordValidationFailedEvent(ActorId actorId) | ||
{ | ||
ActorId = actorId; | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/Logitar.Identity.Domain/Passwords/Events/OneTimePasswordValidationSucceededEvent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using Logitar.EventSourcing; | ||
using MediatR; | ||
|
||
namespace Logitar.Identity.Domain.Passwords.Events; | ||
|
||
/// <summary> | ||
/// The event raised when a One-Time Password (OTP) is successfully validated. | ||
/// </summary> | ||
public record OneTimePasswordValidationSucceededEvent : DomainEvent, INotification | ||
{ | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="OneTimePasswordValidationSucceededEvent"/> class. | ||
/// </summary> | ||
/// <param name="actorId">The actor identifier.</param> | ||
public OneTimePasswordValidationSucceededEvent(ActorId actorId) | ||
{ | ||
ActorId = actorId; | ||
} | ||
} |
103 changes: 103 additions & 0 deletions
103
src/Logitar.Identity.Domain/Passwords/IOneTimePasswordRepository.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
using Logitar.Identity.Domain.Shared; | ||
|
||
namespace Logitar.Identity.Domain.Passwords; | ||
|
||
/// <summary> | ||
/// Defines methods to retrieve and store One-Time Passwords (OTP) to an event store. | ||
/// </summary> | ||
public interface IOneTimePasswordRepository | ||
{ | ||
/// <summary> | ||
/// Loads a One-Time Password (OTP) by the specified unique identifier. | ||
/// </summary> | ||
/// <param name="id">The unique identifier.</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The One-Time Password (OTP), if found.</returns> | ||
Task<OneTimePasswordAggregate?> LoadAsync(OneTimePasswordId id, CancellationToken cancellationToken = default); | ||
/// <summary> | ||
/// Loads a One-Time Password (OTP) by the specified unique identifier. | ||
/// </summary> | ||
/// <param name="id">The unique identifier.</param> | ||
/// <param name="version">The version at which to load the One-Time Password (OTP).</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The One-Time Password (OTP), if found.</returns> | ||
Task<OneTimePasswordAggregate?> LoadAsync(OneTimePasswordId id, long? version, CancellationToken cancellationToken = default); | ||
/// <summary> | ||
/// Loads a One-Time Password (OTP) by the specified unique identifier. | ||
/// </summary> | ||
/// <param name="id">The unique identifier.</param> | ||
/// <param name="includeDeleted">A value indicating whether or not to load the One-Time Password (OTP) if it is deleted.</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The One-Time Password (OTP), if found.</returns> | ||
Task<OneTimePasswordAggregate?> LoadAsync(OneTimePasswordId id, bool includeDeleted, CancellationToken cancellationToken = default); | ||
/// <summary> | ||
/// Loads a One-Time Password (OTP) by the specified unique identifier. | ||
/// </summary> | ||
/// <param name="id">The unique identifier.</param> | ||
/// <param name="version">The version at which to load the One-Time Password (OTP).</param> | ||
/// <param name="includeDeleted">A value indicating whether or not to load the One-Time Password (OTP) if it is deleted.</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The One-Time Password (OTP), if found.</returns> | ||
Task<OneTimePasswordAggregate?> LoadAsync(OneTimePasswordId id, long? version, bool includeDeleted, CancellationToken cancellationToken = default); | ||
|
||
/// <summary> | ||
/// Loads the One-Time Password (OTP)s from the event store. | ||
/// </summary> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The found One-Time Passwords (OTP).</returns> | ||
Task<IEnumerable<OneTimePasswordAggregate>> LoadAsync(CancellationToken cancellationToken = default); | ||
/// <summary> | ||
/// Loads the One-Time Password (OTP)s from the event store. | ||
/// </summary> | ||
/// <param name="includeDeleted">A value indicating whether or not to load deleted One-Time Passwords (OTP).</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The found One-Time Passwords (OTP).</returns> | ||
Task<IEnumerable<OneTimePasswordAggregate>> LoadAsync(bool includeDeleted, CancellationToken cancellationToken = default); | ||
|
||
/// <summary> | ||
/// Loads the One-Time Password (OTP)s by the specified list of unique identifiers. | ||
/// </summary> | ||
/// <param name="ids">The unique identifiers.</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The found One-Time Passwords (OTP).</returns> | ||
Task<IEnumerable<OneTimePasswordAggregate>> LoadAsync(IEnumerable<OneTimePasswordId> ids, CancellationToken cancellationToken = default); | ||
/// <summary> | ||
/// Loads the One-Time Password (OTP)s by the specified list of unique identifiers. | ||
/// </summary> | ||
/// <param name="ids">The unique identifiers.</param> | ||
/// <param name="includeDeleted">A value indicating whether or not to load deleted One-Time Passwords (OTP).</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The found One-Time Passwords (OTP).</returns> | ||
Task<IEnumerable<OneTimePasswordAggregate>> LoadAsync(IEnumerable<OneTimePasswordId> ids, bool includeDeleted, CancellationToken cancellationToken = default); | ||
|
||
/// <summary> | ||
/// Loads the One-Time Password (OTP)s in the specified tenant. | ||
/// </summary> | ||
/// <param name="tenantId">The identifier of the tenant.</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The found One-Time Passwords (OTP).</returns> | ||
Task<IEnumerable<OneTimePasswordAggregate>> LoadAsync(TenantId? tenantId, CancellationToken cancellationToken = default); | ||
/// <summary> | ||
/// Loads the One-Time Password (OTP)s in the specified tenant. | ||
/// </summary> | ||
/// <param name="tenantId">The identifier of the tenant.</param> | ||
/// <param name="includeDeleted">A value indicating whether or not to load deleted One-Time Passwords (OTP).</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The found One-Time Passwords (OTP).</returns> | ||
Task<IEnumerable<OneTimePasswordAggregate>> LoadAsync(TenantId? tenantId, bool includeDeleted, CancellationToken cancellationToken = default); | ||
|
||
/// <summary> | ||
/// Saves the specified One-Time Password (OTP) into the store. | ||
/// </summary> | ||
/// <param name="oneTimePassword">The One-Time Password (OTP) to save.</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The asynchronous operation.</returns> | ||
Task SaveAsync(OneTimePasswordAggregate oneTimePassword, CancellationToken cancellationToken = default); | ||
/// <summary> | ||
/// Saves the specified One-Time Passwords (OTP) into the store. | ||
/// </summary> | ||
/// <param name="oneTimePasswords">The One-Time Password (OTP)s to save.</param> | ||
/// <param name="cancellationToken">The cancellation token.</param> | ||
/// <returns>The asynchronous operation.</returns> | ||
Task SaveAsync(IEnumerable<OneTimePasswordAggregate> oneTimePasswords, CancellationToken cancellationToken = default); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.