mirror of
https://github.com/bitwarden/server.git
synced 2025-04-04 20:50:21 -05:00
Fix policy enforcement against invited users (#1680)
This commit is contained in:
parent
07b8e2a946
commit
e57bef6af4
@ -27,10 +27,19 @@ namespace Bit.Core.Repositories.EntityFramework.Queries
|
||||
on pu.ProviderId equals po.ProviderId
|
||||
select po;
|
||||
|
||||
string userEmail = null;
|
||||
if (_minimumStatus == OrganizationUserStatusType.Invited)
|
||||
{
|
||||
// Invited orgUsers do not have a UserId associated with them, so we have to match up their email
|
||||
userEmail = dbContext.Users.Find(_userId)?.Email;
|
||||
}
|
||||
|
||||
var query = from p in dbContext.Policies
|
||||
join ou in dbContext.OrganizationUsers
|
||||
on p.OrganizationId equals ou.OrganizationId
|
||||
where ou.UserId == _userId &&
|
||||
where
|
||||
((_minimumStatus > OrganizationUserStatusType.Invited && ou.UserId == _userId) ||
|
||||
(_minimumStatus == OrganizationUserStatusType.Invited && ou.Email == userEmail)) &&
|
||||
p.Type == _policyType &&
|
||||
p.Enabled &&
|
||||
ou.Status >= _minimumStatus &&
|
||||
|
@ -23,7 +23,16 @@ LEFT JOIN
|
||||
ON PUPO.UserId = OU.UserId
|
||||
AND PUPO.OrganizationId = P.OrganizationId
|
||||
WHERE
|
||||
OU.[UserId] = @UserId
|
||||
(
|
||||
(
|
||||
OU.[Status] > 0
|
||||
AND OU.[UserId] = @UserId
|
||||
)
|
||||
OR (
|
||||
OU.[Status] = 0 -- 'Invited' OrgUsers are not linked to a UserId yet, so we have to look up their email
|
||||
AND OU.[Email] IN (SELECT U.Email FROM [dbo].[UserView] U WHERE U.Id = @UserId)
|
||||
)
|
||||
)
|
||||
AND P.[Type] = @PolicyType
|
||||
AND P.[Enabled] = 1
|
||||
AND OU.[Status] >= @MinimumStatus
|
||||
|
@ -60,19 +60,22 @@ namespace Bit.Core.Test.Repositories.EntityFramework
|
||||
}
|
||||
|
||||
[CiSkippedTheory]
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, true, true, false)] // Ordinary user
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.Owner, false, OrganizationUserStatusType.Confirmed, true, true, false)] // Owner
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.Admin, false, OrganizationUserStatusType.Confirmed, true, true, false)] // Admin
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, true, OrganizationUserStatusType.Confirmed, true, true, false)] // canManagePolicies
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, true, true, true)] // Provider
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, false, true, false)] // Policy disabled
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, true, false, false)] // No policy of Type
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Invited, true, true, false)] // User not minStatus
|
||||
public async void GetManyByTypeApplicableToUser_Works_DataMatches_Corre(
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, false, true, true, false)] // Ordinary user
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Invited, true, true, true, false)] // Invited user
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.Owner, false, OrganizationUserStatusType.Confirmed, false, true, true, false)] // Owner
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.Admin, false, OrganizationUserStatusType.Confirmed, false, true, true, false)] // Admin
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, true, OrganizationUserStatusType.Confirmed, false, true, true, false)] // canManagePolicies
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, false, true, true, true)] // Provider
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, false, false, true, false)] // Policy disabled
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, false, true, false, false)] // No policy of Type
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Invited, false, true, true, false)] // User not minStatus
|
||||
|
||||
public async void GetManyByTypeApplicableToUser_Works_DataMatches(
|
||||
// Inline data
|
||||
OrganizationUserType userType,
|
||||
bool canManagePolicies,
|
||||
OrganizationUserStatusType orgUserStatus,
|
||||
bool includeInvited,
|
||||
bool policyEnabled,
|
||||
bool policySameType,
|
||||
bool isProvider,
|
||||
@ -147,7 +150,17 @@ namespace Bit.Core.Test.Repositories.EntityFramework
|
||||
var savedUser = await userRepos[i].CreateAsync(user);
|
||||
var savedOrg = await orgRepos[i].CreateAsync(organization);
|
||||
|
||||
orgUser.UserId = savedUser.Id;
|
||||
// Invited orgUsers are not associated with an account yet, so they are identified by Email not UserId
|
||||
if (orgUserStatus == OrganizationUserStatusType.Invited)
|
||||
{
|
||||
orgUser.Email = savedUser.Email;
|
||||
orgUser.UserId = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
orgUser.UserId = savedUser.Id;
|
||||
}
|
||||
|
||||
orgUser.OrganizationId = savedOrg.Id;
|
||||
await orgUserRepos[i].CreateAsync(orgUser);
|
||||
|
||||
@ -171,8 +184,10 @@ namespace Bit.Core.Test.Repositories.EntityFramework
|
||||
(policyRepo as BaseEntityFrameworkRepository).ClearChangeTracking();
|
||||
}
|
||||
|
||||
var minStatus = includeInvited ? OrganizationUserStatusType.Invited : OrganizationUserStatusType.Accepted;
|
||||
|
||||
// Act
|
||||
var result = await policyRepo.GetManyByTypeApplicableToUserIdAsync(savedUser.Id, queriedPolicyType, OrganizationUserStatusType.Accepted);
|
||||
var result = await policyRepo.GetManyByTypeApplicableToUserIdAsync(savedUser.Id, queriedPolicyType, minStatus);
|
||||
results.Add(result.FirstOrDefault());
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,52 @@
|
||||
-- PolicyApplicableToUser
|
||||
IF OBJECT_ID('[dbo].[PolicyApplicableToUser]') IS NOT NULL
|
||||
BEGIN
|
||||
DROP FUNCTION [dbo].[PolicyApplicableToUser]
|
||||
END
|
||||
GO
|
||||
|
||||
CREATE FUNCTION [dbo].[PolicyApplicableToUser]
|
||||
(
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@PolicyType TINYINT,
|
||||
@MinimumStatus TINYINT
|
||||
)
|
||||
RETURNS TABLE
|
||||
AS RETURN
|
||||
SELECT
|
||||
P.*
|
||||
FROM
|
||||
[dbo].[PolicyView] P
|
||||
INNER JOIN
|
||||
[dbo].[OrganizationUserView] OU ON P.[OrganizationId] = OU.[OrganizationId]
|
||||
LEFT JOIN
|
||||
(SELECT
|
||||
PU.UserId,
|
||||
PO.OrganizationId
|
||||
FROM
|
||||
[dbo].[ProviderUserView] PU
|
||||
INNER JOIN
|
||||
[ProviderOrganizationView] PO ON PO.[ProviderId] = PU.[ProviderId]) PUPO
|
||||
ON PUPO.UserId = OU.UserId
|
||||
AND PUPO.OrganizationId = P.OrganizationId
|
||||
WHERE
|
||||
(
|
||||
(
|
||||
OU.[Status] > 0
|
||||
AND OU.[UserId] = @UserId
|
||||
)
|
||||
OR (
|
||||
OU.[Status] = 0 -- 'Invited' OrgUsers are not associated with a UserId yet, so we have to look up their email
|
||||
AND OU.[Email] IN (SELECT U.Email FROM [dbo].[UserView] U WHERE U.Id = @UserId)
|
||||
)
|
||||
)
|
||||
AND P.[Type] = @PolicyType
|
||||
AND P.[Enabled] = 1
|
||||
AND OU.[Status] >= @MinimumStatus
|
||||
AND OU.[Type] >= 2 -- Not an owner (0) or admin (1)
|
||||
AND ( -- Can't manage policies
|
||||
OU.[Permissions] IS NULL
|
||||
OR COALESCE(JSON_VALUE(OU.[Permissions], '$.managePolicies'), 'false') = 'false'
|
||||
)
|
||||
AND PUPO.[UserId] IS NULL -- Not a provider
|
||||
GO
|
Loading…
x
Reference in New Issue
Block a user