-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[PM-10311] Account Management: Create helper methods for checking against verified domains #4636
Changes from 35 commits
113851b
5b7e189
594e5f3
0e9e532
7bdcea7
f34e643
6788d65
c3fd0a0
f3924ad
ee575de
67cd929
4a24b3e
6cd25de
a9dbc31
445f7e4
4d4ec8e
9092295
ca2e727
b6672d1
6785c50
ba52318
2a94bdf
ad03931
f318511
f6cecf0
7ffd16d
fdedcf9
399bf01
8beea6b
e7c7d99
a69b2e3
e612929
e088574
083fe91
d5ef49c
274390c
530c43e
c040638
6254665
a543efd
975e70a
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,41 @@ | ||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; | ||
using Bit.Core.Repositories; | ||
using Bit.Core.Services; | ||
|
||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers; | ||
|
||
public class GetOrganizationUsersManagementStatusQuery : IGetOrganizationUsersManagementStatusQuery | ||
{ | ||
private readonly IApplicationCacheService _applicationCacheService; | ||
private readonly IOrganizationUserRepository _organizationUserRepository; | ||
|
||
public GetOrganizationUsersManagementStatusQuery( | ||
IApplicationCacheService applicationCacheService, | ||
IOrganizationUserRepository organizationUserRepository) | ||
{ | ||
_applicationCacheService = applicationCacheService; | ||
_organizationUserRepository = organizationUserRepository; | ||
} | ||
|
||
public async Task<IDictionary<Guid, bool>> GetUsersOrganizationManagementStatusAsync(Guid organizationId, IEnumerable<Guid> organizationUserIds) | ||
{ | ||
if (organizationUserIds.Any()) | ||
{ | ||
// Users can only be managed by an Organization that is enabled and can have organization domains | ||
var organizationAbility = await _applicationCacheService.GetOrganizationAbilityAsync(organizationId); | ||
|
||
// TODO: Replace "UseSso" with a new organization ability like "UseOrganizationDomains" (PM-11622). | ||
// Verified domains were tied to SSO, so we currently check the "UseSso" organization ability. | ||
if (organizationAbility is { Enabled: true, UseSso: true }) | ||
{ | ||
// Get all organization users with claimed domains by the organization | ||
var organizationUsersWithClaimedDomain = await _organizationUserRepository.GetManyByOrganizationWithClaimedDomainsAsync(organizationId); | ||
|
||
// Create a dictionary with the OrganizationUserId and a boolean indicating if the user is managed by the organization | ||
return organizationUserIds.ToDictionary(ouId => ouId, ouId => organizationUsersWithClaimedDomain.Any(ou => ou.Id == ouId)); | ||
} | ||
} | ||
|
||
return organizationUserIds.ToDictionary(ouId => ouId, _ => false); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; | ||
|
||
public interface IGetOrganizationUsersManagementStatusQuery | ||
{ | ||
/// <summary> | ||
/// Checks whether each user in the provided list of organization user IDs is managed by the specified organization. | ||
/// </summary> | ||
/// <param name="organizationId">The unique identifier of the organization to check against.</param> | ||
/// <param name="organizationUserIds">A list of OrganizationUserIds to be checked.</param> | ||
/// <remarks> | ||
/// A managed user is a user whose email domain matches one of the Organization's verified domains. | ||
/// The organization must be enabled and be on an Enterprise plan. | ||
/// </remarks> | ||
/// <returns> | ||
/// A dictionary containing the OrganizationUserId and a boolean indicating if the user is managed by the organization. | ||
/// </returns> | ||
Task<IDictionary<Guid, bool>> GetUsersOrganizationManagementStatusAsync(Guid organizationId, | ||
IEnumerable<Guid> organizationUserIds); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace Bit.Core.AdminConsole.Services; | ||
|
||
public interface IOrganizationDomainService | ||
{ | ||
Task ValidateOrganizationsDomainAsync(); | ||
Task OrganizationDomainMaintenanceAsync(); | ||
/// <summary> | ||
/// Indicates if the organization has any verified domains. | ||
/// </summary> | ||
Task<bool> HasVerifiedDomainsAsync(Guid orgId); | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
using Bit.Core.Entities; | ||
|
||
namespace Bit.Infrastructure.EntityFramework.Repositories.Queries; | ||
|
||
public class OrganizationUserReadByClaimedOrganizationDomainsQuery : IQuery<OrganizationUser> | ||
{ | ||
private readonly Guid _organizationId; | ||
|
||
public OrganizationUserReadByClaimedOrganizationDomainsQuery(Guid organizationId) | ||
{ | ||
_organizationId = organizationId; | ||
} | ||
Check warning on line 12 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/Queries/OrganizationUserReadByClaimedOrganizationDomainsQuery.cs Codecov / codecov/patchsrc/Infrastructure.EntityFramework/AdminConsole/Repositories/Queries/OrganizationUserReadByClaimedOrganizationDomainsQuery.cs#L9-L12
|
||
|
||
public IQueryable<OrganizationUser> Run(DatabaseContext dbContext) | ||
{ | ||
var query = from ou in dbContext.OrganizationUsers | ||
join u in dbContext.Users on ou.UserId equals u.Id | ||
where ou.OrganizationId == _organizationId | ||
&& dbContext.OrganizationDomains | ||
.Any(od => od.OrganizationId == _organizationId && | ||
od.VerifiedDate != null && | ||
u.Email.ToLower().EndsWith("@" + od.DomainName.ToLower())) | ||
select ou; | ||
Check warning on line 23 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/Queries/OrganizationUserReadByClaimedOrganizationDomainsQuery.cs Codecov / codecov/patchsrc/Infrastructure.EntityFramework/AdminConsole/Repositories/Queries/OrganizationUserReadByClaimedOrganizationDomainsQuery.cs#L15-L23
|
||
|
||
return query; | ||
} | ||
Check warning on line 26 in src/Infrastructure.EntityFramework/AdminConsole/Repositories/Queries/OrganizationUserReadByClaimedOrganizationDomainsQuery.cs Codecov / codecov/patchsrc/Infrastructure.EntityFramework/AdminConsole/Repositories/Queries/OrganizationUserReadByClaimedOrganizationDomainsQuery.cs#L25-L26
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
CREATE PROCEDURE [dbo].[OrganizationUser_ReadByOrganizationIdWithClaimedDomains] | ||
@OrganizationId UNIQUEIDENTIFIER | ||
AS | ||
BEGIN | ||
SET NOCOUNT ON; | ||
|
||
SELECT OU.* | ||
FROM [dbo].[OrganizationUserView] OU | ||
INNER JOIN [dbo].[UserView] U ON OU.[UserId] = U.[Id] | ||
WHERE OU.[OrganizationId] = @OrganizationId | ||
AND EXISTS ( | ||
SELECT 1 | ||
FROM [dbo].[OrganizationDomainView] OD | ||
WHERE OD.[OrganizationId] = @OrganizationId | ||
AND OD.[VerifiedDate] IS NOT NULL | ||
AND U.[Email] LIKE '%@' + OD.[DomainName] | ||
); | ||
END |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
CREATE PROCEDURE [dbo].[Organization_ReadByClaimedUserEmailDomain] | ||
@UserId UNIQUEIDENTIFIER | ||
AS | ||
BEGIN | ||
SET NOCOUNT ON; | ||
|
||
SELECT O.* | ||
FROM [dbo].[UserView] U | ||
INNER JOIN [dbo].[OrganizationUserView] OU ON U.[Id] = OU.[UserId] | ||
INNER JOIN [dbo].[OrganizationView] O ON OU.[OrganizationId] = O.[Id] | ||
INNER JOIN [dbo].[OrganizationDomainView] OD ON OU.[OrganizationId] = OD.[OrganizationId] | ||
WHERE U.[Id] = @UserId | ||
AND OD.[VerifiedDate] IS NOT NULL | ||
AND U.[Email] LIKE '%@' + OD.[DomainName]; | ||
END |
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.
Since we've identified that
UseSso
is not very apt here and are going to improve this as tech debt: lets add a comment here indicating thatUseSso
is used to signify that the organization has access to domain verification. Bonus points if it includes a link to a Jira ticket.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.
I said I'd follow this up, so I've created a ticket for it here that you can link to: https://bitwarden.atlassian.net/browse/PM-11622