mirror of
https://github.com/bitwarden/server
synced 2025-12-28 06:03:29 +00:00
Merge remote-tracking branch 'origin/master' into feature/sm-billing
This commit is contained in:
@@ -287,6 +287,12 @@ public class OrganizationsController : Controller
|
||||
organization.UseTotp = model.UseTotp;
|
||||
organization.UsersGetPremium = model.UsersGetPremium;
|
||||
organization.UseSecretsManager = model.UseSecretsManager;
|
||||
|
||||
//secrets
|
||||
organization.SmSeats = model.SmSeats;
|
||||
organization.MaxAutoscaleSmSeats = model.MaxAutoscaleSmSeats;
|
||||
organization.SmServiceAccounts = model.SmServiceAccounts;
|
||||
organization.MaxAutoscaleSmServiceAccounts = model.MaxAutoscaleSmServiceAccounts;
|
||||
}
|
||||
|
||||
if (_accessControlService.UserHasPermission(Permission.Org_Licensing_Edit))
|
||||
|
||||
@@ -63,6 +63,10 @@ public class OrganizationEditModel : OrganizationViewModel
|
||||
Enabled = org.Enabled;
|
||||
LicenseKey = org.LicenseKey;
|
||||
ExpirationDate = org.ExpirationDate;
|
||||
SmSeats = org.SmSeats;
|
||||
MaxAutoscaleSmSeats = org.MaxAutoscaleSmSeats;
|
||||
SmServiceAccounts = org.SmServiceAccounts;
|
||||
MaxAutoscaleSmServiceAccounts = org.MaxAutoscaleSmServiceAccounts;
|
||||
}
|
||||
|
||||
public BillingInfo BillingInfo { get; set; }
|
||||
@@ -134,6 +138,14 @@ public class OrganizationEditModel : OrganizationViewModel
|
||||
[Display(Name = "Expiration Date")]
|
||||
public DateTime? ExpirationDate { get; set; }
|
||||
public bool SalesAssistedTrialStarted { get; set; }
|
||||
[Display(Name = "Seats")]
|
||||
public int? SmSeats { get; set; }
|
||||
[Display(Name = "Max Autoscale Seats")]
|
||||
public int? MaxAutoscaleSmSeats { get; set; }
|
||||
[Display(Name = "Max Service Accounts")]
|
||||
public int? SmServiceAccounts { get; set; }
|
||||
[Display(Name = "Max Autoscale Service Accounts")]
|
||||
public int? MaxAutoscaleSmServiceAccounts { get; set; }
|
||||
|
||||
public Organization CreateOrganization(Provider provider)
|
||||
{
|
||||
@@ -174,6 +186,10 @@ public class OrganizationEditModel : OrganizationViewModel
|
||||
existingOrganization.LicenseKey = LicenseKey;
|
||||
existingOrganization.ExpirationDate = ExpirationDate;
|
||||
existingOrganization.MaxAutoscaleSeats = MaxAutoscaleSeats;
|
||||
existingOrganization.SmSeats = SmSeats;
|
||||
existingOrganization.MaxAutoscaleSmSeats = MaxAutoscaleSmSeats;
|
||||
existingOrganization.SmServiceAccounts = SmServiceAccounts;
|
||||
existingOrganization.MaxAutoscaleSmServiceAccounts = MaxAutoscaleSmServiceAccounts;
|
||||
return existingOrganization;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,34 +99,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="Seats"></label>
|
||||
<input type="number" class="form-control" asp-for="Seats" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxCollections"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxCollections" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxStorageGb"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxStorageGb" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxAutoscaleSeats"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxAutoscaleSeats" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Features</h2>
|
||||
<div class="row mb-3">
|
||||
<div class="col-4">
|
||||
@@ -200,6 +172,75 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (canViewPlan)
|
||||
{
|
||||
<h2>Password Manager Configuration</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="Seats"></label>
|
||||
<input type="number" class="form-control" asp-for="Seats" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxCollections"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxCollections" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxStorageGb"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxStorageGb" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxAutoscaleSeats"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxAutoscaleSeats" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (canViewPlan)
|
||||
{
|
||||
<div id="organization-secrets-configuration" hidden="@(!Model.UseSecretsManager)">
|
||||
<h2>Secrets Manager Configuration</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="SmSeats"></label>
|
||||
<input type="number" class="form-control" asp-for="SmSeats" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxAutoscaleSmSeats"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxAutoscaleSmSeats" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm">
|
||||
<div class="form-group">
|
||||
<label asp-for="SmServiceAccounts"></label>
|
||||
<input type="number" class="form-control" asp-for="SmServiceAccounts" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<div class="form-group">
|
||||
<label asp-for="MaxAutoscaleSmServiceAccounts"></label>
|
||||
<input type="number" class="form-control" asp-for="MaxAutoscaleSmServiceAccounts" min="1" readonly='@(!canEditPlan)'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if(canViewLicensing)
|
||||
{
|
||||
<h2>Licensing</h2>
|
||||
|
||||
@@ -32,6 +32,18 @@
|
||||
'subscriptions/' + subId.value, '_blank');
|
||||
}
|
||||
});
|
||||
document.getElementById('@(nameof(Model.UseSecretsManager))').addEventListener('change', (event) => {
|
||||
document.getElementById('organization-secrets-configuration').hidden = !event.target.checked;
|
||||
|
||||
if (event.target.checked) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('@(nameof(Model.SmSeats))').value = '';
|
||||
document.getElementById('@(nameof(Model.MaxAutoscaleSmSeats))').value = '';
|
||||
document.getElementById('@(nameof(Model.SmServiceAccounts))').value = '';
|
||||
document.getElementById('@(nameof(Model.MaxAutoscaleSmServiceAccounts))').value = '';
|
||||
});
|
||||
})();
|
||||
|
||||
function togglePlanSettings(planType) {
|
||||
@@ -43,6 +55,10 @@
|
||||
document.getElementById('@(nameof(Model.Seats))').value = '10';
|
||||
document.getElementById('@(nameof(Model.MaxCollections))').value = '';
|
||||
document.getElementById('@(nameof(Model.MaxStorageGb))').value = '1';
|
||||
// Secrets
|
||||
if (document.getElementById('@(nameof(Model.UseSecretsManager))').checked) {
|
||||
document.getElementById('@(nameof(Model.SmServiceAccounts))').value = '50';
|
||||
}
|
||||
// Features
|
||||
document.getElementById('@(nameof(Model.UsePolicies))').checked = false;
|
||||
document.getElementById('@(nameof(Model.UseSso))').checked = false;
|
||||
@@ -69,6 +85,10 @@
|
||||
document.getElementById('@(nameof(Model.Seats))').value = '10';
|
||||
document.getElementById('@(nameof(Model.MaxCollections))').value = '';
|
||||
document.getElementById('@(nameof(Model.MaxStorageGb))').value = '1';
|
||||
// Secrets
|
||||
if (document.getElementById('@(nameof(Model.UseSecretsManager))').checked) {
|
||||
document.getElementById('@(nameof(Model.SmServiceAccounts))').value = '200';
|
||||
}
|
||||
// Features
|
||||
document.getElementById('@(nameof(Model.UsePolicies))').checked = true;
|
||||
document.getElementById('@(nameof(Model.UseSso))').checked = true;
|
||||
|
||||
@@ -2834,7 +2834,7 @@
|
||||
"commercial.core": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0"
|
||||
"Core": "2023.4.3"
|
||||
}
|
||||
},
|
||||
"core": {
|
||||
@@ -2882,7 +2882,7 @@
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Dapper": "2.0.123"
|
||||
}
|
||||
},
|
||||
@@ -2890,7 +2890,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
@@ -2902,7 +2902,7 @@
|
||||
"migrator": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.Extensions.Logging": "6.0.0",
|
||||
"dbup-sqlserver": "5.0.8"
|
||||
}
|
||||
@@ -2910,30 +2910,30 @@
|
||||
"mysqlmigrations": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
},
|
||||
"postgresmigrations": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
},
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.Dapper": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.Dapper": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
},
|
||||
"sqlitemigrations": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,15 @@
|
||||
</Choose>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="6.1.0" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.AzureStorage" Version="6.1.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Network" Version="6.0.4" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="6.0.4" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SendGrid" Version="6.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="6.0.2" />
|
||||
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="6.0.3" />
|
||||
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.10.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Bit.Api.Models.Request;
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
@@ -65,6 +66,15 @@ public class DevicesController : Controller
|
||||
return new ListResponseModel<DeviceResponseModel>(responses);
|
||||
}
|
||||
|
||||
[HttpPost("exist-by-types")]
|
||||
public async Task<ActionResult<bool>> GetExistenceByTypes([FromBody] DeviceType[] deviceTypes)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var devices = await _deviceRepository.GetManyByUserIdAsync(userId);
|
||||
var userHasDeviceOfTypes = devices.Any(d => deviceTypes.Contains(d.Type));
|
||||
return Ok(userHasDeviceOfTypes);
|
||||
}
|
||||
|
||||
[HttpPost("")]
|
||||
public async Task<DeviceResponseModel> Post([FromBody] DeviceRequestModel model)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ using Bit.Core.Identity;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.SecretsManager.AuthorizationRequirements;
|
||||
using Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tools.Enums;
|
||||
@@ -170,9 +171,40 @@ public class SecretsController : Controller
|
||||
[HttpPost("secrets/delete")]
|
||||
public async Task<ListResponseModel<BulkDeleteResponseModel>> BulkDeleteAsync([FromBody] List<Guid> ids)
|
||||
{
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
var results = await _deleteSecretCommand.DeleteSecrets(ids, userId);
|
||||
var responses = results.Select(r => new BulkDeleteResponseModel(r.Item1.Id, r.Item2));
|
||||
var secrets = (await _secretRepository.GetManyByIds(ids)).ToList();
|
||||
if (!secrets.Any() || secrets.Count != ids.Count)
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
// Ensure all secrets belong to the same organization.
|
||||
var organizationId = secrets.First().OrganizationId;
|
||||
if (secrets.Any(secret => secret.OrganizationId != organizationId) ||
|
||||
!_currentContext.AccessSecretsManager(organizationId))
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var secretsToDelete = new List<Secret>();
|
||||
var results = new List<(Secret Secret, string Error)>();
|
||||
|
||||
foreach (var secret in secrets)
|
||||
{
|
||||
var authorizationResult =
|
||||
await _authorizationService.AuthorizeAsync(User, secret, SecretOperations.Delete);
|
||||
if (authorizationResult.Succeeded)
|
||||
{
|
||||
secretsToDelete.Add(secret);
|
||||
results.Add((secret, ""));
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add((secret, "access denied"));
|
||||
}
|
||||
}
|
||||
|
||||
await _deleteSecretCommand.DeleteSecrets(secretsToDelete);
|
||||
var responses = results.Select(r => new BulkDeleteResponseModel(r.Secret.Id, r.Error));
|
||||
return new ListResponseModel<BulkDeleteResponseModel>(responses);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable enable
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
namespace Bit.Api.SecretsManager.Models.Response;
|
||||
|
||||
@@ -8,14 +8,14 @@ public class AccessTokenCreationResponseModel : ResponseModel
|
||||
{
|
||||
private const string _objectName = "accessTokenCreation";
|
||||
|
||||
public AccessTokenCreationResponseModel(ApiKey apiKey) : base(_objectName)
|
||||
public AccessTokenCreationResponseModel(ApiKeyClientSecretDetails details) : base(_objectName)
|
||||
{
|
||||
Id = apiKey.Id;
|
||||
Name = apiKey.Name;
|
||||
ClientSecret = apiKey.ClientSecret;
|
||||
ExpireAt = apiKey.ExpireAt;
|
||||
CreationDate = apiKey.CreationDate;
|
||||
RevisionDate = apiKey.RevisionDate;
|
||||
Id = details.ApiKey.Id;
|
||||
Name = details.ApiKey.Name;
|
||||
ExpireAt = details.ApiKey.ExpireAt;
|
||||
CreationDate = details.ApiKey.CreationDate;
|
||||
RevisionDate = details.ApiKey.RevisionDate;
|
||||
ClientSecret = details.ClientSecret;
|
||||
}
|
||||
|
||||
public AccessTokenCreationResponseModel() : base(_objectName)
|
||||
|
||||
@@ -8,9 +8,11 @@ using Bit.Core.Utilities;
|
||||
using IdentityModel;
|
||||
using System.Globalization;
|
||||
using Bit.Core.IdentityServer;
|
||||
using Bit.SharedWeb.Health;
|
||||
using Microsoft.IdentityModel.Logging;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Bit.SharedWeb.Utilities;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Bit.Core.Auth.Identity;
|
||||
|
||||
@@ -133,6 +135,9 @@ public class Startup
|
||||
services.AddDefaultServices(globalSettings);
|
||||
services.AddCoreLocalizationServices();
|
||||
|
||||
//health check
|
||||
services.AddHealthChecks(globalSettings);
|
||||
|
||||
#if OSS
|
||||
services.AddOosServices();
|
||||
#else
|
||||
@@ -206,7 +211,17 @@ public class Startup
|
||||
app.UseMiddleware<CurrentContextMiddleware>();
|
||||
|
||||
// Add endpoints to the request pipeline.
|
||||
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapDefaultControllerRoute();
|
||||
|
||||
endpoints.MapHealthChecks("/healthz");
|
||||
|
||||
endpoints.MapHealthChecks("/healthz/extended", new HealthCheckOptions
|
||||
{
|
||||
ResponseWriter = HealthCheckServiceExtensions.WriteResponse
|
||||
});
|
||||
});
|
||||
|
||||
// Add Swagger
|
||||
if (Environment.IsDevelopment() || globalSettings.SelfHosted)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Bit.Core.IdentityServer;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.SharedWeb.Health;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Bit.Api.Utilities;
|
||||
@@ -69,4 +70,48 @@ public static class ServiceCollectionExtensions
|
||||
config.IncludeXmlComments(coreFilePath);
|
||||
});
|
||||
}
|
||||
|
||||
public static void AddHealthChecks(this IServiceCollection services, GlobalSettings globalSettings)
|
||||
{
|
||||
services.AddHealthCheckServices(globalSettings, builder =>
|
||||
{
|
||||
var identityUri = new Uri(globalSettings.BaseServiceUri.Identity
|
||||
+ "/.well-known/openid-configuration");
|
||||
|
||||
builder.AddUrlGroup(identityUri, "identity");
|
||||
|
||||
if (!string.IsNullOrEmpty(globalSettings.SqlServer.ConnectionString))
|
||||
{
|
||||
builder.AddSqlServer(globalSettings.SqlServer.ConnectionString);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(globalSettings.Redis.ConnectionString))
|
||||
{
|
||||
builder.AddRedis(globalSettings.Redis.ConnectionString);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(globalSettings.Storage.ConnectionString))
|
||||
{
|
||||
builder.AddAzureQueueStorage(globalSettings.Storage.ConnectionString, name: "storage_queue")
|
||||
.AddAzureQueueStorage(globalSettings.Events.ConnectionString, name: "events_queue");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(globalSettings.Notifications.ConnectionString))
|
||||
{
|
||||
builder.AddAzureQueueStorage(globalSettings.Notifications.ConnectionString,
|
||||
name: "notifications_queue");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(globalSettings.ServiceBus.ConnectionString))
|
||||
{
|
||||
builder.AddAzureServiceBusTopic(_ => globalSettings.ServiceBus.ConnectionString,
|
||||
_ => globalSettings.ServiceBus.ApplicationCacheTopicName, name: "service_bus");
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(globalSettings.Mail.SendGridApiKey))
|
||||
{
|
||||
builder.AddSendGrid(globalSettings.Mail.SendGridApiKey);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,81 @@
|
||||
"version": 1,
|
||||
"dependencies": {
|
||||
"net6.0": {
|
||||
"AspNetCore.HealthChecks.AzureServiceBus": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.1.0, )",
|
||||
"resolved": "6.1.0",
|
||||
"contentHash": "LepLE6NO4bLBVDzlx/730pD6jnfkV6zaaRUrbN1LqnNk4m1hROsv7wOpgbKgVDgYIfeLzdiVnBviEevSxWFKMQ==",
|
||||
"dependencies": {
|
||||
"Azure.Messaging.EventHubs": "5.7.4",
|
||||
"Azure.Messaging.ServiceBus": "7.11.1",
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks": "6.0.10"
|
||||
}
|
||||
},
|
||||
"AspNetCore.HealthChecks.AzureStorage": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.1.2, )",
|
||||
"resolved": "6.1.2",
|
||||
"contentHash": "R/uHJ40Cc0fBLi48SqDtT6fHyR5G8L3+PeKlbe8t498GLebeBIR3ve4l4n7UzCD0qgmQDDvyIYvVywx3i5Y6Ng==",
|
||||
"dependencies": {
|
||||
"Azure.Storage.Blobs": "12.14.1",
|
||||
"Azure.Storage.Files.Shares": "12.11.0",
|
||||
"Azure.Storage.Queues": "12.11.1",
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks": "6.0.10"
|
||||
}
|
||||
},
|
||||
"AspNetCore.HealthChecks.Network": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.0.4, )",
|
||||
"resolved": "6.0.4",
|
||||
"contentHash": "rvoPkqlvhX1HW6dpqjE1rbvmmMo9v7+Uf9dJffEcd3mA/DyyEitlZFc6cwYtmZVFdgy2gbIU4ubs3654nVfvjA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks": "6.0.7",
|
||||
"SSH.NET": "2020.0.2",
|
||||
"System.Buffers": "4.5.1"
|
||||
}
|
||||
},
|
||||
"AspNetCore.HealthChecks.Redis": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.0.4, )",
|
||||
"resolved": "6.0.4",
|
||||
"contentHash": "adNNWF6kV8v1HLTmF3b9F5K6ubvgx+S7VqhzA8T/5YuIpRWsCDk8+q3RIDDV8Twvl9pRahLfzCbFrPYxvzmk7g==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks": "6.0.4",
|
||||
"StackExchange.Redis": "2.5.61"
|
||||
}
|
||||
},
|
||||
"AspNetCore.HealthChecks.SendGrid": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.0.2, )",
|
||||
"resolved": "6.0.2",
|
||||
"contentHash": "VgskjkCUmSpAxil20rZlrj14bMi9aFNdiGLDtDTKjkUU0GYkoyi4HRVEy9Gp0FIgu9ce7quN+dNCpydKvMxjqA==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks": "6.0.2",
|
||||
"Microsoft.Extensions.Http": "6.0.0",
|
||||
"SendGrid": "9.24.4"
|
||||
}
|
||||
},
|
||||
"AspNetCore.HealthChecks.SqlServer": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.0.2, )",
|
||||
"resolved": "6.0.2",
|
||||
"contentHash": "Af7ws27DnZZ4bKCiEREm7emSAKEtIiYirEAkI0ixFgK1fwJ99jmMnPC+kU01zfqn3FyCO/gZOUO7WbyVvTPpFg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Data.SqlClient": "3.0.1",
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks": "6.0.0"
|
||||
}
|
||||
},
|
||||
"AspNetCore.HealthChecks.Uris": {
|
||||
"type": "Direct",
|
||||
"requested": "[6.0.3, )",
|
||||
"resolved": "6.0.3",
|
||||
"contentHash": "EY0Vh8s2UrbnyvM/QhbyYuCnbrBw36BKkdh5LqdINxqAGnlPFQXf+/UoNlH/76MTEyg+nvdp2wjr5MqWDkVFaQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks": "6.0.0",
|
||||
"Microsoft.Extensions.Http": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Azure.Messaging.EventGrid": {
|
||||
"type": "Direct",
|
||||
"requested": "[4.10.0, )",
|
||||
@@ -97,6 +172,14 @@
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Azure.Core.Amqp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.2.0",
|
||||
"contentHash": "vrF4isvhwdZspzorLwYhukXz3DA8/ONSnZUIBAqBtOCzsDNUgAsuILbCzvtDrn2oDxyq7DZx5Nh81pe0BeWmDQ==",
|
||||
"dependencies": {
|
||||
"System.Memory": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Azure.Extensions.AspNetCore.DataProtection.Blobs": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.2",
|
||||
@@ -121,6 +204,34 @@
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Azure.Messaging.EventHubs": {
|
||||
"type": "Transitive",
|
||||
"resolved": "5.7.4",
|
||||
"contentHash": "8vC4efO5HzDgZjx6LaViScywbyKu3xIkL+y+QoyN7Yo6u1pEmMAPW4ptaWIj1JW4gypeWC1tFy+U3zdQ/E7bGA==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.Core.Amqp": "1.2.0",
|
||||
"Microsoft.Azure.Amqp": "2.5.12",
|
||||
"Microsoft.Bcl.AsyncInterfaces": "1.1.1",
|
||||
"System.Diagnostics.DiagnosticSource": "4.6.0",
|
||||
"System.Memory.Data": "1.0.2",
|
||||
"System.Reflection.TypeExtensions": "4.7.0",
|
||||
"System.Threading.Channels": "4.7.1",
|
||||
"System.Threading.Tasks.Extensions": "4.5.4"
|
||||
}
|
||||
},
|
||||
"Azure.Messaging.ServiceBus": {
|
||||
"type": "Transitive",
|
||||
"resolved": "7.11.1",
|
||||
"contentHash": "ioGedXeH8KK4HdTDEyOzdgNbEXGstGItVljI1EKYsz08sgwej6LpODCZmwPR2ui1fjXBWt8Zea0RJT4d9LwlMg==",
|
||||
"dependencies": {
|
||||
"Azure.Core": "1.25.0",
|
||||
"Azure.Core.Amqp": "1.2.0",
|
||||
"Microsoft.Azure.Amqp": "2.5.12",
|
||||
"Microsoft.Bcl.AsyncInterfaces": "1.1.1",
|
||||
"System.Memory.Data": "1.0.2"
|
||||
}
|
||||
},
|
||||
"Azure.Storage.Blobs": {
|
||||
"type": "Transitive",
|
||||
"resolved": "12.14.1",
|
||||
@@ -139,6 +250,15 @@
|
||||
"System.IO.Hashing": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Azure.Storage.Files.Shares": {
|
||||
"type": "Transitive",
|
||||
"resolved": "12.11.0",
|
||||
"contentHash": "C747FRSZNe/L4hu1wrvzQImVaIfNDcZXfttaV3FwX96+TsbgXotHe6Y0lmSu65H/gVYKt07sIW9E1mDi3bdADw==",
|
||||
"dependencies": {
|
||||
"Azure.Storage.Common": "12.12.0",
|
||||
"System.Text.Json": "4.7.2"
|
||||
}
|
||||
},
|
||||
"Azure.Storage.Queues": {
|
||||
"type": "Transitive",
|
||||
"resolved": "12.12.0",
|
||||
@@ -389,12 +509,8 @@
|
||||
},
|
||||
"Microsoft.Azure.Amqp": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.4.11",
|
||||
"contentHash": "7x5fu2f6TLQDDJS0sY5qW8/daFwJaY9O75YvU8RcUfRzbug+9YGjXUBxoRrprgyi0jxdBAMQL05p1s783SOSFQ==",
|
||||
"dependencies": {
|
||||
"System.Net.WebSockets.Client": "4.0.2",
|
||||
"System.Runtime.Serialization.Primitives": "4.1.1"
|
||||
}
|
||||
"resolved": "2.5.12",
|
||||
"contentHash": "0SlEl+TSQdpjXWf9/37dXWAa0zk6R1EJKmGtGZeKUAH7WEQpJOWMxJ9I43igcBCnTkFwa28CdPnpSCjFZVQlkw=="
|
||||
},
|
||||
"Microsoft.Azure.Cosmos": {
|
||||
"type": "Transitive",
|
||||
@@ -722,6 +838,22 @@
|
||||
"System.Text.Json": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.10",
|
||||
"contentHash": "YmTyFOc7xx2/9FKuAlCmcWYKYLr0bYgNrRlcNPy/vc8qXnxnRV+kua6z96RUXSJVSQadCbJcEjmnTUMTEVfXOQ==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions": "6.0.10",
|
||||
"Microsoft.Extensions.Hosting.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "6.0.2",
|
||||
"Microsoft.Extensions.Options": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.10",
|
||||
"contentHash": "U1PO967am1BIWbxBiLcYzVx8KOTYa9NvhBNgTn8Oii3LcsjvIwHzM+GTYy6bTiHnAFAlK5HAjxusAnAHSHJRoA=="
|
||||
},
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.0",
|
||||
@@ -747,13 +879,12 @@
|
||||
},
|
||||
"Microsoft.Extensions.Hosting.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "3.1.32",
|
||||
"contentHash": "00J6eE920t5vfPnEHBSGyj1Ya9lG6WYsMwqvLZ0nMPPTD2UxkaL+FNJM5DNSnMFJtV84KkUudPRngmNiCkqhuA==",
|
||||
"resolved": "6.0.0",
|
||||
"contentHash": "GcT5l2CYXL6Sa27KCSh0TixsRfADUgth+ojQSD5EkzisZxmGFh7CwzkcYuGwvmXLjr27uWRNrJ2vuuEjMhU05Q==",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "3.1.32",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.32",
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "3.1.32",
|
||||
"Microsoft.Extensions.Logging.Abstractions": "3.1.32"
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
|
||||
"Microsoft.Extensions.FileProviders.Abstractions": "6.0.0"
|
||||
}
|
||||
},
|
||||
"Microsoft.Extensions.Http": {
|
||||
@@ -801,8 +932,8 @@
|
||||
},
|
||||
"Microsoft.Extensions.Logging.Abstractions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "6.0.1",
|
||||
"contentHash": "dzB2Cgg+JmrouhjkcQGzSFjjvpwlq353i8oBQO2GWNjCXSzhbtBRUf28HSauWe7eib3wYOdb3tItdjRwAdwCSg=="
|
||||
"resolved": "6.0.2",
|
||||
"contentHash": "pwXCZKaA7m5wgmCj49dW+H1RPSY7U62SKLTQYCcavf/k3Nyt/WnBgAjG4jMGnwy9rElfAZ2KvxvM5CJzJWG0hg=="
|
||||
},
|
||||
"Microsoft.Extensions.Options": {
|
||||
"type": "Transitive",
|
||||
@@ -1423,10 +1554,23 @@
|
||||
"SQLitePCLRaw.core": "2.1.2"
|
||||
}
|
||||
},
|
||||
"SSH.NET": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2020.0.2",
|
||||
"contentHash": "G0dNlTBAM00KZXv1wWVwgg26d9/METcM6qWBpNQwllzQmmbu+Zu+FS1L1X4fFgGdPu3e8k9mmTBu6SwtQ0614g==",
|
||||
"dependencies": {
|
||||
"SshNet.Security.Cryptography": "[1.3.0]"
|
||||
}
|
||||
},
|
||||
"SshNet.Security.Cryptography": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.3.0",
|
||||
"contentHash": "5pBIXRjcSO/amY8WztpmNOhaaCNHY/B6CcYDI7FSTgqSyo/ZUojlLiKcsl+YGbxQuLX439qIkMfP0PHqxqJi/Q=="
|
||||
},
|
||||
"StackExchange.Redis": {
|
||||
"type": "Transitive",
|
||||
"resolved": "2.5.43",
|
||||
"contentHash": "YQ38jVbX1b5mBi6lizESou+NpV6QZpeo6ofRR6qeuqJ8ePOmhcwhje3nDTNIGEkfPSK0sLuF6pR5rtFyq2F46g==",
|
||||
"resolved": "2.5.61",
|
||||
"contentHash": "h1Gz4itrHL/PQ0GBLTEiPK8bBkOp5SFO6iaRFSSn/x1qltBWENsz/NUxPid6WHX9yf2Tiyzn9D3R7mtnksODxg==",
|
||||
"dependencies": {
|
||||
"Pipelines.Sockets.Unofficial": "2.2.2",
|
||||
"System.Diagnostics.PerformanceCounter": "5.0.0"
|
||||
@@ -2061,42 +2205,6 @@
|
||||
"System.Runtime.Extensions": "4.1.0"
|
||||
}
|
||||
},
|
||||
"System.Net.WebSockets": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.0",
|
||||
"contentHash": "2KJo8hir6Edi9jnMDAMhiJoI691xRBmKcbNpwjrvpIMOCTYOtBpSsSEGBxBDV7PKbasJNaFp1+PZz1D7xS41Hg==",
|
||||
"dependencies": {
|
||||
"Microsoft.Win32.Primitives": "4.0.1",
|
||||
"System.Resources.ResourceManager": "4.0.1",
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Threading.Tasks": "4.0.11"
|
||||
}
|
||||
},
|
||||
"System.Net.WebSockets.Client": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.2",
|
||||
"contentHash": "NUCcDroX4lCQXgOrzlwIZ1u9YJ0krfyF0wk0ONnyLUmcQoEiYV2/OfUPRqUwQBbpH1BlGApkLgoQUwMqb5+c1g==",
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.2",
|
||||
"Microsoft.Win32.Primitives": "4.0.1",
|
||||
"System.Collections": "4.0.11",
|
||||
"System.Diagnostics.Debug": "4.0.11",
|
||||
"System.Diagnostics.Tracing": "4.1.0",
|
||||
"System.Globalization": "4.0.11",
|
||||
"System.Net.Primitives": "4.0.11",
|
||||
"System.Net.WebHeaderCollection": "4.0.1",
|
||||
"System.Net.WebSockets": "4.0.0",
|
||||
"System.Resources.ResourceManager": "4.0.1",
|
||||
"System.Runtime": "4.1.0",
|
||||
"System.Runtime.Extensions": "4.1.0",
|
||||
"System.Runtime.Handles": "4.0.1",
|
||||
"System.Runtime.InteropServices": "4.1.0",
|
||||
"System.Security.Cryptography.X509Certificates": "4.1.0",
|
||||
"System.Text.Encoding": "4.0.11",
|
||||
"System.Threading": "4.0.11",
|
||||
"System.Threading.Tasks": "4.0.11"
|
||||
}
|
||||
},
|
||||
"System.Numerics.Vectors": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.5.0",
|
||||
@@ -2213,12 +2321,8 @@
|
||||
},
|
||||
"System.Reflection.TypeExtensions": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.3.0",
|
||||
"contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==",
|
||||
"dependencies": {
|
||||
"System.Reflection": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
}
|
||||
"resolved": "4.7.0",
|
||||
"contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
|
||||
},
|
||||
"System.Resources.ResourceManager": {
|
||||
"type": "Transitive",
|
||||
@@ -2606,6 +2710,11 @@
|
||||
"System.Threading.Tasks": "4.3.0"
|
||||
}
|
||||
},
|
||||
"System.Threading.Channels": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.7.1",
|
||||
"contentHash": "6akRtHK/wab3246t4p5v3HQrtQk8LboOt5T4dtpNgsp3zvDeM4/Gx8V12t0h+c/W9/enUrilk8n6EQqdQorZAA=="
|
||||
},
|
||||
"System.Threading.Overlapped": {
|
||||
"type": "Transitive",
|
||||
"resolved": "4.0.1",
|
||||
@@ -2798,85 +2907,85 @@
|
||||
"commercial.core": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0"
|
||||
"Core": "[2023.5.0, )"
|
||||
}
|
||||
},
|
||||
"commercial.infrastructure.entityframework": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
|
||||
"Core": "[2023.5.0, )",
|
||||
"Infrastructure.EntityFramework": "[2023.5.0, )"
|
||||
}
|
||||
},
|
||||
"core": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AWSSDK.SQS": "3.7.2.47",
|
||||
"AWSSDK.SimpleEmail": "3.7.0.150",
|
||||
"AspNetCoreRateLimit": "4.0.2",
|
||||
"AspNetCoreRateLimit.Redis": "1.0.1",
|
||||
"Azure.Extensions.AspNetCore.DataProtection.Blobs": "1.3.2",
|
||||
"Azure.Storage.Blobs": "12.14.1",
|
||||
"Azure.Storage.Queues": "12.12.0",
|
||||
"BitPay.Light": "1.0.1907",
|
||||
"Braintree": "5.12.0",
|
||||
"DnsClient": "1.7.0",
|
||||
"Fido2.AspNet": "3.0.1",
|
||||
"Handlebars.Net": "2.1.2",
|
||||
"IdentityServer4": "4.1.2",
|
||||
"IdentityServer4.AccessTokenValidation": "3.0.1",
|
||||
"LaunchDarkly.ServerSdk": "7.0.0",
|
||||
"MailKit": "3.2.0",
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer": "6.0.4",
|
||||
"Microsoft.Azure.Cosmos.Table": "1.0.8",
|
||||
"Microsoft.Azure.NotificationHubs": "4.1.0",
|
||||
"Microsoft.Azure.ServiceBus": "5.2.0",
|
||||
"Microsoft.Data.SqlClient": "5.0.1",
|
||||
"Microsoft.Extensions.Caching.StackExchangeRedis": "6.0.6",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "6.0.1",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "6.0.1",
|
||||
"Microsoft.Extensions.Identity.Stores": "6.0.4",
|
||||
"Newtonsoft.Json": "13.0.1",
|
||||
"Otp.NET": "1.2.2",
|
||||
"Quartz": "3.4.0",
|
||||
"SendGrid": "9.27.0",
|
||||
"Sentry.Serilog": "3.16.0",
|
||||
"Serilog.AspNetCore": "5.0.0",
|
||||
"Serilog.Extensions.Logging": "3.1.0",
|
||||
"Serilog.Extensions.Logging.File": "2.0.0",
|
||||
"Serilog.Sinks.AzureCosmosDB": "2.0.0",
|
||||
"Serilog.Sinks.SyslogMessages": "2.0.6",
|
||||
"Stripe.net": "40.0.0",
|
||||
"YubicoDotNetClient": "1.2.0"
|
||||
"AWSSDK.SQS": "[3.7.2.47, )",
|
||||
"AWSSDK.SimpleEmail": "[3.7.0.150, )",
|
||||
"AspNetCoreRateLimit": "[4.0.2, )",
|
||||
"AspNetCoreRateLimit.Redis": "[1.0.1, )",
|
||||
"Azure.Extensions.AspNetCore.DataProtection.Blobs": "[1.3.2, )",
|
||||
"Azure.Storage.Blobs": "[12.14.1, )",
|
||||
"Azure.Storage.Queues": "[12.12.0, )",
|
||||
"BitPay.Light": "[1.0.1907, )",
|
||||
"Braintree": "[5.12.0, )",
|
||||
"DnsClient": "[1.7.0, )",
|
||||
"Fido2.AspNet": "[3.0.1, )",
|
||||
"Handlebars.Net": "[2.1.2, )",
|
||||
"IdentityServer4": "[4.1.2, )",
|
||||
"IdentityServer4.AccessTokenValidation": "[3.0.1, )",
|
||||
"LaunchDarkly.ServerSdk": "[7.0.0, )",
|
||||
"MailKit": "[3.2.0, )",
|
||||
"Microsoft.AspNetCore.Authentication.JwtBearer": "[6.0.4, )",
|
||||
"Microsoft.Azure.Cosmos.Table": "[1.0.8, )",
|
||||
"Microsoft.Azure.NotificationHubs": "[4.1.0, )",
|
||||
"Microsoft.Azure.ServiceBus": "[5.2.0, )",
|
||||
"Microsoft.Data.SqlClient": "[5.0.1, )",
|
||||
"Microsoft.Extensions.Caching.StackExchangeRedis": "[6.0.6, )",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "[6.0.1, )",
|
||||
"Microsoft.Extensions.Configuration.UserSecrets": "[6.0.1, )",
|
||||
"Microsoft.Extensions.Identity.Stores": "[6.0.4, )",
|
||||
"Newtonsoft.Json": "[13.0.1, )",
|
||||
"Otp.NET": "[1.2.2, )",
|
||||
"Quartz": "[3.4.0, )",
|
||||
"SendGrid": "[9.27.0, )",
|
||||
"Sentry.Serilog": "[3.16.0, )",
|
||||
"Serilog.AspNetCore": "[5.0.0, )",
|
||||
"Serilog.Extensions.Logging": "[3.1.0, )",
|
||||
"Serilog.Extensions.Logging.File": "[2.0.0, )",
|
||||
"Serilog.Sinks.AzureCosmosDB": "[2.0.0, )",
|
||||
"Serilog.Sinks.SyslogMessages": "[2.0.6, )",
|
||||
"Stripe.net": "[40.0.0, )",
|
||||
"YubicoDotNetClient": "[1.2.0, )"
|
||||
}
|
||||
},
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Dapper": "2.0.123"
|
||||
"Core": "[2023.5.0, )",
|
||||
"Dapper": "[2.0.123, )"
|
||||
}
|
||||
},
|
||||
"infrastructure.entityframework": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "6.0.8",
|
||||
"Pomelo.EntityFrameworkCore.MySql": "6.0.2",
|
||||
"linq2db.EntityFrameworkCore": "6.11.0"
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "[12.0.1, )",
|
||||
"Core": "[2023.5.0, )",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "[6.0.12, )",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "[6.0.12, )",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "[6.0.12, )",
|
||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "[6.0.8, )",
|
||||
"Pomelo.EntityFrameworkCore.MySql": "[6.0.2, )",
|
||||
"linq2db.EntityFrameworkCore": "[6.11.0, )"
|
||||
}
|
||||
},
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.Dapper": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "[2023.5.0, )",
|
||||
"Infrastructure.Dapper": "[2023.5.0, )",
|
||||
"Infrastructure.EntityFramework": "[2023.5.0, )"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2786,7 +2786,7 @@
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Dapper": "2.0.123"
|
||||
}
|
||||
},
|
||||
@@ -2794,7 +2794,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
@@ -2806,9 +2806,9 @@
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.Dapper": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.Dapper": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,18 +12,18 @@ public class UserDecryptionOptions : ResponseModel
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Gets or sets whether the current user has a master password that can be used to decrypt their vault.
|
||||
/// </summary>
|
||||
public bool HasMasterPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Gets or sets information regarding this users trusted device decryption setup.
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public TrustedDeviceUserDecryptionOption? TrustedDeviceOption { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Gets or set information about the current users KeyConnector setup.
|
||||
/// </summary>
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||
public KeyConnectorUserDecryptionOption? KeyConnectorOption { get; set; }
|
||||
|
||||
@@ -10,4 +10,5 @@ public static class SecretOperations
|
||||
{
|
||||
public static readonly SecretOperationRequirement Create = new() { Name = nameof(Create) };
|
||||
public static readonly SecretOperationRequirement Update = new() { Name = nameof(Update) };
|
||||
public static readonly SecretOperationRequirement Delete = new() { Name = nameof(Delete) };
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
using Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces;
|
||||
|
||||
public interface ICreateAccessTokenCommand
|
||||
{
|
||||
Task<ApiKey> CreateAsync(ApiKey apiKey);
|
||||
Task<ApiKeyClientSecretDetails> CreateAsync(ApiKey apiKey);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@ namespace Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
|
||||
|
||||
public interface IDeleteSecretCommand
|
||||
{
|
||||
Task<List<Tuple<Secret, string>>> DeleteSecrets(List<Guid> ids, Guid userId);
|
||||
Task DeleteSecrets(IEnumerable<Secret> secrets);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ public class ApiKey : ITableObject<Guid>
|
||||
public Guid? ServiceAccountId { get; set; }
|
||||
[MaxLength(200)]
|
||||
public string Name { get; set; }
|
||||
[MaxLength(30)]
|
||||
public string ClientSecret { get; set; }
|
||||
[MaxLength(128)]
|
||||
public string ClientSecretHash { get; set; }
|
||||
[MaxLength(4000)]
|
||||
public string Scope { get; set; }
|
||||
[MaxLength(4000)]
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Bit.Core.SecretsManager.Entities;
|
||||
|
||||
namespace Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
public class ApiKeyClientSecretDetails
|
||||
{
|
||||
public ApiKey ApiKey { get; set; }
|
||||
public string ClientSecret { get; set; }
|
||||
}
|
||||
@@ -4,6 +4,8 @@ namespace Bit.Core.SecretsManager.Models.Data;
|
||||
|
||||
public class ApiKeyDetails : ApiKey
|
||||
{
|
||||
public string ClientSecret { get; set; } // Deprecated as of 2023-05-17
|
||||
|
||||
protected ApiKeyDetails() { }
|
||||
|
||||
protected ApiKeyDetails(ApiKey apiKey)
|
||||
@@ -11,7 +13,7 @@ public class ApiKeyDetails : ApiKey
|
||||
Id = apiKey.Id;
|
||||
ServiceAccountId = apiKey.ServiceAccountId;
|
||||
Name = apiKey.Name;
|
||||
ClientSecret = apiKey.ClientSecret;
|
||||
ClientSecretHash = apiKey.ClientSecretHash;
|
||||
Scope = apiKey.Scope;
|
||||
EncryptedPayload = apiKey.EncryptedPayload;
|
||||
Key = apiKey.Key;
|
||||
|
||||
@@ -2786,7 +2786,7 @@
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Dapper": "2.0.123"
|
||||
}
|
||||
},
|
||||
@@ -2794,7 +2794,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
@@ -2806,9 +2806,9 @@
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.Dapper": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.Dapper": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2786,7 +2786,7 @@
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Dapper": "2.0.123"
|
||||
}
|
||||
},
|
||||
@@ -2794,7 +2794,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
@@ -2806,9 +2806,9 @@
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.Dapper": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.Dapper": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2796,7 +2796,7 @@
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Dapper": "2.0.123"
|
||||
}
|
||||
},
|
||||
@@ -2804,7 +2804,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
@@ -2816,9 +2816,9 @@
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.Dapper": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.Dapper": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,10 @@ using Bit.Core;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Auth.Models;
|
||||
using Bit.Core.Auth.Models.Api.Response;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
@@ -43,6 +46,8 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
|
||||
protected ICurrentContext CurrentContext { get; }
|
||||
protected IPolicyService PolicyService { get; }
|
||||
protected IFeatureService FeatureService { get; }
|
||||
protected ISsoConfigRepository SsoConfigRepository { get; }
|
||||
|
||||
public BaseRequestValidator(
|
||||
UserManager<User> userManager,
|
||||
@@ -58,10 +63,11 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
ILogger logger,
|
||||
ICurrentContext currentContext,
|
||||
GlobalSettings globalSettings,
|
||||
IPolicyRepository policyRepository,
|
||||
IUserRepository userRepository,
|
||||
IPolicyService policyService,
|
||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory)
|
||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
||||
IFeatureService featureService,
|
||||
ISsoConfigRepository ssoConfigRepository)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_deviceRepository = deviceRepository;
|
||||
@@ -79,6 +85,8 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
PolicyService = policyService;
|
||||
_userRepository = userRepository;
|
||||
_tokenDataFactory = tokenDataFactory;
|
||||
FeatureService = featureService;
|
||||
SsoConfigRepository = ssoConfigRepository;
|
||||
}
|
||||
|
||||
protected async Task ValidateAsync(T context, ValidatedTokenRequest request,
|
||||
@@ -199,6 +207,7 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
customResponse.Add("KdfIterations", user.KdfIterations);
|
||||
customResponse.Add("KdfMemory", user.KdfMemory);
|
||||
customResponse.Add("KdfParallelism", user.KdfParallelism);
|
||||
customResponse.Add("UserDecryptionOptions", await CreateUserDecryptionOptionsAsync(user, GetSubject(context)));
|
||||
|
||||
if (sendRememberToken)
|
||||
{
|
||||
@@ -300,6 +309,7 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
Dictionary<string, object> customResponse);
|
||||
|
||||
protected abstract void SetErrorResult(T context, Dictionary<string, object> customResponse);
|
||||
protected abstract ClaimsPrincipal GetSubject(T context);
|
||||
|
||||
private async Task<Tuple<bool, Organization>> RequiresTwoFactorAsync(User user, ValidatedTokenRequest request)
|
||||
{
|
||||
@@ -572,4 +582,53 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
|
||||
return new MasterPasswordPolicyResponseModel(await PolicyService.GetMasterPasswordPolicyForUserAsync(user));
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
/// <summary>
|
||||
/// Used to create a list of all possible ways the newly authenticated user can decrypt their vault contents
|
||||
/// </summary>
|
||||
private async Task<UserDecryptionOptions> CreateUserDecryptionOptionsAsync(User user, ClaimsPrincipal subject)
|
||||
{
|
||||
var ssoConfigurationData = await GetSsoConfigurationDataAsync(subject);
|
||||
|
||||
var userDecryptionOption = new UserDecryptionOptions
|
||||
{
|
||||
HasMasterPassword = !string.IsNullOrEmpty(user.MasterPassword)
|
||||
};
|
||||
|
||||
if (ssoConfigurationData is { MemberDecryptionType: MemberDecryptionType.KeyConnector } && !string.IsNullOrEmpty(ssoConfigurationData.KeyConnectorUrl))
|
||||
{
|
||||
// KeyConnector makes it mutually exclusive
|
||||
userDecryptionOption.KeyConnectorOption = new KeyConnectorUserDecryptionOption(ssoConfigurationData.KeyConnectorUrl);
|
||||
return userDecryptionOption;
|
||||
}
|
||||
|
||||
// Only add the trusted device specific option when the flag is turned on
|
||||
if (FeatureService.IsEnabled(FeatureFlagKeys.TrustedDeviceEncryption, CurrentContext) && ssoConfigurationData is { MemberDecryptionType: MemberDecryptionType.TrustedDeviceEncryption })
|
||||
{
|
||||
var hasAdminApproval = await PolicyService.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.ResetPassword);
|
||||
// TrustedDeviceEncryption only exists for SSO, but if that ever changes this value won't always be true
|
||||
userDecryptionOption.TrustedDeviceOption = new TrustedDeviceUserDecryptionOption(hasAdminApproval);
|
||||
}
|
||||
|
||||
return userDecryptionOption;
|
||||
}
|
||||
|
||||
private async Task<SsoConfigurationData?> GetSsoConfigurationDataAsync(ClaimsPrincipal subject)
|
||||
{
|
||||
var organizationClaim = subject?.FindFirstValue("organizationId");
|
||||
|
||||
if (organizationClaim == null || !Guid.TryParse(organizationClaim, out var organizationId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ssoConfig = await SsoConfigRepository.GetByOrganizationIdAsync(organizationId);
|
||||
if (ssoConfig == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ssoConfig.GetData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,11 +107,16 @@ public class ClientStore : IClientStore
|
||||
break;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(apiKey.ClientSecretHash))
|
||||
{
|
||||
apiKey.ClientSecretHash = apiKey.ClientSecret.Sha256();
|
||||
}
|
||||
|
||||
var client = new Client
|
||||
{
|
||||
ClientId = clientId,
|
||||
RequireClientSecret = true,
|
||||
ClientSecrets = { new Secret(apiKey.ClientSecret.Sha256()) },
|
||||
ClientSecrets = { new Secret(apiKey.ClientSecretHash) },
|
||||
AllowedScopes = apiKey.GetScopes(),
|
||||
AllowedGrantTypes = GrantTypes.ClientCredentials,
|
||||
AccessTokenLifetime = 3600 * 1,
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Auth.Models.Api.Response;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.IdentityServer;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
@@ -27,8 +23,6 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
||||
ICustomTokenRequestValidator
|
||||
{
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly ISsoConfigRepository _ssoConfigRepository;
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
public CustomTokenRequestValidator(
|
||||
UserManager<User> userManager,
|
||||
@@ -44,7 +38,6 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
||||
ILogger<CustomTokenRequestValidator> logger,
|
||||
ICurrentContext currentContext,
|
||||
GlobalSettings globalSettings,
|
||||
IPolicyRepository policyRepository,
|
||||
ISsoConfigRepository ssoConfigRepository,
|
||||
IUserRepository userRepository,
|
||||
IPolicyService policyService,
|
||||
@@ -52,12 +45,10 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
||||
IFeatureService featureService)
|
||||
: base(userManager, deviceRepository, deviceService, userService, eventService,
|
||||
organizationDuoWebTokenProvider, organizationRepository, organizationUserRepository,
|
||||
applicationCacheService, mailService, logger, currentContext, globalSettings, policyRepository,
|
||||
userRepository, policyService, tokenDataFactory)
|
||||
applicationCacheService, mailService, logger, currentContext, globalSettings,
|
||||
userRepository, policyService, tokenDataFactory, featureService, ssoConfigRepository)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_ssoConfigRepository = ssoConfigRepository;
|
||||
_featureService = featureService;
|
||||
}
|
||||
|
||||
public async Task ValidateAsync(CustomTokenRequestValidationContext context)
|
||||
@@ -96,7 +87,7 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
||||
return validatorContext.User != null;
|
||||
}
|
||||
|
||||
protected override async Task SetSuccessResult(CustomTokenRequestValidationContext context, User user,
|
||||
protected override Task SetSuccessResult(CustomTokenRequestValidationContext context, User user,
|
||||
List<Claim> claims, Dictionary<string, object> customResponse)
|
||||
{
|
||||
context.Result.CustomResponse = customResponse;
|
||||
@@ -110,23 +101,9 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to find ssoConfigData for a given validate request subject
|
||||
// this is actually guarenteed to pretty often be null, because more than just sso login requests will come
|
||||
// through here
|
||||
var ssoConfigData = await GetSsoConfigurationDataAsync(context.Result.ValidatedRequest.Subject);
|
||||
|
||||
// You can't put this below the user.MasterPassword != null check because TDE users can still have a MasterPassword
|
||||
// It's worth noting that CurrentContext here will build a user in LaunchDarkly that is anonymous but DOES belong
|
||||
// to an organization. So we will not be able to turn this feature on for only a single user, only for an entire
|
||||
// organization at a time.
|
||||
if (ssoConfigData != null && _featureService.IsEnabled(FeatureFlagKeys.TrustedDeviceEncryption, CurrentContext))
|
||||
{
|
||||
context.Result.CustomResponse["UserDecryptionOptions"] = await CreateUserDecryptionOptionsAsync(ssoConfigData, user);
|
||||
}
|
||||
|
||||
if (context.Result.CustomResponse == null || user.MasterPassword != null)
|
||||
{
|
||||
return;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// KeyConnector responses below
|
||||
@@ -141,36 +118,30 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
||||
context.Result.CustomResponse["ResetMasterPassword"] = false;
|
||||
}
|
||||
|
||||
return;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// SSO login
|
||||
// This does a double check, that ssoConfigData is not null and that it has the KeyConnector member decryption type
|
||||
if (ssoConfigData is { MemberDecryptionType: MemberDecryptionType.KeyConnector } && !string.IsNullOrEmpty(ssoConfigData.KeyConnectorUrl))
|
||||
// Key connector data should have already been set in the decryption options
|
||||
// for backwards compatibility we set them this way too. We can eventually get rid of this
|
||||
// when all clients don't read them from the existing locations.
|
||||
if (!context.Result.CustomResponse.TryGetValue("UserDecryptionOptions", out var userDecryptionOptionsObj) ||
|
||||
userDecryptionOptionsObj is not UserDecryptionOptions userDecryptionOptions)
|
||||
{
|
||||
// TODO: Can be removed in the future
|
||||
context.Result.CustomResponse["KeyConnectorUrl"] = ssoConfigData.KeyConnectorUrl;
|
||||
// Prevent clients redirecting to set-password
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
if (userDecryptionOptions is { KeyConnectorOption: { } })
|
||||
{
|
||||
context.Result.CustomResponse["KeyConnectorUrl"] = userDecryptionOptions.KeyConnectorOption.KeyConnectorUrl;
|
||||
context.Result.CustomResponse["ResetMasterPassword"] = false;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task<SsoConfigurationData?> GetSsoConfigurationDataAsync(ClaimsPrincipal? subject)
|
||||
protected override ClaimsPrincipal GetSubject(CustomTokenRequestValidationContext context)
|
||||
{
|
||||
var organizationClaim = subject?.FindFirstValue("organizationId");
|
||||
|
||||
if (organizationClaim == null || !Guid.TryParse(organizationClaim, out var organizationId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(organizationId);
|
||||
if (ssoConfig == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ssoConfig.GetData();
|
||||
return context.Result.ValidatedRequest.Subject;
|
||||
}
|
||||
|
||||
protected override void SetTwoFactorResult(CustomTokenRequestValidationContext context,
|
||||
@@ -198,29 +169,4 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
||||
context.Result.IsError = true;
|
||||
context.Result.CustomResponse = customResponse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to create a list of all possible ways the newly authenticated user can decrypt their vault contents
|
||||
/// </summary>
|
||||
private async Task<UserDecryptionOptions> CreateUserDecryptionOptionsAsync(SsoConfigurationData ssoConfigurationData, User user)
|
||||
{
|
||||
var userDecryptionOption = new UserDecryptionOptions();
|
||||
if (ssoConfigurationData is { MemberDecryptionType: MemberDecryptionType.KeyConnector } && !string.IsNullOrEmpty(ssoConfigurationData.KeyConnectorUrl))
|
||||
{
|
||||
// KeyConnector makes it mutually exclusive
|
||||
userDecryptionOption.KeyConnectorOption = new KeyConnectorUserDecryptionOption(ssoConfigurationData.KeyConnectorUrl);
|
||||
return userDecryptionOption;
|
||||
}
|
||||
|
||||
if (ssoConfigurationData is { MemberDecryptionType: MemberDecryptionType.TrustedDeviceEncryption })
|
||||
{
|
||||
var hasAdminApproval = await PolicyService.AnyPoliciesApplicableToUserAsync(user.Id, PolicyType.ResetPassword);
|
||||
// TrustedDeviceEncryption only exists for SSO, but if that ever changes this value won't always be true
|
||||
userDecryptionOption.TrustedDeviceOption = new TrustedDeviceUserDecryptionOption(hasAdminApproval);
|
||||
}
|
||||
|
||||
userDecryptionOption.HasMasterPassword = !string.IsNullOrEmpty(user.MasterPassword);
|
||||
|
||||
return userDecryptionOption;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Security.Claims;
|
||||
using Bit.Core.Auth.Identity;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Auth.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
@@ -37,16 +38,17 @@ public class ResourceOwnerPasswordValidator : BaseRequestValidator<ResourceOwner
|
||||
ILogger<ResourceOwnerPasswordValidator> logger,
|
||||
ICurrentContext currentContext,
|
||||
GlobalSettings globalSettings,
|
||||
IPolicyRepository policyRepository,
|
||||
ICaptchaValidationService captchaValidationService,
|
||||
IAuthRequestRepository authRequestRepository,
|
||||
IUserRepository userRepository,
|
||||
IPolicyService policyService,
|
||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory)
|
||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> tokenDataFactory,
|
||||
IFeatureService featureService,
|
||||
ISsoConfigRepository ssoConfigRepository)
|
||||
: base(userManager, deviceRepository, deviceService, userService, eventService,
|
||||
organizationDuoWebTokenProvider, organizationRepository, organizationUserRepository,
|
||||
applicationCacheService, mailService, logger, currentContext, globalSettings, policyRepository,
|
||||
userRepository, policyService, tokenDataFactory)
|
||||
applicationCacheService, mailService, logger, currentContext, globalSettings, userRepository, policyService,
|
||||
tokenDataFactory, featureService, ssoConfigRepository)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userService = userService;
|
||||
@@ -166,6 +168,11 @@ public class ResourceOwnerPasswordValidator : BaseRequestValidator<ResourceOwner
|
||||
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, customResponse: customResponse);
|
||||
}
|
||||
|
||||
protected override ClaimsPrincipal GetSubject(ResourceOwnerPasswordValidationContext context)
|
||||
{
|
||||
return context.Result.Subject;
|
||||
}
|
||||
|
||||
private bool AuthEmailHeaderIsValid(ResourceOwnerPasswordValidationContext context)
|
||||
{
|
||||
if (!_currentContext.HttpContext.Request.Headers.ContainsKey("Auth-Email"))
|
||||
|
||||
@@ -2808,7 +2808,7 @@
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Dapper": "2.0.123"
|
||||
}
|
||||
},
|
||||
@@ -2816,7 +2816,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
@@ -2828,9 +2828,9 @@
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.Dapper": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.Dapper": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2836,7 +2836,7 @@
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Dapper": "2.0.123"
|
||||
}
|
||||
},
|
||||
@@ -2844,7 +2844,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
@@ -2856,9 +2856,9 @@
|
||||
"sharedweb": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Infrastructure.Dapper": "2023.3.0",
|
||||
"Infrastructure.EntityFramework": "2023.3.0"
|
||||
"Core": "2023.4.3",
|
||||
"Infrastructure.Dapper": "2023.4.3",
|
||||
"Infrastructure.EntityFramework": "2023.4.3"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
src/SharedWeb/Health/HealthCheckServiceExtensions.cs
Normal file
60
src/SharedWeb/Health/HealthCheckServiceExtensions.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
|
||||
namespace Bit.SharedWeb.Health;
|
||||
|
||||
public static class HealthCheckServiceExtensions
|
||||
{
|
||||
public static void AddHealthCheckServices(this IServiceCollection services, GlobalSettings globalSettings,
|
||||
Action<IHealthChecksBuilder> addBuilder = null)
|
||||
{
|
||||
var builder = services.AddHealthChecks();
|
||||
addBuilder?.Invoke(builder);
|
||||
}
|
||||
|
||||
public static Task WriteResponse(HttpContext context, HealthReport healthReport)
|
||||
{
|
||||
context.Response.ContentType = "application/json; charset=utf-8";
|
||||
|
||||
var options = new JsonWriterOptions { Indented = true };
|
||||
|
||||
using var memoryStream = new MemoryStream();
|
||||
using (var jsonWriter = new Utf8JsonWriter(memoryStream, options))
|
||||
{
|
||||
jsonWriter.WriteStartObject();
|
||||
jsonWriter.WriteString("status", healthReport.Status.ToString());
|
||||
jsonWriter.WriteStartObject("results");
|
||||
|
||||
foreach (var healthReportEntry in healthReport.Entries)
|
||||
{
|
||||
jsonWriter.WriteStartObject(healthReportEntry.Key);
|
||||
jsonWriter.WriteString("status",
|
||||
healthReportEntry.Value.Status.ToString());
|
||||
jsonWriter.WriteString("description",
|
||||
healthReportEntry.Value.Description ?? healthReportEntry.Value.Exception?.Message);
|
||||
jsonWriter.WriteStartObject("data");
|
||||
|
||||
foreach (var item in healthReportEntry.Value.Data)
|
||||
{
|
||||
jsonWriter.WritePropertyName(item.Key);
|
||||
|
||||
JsonSerializer.Serialize(jsonWriter, item.Value,
|
||||
item.Value?.GetType() ?? typeof(object));
|
||||
}
|
||||
|
||||
jsonWriter.WriteEndObject();
|
||||
jsonWriter.WriteEndObject();
|
||||
}
|
||||
|
||||
jsonWriter.WriteEndObject();
|
||||
jsonWriter.WriteEndObject();
|
||||
}
|
||||
|
||||
return context.Response.WriteAsync(
|
||||
Encoding.UTF8.GetString(memoryStream.ToArray()));
|
||||
}
|
||||
}
|
||||
@@ -2786,7 +2786,7 @@
|
||||
"infrastructure.dapper": {
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Dapper": "2.0.123"
|
||||
}
|
||||
},
|
||||
@@ -2794,7 +2794,7 @@
|
||||
"type": "Project",
|
||||
"dependencies": {
|
||||
"AutoMapper.Extensions.Microsoft.DependencyInjection": "12.0.1",
|
||||
"Core": "2023.3.0",
|
||||
"Core": "2023.4.3",
|
||||
"Microsoft.EntityFrameworkCore.Relational": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.SqlServer": "6.0.12",
|
||||
"Microsoft.EntityFrameworkCore.Sqlite": "6.0.12",
|
||||
|
||||
@@ -2,7 +2,8 @@ CREATE PROCEDURE [dbo].[ApiKey_Create]
|
||||
@Id UNIQUEIDENTIFIER OUTPUT,
|
||||
@ServiceAccountId UNIQUEIDENTIFIER,
|
||||
@Name VARCHAR(200),
|
||||
@ClientSecret VARCHAR(30),
|
||||
@ClientSecret VARCHAR(30) = 'migrated', -- Deprecated as of 2023-05-17
|
||||
@ClientSecretHash VARCHAR(128) = NULL,
|
||||
@Scope NVARCHAR(4000),
|
||||
@EncryptedPayload NVARCHAR(4000),
|
||||
@Key VARCHAR(MAX),
|
||||
@@ -13,12 +14,19 @@ AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
IF (@ClientSecretHash IS NULL)
|
||||
BEGIN
|
||||
DECLARE @hb VARBINARY(128) = HASHBYTES('SHA2_256', @ClientSecret);
|
||||
SET @ClientSecretHash = CAST(N'' as xml).value('xs:base64Binary(sql:variable("@hb"))', 'VARCHAR(128)');
|
||||
END
|
||||
|
||||
INSERT INTO [dbo].[ApiKey]
|
||||
(
|
||||
[Id],
|
||||
[ServiceAccountId],
|
||||
[Name],
|
||||
[ClientSecret],
|
||||
[ClientSecretHash],
|
||||
[Scope],
|
||||
[EncryptedPayload],
|
||||
[Key],
|
||||
@@ -32,6 +40,7 @@ BEGIN
|
||||
@ServiceAccountId,
|
||||
@Name,
|
||||
@ClientSecret,
|
||||
@ClientSecretHash,
|
||||
@Scope,
|
||||
@EncryptedPayload,
|
||||
@Key,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
CREATE TABLE [dbo].[ApiKey] (
|
||||
[Id] UNIQUEIDENTIFIER,
|
||||
[ServiceAccountId] UNIQUEIDENTIFIER NULL,
|
||||
[Name] VARCHAR(200) NOT NULL,
|
||||
[ClientSecret] VARCHAR(30) NOT NULL,
|
||||
[Scope] NVARCHAR (4000) NOT NULL,
|
||||
[EncryptedPayload] NVARCHAR (4000) NOT NULL,
|
||||
[Key] VARCHAR (MAX) NOT NULL,
|
||||
[ExpireAt] DATETIME2(7) NULL,
|
||||
[CreationDate] DATETIME2(7) NOT NULL,
|
||||
[RevisionDate] DATETIME2(7) NOT NULL,
|
||||
[Id] UNIQUEIDENTIFIER,
|
||||
[ServiceAccountId] UNIQUEIDENTIFIER NULL,
|
||||
[Name] VARCHAR(200) NOT NULL,
|
||||
[ClientSecret] VARCHAR(30) NOT NULL,
|
||||
[ClientSecretHash] VARCHAR(128) NULL,
|
||||
[Scope] NVARCHAR (4000) NOT NULL,
|
||||
[EncryptedPayload] NVARCHAR (4000) NOT NULL,
|
||||
[Key] VARCHAR (MAX) NOT NULL,
|
||||
[ExpireAt] DATETIME2(7) NULL,
|
||||
[CreationDate] DATETIME2(7) NOT NULL,
|
||||
[RevisionDate] DATETIME2(7) NOT NULL,
|
||||
CONSTRAINT [PK_ApiKey] PRIMARY KEY CLUSTERED ([Id] ASC),
|
||||
CONSTRAINT [FK_ApiKey_ServiceAccountId] FOREIGN KEY ([ServiceAccountId]) REFERENCES [dbo].[ServiceAccount] ([Id])
|
||||
);
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
CREATE FUNCTION [dbo].[PolicyApplicableToUser]
|
||||
(
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@PolicyType TINYINT,
|
||||
@MinimumStatus SMALLINT
|
||||
)
|
||||
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 -- OrgUsers who have accepted their invite and are linked to a UserId
|
||||
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
|
||||
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
|
||||
@@ -1,41 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[Collection_CreateWithGroups]
|
||||
@Id UNIQUEIDENTIFIER,
|
||||
@OrganizationId UNIQUEIDENTIFIER,
|
||||
@Name VARCHAR(MAX),
|
||||
@ExternalId NVARCHAR(300),
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7),
|
||||
@Groups AS [dbo].[SelectionReadOnlyArray] READONLY
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
EXEC [dbo].[Collection_Create] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate
|
||||
|
||||
;WITH [AvailableGroupsCTE] AS(
|
||||
SELECT
|
||||
[Id]
|
||||
FROM
|
||||
[dbo].[Group]
|
||||
WHERE
|
||||
[OrganizationId] = @OrganizationId
|
||||
)
|
||||
INSERT INTO [dbo].[CollectionGroup]
|
||||
(
|
||||
[CollectionId],
|
||||
[GroupId],
|
||||
[ReadOnly],
|
||||
[HidePasswords]
|
||||
)
|
||||
SELECT
|
||||
@Id,
|
||||
[Id],
|
||||
[ReadOnly],
|
||||
[HidePasswords]
|
||||
FROM
|
||||
@Groups
|
||||
WHERE
|
||||
[Id] IN (SELECT [Id] FROM [AvailableGroupsCTE])
|
||||
|
||||
EXEC [dbo].[User_BumpAccountRevisionDateByOrganizationId] @OrganizationId
|
||||
END
|
||||
@@ -1,17 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[Collection_ReadWithGroupsById]
|
||||
@Id UNIQUEIDENTIFIER
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
EXEC [dbo].[Collection_ReadById] @Id
|
||||
|
||||
SELECT
|
||||
[GroupId] [Id],
|
||||
[ReadOnly],
|
||||
[HidePasswords]
|
||||
FROM
|
||||
[dbo].[CollectionGroup]
|
||||
WHERE
|
||||
[CollectionId] = @Id
|
||||
END
|
||||
@@ -1,18 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[Collection_ReadWithGroupsByIdUserId]
|
||||
@Id UNIQUEIDENTIFIER,
|
||||
@UserId UNIQUEIDENTIFIER
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
EXEC [dbo].[Collection_ReadByIdUserId] @Id, @UserId
|
||||
|
||||
SELECT
|
||||
[GroupId] [Id],
|
||||
[ReadOnly],
|
||||
[HidePasswords]
|
||||
FROM
|
||||
[dbo].[CollectionGroup]
|
||||
WHERE
|
||||
[CollectionId] = @Id
|
||||
END
|
||||
@@ -1,51 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[Collection_UpdateWithGroups]
|
||||
@Id UNIQUEIDENTIFIER,
|
||||
@OrganizationId UNIQUEIDENTIFIER,
|
||||
@Name VARCHAR(MAX),
|
||||
@ExternalId NVARCHAR(300),
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7),
|
||||
@Groups AS [dbo].[SelectionReadOnlyArray] READONLY
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
EXEC [dbo].[Collection_Update] @Id, @OrganizationId, @Name, @ExternalId, @CreationDate, @RevisionDate
|
||||
|
||||
;WITH [AvailableGroupsCTE] AS(
|
||||
SELECT
|
||||
Id
|
||||
FROM
|
||||
[dbo].[Group]
|
||||
WHERE
|
||||
OrganizationId = @OrganizationId
|
||||
)
|
||||
MERGE
|
||||
[dbo].[CollectionGroup] AS [Target]
|
||||
USING
|
||||
@Groups AS [Source]
|
||||
ON
|
||||
[Target].[CollectionId] = @Id
|
||||
AND [Target].[GroupId] = [Source].[Id]
|
||||
WHEN NOT MATCHED BY TARGET
|
||||
AND [Source].[Id] IN (SELECT [Id] FROM [AvailableGroupsCTE]) THEN
|
||||
INSERT VALUES
|
||||
(
|
||||
@Id,
|
||||
[Source].[Id],
|
||||
[Source].[ReadOnly],
|
||||
[Source].[HidePasswords]
|
||||
)
|
||||
WHEN MATCHED AND (
|
||||
[Target].[ReadOnly] != [Source].[ReadOnly]
|
||||
OR [Target].[HidePasswords] != [Source].[HidePasswords]
|
||||
) THEN
|
||||
UPDATE SET [Target].[ReadOnly] = [Source].[ReadOnly],
|
||||
[Target].[HidePasswords] = [Source].[HidePasswords]
|
||||
WHEN NOT MATCHED BY SOURCE
|
||||
AND [Target].[CollectionId] = @Id THEN
|
||||
DELETE
|
||||
;
|
||||
|
||||
EXEC [dbo].[User_BumpAccountRevisionDateByCollectionId] @Id, @OrganizationId
|
||||
END
|
||||
@@ -1,11 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[Policy_CountByTypeApplicableToUser]
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@PolicyType TINYINT,
|
||||
@MinimumStatus SMALLINT
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT COUNT(1)
|
||||
FROM [dbo].[PolicyApplicableToUser](@UserId, @PolicyType, @MinimumStatus)
|
||||
END
|
||||
@@ -1,11 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[Policy_ReadByTypeApplicableToUser]
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@PolicyType TINYINT,
|
||||
@MinimumStatus SMALLINT
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT *
|
||||
FROM [dbo].[PolicyApplicableToUser](@UserId, @PolicyType, @MinimumStatus)
|
||||
END
|
||||
42
src/Sql/dbo_future/Stored Procedures/ApiKey_Create.sql
Normal file
42
src/Sql/dbo_future/Stored Procedures/ApiKey_Create.sql
Normal file
@@ -0,0 +1,42 @@
|
||||
CREATE PROCEDURE [dbo].[ApiKey_Create]
|
||||
@Id UNIQUEIDENTIFIER OUTPUT,
|
||||
@ServiceAccountId UNIQUEIDENTIFIER,
|
||||
@Name VARCHAR(200),
|
||||
@ClientSecretHash VARCHAR(128),
|
||||
@Scope NVARCHAR(4000),
|
||||
@EncryptedPayload NVARCHAR(4000),
|
||||
@Key VARCHAR(MAX),
|
||||
@ExpireAt DATETIME2(7),
|
||||
@CreationDate DATETIME2(7),
|
||||
@RevisionDate DATETIME2(7)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
INSERT INTO [dbo].[ApiKey]
|
||||
(
|
||||
[Id],
|
||||
[ServiceAccountId],
|
||||
[Name],
|
||||
[ClientSecretHash],
|
||||
[Scope],
|
||||
[EncryptedPayload],
|
||||
[Key],
|
||||
[ExpireAt],
|
||||
[CreationDate],
|
||||
[RevisionDate]
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@Id,
|
||||
@ServiceAccountId,
|
||||
@Name,
|
||||
@ClientSecretHash,
|
||||
@Scope,
|
||||
@EncryptedPayload,
|
||||
@Key,
|
||||
@ExpireAt,
|
||||
@CreationDate,
|
||||
@RevisionDate
|
||||
)
|
||||
END
|
||||
18
src/Sql/dbo_future/Tables/ApiKey.sql
Normal file
18
src/Sql/dbo_future/Tables/ApiKey.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE [dbo].[ApiKey] (
|
||||
[Id] UNIQUEIDENTIFIER,
|
||||
[ServiceAccountId] UNIQUEIDENTIFIER NULL,
|
||||
[Name] VARCHAR(200) NOT NULL,
|
||||
[ClientSecretHash] VARCHAR(128) NULL,
|
||||
[Scope] NVARCHAR (4000) NOT NULL,
|
||||
[EncryptedPayload] NVARCHAR (4000) NOT NULL,
|
||||
[Key] VARCHAR (MAX) NOT NULL,
|
||||
[ExpireAt] DATETIME2(7) NULL,
|
||||
[CreationDate] DATETIME2(7) NOT NULL,
|
||||
[RevisionDate] DATETIME2(7) NOT NULL,
|
||||
CONSTRAINT [PK_ApiKey] PRIMARY KEY CLUSTERED ([Id] ASC),
|
||||
CONSTRAINT [FK_ApiKey_ServiceAccountId] FOREIGN KEY ([ServiceAccountId]) REFERENCES [dbo].[ServiceAccount] ([Id])
|
||||
);
|
||||
|
||||
GO
|
||||
CREATE NONCLUSTERED INDEX [IX_ApiKey_ServiceAccountId]
|
||||
ON [dbo].[ApiKey]([ServiceAccountId] ASC);
|
||||
Reference in New Issue
Block a user