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

[PM-14378] SecurityTask Authorization Handler #5039

Merged
merged 25 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
69da981
[PM-14378] Introduce GetCipherPermissionsForOrganization query for Daโ€ฆ
shane-melton Dec 6, 2024
c85a930
[PM-14378] Introduce GetCipherPermissionsForOrganization method for Eโ€ฆ
shane-melton Dec 6, 2024
db5bd64
[PM-14378] Add integration tests for new repository method
shane-melton Dec 6, 2024
a03ddee
[PM-14378] Introduce IGetCipherPermissionsForUserQuery CQRS query
shane-melton Dec 6, 2024
532dd07
[PM-14378] Introduce SecurityTaskOperationRequirement
shane-melton Dec 6, 2024
5c38328
[PM-14378] Introduce SecurityTaskAuthorizationHandler.cs
shane-melton Dec 6, 2024
19a1814
[PM-14378] Introduce SecurityTaskOrganizationAuthorizationHandler.cs
shane-melton Dec 6, 2024
df3e424
[PM-14378] Register new authorization handlers
shane-melton Dec 6, 2024
78ea8b5
[PM-14378] Formatting
shane-melton Dec 6, 2024
4d80238
[PM-14378] Add unit tests for GetCipherPermissionsForUserQuery
shane-melton Dec 11, 2024
b40d144
[PM-15378] Cleanup SecurityTaskAuthorizationHandler and add tests
shane-melton Dec 12, 2024
ca15550
[PM-14378] Add tests for SecurityTaskOrganizationAuthorizationHandler
shane-melton Dec 12, 2024
bcf3210
[PM-14378] Formatting
shane-melton Dec 12, 2024
021634c
[PM-14378] Update date in migration file
shane-melton Dec 12, 2024
d222923
Merge branch 'main' into vault/pm-14378/security-task-auth-handler
shane-melton Dec 12, 2024
6eb33cf
Merge branch 'main' into vault/pm-14378/security-task-auth-handler
shane-melton Dec 12, 2024
b10df9b
[PM-14378] Add missing awaits
shane-melton Dec 13, 2024
9cef90b
Merge branch 'main' into vault/pm-14378/security-task-auth-handler
shane-melton Dec 16, 2024
ba85ba3
Merge branch 'main' into vault/pm-14378/security-task-auth-handler
shane-melton Jan 2, 2025
abfa9d5
[PM-14378] Bump migration script date
shane-melton Jan 2, 2025
310e9f5
Merge branch 'main' into vault/pm-14378/security-task-auth-handler
shane-melton Jan 7, 2025
ba511a9
[PM-14378] Remove Unassigned property from OrganizationCipherPermissiโ€ฆ
shane-melton Jan 8, 2025
53d81e2
[PM-14378] Update sproc to use Union All to improve query performance
shane-melton Jan 8, 2025
e3e3947
Merge branch 'main' into vault/pm-14378/security-task-auth-handler
shane-melton Jan 8, 2025
9cd24da
[PM-14378] Bump migration script date
shane-melton Jan 8, 2025
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
3 changes: 3 additions & 0 deletions src/Api/Utilities/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Bit.Core.IdentityServer;
using Bit.Core.Settings;
using Bit.Core.Utilities;
using Bit.Core.Vault.Authorization.SecurityTasks;
using Bit.SharedWeb.Health;
using Bit.SharedWeb.Swagger;
using Microsoft.AspNetCore.Authorization;
Expand Down Expand Up @@ -104,5 +105,7 @@ public static void AddAuthorizationHandlers(this IServiceCollection services)
services.AddScoped<IAuthorizationHandler, CollectionAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, GroupAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, VaultExportAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, SecurityTaskAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, SecurityTaskOrganizationAuthorizationHandler>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
๏ปฟusing Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Vault.Entities;
using Bit.Core.Vault.Models.Data;
using Bit.Core.Vault.Queries;
using Microsoft.AspNetCore.Authorization;

namespace Bit.Core.Vault.Authorization.SecurityTasks;

public class SecurityTaskAuthorizationHandler : AuthorizationHandler<SecurityTaskOperationRequirement, SecurityTask>
{
private readonly ICurrentContext _currentContext;
private readonly IGetCipherPermissionsForUserQuery _getCipherPermissionsForUserQuery;

private readonly Dictionary<Guid, IDictionary<Guid, OrganizationCipherPermission>> _cipherPermissionCache = new();

public SecurityTaskAuthorizationHandler(ICurrentContext currentContext, IGetCipherPermissionsForUserQuery getCipherPermissionsForUserQuery)
{
_currentContext = currentContext;
_getCipherPermissionsForUserQuery = getCipherPermissionsForUserQuery;
}

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
SecurityTaskOperationRequirement requirement,
SecurityTask task)
{
if (!_currentContext.UserId.HasValue)
{
return;

Check warning on line 29 in src/Core/Vault/Authorization/SecurityTasks/SecurityTaskAuthorizationHandler.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Vault/Authorization/SecurityTasks/SecurityTaskAuthorizationHandler.cs#L28-L29

Added lines #L28 - L29 were not covered by tests
}

var org = _currentContext.GetOrganization(task.OrganizationId);

if (org == null)
{
// User must be a member of the organization
return;
}

var authorized = requirement switch
{
not null when requirement == SecurityTaskOperations.Read => await CanReadAsync(task, org),
not null when requirement == SecurityTaskOperations.Create => await CanCreateAsync(task, org),
not null when requirement == SecurityTaskOperations.Update => await CanUpdateAsync(task, org),
_ => throw new ArgumentOutOfRangeException(nameof(requirement), requirement, null)

Check warning on line 45 in src/Core/Vault/Authorization/SecurityTasks/SecurityTaskAuthorizationHandler.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Vault/Authorization/SecurityTasks/SecurityTaskAuthorizationHandler.cs#L45

Added line #L45 was not covered by tests
};

if (authorized)
{
context.Succeed(requirement);
}
}

private async Task<bool> CanReadAsync(SecurityTask task, CurrentContextOrganization org)
{
if (!task.CipherId.HasValue)
{
// Tasks without cipher IDs are not possible currently
return false;
}

if (HasAdminAccessToSecurityTasks(org))
{
// Admins can read any task for ciphers in the organization
return await CipherBelongsToOrgAsync(org, task.CipherId.Value);
}

return await CanReadCipherForOrgAsync(org, task.CipherId.Value);
}

private async Task<bool> CanCreateAsync(SecurityTask task, CurrentContextOrganization org)
{
if (!task.CipherId.HasValue)
{
// Tasks without cipher IDs are not possible currently
return false;
}

if (!HasAdminAccessToSecurityTasks(org))
{
// User must be an Admin/Owner or have custom permissions for reporting
return false;
}

return await CipherBelongsToOrgAsync(org, task.CipherId.Value);
}

private async Task<bool> CanUpdateAsync(SecurityTask task, CurrentContextOrganization org)
{
if (!task.CipherId.HasValue)
{
// Tasks without cipher IDs are not possible currently
return false;
}

// Only users that can edit the cipher can update the task
return await CanEditCipherForOrgAsync(org, task.CipherId.Value);
}

private async Task<bool> CanEditCipherForOrgAsync(CurrentContextOrganization org, Guid cipherId)
{
var ciphers = await GetCipherPermissionsForOrgAsync(org);

return ciphers.TryGetValue(cipherId, out var cipher) && cipher.Edit;
}

private async Task<bool> CanReadCipherForOrgAsync(CurrentContextOrganization org, Guid cipherId)
{
var ciphers = await GetCipherPermissionsForOrgAsync(org);

return ciphers.TryGetValue(cipherId, out var cipher) && cipher.Read;
}

private async Task<bool> CipherBelongsToOrgAsync(CurrentContextOrganization org, Guid cipherId)
{
var ciphers = await GetCipherPermissionsForOrgAsync(org);

return ciphers.ContainsKey(cipherId);
}

private bool HasAdminAccessToSecurityTasks(CurrentContextOrganization org)
{
return org is
{ Type: OrganizationUserType.Admin or OrganizationUserType.Owner } or
{ Type: OrganizationUserType.Custom, Permissions.AccessReports: true };
}

private async Task<IDictionary<Guid, OrganizationCipherPermission>> GetCipherPermissionsForOrgAsync(CurrentContextOrganization organization)
{
// Re-use permissions we've already fetched for the organization
if (_cipherPermissionCache.TryGetValue(organization.Id, out var cachedCiphers))
{
return cachedCiphers;

Check warning on line 133 in src/Core/Vault/Authorization/SecurityTasks/SecurityTaskAuthorizationHandler.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Vault/Authorization/SecurityTasks/SecurityTaskAuthorizationHandler.cs#L132-L133

Added lines #L132 - L133 were not covered by tests
}

var cipherPermissions = await _getCipherPermissionsForUserQuery.GetByOrganization(organization.Id);

_cipherPermissionCache.Add(organization.Id, cipherPermissions);

return cipherPermissions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
๏ปฟusing Microsoft.AspNetCore.Authorization.Infrastructure;

namespace Bit.Core.Vault.Authorization.SecurityTasks;

public class SecurityTaskOperationRequirement : OperationAuthorizationRequirement
{
public SecurityTaskOperationRequirement(string name)
{
Name = name;
}
}

public static class SecurityTaskOperations
{
public static readonly SecurityTaskOperationRequirement Read = new SecurityTaskOperationRequirement(nameof(Read));
public static readonly SecurityTaskOperationRequirement Create = new SecurityTaskOperationRequirement(nameof(Create));
public static readonly SecurityTaskOperationRequirement Update = new SecurityTaskOperationRequirement(nameof(Update));

/// <summary>
/// List all security tasks for a specific organization.
/// <example><code>
/// var orgContext = _currentContext.GetOrganization(organizationId);
/// _authorizationService.AuthorizeOrThrowAsync(User, SecurityTaskOperations.ListAllForOrganization, orgContext);
/// </code></example>
/// </summary>
public static readonly SecurityTaskOperationRequirement ListAllForOrganization = new SecurityTaskOperationRequirement(nameof(ListAllForOrganization));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
๏ปฟusing Bit.Core.Context;
using Bit.Core.Enums;
using Microsoft.AspNetCore.Authorization;

namespace Bit.Core.Vault.Authorization.SecurityTasks;

public class
SecurityTaskOrganizationAuthorizationHandler : AuthorizationHandler<SecurityTaskOperationRequirement,
CurrentContextOrganization>
{
private readonly ICurrentContext _currentContext;

public SecurityTaskOrganizationAuthorizationHandler(ICurrentContext currentContext)
{
_currentContext = currentContext;
}

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
SecurityTaskOperationRequirement requirement,
CurrentContextOrganization resource)
{
if (!_currentContext.UserId.HasValue)
{
return Task.CompletedTask;
}

var authorized = requirement switch
{
not null when requirement == SecurityTaskOperations.ListAllForOrganization => CanListAllTasksForOrganization(resource),
_ => throw new ArgumentOutOfRangeException(nameof(requirement), requirement, null)

Check warning on line 30 in src/Core/Vault/Authorization/SecurityTasks/SecurityTaskOrganizationAuthorizationHandler.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Vault/Authorization/SecurityTasks/SecurityTaskOrganizationAuthorizationHandler.cs#L30

Added line #L30 was not covered by tests
};

if (authorized)
{
context.Succeed(requirement);
}

return Task.CompletedTask;
}

private static bool CanListAllTasksForOrganization(CurrentContextOrganization org)
{
return org is
{ Type: OrganizationUserType.Admin or OrganizationUserType.Owner } or
{ Type: OrganizationUserType.Custom, Permissions.AccessReports: true };
}
}
40 changes: 40 additions & 0 deletions src/Core/Vault/Models/Data/OrganizationCipherPermission.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
๏ปฟnamespace Bit.Core.Vault.Models.Data;

/// <summary>
/// Data model that represents a Users permissions for a given cipher
/// that belongs to an organization.
/// To be used internally for authorization.
/// </summary>
public class OrganizationCipherPermission
{
/// <summary>
/// The cipher Id
/// </summary>
public Guid Id { get; set; }

/// <summary>
/// The organization Id that the cipher belongs to.
/// </summary>
public Guid OrganizationId { get; set; }

Check warning on line 18 in src/Core/Vault/Models/Data/OrganizationCipherPermission.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Vault/Models/Data/OrganizationCipherPermission.cs#L18

Added line #L18 was not covered by tests

/// <summary>
/// The user can read the cipher.
/// See <see cref="ViewPassword"/> for password visibility.
/// </summary>
public bool Read { get; set; }

/// <summary>
/// The user has permission to view the password of the cipher.
/// </summary>
public bool ViewPassword { get; set; }

/// <summary>
/// The user has permission to edit the cipher.
/// </summary>
public bool Edit { get; set; }

/// <summary>
/// The user has manage level access to the cipher.
/// </summary>
public bool Manage { get; set; }
}
97 changes: 97 additions & 0 deletions src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
๏ปฟusing Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Services;
using Bit.Core.Vault.Models.Data;
using Bit.Core.Vault.Repositories;

namespace Bit.Core.Vault.Queries;

public class GetCipherPermissionsForUserQuery : IGetCipherPermissionsForUserQuery
{
private readonly ICurrentContext _currentContext;
private readonly ICipherRepository _cipherRepository;
private readonly IApplicationCacheService _applicationCacheService;

public GetCipherPermissionsForUserQuery(ICurrentContext currentContext, ICipherRepository cipherRepository, IApplicationCacheService applicationCacheService)
{
_currentContext = currentContext;
_cipherRepository = cipherRepository;
_applicationCacheService = applicationCacheService;
}

public async Task<IDictionary<Guid, OrganizationCipherPermission>> GetByOrganization(Guid organizationId)
{
var org = _currentContext.GetOrganization(organizationId);
var userId = _currentContext.UserId;

if (org == null || !userId.HasValue)
{
throw new NotFoundException();

Check warning on line 30 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs#L29-L30

Added lines #L29 - L30 were not covered by tests
}

var cipherPermissions =
(await _cipherRepository.GetCipherPermissionsForOrganizationAsync(organizationId, userId.Value))
.ToList()
.ToDictionary(c => c.Id);

if (await CanEditAllCiphersAsync(org))
{
foreach (var cipher in cipherPermissions)
{
cipher.Value.Read = true;
cipher.Value.Edit = true;
cipher.Value.Manage = true;
cipher.Value.ViewPassword = true;
}
}
else if (await CanAccessUnassignedCiphersAsync(org))
{
var unassignedCiphers = await _cipherRepository.GetManyUnassignedOrganizationDetailsByOrganizationIdAsync(organizationId);
foreach (var unassignedCipher in unassignedCiphers)
{
if (cipherPermissions.TryGetValue(unassignedCipher.Id, out var p))
{
p.Read = true;
p.Edit = true;
p.Manage = true;
p.ViewPassword = true;
}
}
}

return cipherPermissions;
}

private async Task<bool> CanEditAllCiphersAsync(CurrentContextOrganization org)
{
// Custom users with EditAnyCollection permissions can always edit all ciphers
if (org is { Type: OrganizationUserType.Custom, Permissions.EditAnyCollection: true })
{
return true;
}

var orgAbility = await _applicationCacheService.GetOrganizationAbilityAsync(org.Id);

// Owners/Admins can only edit all ciphers if the organization has the setting enabled
if (orgAbility is { AllowAdminAccessToAllCollectionItems: true } && org is
{ Type: OrganizationUserType.Admin or OrganizationUserType.Owner })
{
return true;
}

return false;
}

private async Task<bool> CanAccessUnassignedCiphersAsync(CurrentContextOrganization org)

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Run validation

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build MSSQL migrator utility (win-x64)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (MsSqlMigratorUtility, ./util, true)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build MSSQL migrator utility (osx-x64)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build MSSQL migrator utility (linux-x64)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Events, ./src)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Setup, ./util)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Identity, ./src)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (EventsProcessor, ./src)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Icons, ./src)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Notifications, ./src)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Scim, ./bitwarden_license/src, true)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Billing, ./src)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Sso, ./bitwarden_license/src, true)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Api, ./src)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Build artifacts (Admin, ./src, true)

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Quality scan

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Run tests

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 86 in src/Core/Vault/Queries/GetCipherPermissionsForUserQuery.cs

View workflow job for this annotation

GitHub Actions / Upload

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
if (org is
{ Type: OrganizationUserType.Owner or OrganizationUserType.Admin } or
{ Permissions.EditAnyCollection: true })
{
return true;
}

return false;
}
}
19 changes: 19 additions & 0 deletions src/Core/Vault/Queries/IGetCipherPermissionsForUserQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
๏ปฟusing Bit.Core.Vault.Models.Data;

namespace Bit.Core.Vault.Queries;

public interface IGetCipherPermissionsForUserQuery
{
/// <summary>
/// Retrieves the permissions of every organization cipher (including unassigned) for the
/// ICurrentContext's user.
///
/// It considers the Collection Management setting for allowing Admin/Owners access to all ciphers.
/// </summary>
/// <remarks>
/// The primary use case of this query is internal cipher authorization logic.
/// </remarks>
/// <param name="organizationId"></param>
/// <returns>A dictionary of CipherIds and a corresponding OrganizationCipherPermission</returns>
public Task<IDictionary<Guid, OrganizationCipherPermission>> GetByOrganization(Guid organizationId);
}
Loading
Loading