Skip to content
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

Auth/PM-3275 - Changes to support TDE User without MP being able to Set a Password + misc refactoring #3242

Merged
Merged
Show file tree
Hide file tree
Changes from 108 commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
c23d913
PM-3275 - Add new GetMasterPasswordPolicy endpoint which will allow a…
JaredSnider-Bitwarden Aug 29, 2023
5142d55
PM-3275 - AccountsController.cs - PostSetPasswordAsync - (1) Convert …
JaredSnider-Bitwarden Aug 30, 2023
c28035b
PM-3275 - Update AccountsControllerTests.cs to add new SetInitialMast…
JaredSnider-Bitwarden Aug 30, 2023
96cb464
PM-3275 - UserService.cs - Remove non implemented ChangePasswordAsync…
JaredSnider-Bitwarden Aug 30, 2023
c6ce522
PM-3275 - The new SetInitialMasterPasswordCommand leveraged the Organ…
JaredSnider-Bitwarden Aug 31, 2023
6ccd5b5
PM-3275 - Dotnet format
JaredSnider-Bitwarden Aug 31, 2023
34ea740
PM-3275 - Test SetInitialMasterPasswordCommand
JaredSnider-Bitwarden Aug 31, 2023
505c2c2
Dotnet format
JaredSnider-Bitwarden Sep 4, 2023
4da9fb2
PM-3275 - In process AcceptOrgUserCommandTests.cs
JaredSnider-Bitwarden Sep 4, 2023
0406d84
Merge remote-tracking branch 'origin/master' into auth/pm-3275/tde-ad…
JaredSnider-Bitwarden Sep 13, 2023
083e41e
PM-3275 - Migrate changes from AC-244 / #3199 over into new AcceptOrg…
JaredSnider-Bitwarden Sep 13, 2023
724fdb0
PM-3275 - AcceptOrgUserCommand.cs - create data protector specificall…
JaredSnider-Bitwarden Sep 13, 2023
dea79ab
PM-3275 - Add TODO for renaming / removing overloading of methods to …
JaredSnider-Bitwarden Sep 13, 2023
a2f1623
PM-3275 - AcceptOrgUserCommand.cs - refactor AcceptOrgUserAsync by Or…
JaredSnider-Bitwarden Sep 13, 2023
bc9a46b
PM-3275 - AcceptOrgUserCommand.cs - update name in TODO for evaluatio…
JaredSnider-Bitwarden Sep 13, 2023
483ea38
PM-3275 / PM-1196 - (1) Slightly refactor SsoEmail2faSessionTokenable…
JaredSnider-Bitwarden Sep 14, 2023
94bf6c2
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Sep 14, 2023
bd0785e
PM-3275 / PM-1196 - Removing SsoEmail2faSessionTokenable.cs changes +…
JaredSnider-Bitwarden Sep 14, 2023
33804a5
Merge remote-tracking branch 'origin/auth/pm-3275/tde-add-get-mp-poli…
JaredSnider-Bitwarden Sep 14, 2023
73ab565
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Sep 15, 2023
b30e2da
PM-3275 - ExpiringTokenable.cs - add clarifying comments to help dist…
JaredSnider-Bitwarden Sep 15, 2023
1d279ee
PM-3275 - Create OrgUserInviteTokenable.cs and add tests in OrgUserIn…
JaredSnider-Bitwarden Sep 15, 2023
daffc93
PM-3275 - OrganizationService.cs - Refactor Org User Invite methods t…
JaredSnider-Bitwarden Sep 18, 2023
1bde672
PM-3275 - OrgUserInviteTokenable.cs - clarify backwards compat note
JaredSnider-Bitwarden Sep 18, 2023
6fd9a0c
PM-3275 - AcceptOrgUserCommand.cs - Add TODOs + minor name refactor
JaredSnider-Bitwarden Sep 18, 2023
9654b88
PM-3275 - AcceptOrgUserCommand.cs - replace method overloading with m…
JaredSnider-Bitwarden Sep 18, 2023
dda6c90
PM-3275 - AcceptOrgUserCommand.cs - Update ValidateOrgUserInviteToken…
JaredSnider-Bitwarden Sep 18, 2023
b27c187
dotnet format
JaredSnider-Bitwarden Sep 18, 2023
33ba8db
PM-3275 - AcceptOrgUserCommand.cs - Move private method below where i…
JaredSnider-Bitwarden Sep 18, 2023
ae29432
PM-3275 - ServiceCollectionExtensions.cs - Must register IDataProtect…
JaredSnider-Bitwarden Sep 18, 2023
8b44977
PM-3275 - OrgUserInviteTokenable needed access to global settings to …
JaredSnider-Bitwarden Sep 18, 2023
2eeacfc
PM-3275 - In process work of creating AcceptOrgUserCommandTests.cs
JaredSnider-Bitwarden Sep 18, 2023
9c5b808
PM-3275 - Remove no longer relevant AcceptOrgUser tests from Organiza…
JaredSnider-Bitwarden Sep 19, 2023
f33e515
PM-3275 - Register OrgUserInviteTokenableFactory alongside tokenizer
JaredSnider-Bitwarden Sep 19, 2023
5cda892
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Sep 19, 2023
3d55d70
PM-3275 - AcceptOrgUserCommandTests.cs - AcceptOrgUserAsync basic tes…
JaredSnider-Bitwarden Sep 19, 2023
a7a6712
PM-3275 - AcceptOrgUserCommandTests.cs - tweak test names
JaredSnider-Bitwarden Sep 19, 2023
62f5f49
PM-3275 - AcceptOrgUserCommandTests.cs - (1) Remove old tests from Or…
JaredSnider-Bitwarden Sep 19, 2023
97b3503
PM-3275 - Create interface for OrgUserInviteTokenableFactory b/c that…
JaredSnider-Bitwarden Sep 19, 2023
d6791ab
PM-3275 - AcceptOrgUserCommandTests.cs - (1) Start work on AcceptOrgU…
JaredSnider-Bitwarden Sep 19, 2023
b1b786f
PM-3275 - (1) Get AcceptOrgUserByToken_NewToken_AcceptsUserAndVerifie…
JaredSnider-Bitwarden Sep 20, 2023
bb64e4c
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Sep 20, 2023
bb071ab
PM-3275 - AcceptOrgUserCommandTests.cs - Finish up tests for AcceptOr…
JaredSnider-Bitwarden Sep 20, 2023
bbdd927
Merge remote-tracking branch 'origin/auth/pm-3275/tde-add-get-mp-poli…
JaredSnider-Bitwarden Sep 20, 2023
85e531e
PM-3275 - Add pseudo section comments
JaredSnider-Bitwarden Sep 20, 2023
d49f994
PM-3275 - Clean up unused params on AcceptOrgUserByToken_EmailMismatc…
JaredSnider-Bitwarden Sep 20, 2023
a022de8
PM-3275 - (1) Tests written for AcceptOrgUserByOrgSsoIdAsync (2) Refa…
JaredSnider-Bitwarden Sep 20, 2023
847d6ae
PM-3275 - Finish up testing AcceptOrgUserCommandTests.cs by adding te…
JaredSnider-Bitwarden Sep 20, 2023
3599438
PM-3275 - Tweaking test naming to ensure consistency.
JaredSnider-Bitwarden Sep 20, 2023
ca95b25
PM-3275 - Bugfix - OrgUserInviteTokenableFactory implementation requi…
JaredSnider-Bitwarden Sep 20, 2023
e689788
PM-3275 - Resolve failing OrganizationServiceTests.cs
JaredSnider-Bitwarden Sep 20, 2023
7c9c1ba
dotnet format
JaredSnider-Bitwarden Sep 20, 2023
675079a
PM-3275 - PoliciesController.cs - GetMasterPasswordPolicy bugfix - fo…
JaredSnider-Bitwarden Sep 21, 2023
3954b65
PM-3275 - Add PoliciesControllerTests.cs specifically for new GetMast…
JaredSnider-Bitwarden Sep 21, 2023
151f4a2
PM-3275 - dotnet format PoliciesControllerTests.cs
JaredSnider-Bitwarden Sep 21, 2023
db44b97
PM-3275 - PoliciesController.cs - (1) Add tech debt task number (2) P…
JaredSnider-Bitwarden Sep 25, 2023
6f6d14c
PM-3275 - Add new hasManageResetPasswordPermission property to Profil…
JaredSnider-Bitwarden Sep 25, 2023
aec314d
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Sep 26, 2023
7ff5022
PM-3275 - Fix AccountsControllerTests.cs
JaredSnider-Bitwarden Sep 26, 2023
c425268
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Sep 28, 2023
cd2c0a9
PM-3275 - OrgUserInviteTokenable.cs - clarify TODO
JaredSnider-Bitwarden Sep 28, 2023
4e48e21
Merge remote-tracking branch 'origin/auth/pm-3275/tde-add-get-mp-poli…
JaredSnider-Bitwarden Sep 28, 2023
7cde427
PM-3275 - AcceptOrgUserCommand.cs - Refactor token validation to use …
JaredSnider-Bitwarden Sep 29, 2023
138d4a2
PM-3275 - OrgUserInviteTokenable.cs - (1) Add new static methods to c…
JaredSnider-Bitwarden Sep 29, 2023
eff02c0
PM-3275 - Realized that the old token validation was used in the Poli…
JaredSnider-Bitwarden Sep 29, 2023
5ab422f
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Sep 29, 2023
49c1701
dotnet format
JaredSnider-Bitwarden Sep 29, 2023
15d728b
Merge remote-tracking branch 'origin/auth/pm-3275/tde-add-get-mp-poli…
JaredSnider-Bitwarden Sep 29, 2023
0dcc86d
PM-3275 - (1) AccountsController.cs - Update PostSetPasswordAsync Set…
JaredSnider-Bitwarden Oct 3, 2023
620efd7
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 4, 2023
056636d
PM-3275 - PR review feedback - (1) set CurrentContext to private (2) …
JaredSnider-Bitwarden Oct 6, 2023
5710729
Merge remote-tracking branch 'origin/auth/pm-3275/tde-add-get-mp-poli…
JaredSnider-Bitwarden Oct 6, 2023
1c099a0
PM-3275 - SyncController.cs - PR Review Feedback - Set current contex…
JaredSnider-Bitwarden Oct 6, 2023
d83da37
PM-3275 - CurrentContextExtensions.cs - PR Feedback - move parenthesi…
JaredSnider-Bitwarden Oct 6, 2023
f651f85
PM-3275 - SetInitialMasterPasswordCommandTests.cs - Replace unnecessa…
JaredSnider-Bitwarden Oct 6, 2023
be5ad49
PM-3275 - SetInitialMasterPasswordCommandTests.cs - PR Feedback - Add…
JaredSnider-Bitwarden Oct 6, 2023
6b92cde
PM-3275 - Set Initial Password command and tests - PR Feedback change…
JaredSnider-Bitwarden Oct 6, 2023
bc476b7
PM-3275 - SetInitialMasterPasswordCommand.cs - Move summary from impl…
JaredSnider-Bitwarden Oct 6, 2023
a40b5c4
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 10, 2023
c891f43
PM-3275 - AcceptOrgUserCommand.cs - Per PR feedback, rename AcceptOrg…
JaredSnider-Bitwarden Oct 10, 2023
4ba466c
Merge remote-tracking branch 'origin/auth/pm-3275/tde-add-get-mp-poli…
JaredSnider-Bitwarden Oct 10, 2023
07c5374
PM-3275 - OrganizationService.cs - Per PR feedback, remove dupe line
JaredSnider-Bitwarden Oct 13, 2023
0ab5825
PM-3275 - AcceptOrgUserCommand.cs - Per PR feedback, remove new lines…
JaredSnider-Bitwarden Oct 13, 2023
9b78c53
PM-3275 - SetInitialMasterPasswordCommand.cs - Per PR feedback, adjus…
JaredSnider-Bitwarden Oct 13, 2023
f3bda42
PM-3275 - CurrentContextExtensions.cs - Refactor AnyOrgUserHasManageR…
JaredSnider-Bitwarden Oct 13, 2023
44bc574
PM-3275 - AcceptOrgUserCommand.cs - Per PR feedback, remove completed…
JaredSnider-Bitwarden Oct 13, 2023
a569fe7
PM-3275 - PoliciesController.cs - Per PR feedback, update GetByInvite…
JaredSnider-Bitwarden Oct 13, 2023
011fda9
PM-3275 - OrgUserInviteTokenable.cs - per PR feedback, add tech debt …
JaredSnider-Bitwarden Oct 13, 2023
9c142bf
PM-3275 - AcceptOrgUserCommand.cs - Per PR feedback, use const purpos…
JaredSnider-Bitwarden Oct 13, 2023
115d18d
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 13, 2023
2841b96
PM-3275 - Restore non duplicate line to fix tests
JaredSnider-Bitwarden Oct 13, 2023
4fc7733
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 16, 2023
36c8d4b
PM-3275 - Per PR feedback, revert all sync controller changes as the …
JaredSnider-Bitwarden Oct 16, 2023
83c278e
Merge remote-tracking branch 'origin/auth/pm-3275/tde-add-get-mp-poli…
JaredSnider-Bitwarden Oct 16, 2023
a8fb82b
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 16, 2023
50b954b
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 18, 2023
4b476e1
Merge remote-tracking branch 'origin/master' into auth/pm-3275/tde-ad…
JaredSnider-Bitwarden Oct 18, 2023
eaf3197
PM-3275 - PoliciesControllerTests.cs - Update imports as the Policies…
JaredSnider-Bitwarden Oct 18, 2023
40c7b35
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 20, 2023
b495711
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 23, 2023
65882ea
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 23, 2023
05e8d82
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 24, 2023
889acba
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 26, 2023
2e6f90f
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Oct 27, 2023
699bfa8
Merge remote-tracking branch 'origin/master' into auth/pm-3275/tde-ad…
JaredSnider-Bitwarden Oct 30, 2023
6806047
PM-3275 - Resolve issues from merge conflict resolutions to get solut…
JaredSnider-Bitwarden Oct 30, 2023
c546897
PM-3275 / PM-4633 - PoliciesController.cs - use orgUserId to look up …
JaredSnider-Bitwarden Oct 30, 2023
c8aa953
Fix user service tests
JaredSnider-Bitwarden Oct 30, 2023
e8e0d6c
Merge remote-tracking branch 'origin/master' into auth/pm-3275/tde-ad…
JaredSnider-Bitwarden Nov 1, 2023
050b691
Resolve merge conflict
JaredSnider-Bitwarden Nov 1, 2023
3f86e4d
Merge branch 'master' into auth/pm-3275/tde-add-get-mp-policy-endpoint
JaredSnider-Bitwarden Nov 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/Api/AdminConsole/Controllers/OrganizationUsersController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Models.Data.Organizations.Policies;
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
using Bit.Core.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Microsoft.AspNetCore.Authorization;
Expand All @@ -33,6 +34,7 @@ public class OrganizationUsersController : Controller
private readonly ICountNewSmSeatsRequiredQuery _countNewSmSeatsRequiredQuery;
private readonly IUpdateSecretsManagerSubscriptionCommand _updateSecretsManagerSubscriptionCommand;
private readonly IUpdateOrganizationUserGroupsCommand _updateOrganizationUserGroupsCommand;
private readonly IAcceptOrgUserCommand _acceptOrgUserCommand;

public OrganizationUsersController(
IOrganizationRepository organizationRepository,
Expand All @@ -45,7 +47,8 @@ public OrganizationUsersController(
ICurrentContext currentContext,
ICountNewSmSeatsRequiredQuery countNewSmSeatsRequiredQuery,
IUpdateSecretsManagerSubscriptionCommand updateSecretsManagerSubscriptionCommand,
IUpdateOrganizationUserGroupsCommand updateOrganizationUserGroupsCommand)
IUpdateOrganizationUserGroupsCommand updateOrganizationUserGroupsCommand,
IAcceptOrgUserCommand acceptOrgUserCommand)
{
_organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;
Expand All @@ -58,6 +61,7 @@ public OrganizationUsersController(
_countNewSmSeatsRequiredQuery = countNewSmSeatsRequiredQuery;
_updateSecretsManagerSubscriptionCommand = updateSecretsManagerSubscriptionCommand;
_updateOrganizationUserGroupsCommand = updateOrganizationUserGroupsCommand;
_acceptOrgUserCommand = acceptOrgUserCommand;
}

[HttpGet("{id}")]
Expand Down Expand Up @@ -199,7 +203,7 @@ public async Task AcceptInit(Guid orgId, Guid organizationUserId, [FromBody] Org
}

await _organizationService.InitPendingOrganization(user.Id, orgId, model.Keys.PublicKey, model.Keys.EncryptedPrivateKey, model.CollectionName);
await _organizationService.AcceptUserAsync(organizationUserId, user, model.Token, _userService);
await _acceptOrgUserCommand.AcceptOrgUserByEmailTokenAsync(organizationUserId, user, model.Token, _userService);
await _organizationService.ConfirmUserAsync(orgId, organizationUserId, model.Key, user.Id, _userService);
}

Expand All @@ -221,7 +225,7 @@ public async Task Accept(Guid orgId, Guid organizationUserId, [FromBody] Organiz
throw new BadRequestException(string.Empty, "Master Password reset is required, but not provided.");
}

await _organizationService.AcceptUserAsync(organizationUserId, user, model.Token, _userService);
await _acceptOrgUserCommand.AcceptOrgUserByEmailTokenAsync(organizationUserId, user, model.Token, _userService);

if (useMasterPasswordPolicy)
{
Expand Down Expand Up @@ -332,7 +336,7 @@ await _organizationService.UpdateUserResetPasswordEnrollmentAsync(
var orgUser = await _organizationUserRepository.GetByOrganizationAsync(orgId, user.Id);
if (orgUser.Status == OrganizationUserStatusType.Invited)
{
await _organizationService.AcceptUserAsync(orgId, user, _userService);
await _acceptOrgUserCommand.AcceptOrgUserByOrgIdAsync(orgId, user, _userService);
}
}

Expand Down
63 changes: 48 additions & 15 deletions src/Api/AdminConsole/Controllers/PoliciesController.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using Bit.Api.AdminConsole.Models.Request;
using Bit.Api.Models.Response;
using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Response;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
using Bit.Core.Tokens;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection;
Expand All @@ -26,6 +28,7 @@ public class PoliciesController : Controller
private readonly ICurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
private readonly IDataProtector _organizationServiceDataProtector;
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;

public PoliciesController(
IPolicyRepository policyRepository,
Expand All @@ -35,7 +38,8 @@ public PoliciesController(
IUserService userService,
ICurrentContext currentContext,
GlobalSettings globalSettings,
IDataProtectionProvider dataProtectionProvider)
IDataProtectionProvider dataProtectionProvider,
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory)
{
_policyRepository = policyRepository;
_policyService = policyService;
Expand All @@ -46,6 +50,8 @@ public PoliciesController(
_globalSettings = globalSettings;
_organizationServiceDataProtector = dataProtectionProvider.CreateProtector(
"OrganizationServiceDataProtector");

_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
}

[HttpGet("{type}")]
Expand Down Expand Up @@ -81,41 +87,46 @@ public async Task<ListResponseModel<PolicyResponseModel>> Get(string orgId)

[AllowAnonymous]
[HttpGet("token")]
public async Task<ListResponseModel<PolicyResponseModel>> GetByToken(string orgId, [FromQuery] string email,
[FromQuery] string token, [FromQuery] string organizationUserId)
public async Task<ListResponseModel<PolicyResponseModel>> GetByToken(Guid orgId, [FromQuery] string email,
[FromQuery] string token, [FromQuery] Guid organizationUserId)
{
var orgUserId = new Guid(organizationUserId);
var tokenValid = CoreHelpers.UserInviteTokenIsValid(_organizationServiceDataProtector, token,
email, orgUserId, _globalSettings);
// TODO: PM-4142 - remove old token validation logic once 3 releases of backwards compatibility are complete
var newTokenValid = OrgUserInviteTokenable.ValidateOrgUserInviteStringToken(
_orgUserInviteTokenDataFactory, token, organizationUserId, email);

var tokenValid = newTokenValid || CoreHelpers.UserInviteTokenIsValid(
_organizationServiceDataProtector, token, email, organizationUserId, _globalSettings
);

if (!tokenValid)
{
throw new NotFoundException();
}

var orgIdGuid = new Guid(orgId);
var orgUser = await _organizationUserRepository.GetByIdAsync(orgUserId);
if (orgUser == null || orgUser.OrganizationId != orgIdGuid)
var orgUser = await _organizationUserRepository.GetByIdAsync(organizationUserId);
if (orgUser == null || orgUser.OrganizationId != orgId)
{
throw new NotFoundException();
}

var policies = await _policyRepository.GetManyByOrganizationIdAsync(orgIdGuid);
var policies = await _policyRepository.GetManyByOrganizationIdAsync(orgId);
var responses = policies.Where(p => p.Enabled).Select(p => new PolicyResponseModel(p));
return new ListResponseModel<PolicyResponseModel>(responses);
}

// TODO: PM-4097 - remove GetByInvitedUser once all clients are updated to use the GetMasterPasswordPolicy endpoint below
[Obsolete("Deprecated API", false)]
[AllowAnonymous]
[HttpGet("invited-user")]
public async Task<ListResponseModel<PolicyResponseModel>> GetByInvitedUser(string orgId, [FromQuery] string userId)
public async Task<ListResponseModel<PolicyResponseModel>> GetByInvitedUser(Guid orgId, [FromQuery] Guid userId)
{
var user = await _userService.GetUserByIdAsync(new Guid(userId));
var user = await _userService.GetUserByIdAsync(userId);
if (user == null)
{
throw new UnauthorizedAccessException();
}
var orgIdGuid = new Guid(orgId);
var orgUsersByUserId = await _organizationUserRepository.GetManyByUserAsync(user.Id);
var orgUser = orgUsersByUserId.SingleOrDefault(u => u.OrganizationId == orgIdGuid);
var orgUser = orgUsersByUserId.SingleOrDefault(u => u.OrganizationId == orgId);
if (orgUser == null)
{
throw new NotFoundException();
Expand All @@ -125,11 +136,33 @@ public async Task<ListResponseModel<PolicyResponseModel>> GetByInvitedUser(strin
throw new UnauthorizedAccessException();
}

var policies = await _policyRepository.GetManyByOrganizationIdAsync(orgIdGuid);
var policies = await _policyRepository.GetManyByOrganizationIdAsync(orgId);
var responses = policies.Where(p => p.Enabled).Select(p => new PolicyResponseModel(p));
return new ListResponseModel<PolicyResponseModel>(responses);
}

[HttpGet("master-password")]
public async Task<PolicyResponseModel> GetMasterPasswordPolicy(Guid orgId)
{
var userId = _userService.GetProperUserId(User).Value;

var orgUser = await _organizationUserRepository.GetByOrganizationAsync(orgId, userId);

if (orgUser == null)
{
throw new NotFoundException();
}

var policy = await _policyRepository.GetByOrganizationIdTypeAsync(orgId, PolicyType.MasterPassword);

if (policy == null || !policy.Enabled)
{
throw new NotFoundException();
}

return new PolicyResponseModel(policy);
}

[HttpPut("{type}")]
public async Task<PolicyResponseModel> Put(string orgId, int type, [FromBody] PolicyRequestModel model)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.ComponentModel.DataAnnotations;
#nullable enable

using System.ComponentModel.DataAnnotations;
using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Entities;
using Bit.Core.Enums;
Expand All @@ -15,8 +17,7 @@ public class SetPasswordRequestModel : IValidatableObject
public string Key { get; set; }
[StringLength(50)]
public string MasterPasswordHint { get; set; }
[Required]
public KeysRequestModel Keys { get; set; }
public KeysRequestModel? Keys { get; set; }
[Required]
public KdfType Kdf { get; set; }
[Required]
Expand All @@ -33,7 +34,7 @@ public User ToUser(User existingUser)
existingUser.KdfMemory = KdfMemory;
existingUser.KdfParallelism = KdfParallelism;
existingUser.Key = Key;
Keys.ToUser(existingUser);
Keys?.ToUser(existingUser);
return existingUser;
}

Expand Down
21 changes: 18 additions & 3 deletions src/Api/Controllers/AccountsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Auth.Models.Api.Response.Accounts;
using Bit.Core.Auth.Services;
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
using Bit.Core.Auth.Utilities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
Expand Down Expand Up @@ -47,6 +48,8 @@ public class AccountsController : Controller
private readonly ISendService _sendService;
private readonly ICaptchaValidationService _captchaValidationService;
private readonly IPolicyService _policyService;
private readonly ISetInitialMasterPasswordCommand _setInitialMasterPasswordCommand;


public AccountsController(
GlobalSettings globalSettings,
Expand All @@ -61,7 +64,9 @@ public AccountsController(
ISendRepository sendRepository,
ISendService sendService,
ICaptchaValidationService captchaValidationService,
IPolicyService policyService)
IPolicyService policyService,
ISetInitialMasterPasswordCommand setInitialMasterPasswordCommand
)
{
_cipherRepository = cipherRepository;
_folderRepository = folderRepository;
Expand All @@ -76,6 +81,7 @@ public AccountsController(
_sendService = sendService;
_captchaValidationService = captchaValidationService;
_policyService = policyService;
_setInitialMasterPasswordCommand = setInitialMasterPasswordCommand;
}

#region DEPRECATED (Moved to Identity Service)
Expand Down Expand Up @@ -253,8 +259,12 @@ public async Task PostSetPasswordAsync([FromBody] SetPasswordRequestModel model)
throw new UnauthorizedAccessException();
}

var result = await _userService.SetPasswordAsync(model.ToUser(user), model.MasterPasswordHash, model.Key,
var result = await _setInitialMasterPasswordCommand.SetInitialMasterPasswordAsync(
model.ToUser(user),
model.MasterPasswordHash,
model.Key,
model.OrgIdentifier);

if (result.Succeeded)
{
return;
Expand Down Expand Up @@ -456,8 +466,13 @@ public async Task<ProfileResponseModel> GetProfile()
var providerUserOrganizationDetails =
await _providerUserRepository.GetManyOrganizationDetailsByUserAsync(user.Id,
ProviderUserStatusType.Confirmed);

var twoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
var hasPremiumFromOrg = await _userService.HasPremiumFromOrganization(user);

var response = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
providerUserOrganizationDetails, await _userService.TwoFactorIsEnabledAsync(user), await _userService.HasPremiumFromOrganization(user));
providerUserOrganizationDetails, twoFactorEnabled,
hasPremiumFromOrg);
return response;
}

Expand Down
1 change: 1 addition & 0 deletions src/Api/Vault/Controllers/SyncController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public async Task<SyncResponseModel> Get([FromQuery] bool excludeDomains = false
await _providerUserRepository.GetManyOrganizationDetailsByUserAsync(user.Id,
ProviderUserStatusType.Confirmed);
var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled);

var folders = await _folderRepository.GetManyByUserIdAsync(user.Id);
var ciphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, hasEnabledOrgs);
var sends = await _sendRepository.GetManyByUserIdAsync(user.Id);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Bit.Core.Entities;

namespace Bit.Core.Auth.Models.Business.Tokenables;

public interface IOrgUserInviteTokenableFactory
{
OrgUserInviteTokenable CreateToken(OrganizationUser orgUser);
}
84 changes: 84 additions & 0 deletions src/Core/Auth/Models/Business/Tokenables/OrgUserInviteTokenable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System.Text.Json.Serialization;
using Bit.Core.Entities;
using Bit.Core.Tokens;

namespace Bit.Core.Auth.Models.Business.Tokenables;

public class OrgUserInviteTokenable : ExpiringTokenable
{
// TODO: PM-4317 - Ideally this would be internal and only visible to the test project.
// but configuring that is out of scope for these changes.
public static TimeSpan GetTokenLifetime() => TimeSpan.FromDays(5);

public const string ClearTextPrefix = "BwOrgUserInviteToken_";

// Backwards compatibility Note:
// Previously, tokens were manually created in the OrganizationService using a data protector
// initialized with purpose: "OrganizationServiceDataProtector"
// So, we must continue to use the existing purpose to be able to decrypt tokens
// in emailed invites that have not yet been accepted.
public const string DataProtectorPurpose = "OrganizationServiceDataProtector";
JaredSnider-Bitwarden marked this conversation as resolved.
Show resolved Hide resolved

public const string TokenIdentifier = "OrgUserInviteToken";

public string Identifier { get; set; } = TokenIdentifier;
public Guid OrgUserId { get; set; }
public string OrgUserEmail { get; set; }

[JsonConstructor]
public OrgUserInviteTokenable()
{
ExpirationDate = DateTime.UtcNow.Add(GetTokenLifetime());
}

public OrgUserInviteTokenable(OrganizationUser orgUser) : this()
{
OrgUserId = orgUser?.Id ?? default;
OrgUserEmail = orgUser?.Email;
}

public bool TokenIsValid(OrganizationUser orgUser)
{
if (OrgUserId == default || OrgUserEmail == default || orgUser == null)
{
return false;
}

return OrgUserId == orgUser.Id &&
OrgUserEmail.Equals(orgUser.Email, StringComparison.InvariantCultureIgnoreCase);
}

public bool TokenIsValid(Guid orgUserId, string orgUserEmail)
{
if (OrgUserId == default || OrgUserEmail == default || orgUserId == default || orgUserEmail == default)
{
return false;
}

return OrgUserId == orgUserId &&
OrgUserEmail.Equals(orgUserEmail, StringComparison.InvariantCultureIgnoreCase);
}

// Validates deserialized
protected override bool TokenIsValid() =>
Identifier == TokenIdentifier && OrgUserId != default && !string.IsNullOrWhiteSpace(OrgUserEmail);


public static bool ValidateOrgUserInviteStringToken(
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
string orgUserInviteToken, OrganizationUser orgUser)
{
return orgUserInviteTokenDataFactory.TryUnprotect(orgUserInviteToken, out var decryptedToken)
&& decryptedToken.Valid
&& decryptedToken.TokenIsValid(orgUser);
}

public static bool ValidateOrgUserInviteStringToken(
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
string orgUserInviteToken, Guid orgUserId, string orgUserEmail)
{
return orgUserInviteTokenDataFactory.TryUnprotect(orgUserInviteToken, out var decryptedToken)
&& decryptedToken.Valid
&& decryptedToken.TokenIsValid(orgUserId, orgUserEmail);
}
}
Loading
Loading