-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Auth/PM-32102 - (1) Create ConvertUserToKeyConnectorCommand (2) Remove salt on key connector conversion #7692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6d130d3
cf9ff0d
bccb7ca
dce0771
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| ๏ปฟusing Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces; | ||
| using Bit.Core.Context; | ||
| using Bit.Core.Entities; | ||
| using Bit.Core.Enums; | ||
| using Bit.Core.Exceptions; | ||
| using Bit.Core.KeyManagement.Commands.Interfaces; | ||
| using Bit.Core.Repositories; | ||
| using Bit.Core.Services; | ||
| using Microsoft.AspNetCore.Identity; | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace Bit.Core.KeyManagement.Commands; | ||
|
|
||
| public class ConvertUserToKeyConnectorCommand : IConvertUserToKeyConnectorCommand | ||
| { | ||
| private readonly IUserRepository _userRepository; | ||
| private readonly IEventService _eventService; | ||
| private readonly ICurrentContext _currentContext; | ||
| private readonly IMasterPasswordService _masterPasswordService; | ||
| private readonly IdentityErrorDescriber _identityErrorDescriber; | ||
| private readonly ILogger<ConvertUserToKeyConnectorCommand> _logger; | ||
|
|
||
| public ConvertUserToKeyConnectorCommand( | ||
| IUserRepository userRepository, | ||
| IEventService eventService, | ||
| ICurrentContext currentContext, | ||
| IMasterPasswordService masterPasswordService, | ||
| IdentityErrorDescriber identityErrorDescriber, | ||
| ILogger<ConvertUserToKeyConnectorCommand> logger) | ||
| { | ||
| _userRepository = userRepository; | ||
| _eventService = eventService; | ||
| _currentContext = currentContext; | ||
| _masterPasswordService = masterPasswordService; | ||
| _identityErrorDescriber = identityErrorDescriber; | ||
| _logger = logger; | ||
| } | ||
|
|
||
| public async Task<IdentityResult> ConvertAsync(User user, string? keyConnectorKeyWrappedUserKey = null) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(user); | ||
|
|
||
| var canUseResult = CheckCanUseKeyConnector(user); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐จ Should we either rename Just looking for ways to flag that there is no significant confirmation of success, only significant confirmation of failure. |
||
| if (canUseResult != null) | ||
| { | ||
| return canUseResult; | ||
| } | ||
|
|
||
| _masterPasswordService.PrepareClearMasterPassword(user); | ||
| user.UsesKeyConnector = true; | ||
|
|
||
| if (!string.IsNullOrWhiteSpace(keyConnectorKeyWrappedUserKey)) | ||
| { | ||
| user.Key = keyConnectorKeyWrappedUserKey; | ||
| } | ||
|
|
||
| await _userRepository.ReplaceAsync(user); | ||
| await _eventService.LogUserEventAsync(user.Id, EventType.User_MigratedKeyToKeyConnector); | ||
|
|
||
| return IdentityResult.Success; | ||
| } | ||
|
|
||
| private IdentityResult? CheckCanUseKeyConnector(User user) | ||
| { | ||
| if (user.UsesKeyConnector) | ||
| { | ||
| _logger.LogWarning("Already uses Key Connector."); | ||
| return IdentityResult.Failed(_identityErrorDescriber.UserAlreadyHasPassword()); | ||
| } | ||
|
|
||
| if (_currentContext.Organizations.Any(u => | ||
| u.Type is OrganizationUserType.Owner or OrganizationUserType.Admin)) | ||
| { | ||
| throw new BadRequestException("Cannot use Key Connector when admin or owner of an organization."); | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| ๏ปฟusing Bit.Core.Entities; | ||
| using Microsoft.AspNetCore.Identity; | ||
|
|
||
| namespace Bit.Core.KeyManagement.Commands.Interfaces; | ||
|
|
||
| /// <summary> | ||
| /// Converts an existing master-password user into a Key Connector user โ clears the master | ||
| /// password credential, marks the account as using Key Connector, optionally rotates the | ||
| /// user key wrap to a Key-Connector-wrapped form, persists the user, and emits an event. | ||
| /// </summary> | ||
| public interface IConvertUserToKeyConnectorCommand | ||
| { | ||
| Task<IdentityResult> ConvertAsync(User user, string? keyConnectorKeyWrappedUserKey = null); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐ค should this also update the
LastPasswordChangeDate?It does not in the precedent (ConvertToKeyConnectorAsync), so this would constitute a behavior change.
However,
AccountRevisionDatecan and will be updated by discrete future actions, and IMO this does represent an intent to change (destructively, in this case) the user's master password -- is there (and should there be) another durable marker of when this user was converted to Key Connector?