Browse Source
* [AC-1192] Create new OrganizationAuthRequestsController.cs * [AC-1192] Introduce OrganizationAdminAuthRequest model * [AC-1192] Add GetManyPendingByOrganizationId method to AuthRequest repository * [AC-1192] Add new list pending organization auth requests endpoint * [AC-1192] Add new GetManyAdminApprovalsByManyIdsAsync method to the AuthRequestRepository * [AC-1192] Make the response device identifier optional for admin approval requests * [AC-1192] Add endpoint for bulk denying admin device auth requests * [AC-1192] Add OrganizationUserId to PendingOrganizationAuthRequestResponseModel * [AC-1192] Add UpdateAuthRequest endpoint and logic to OrganizationAuthRequestsController * [AC-1192] Secure new endpoints behind TDE feature flag * [AC-1192] Formatting * [AC-1192] Add sql migration script * [AC-1192] Add optional OrganizationId column to AuthRequest entity - Rename migration script to match existing formatting - Add new column - Add migration scripts - Update new sprocs to filter/join on OrganizationId - Update old sprocs to include OrganizationId * [AC-1192] Format migration scripts * [AC-1192] Fix failing AuthRequest EF unit test * [AC-1192] Make OrganizationId optional in updated AuthRequest sprocs for backwards compatability * [AC-1192] Fix missing comma in migration file * [AC-1192] Rename Key to EncryptedUserKey to be more descriptive * [AC-1192] Move request validation into helper method to reduce repetition * [AC-1192] Return UnauthorizedAccessException instead of NotFound when user is missing permission * [AC-1192] Introduce FeatureUnavailableException * [AC-1192] Introduce RequireFeatureAttribute * [AC-1192] Utilize the new RequireFeatureAttribute in the OrganizationAuthRequestsController * [AC-1192] Attempt to fix out of sync database migration by moving new OrganizationId column * [AC-1192] More attempts to sync database migrations * [AC-1192] Formatting * [AC-1192] Remove unused reference to FeatureService * [AC-1192] Change Id types from String to Guid * [AC-1192] Add EncryptedString attribute * [AC-1192] Remove redundant OrganizationId property * [AC-1192] Switch to projection for OrganizationAdminAuthRequest mapping - Add new OrganizationUser relationship to EF entity - Replace AuthRequest DBContext config with new IEntityTypeConfiguration - Add navigation property to AuthRequest entity configuration for OrganizationUser - Update EF AuthRequestRepository to use new mapping and navigation properties * [AC-1192] Remove OrganizationUser navigation propertypull/3025/head
34 changed files with 7417 additions and 11 deletions
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations; |
||||
using Bit.Core.Utilities; |
||||
|
||||
namespace Bit.Api.Auth.Models.Request; |
||||
|
||||
public class AdminAuthRequestUpdateRequestModel |
||||
{ |
||||
[EncryptedString] |
||||
public string EncryptedUserKey { get; set; } |
||||
|
||||
[Required] |
||||
public bool RequestApproved { get; set; } |
||||
} |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
namespace Bit.Api.Auth.Models.Request; |
||||
|
||||
public class BulkDenyAdminAuthRequestRequestModel |
||||
{ |
||||
public IEnumerable<Guid> Ids { get; set; } |
||||
} |
||||
@ -0,0 +1,38 @@
@@ -0,0 +1,38 @@
|
||||
using System.ComponentModel.DataAnnotations; |
||||
using System.Reflection; |
||||
using Bit.Core.Auth.Models.Data; |
||||
using Bit.Core.Models.Api; |
||||
|
||||
namespace Bit.Api.Auth.Models.Response; |
||||
|
||||
public class PendingOrganizationAuthRequestResponseModel : ResponseModel |
||||
{ |
||||
public PendingOrganizationAuthRequestResponseModel(OrganizationAdminAuthRequest authRequest, string obj = "pending-org-auth-request") : base(obj) |
||||
{ |
||||
if (authRequest == null) |
||||
{ |
||||
throw new ArgumentNullException(nameof(authRequest)); |
||||
} |
||||
|
||||
Id = authRequest.Id; |
||||
UserId = authRequest.UserId; |
||||
OrganizationUserId = authRequest.OrganizationUserId; |
||||
Email = authRequest.Email; |
||||
PublicKey = authRequest.PublicKey; |
||||
RequestDeviceIdentifier = authRequest.RequestDeviceIdentifier; |
||||
RequestDeviceType = authRequest.RequestDeviceType.GetType().GetMember(authRequest.RequestDeviceType.ToString()) |
||||
.FirstOrDefault()?.GetCustomAttribute<DisplayAttribute>()?.GetName(); |
||||
RequestIpAddress = authRequest.RequestIpAddress; |
||||
CreationDate = authRequest.CreationDate; |
||||
} |
||||
|
||||
public Guid Id { get; set; } |
||||
public Guid UserId { get; set; } |
||||
public Guid OrganizationUserId { get; set; } |
||||
public string Email { get; set; } |
||||
public string PublicKey { get; set; } |
||||
public string RequestDeviceIdentifier { get; set; } |
||||
public string RequestDeviceType { get; set; } |
||||
public string RequestIpAddress { get; set; } |
||||
public DateTime CreationDate { get; set; } |
||||
} |
||||
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
using Bit.Api.Auth.Models.Request; |
||||
using Bit.Api.Auth.Models.Response; |
||||
using Bit.Api.Models.Response; |
||||
using Bit.Core; |
||||
using Bit.Core.Auth.Models.Api.Request.AuthRequest; |
||||
using Bit.Core.Auth.Services; |
||||
using Bit.Core.Context; |
||||
using Bit.Core.Exceptions; |
||||
using Bit.Core.Repositories; |
||||
using Bit.Core.Utilities; |
||||
using Microsoft.AspNetCore.Authorization; |
||||
using Microsoft.AspNetCore.Mvc; |
||||
|
||||
namespace Bit.Api.Controllers; |
||||
|
||||
[Route("organizations/{orgId}/auth-requests")] |
||||
[Authorize("Application")] |
||||
[RequireFeature(FeatureFlagKeys.TrustedDeviceEncryption)] |
||||
public class OrganizationAuthRequestsController : Controller |
||||
{ |
||||
private readonly IAuthRequestRepository _authRequestRepository; |
||||
private readonly ICurrentContext _currentContext; |
||||
private readonly IAuthRequestService _authRequestService; |
||||
|
||||
public OrganizationAuthRequestsController(IAuthRequestRepository authRequestRepository, |
||||
ICurrentContext currentContext, IAuthRequestService authRequestService) |
||||
{ |
||||
_authRequestRepository = authRequestRepository; |
||||
_currentContext = currentContext; |
||||
_authRequestService = authRequestService; |
||||
} |
||||
|
||||
[HttpGet("")] |
||||
public async Task<ListResponseModel<PendingOrganizationAuthRequestResponseModel>> GetPendingRequests(Guid orgId) |
||||
{ |
||||
await ValidateAdminRequest(orgId); |
||||
|
||||
var authRequests = await _authRequestRepository.GetManyPendingByOrganizationIdAsync(orgId); |
||||
var responses = authRequests |
||||
.Select(a => new PendingOrganizationAuthRequestResponseModel(a)) |
||||
.ToList(); |
||||
return new ListResponseModel<PendingOrganizationAuthRequestResponseModel>(responses); |
||||
} |
||||
|
||||
[HttpPost("{requestId}")] |
||||
public async Task UpdateAuthRequest(Guid orgId, Guid requestId, [FromBody] AdminAuthRequestUpdateRequestModel model) |
||||
{ |
||||
await ValidateAdminRequest(orgId); |
||||
|
||||
var authRequest = |
||||
(await _authRequestRepository.GetManyAdminApprovalRequestsByManyIdsAsync(orgId, new[] { requestId })).FirstOrDefault(); |
||||
|
||||
if (authRequest == null || authRequest.OrganizationId != orgId) |
||||
{ |
||||
throw new NotFoundException(); |
||||
} |
||||
|
||||
await _authRequestService.UpdateAuthRequestAsync(authRequest.Id, authRequest.UserId, |
||||
new AuthRequestUpdateRequestModel { RequestApproved = model.RequestApproved, Key = model.EncryptedUserKey }); |
||||
} |
||||
|
||||
[HttpPost("deny")] |
||||
public async Task BulkDenyRequests(Guid orgId, [FromBody] BulkDenyAdminAuthRequestRequestModel model) |
||||
{ |
||||
await ValidateAdminRequest(orgId); |
||||
|
||||
var authRequests = await _authRequestRepository.GetManyAdminApprovalRequestsByManyIdsAsync(orgId, model.Ids); |
||||
|
||||
foreach (var authRequest in authRequests) |
||||
{ |
||||
await _authRequestService.UpdateAuthRequestAsync(authRequest.Id, authRequest.UserId, |
||||
new AuthRequestUpdateRequestModel { RequestApproved = false, }); |
||||
} |
||||
} |
||||
|
||||
private async Task ValidateAdminRequest(Guid orgId) |
||||
{ |
||||
if (!await _currentContext.ManageResetPassword(orgId)) |
||||
{ |
||||
throw new UnauthorizedAccessException(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
using Bit.Core.Auth.Entities; |
||||
using Bit.Core.Auth.Enums; |
||||
|
||||
namespace Bit.Core.Auth.Models.Data; |
||||
|
||||
/// <summary> |
||||
/// Represents an <see cref="AuthRequestType.AdminApproval"/> AuthRequest. |
||||
/// Includes additional user and organization information. |
||||
/// </summary> |
||||
public class OrganizationAdminAuthRequest : AuthRequest |
||||
{ |
||||
/// <summary> |
||||
/// Email address of the requesting user |
||||
/// </summary> |
||||
public string Email { get; set; } |
||||
|
||||
public Guid OrganizationUserId { get; set; } |
||||
} |
||||
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
namespace Bit.Core.Exceptions; |
||||
|
||||
/// <summary> |
||||
/// Exception to throw when a requested feature is not yet enabled/available for the requesting context. |
||||
/// </summary> |
||||
public class FeatureUnavailableException : NotFoundException |
||||
{ |
||||
public FeatureUnavailableException() |
||||
{ } |
||||
|
||||
public FeatureUnavailableException(string message) |
||||
: base(message) |
||||
{ } |
||||
} |
||||
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
using Bit.Core.Context; |
||||
using Bit.Core.Exceptions; |
||||
using Bit.Core.Services; |
||||
using Microsoft.AspNetCore.Mvc.Filters; |
||||
using Microsoft.Extensions.DependencyInjection; |
||||
|
||||
namespace Bit.Core.Utilities; |
||||
|
||||
/// <summary> |
||||
/// Specifies that the class or method that this attribute is applied to requires the specified boolean feature flag |
||||
/// to be enabled. If the feature flag is not enabled, a <see cref="FeatureUnavailableException"/> is thrown |
||||
/// </summary> |
||||
public class RequireFeatureAttribute : ActionFilterAttribute |
||||
{ |
||||
private readonly string _featureFlagKey; |
||||
|
||||
/// <summary> |
||||
/// Initializes a new instance of the <see cref="RequireFeatureAttribute"/> class with the specified feature flag key. |
||||
/// </summary> |
||||
/// <param name="featureFlagKey">The name of the feature flag to require.</param> |
||||
public RequireFeatureAttribute(string featureFlagKey) |
||||
{ |
||||
_featureFlagKey = featureFlagKey; |
||||
} |
||||
|
||||
public override void OnActionExecuting(ActionExecutingContext context) |
||||
{ |
||||
var currentContext = context.HttpContext.RequestServices.GetRequiredService<ICurrentContext>(); |
||||
var featureService = context.HttpContext.RequestServices.GetRequiredService<IFeatureService>(); |
||||
|
||||
if (!featureService.IsEnabled(_featureFlagKey, currentContext)) |
||||
{ |
||||
throw new FeatureUnavailableException(); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
using Bit.Infrastructure.EntityFramework.Auth.Models; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders; |
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Auth.Configurations; |
||||
|
||||
public class AuthRequestConfiguration : IEntityTypeConfiguration<AuthRequest> |
||||
{ |
||||
public void Configure(EntityTypeBuilder<AuthRequest> builder) |
||||
{ |
||||
builder.Property(ar => ar.Id).ValueGeneratedNever(); |
||||
builder.ToTable(nameof(AuthRequest)); |
||||
} |
||||
} |
||||
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
CREATE PROCEDURE [dbo].[AuthRequest_ReadAdminApprovalsByIds] |
||||
@OrganizationId UNIQUEIDENTIFIER, |
||||
@Ids AS [dbo].[GuidIdArray] READONLY |
||||
AS |
||||
BEGIN |
||||
SET NOCOUNT ON |
||||
|
||||
SELECT |
||||
ar.*, ou.[Email], ou.[Id] AS [OrganizationUserId] |
||||
FROM |
||||
[dbo].[AuthRequestView] ar |
||||
INNER JOIN |
||||
[dbo].[OrganizationUser] ou ON ou.[UserId] = ar.[UserId] AND ou.[OrganizationId] = ar.[OrganizationId] |
||||
WHERE |
||||
ar.[OrganizationId] = @OrganizationId |
||||
AND |
||||
ar.[Type] = 2 -- AdminApproval |
||||
AND |
||||
ar.[Id] IN (SELECT [Id] FROM @Ids) |
||||
END |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
CREATE PROCEDURE [dbo].[AuthRequest_ReadPendingByOrganizationId] |
||||
@OrganizationId UNIQUEIDENTIFIER |
||||
AS |
||||
BEGIN |
||||
SET NOCOUNT ON |
||||
|
||||
SELECT |
||||
ar.*, ou.[Email], ou.[OrganizationId], ou.[Id] AS [OrganizationUserId] |
||||
FROM |
||||
[dbo].[AuthRequestView] ar |
||||
INNER JOIN |
||||
[dbo].[OrganizationUser] ou ON ou.[UserId] = ar.[UserId] AND ou.[OrganizationId] = ar.[OrganizationId] |
||||
WHERE |
||||
ar.[OrganizationId] = @OrganizationId |
||||
AND |
||||
ar.[ResponseDate] IS NULL |
||||
AND |
||||
ar.[Type] = 2 -- AdminApproval |
||||
END |
||||
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
using Bit.Core.Context; |
||||
using Bit.Core.Exceptions; |
||||
using Bit.Core.Services; |
||||
using Bit.Core.Utilities; |
||||
using Microsoft.AspNetCore.Http; |
||||
using Microsoft.AspNetCore.Mvc; |
||||
using Microsoft.AspNetCore.Mvc.Abstractions; |
||||
using Microsoft.AspNetCore.Mvc.Filters; |
||||
using Microsoft.AspNetCore.Routing; |
||||
using Microsoft.Extensions.DependencyInjection; |
||||
using NSubstitute; |
||||
using Xunit; |
||||
|
||||
namespace Bit.Core.Test.Utilities; |
||||
|
||||
public class RequireFeatureAttributeTests |
||||
{ |
||||
private const string _testFeature = "test-feature"; |
||||
|
||||
[Fact] |
||||
public void Throws_When_Feature_Disabled() |
||||
{ |
||||
// Arrange |
||||
var rfa = new RequireFeatureAttribute(_testFeature); |
||||
|
||||
// Act & Assert |
||||
Assert.Throws<FeatureUnavailableException>(() => rfa.OnActionExecuting(GetContext(enabled: false))); |
||||
} |
||||
|
||||
[Fact] |
||||
public void Throws_When_Feature_Not_Found() |
||||
{ |
||||
// Arrange |
||||
var rfa = new RequireFeatureAttribute("missing-feature"); |
||||
|
||||
// Act & Assert |
||||
Assert.Throws<FeatureUnavailableException>(() => rfa.OnActionExecuting(GetContext(enabled: false))); |
||||
} |
||||
|
||||
[Fact] |
||||
public void Success_When_Feature_Enabled() |
||||
{ |
||||
// Arrange |
||||
var rfa = new RequireFeatureAttribute(_testFeature); |
||||
|
||||
// Act |
||||
rfa.OnActionExecuting(GetContext(enabled: true)); |
||||
|
||||
// Assert |
||||
// The Assert here is NOT throwing an exception |
||||
} |
||||
|
||||
|
||||
/// <summary> |
||||
/// Generates a ActionExecutingContext with the necessary services registered to test |
||||
/// the <see cref="RequireFeatureAttribute"/> |
||||
/// </summary> |
||||
/// <param name="enabled">Mock value for the <see cref="_testFeature"/> flag</param> |
||||
/// <returns></returns> |
||||
private static ActionExecutingContext GetContext(bool enabled) |
||||
{ |
||||
IServiceCollection services = new ServiceCollection(); |
||||
|
||||
var featureService = Substitute.For<IFeatureService>(); |
||||
var currentContext = Substitute.For<ICurrentContext>(); |
||||
|
||||
featureService.IsEnabled(_testFeature, Arg.Any<ICurrentContext>()).Returns(enabled); |
||||
|
||||
services.AddSingleton(featureService); |
||||
services.AddSingleton(currentContext); |
||||
|
||||
var httpContext = new DefaultHttpContext(); |
||||
httpContext.RequestServices = services.BuildServiceProvider(); |
||||
|
||||
var context = Substitute.For<ActionExecutingContext>( |
||||
Substitute.For<ActionContext>(httpContext, |
||||
new RouteData(), |
||||
Substitute.For<ActionDescriptor>()), |
||||
new List<IFilterMetadata>(), |
||||
new Dictionary<string, object>(), |
||||
Substitute.For<Controller>()); |
||||
|
||||
return context; |
||||
} |
||||
} |
||||
@ -0,0 +1,193 @@
@@ -0,0 +1,193 @@
|
||||
--Add OrganizationId Column and Foreign Key |
||||
IF COL_LENGTH('[dbo].[AuthRequest]', 'OrganizationId') IS NULL |
||||
BEGIN |
||||
ALTER TABLE |
||||
[dbo].[AuthRequest] |
||||
ADD [OrganizationId] UNIQUEIDENTIFIER NULL; |
||||
ALTER TABLE |
||||
[dbo].[AuthRequest] |
||||
ADD CONSTRAINT [FK_AuthRequest_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) |
||||
END |
||||
GO |
||||
|
||||
-- Drop and recreate view |
||||
IF EXISTS(SELECT * FROM sys.views WHERE [Name] = 'AuthRequestView') |
||||
BEGIN |
||||
DROP VIEW [dbo].[AuthRequestView] |
||||
END |
||||
GO |
||||
|
||||
CREATE VIEW [dbo].[AuthRequestView] |
||||
AS |
||||
SELECT |
||||
* |
||||
FROM |
||||
[dbo].[AuthRequest] |
||||
GO |
||||
|
||||
--Drop existing SPROC |
||||
IF OBJECT_ID('[dbo].[AuthRequest_Update]') IS NOT NULL |
||||
BEGIN |
||||
DROP PROCEDURE [dbo].[AuthRequest_Update] |
||||
END |
||||
GO |
||||
|
||||
--Create SPROC with OrganizationId column |
||||
CREATE PROCEDURE [dbo].[AuthRequest_Update] |
||||
@Id UNIQUEIDENTIFIER OUTPUT, |
||||
@UserId UNIQUEIDENTIFIER, |
||||
@OrganizationId UNIQUEIDENTIFIER = NULL, |
||||
@Type SMALLINT, |
||||
@RequestDeviceIdentifier NVARCHAR(50), |
||||
@RequestDeviceType SMALLINT, |
||||
@RequestIpAddress VARCHAR(50), |
||||
@ResponseDeviceId UNIQUEIDENTIFIER, |
||||
@AccessCode VARCHAR(25), |
||||
@PublicKey VARCHAR(MAX), |
||||
@Key VARCHAR(MAX), |
||||
@MasterPasswordHash VARCHAR(MAX), |
||||
@Approved BIT, |
||||
@CreationDate DATETIME2 (7), |
||||
@ResponseDate DATETIME2 (7), |
||||
@AuthenticationDate DATETIME2 (7) |
||||
AS |
||||
BEGIN |
||||
SET NOCOUNT ON |
||||
|
||||
UPDATE |
||||
[dbo].[AuthRequest] |
||||
SET |
||||
[UserId] = @UserId, |
||||
[Type] = @Type, |
||||
[OrganizationId] = @OrganizationId, |
||||
[RequestDeviceIdentifier] = @RequestDeviceIdentifier, |
||||
[RequestDeviceType] = @RequestDeviceType, |
||||
[RequestIpAddress] = @RequestIpAddress, |
||||
[ResponseDeviceId] = @ResponseDeviceId, |
||||
[AccessCode] = @AccessCode, |
||||
[PublicKey] = @PublicKey, |
||||
[Key] = @Key, |
||||
[MasterPasswordHash] = @MasterPasswordHash, |
||||
[Approved] = @Approved, |
||||
[CreationDate] = @CreationDate, |
||||
[ResponseDate] = @ResponseDate, |
||||
[AuthenticationDate] = @AuthenticationDate |
||||
WHERE |
||||
[Id] = @Id |
||||
END |
||||
GO |
||||
|
||||
--Drop existing SPROC |
||||
IF OBJECT_ID('[dbo].[AuthRequest_Create]') IS NOT NULL |
||||
BEGIN |
||||
DROP PROCEDURE [dbo].[AuthRequest_Create] |
||||
END |
||||
GO |
||||
|
||||
--Create SPROC with OrganizationId column |
||||
CREATE PROCEDURE [dbo].[AuthRequest_Create] |
||||
@Id UNIQUEIDENTIFIER OUTPUT, |
||||
@UserId UNIQUEIDENTIFIER, |
||||
@OrganizationId UNIQUEIDENTIFIER = NULL, |
||||
@Type TINYINT, |
||||
@RequestDeviceIdentifier NVARCHAR(50), |
||||
@RequestDeviceType TINYINT, |
||||
@RequestIpAddress VARCHAR(50), |
||||
@ResponseDeviceId UNIQUEIDENTIFIER, |
||||
@AccessCode VARCHAR(25), |
||||
@PublicKey VARCHAR(MAX), |
||||
@Key VARCHAR(MAX), |
||||
@MasterPasswordHash VARCHAR(MAX), |
||||
@Approved BIT, |
||||
@CreationDate DATETIME2(7), |
||||
@ResponseDate DATETIME2(7), |
||||
@AuthenticationDate DATETIME2(7) |
||||
AS |
||||
BEGIN |
||||
SET NOCOUNT ON |
||||
|
||||
INSERT INTO [dbo].[AuthRequest] |
||||
( |
||||
[Id], |
||||
[UserId], |
||||
[OrganizationId], |
||||
[Type], |
||||
[RequestDeviceIdentifier], |
||||
[RequestDeviceType], |
||||
[RequestIpAddress], |
||||
[ResponseDeviceId], |
||||
[AccessCode], |
||||
[PublicKey], |
||||
[Key], |
||||
[MasterPasswordHash], |
||||
[Approved], |
||||
[CreationDate], |
||||
[ResponseDate], |
||||
[AuthenticationDate] |
||||
) |
||||
VALUES |
||||
( |
||||
@Id, |
||||
@UserId, |
||||
@OrganizationId, |
||||
@Type, |
||||
@RequestDeviceIdentifier, |
||||
@RequestDeviceType, |
||||
@RequestIpAddress, |
||||
@ResponseDeviceId, |
||||
@AccessCode, |
||||
@PublicKey, |
||||
@Key, |
||||
@MasterPasswordHash, |
||||
@Approved, |
||||
@CreationDate, |
||||
@ResponseDate, |
||||
@AuthenticationDate |
||||
) |
||||
END |
||||
Go |
||||
|
||||
-- New SPROC |
||||
CREATE OR ALTER PROCEDURE [dbo].[AuthRequest_ReadAdminApprovalsByIds] |
||||
@OrganizationId UNIQUEIDENTIFIER, |
||||
@Ids AS [dbo].[GuidIdArray] READONLY |
||||
AS |
||||
BEGIN |
||||
SET NOCOUNT ON |
||||
|
||||
SELECT |
||||
ar.*, ou.[Email], ou.[Id] AS [OrganizationUserId] |
||||
FROM |
||||
[dbo].[AuthRequestView] ar |
||||
INNER JOIN |
||||
[dbo].[OrganizationUser] ou ON ou.[UserId] = ar.[UserId] AND ou.[OrganizationId] = ar.[OrganizationId] |
||||
WHERE |
||||
ar.[OrganizationId] = @OrganizationId |
||||
AND |
||||
ar.[Type] = 2 -- AdminApproval |
||||
AND |
||||
ar.[Id] IN (SELECT [Id] FROM @Ids) |
||||
END |
||||
GO |
||||
|
||||
-- New SPROC |
||||
CREATE OR ALTER PROCEDURE [dbo].[AuthRequest_ReadPendingByOrganizationId] |
||||
@OrganizationId UNIQUEIDENTIFIER |
||||
AS |
||||
BEGIN |
||||
SET NOCOUNT ON |
||||
|
||||
SELECT |
||||
ar.*, ou.[Email], ou.[OrganizationId], ou.[Id] AS [OrganizationUserId] |
||||
FROM |
||||
[dbo].[AuthRequestView] ar |
||||
INNER JOIN |
||||
[dbo].[OrganizationUser] ou ON ou.[UserId] = ar.[UserId] AND ou.[OrganizationId] = ar.[OrganizationId] |
||||
WHERE |
||||
ar.[OrganizationId] = @OrganizationId |
||||
AND |
||||
ar.[ResponseDate] IS NULL |
||||
AND |
||||
ar.[Type] = 2 -- AdminApproval |
||||
END |
||||
GO |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
||||
#nullable disable |
||||
|
||||
namespace Bit.MySqlMigrations.Migrations; |
||||
|
||||
public partial class TdeAdminApproval : Migration |
||||
{ |
||||
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.AddColumn<Guid>( |
||||
name: "OrganizationId", |
||||
table: "AuthRequest", |
||||
type: "char(36)", |
||||
nullable: true, |
||||
collation: "ascii_general_ci"); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_AuthRequest_OrganizationId", |
||||
table: "AuthRequest", |
||||
column: "OrganizationId"); |
||||
|
||||
migrationBuilder.AddForeignKey( |
||||
name: "FK_AuthRequest_Organization_OrganizationId", |
||||
table: "AuthRequest", |
||||
column: "OrganizationId", |
||||
principalTable: "Organization", |
||||
principalColumn: "Id"); |
||||
} |
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.DropForeignKey( |
||||
name: "FK_AuthRequest_Organization_OrganizationId", |
||||
table: "AuthRequest"); |
||||
|
||||
migrationBuilder.DropIndex( |
||||
name: "IX_AuthRequest_OrganizationId", |
||||
table: "AuthRequest"); |
||||
|
||||
migrationBuilder.DropColumn( |
||||
name: "OrganizationId", |
||||
table: "AuthRequest"); |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
||||
#nullable disable |
||||
|
||||
namespace Bit.PostgresMigrations.Migrations; |
||||
|
||||
public partial class TdeAdminApproval : Migration |
||||
{ |
||||
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.AddColumn<Guid>( |
||||
name: "OrganizationId", |
||||
table: "AuthRequest", |
||||
type: "uuid", |
||||
nullable: true); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_AuthRequest_OrganizationId", |
||||
table: "AuthRequest", |
||||
column: "OrganizationId"); |
||||
|
||||
migrationBuilder.AddForeignKey( |
||||
name: "FK_AuthRequest_Organization_OrganizationId", |
||||
table: "AuthRequest", |
||||
column: "OrganizationId", |
||||
principalTable: "Organization", |
||||
principalColumn: "Id"); |
||||
} |
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.DropForeignKey( |
||||
name: "FK_AuthRequest_Organization_OrganizationId", |
||||
table: "AuthRequest"); |
||||
|
||||
migrationBuilder.DropIndex( |
||||
name: "IX_AuthRequest_OrganizationId", |
||||
table: "AuthRequest"); |
||||
|
||||
migrationBuilder.DropColumn( |
||||
name: "OrganizationId", |
||||
table: "AuthRequest"); |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations; |
||||
|
||||
#nullable disable |
||||
|
||||
namespace Bit.SqliteMigrations.Migrations; |
||||
|
||||
public partial class TdeAdminApproval : Migration |
||||
{ |
||||
protected override void Up(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.AddColumn<Guid>( |
||||
name: "OrganizationId", |
||||
table: "AuthRequest", |
||||
type: "TEXT", |
||||
nullable: true); |
||||
|
||||
migrationBuilder.CreateIndex( |
||||
name: "IX_AuthRequest_OrganizationId", |
||||
table: "AuthRequest", |
||||
column: "OrganizationId"); |
||||
|
||||
migrationBuilder.AddForeignKey( |
||||
name: "FK_AuthRequest_Organization_OrganizationId", |
||||
table: "AuthRequest", |
||||
column: "OrganizationId", |
||||
principalTable: "Organization", |
||||
principalColumn: "Id"); |
||||
} |
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder) |
||||
{ |
||||
migrationBuilder.DropForeignKey( |
||||
name: "FK_AuthRequest_Organization_OrganizationId", |
||||
table: "AuthRequest"); |
||||
|
||||
migrationBuilder.DropIndex( |
||||
name: "IX_AuthRequest_OrganizationId", |
||||
table: "AuthRequest"); |
||||
|
||||
migrationBuilder.DropColumn( |
||||
name: "OrganizationId", |
||||
table: "AuthRequest"); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue