-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: wire-in key id on registration and key rotation flows #8164
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
Changes from all commits
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,17 @@ | ||
| using System.ComponentModel.DataAnnotations; | ||
| using Bit.Core.KeyManagement.Models.Data; | ||
| using Bit.Core.Utilities; | ||
|
|
||
| namespace Bit.Api.KeyManagement.Models.Requests; | ||
|
|
||
| public class SetUserKeyIdRequestModel | ||
| { | ||
| /// <summary> | ||
| /// Hex-encoded key id of the user's current user key. | ||
| /// </summary> | ||
| [Required(AllowEmptyStrings = false)] | ||
| [KeyId] | ||
| public required string UserKeyId { get; init; } | ||
|
|
||
| public KeyId ToKeyId() => KeyId.FromHexEncodedString(UserKeyId)!; | ||
| } |
|
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. 🎨 : do we want to move this to KM ownership?
Contributor
Author
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. I agree, except that we use it for a sub request model, but also a top level request model for JIT crypto init
Do you agree with this split @ike-kottlowski ? |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -114,18 +114,6 @@ public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFac | |
| public string? V2UpgradeToken { get; set; } | ||
| [MaxLength(256)] | ||
| public string? MasterPasswordSalt { get; set; } | ||
|
|
||
| public KeyId? GetUserKeyId() | ||
| { | ||
| // Todo: Database Implementation in follow-up PR | ||
| return null; | ||
| } | ||
|
|
||
| public void SetUserKeyId(KeyId keyId) | ||
| { | ||
| return; // Todo: Database Implementation in follow-up PR | ||
| } | ||
|
|
||
| public DateTime? LastApiKeyRotationDate { get; set; } | ||
| /// <summary> | ||
| /// A hex-endcoded key-id of the user's current user-key. | ||
|
|
@@ -137,8 +125,17 @@ public void SetUserKeyId(KeyId keyId) | |
| /// A key rotation will set a new key id. Account registrations will carry a key id. | ||
| /// </summary> | ||
| [MaxLength(32)] | ||
| [KeyId] | ||
|
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. ❓ Why do we need this on entity ? In other cases, this is used by EF to generate correct column types, but not here.
Contributor
Author
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. Makes sense, I'll remove it in a follow-up PR given this is already approved. |
||
| public string? UserKeyId { get; set; } | ||
|
|
||
| public void SetUserKeyId(KeyId? userKeyId) | ||
| { | ||
| UserKeyId = userKeyId?.ToString(); | ||
| } | ||
|
|
||
| public KeyId? GetUserKeyId() => | ||
| KeyId.FromHexEncodedString(string.IsNullOrEmpty(UserKeyId) ? null : UserKeyId); | ||
|
|
||
| public string GetMasterPasswordSalt() | ||
| { | ||
| return MasterPasswordSalt ?? Email.ToLowerInvariant().Trim(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| using Bit.Core.Entities; | ||
| using Bit.Core.KeyManagement.Models.Data; | ||
|
|
||
| namespace Bit.Core.KeyManagement.Commands.Interfaces; | ||
|
|
||
| public interface ISetUserKeyIdCommand | ||
| { | ||
| /// <summary> | ||
| /// Stores the key id of a user's current user key. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// This is a backfill primitive for accounts that pre-date the key id being reported alongside | ||
| /// key material. It therefore only accepts a value when the account does not already have one — | ||
| /// changing an existing key id must happen through a key rotation. | ||
| /// </remarks> | ||
| /// <param name="user">The user whose key id is being recorded.</param> | ||
| /// <param name="userKeyId">Key id of the user's current user key.</param> | ||
| /// <exception cref="Bit.Core.Exceptions.BadRequestException"> | ||
| /// Thrown when the account already has a key id. | ||
| /// </exception> | ||
| Task SetUserKeyIdAsync(User user, KeyId userKeyId); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| using Bit.Core.Entities; | ||
| using Bit.Core.Exceptions; | ||
| using Bit.Core.KeyManagement.Commands.Interfaces; | ||
| using Bit.Core.KeyManagement.Models.Data; | ||
| using Bit.Core.Repositories; | ||
|
|
||
| namespace Bit.Core.KeyManagement.Commands; | ||
|
|
||
| public class SetUserKeyIdCommand : ISetUserKeyIdCommand | ||
| { | ||
| private readonly IUserRepository _userRepository; | ||
|
|
||
| public SetUserKeyIdCommand(IUserRepository userRepository) | ||
| { | ||
| _userRepository = userRepository; | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public async Task SetUserKeyIdAsync(User user, KeyId userKeyId) | ||
| { | ||
| if (user.GetUserKeyId() is not null) | ||
| { | ||
| throw new BadRequestException("User key id is already set."); | ||
| } | ||
|
|
||
| await _userRepository.UpdateUserDataAsync([_userRepository.SetUserKeyId(user.Id, userKeyId)]); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,5 +10,9 @@ public class KeyConnectorKeysData | |
|
|
||
| public required string OrgIdentifier { get; init; } | ||
|
|
||
| /// <summary> | ||
| /// Key id of the user key wrapped by <see cref="KeyConnectorKeyWrappedUserKey"/>, when the client | ||
| /// supplied it. | ||
| /// </summary> | ||
| public KeyId? ContainedKeyId { get; init; } | ||
|
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. ❓ Why not name it, for what it is:
Contributor
Author
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. On safe primitives, the value is called Essentially, in the current state this is that same value, just not placed on the wrapped key object. |
||
| } | ||
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.
❓ Why not name it, for what it is:
UserKeyId?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.
(See other comment)