diff --git a/bitwarden-server.sln b/bitwarden-server.sln index 958db9148..ded2f6504 100644 --- a/bitwarden-server.sln +++ b/bitwarden-server.sln @@ -70,25 +70,27 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommCore.Test", "bitwarden_ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test - Bitwarden License", "test - Bitwarden License", "{287CFF34-BBDB-4BC4-AF88-1E19A5A4679B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MySqlMigrations", "util\MySqlMigrations\MySqlMigrations.csproj", "{BDC1D592-5947-47ED-9903-7CDBB12A50C8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MySqlMigrations", "util\MySqlMigrations\MySqlMigrations.csproj", "{BDC1D592-5947-47ED-9903-7CDBB12A50C8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PostgresMigrations", "util\PostgresMigrations\PostgresMigrations.csproj", "{F72E0229-2EF7-49B3-9004-FF4C0043816E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PostgresMigrations", "util\PostgresMigrations\PostgresMigrations.csproj", "{F72E0229-2EF7-49B3-9004-FF4C0043816E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "test\Common\Common.csproj", "{17DA09D7-0212-4009-879E-6B9CFDE5FA60}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "test\Common\Common.csproj", "{17DA09D7-0212-4009-879E-6B9CFDE5FA60}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure.Dapper", "src\Infrastructure.Dapper\Infrastructure.Dapper.csproj", "{AD933445-27CE-4D30-A6ED-9065309464AD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure.Dapper", "src\Infrastructure.Dapper\Infrastructure.Dapper.csproj", "{AD933445-27CE-4D30-A6ED-9065309464AD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedWeb", "src\SharedWeb\SharedWeb.csproj", "{713D44C0-1BC1-4024-96A3-A98A49F33908}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharedWeb", "src\SharedWeb\SharedWeb.csproj", "{713D44C0-1BC1-4024-96A3-A98A49F33908}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infrastructure.EntityFramework", "src\Infrastructure.EntityFramework\Infrastructure.EntityFramework.csproj", "{ED880735-0250-43C7-9662-FDC7C7416E7F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure.EntityFramework", "src\Infrastructure.EntityFramework\Infrastructure.EntityFramework.csproj", "{ED880735-0250-43C7-9662-FDC7C7416E7F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Billing.Test", "test\Billing.Test\Billing.Test.csproj", "{B8639B10-2157-44BC-8CE1-D9EB4B50971F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Billing.Test", "test\Billing.Test\Billing.Test.csproj", "{B8639B10-2157-44BC-8CE1-D9EB4B50971F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.Test", "test\Identity.Test\Identity.Test.csproj", "{310A1D8E-2D3F-4FA0-84D4-FFE31FCE193E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.Test", "test\Identity.Test\Identity.Test.csproj", "{310A1D8E-2D3F-4FA0-84D4-FFE31FCE193E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.IntegrationTest", "test\Identity.IntegrationTest\Identity.IntegrationTest.csproj", "{0D3B2BD2-53F3-421D-AD8F-C19B954C796B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.IntegrationTest", "test\Identity.IntegrationTest\Identity.IntegrationTest.csproj", "{0D3B2BD2-53F3-421D-AD8F-C19B954C796B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationTestCommon", "test\IntegrationTestCommon\IntegrationTestCommon.csproj", "{0923DE59-5FB1-44F2-9302-A09D2236B470}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestCommon", "test\IntegrationTestCommon\IntegrationTestCommon.csproj", "{0923DE59-5FB1-44F2-9302-A09D2236B470}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scim", "bitwarden_license\src\Scim\Scim.csproj", "{BC3B3F8C-621A-4CB8-9563-6EC0A2C8C747}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -214,6 +216,10 @@ Global {0923DE59-5FB1-44F2-9302-A09D2236B470}.Debug|Any CPU.Build.0 = Debug|Any CPU {0923DE59-5FB1-44F2-9302-A09D2236B470}.Release|Any CPU.ActiveCfg = Release|Any CPU {0923DE59-5FB1-44F2-9302-A09D2236B470}.Release|Any CPU.Build.0 = Release|Any CPU + {BC3B3F8C-621A-4CB8-9563-6EC0A2C8C747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC3B3F8C-621A-4CB8-9563-6EC0A2C8C747}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC3B3F8C-621A-4CB8-9563-6EC0A2C8C747}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC3B3F8C-621A-4CB8-9563-6EC0A2C8C747}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -248,6 +254,7 @@ Global {310A1D8E-2D3F-4FA0-84D4-FFE31FCE193E} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F} {0D3B2BD2-53F3-421D-AD8F-C19B954C796B} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F} {0923DE59-5FB1-44F2-9302-A09D2236B470} = {DD5BD056-4AAE-43EF-BBD2-0B569B8DA84F} + {BC3B3F8C-621A-4CB8-9563-6EC0A2C8C747} = {4FDB6543-F68B-4202-9EA6-7FEA984D2D0A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E01CBF68-2E20-425F-9EDB-E0A6510CA92F} diff --git a/bitwarden_license/src/Scim/.dockerignore b/bitwarden_license/src/Scim/.dockerignore new file mode 100644 index 000000000..fc12f2514 --- /dev/null +++ b/bitwarden_license/src/Scim/.dockerignore @@ -0,0 +1,4 @@ +* +!obj/build-output/publish/* +!obj/Docker/empty/ +!entrypoint.sh diff --git a/bitwarden_license/src/Scim/Context/IScimContext.cs b/bitwarden_license/src/Scim/Context/IScimContext.cs new file mode 100644 index 000000000..90e5aca3a --- /dev/null +++ b/bitwarden_license/src/Scim/Context/IScimContext.cs @@ -0,0 +1,21 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Models.OrganizationConnectionConfigs; +using Bit.Core.Repositories; +using Bit.Core.Settings; + +namespace Bit.Scim.Context +{ + public interface IScimContext + { + ScimProviderType RequestScimProvider { get; set; } + ScimConfig ScimConfiguration { get; set; } + Guid? OrganizationId { get; set; } + Organization Organization { get; set; } + Task BuildAsync( + HttpContext httpContext, + GlobalSettings globalSettings, + IOrganizationRepository organizationRepository, + IOrganizationConnectionRepository organizationConnectionRepository); + } +} diff --git a/bitwarden_license/src/Scim/Context/ScimContext.cs b/bitwarden_license/src/Scim/Context/ScimContext.cs new file mode 100644 index 000000000..0e489d33d --- /dev/null +++ b/bitwarden_license/src/Scim/Context/ScimContext.cs @@ -0,0 +1,64 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Models.OrganizationConnectionConfigs; +using Bit.Core.Repositories; +using Bit.Core.Settings; + +namespace Bit.Scim.Context +{ + public class ScimContext : IScimContext + { + private bool _builtHttpContext; + + public ScimProviderType RequestScimProvider { get; set; } = ScimProviderType.Default; + public ScimConfig ScimConfiguration { get; set; } + public Guid? OrganizationId { get; set; } + public Organization Organization { get; set; } + + public async virtual Task BuildAsync( + HttpContext httpContext, + GlobalSettings globalSettings, + IOrganizationRepository organizationRepository, + IOrganizationConnectionRepository organizationConnectionRepository) + { + if (_builtHttpContext) + { + return; + } + + _builtHttpContext = true; + + string orgIdString = null; + if (httpContext.Request.RouteValues.TryGetValue("organizationId", out var orgIdObject)) + { + orgIdString = orgIdObject?.ToString(); + } + + if (Guid.TryParse(orgIdString, out var orgId)) + { + OrganizationId = orgId; + Organization = await organizationRepository.GetByIdAsync(orgId); + if (Organization != null) + { + var scimConnections = await organizationConnectionRepository.GetByOrganizationIdTypeAsync(Organization.Id, + OrganizationConnectionType.Scim); + ScimConfiguration = scimConnections?.FirstOrDefault()?.GetConfig(); + } + } + + if (RequestScimProvider == ScimProviderType.Default && + httpContext.Request.Headers.TryGetValue("User-Agent", out var userAgent)) + { + if (userAgent.ToString().StartsWith("Okta")) + { + RequestScimProvider = ScimProviderType.Okta; + } + } + if (RequestScimProvider == ScimProviderType.Default && + httpContext.Request.Headers.ContainsKey("Adscimversion")) + { + RequestScimProvider = ScimProviderType.AzureAd; + } + } + } +} diff --git a/bitwarden_license/src/Scim/Controllers/InfoController.cs b/bitwarden_license/src/Scim/Controllers/InfoController.cs new file mode 100644 index 000000000..47063b833 --- /dev/null +++ b/bitwarden_license/src/Scim/Controllers/InfoController.cs @@ -0,0 +1,21 @@ +using Bit.Core.Utilities; +using Microsoft.AspNetCore.Mvc; + +namespace Bit.Scim.Controllers +{ + public class InfoController : Controller + { + [HttpGet("~/alive")] + [HttpGet("~/now")] + public DateTime GetAlive() + { + return DateTime.UtcNow; + } + + [HttpGet("~/version")] + public JsonResult GetVersion() + { + return Json(CoreHelpers.GetVersion()); + } + } +} diff --git a/bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs b/bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs new file mode 100644 index 000000000..f3c5bbb60 --- /dev/null +++ b/bitwarden_license/src/Scim/Controllers/v2/GroupsController.cs @@ -0,0 +1,290 @@ +using System.Text.Json; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Scim.Context; +using Bit.Scim.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace Bit.Scim.Controllers.v2 +{ + [Authorize("Scim")] + [Route("v2/{organizationId}/groups")] + public class GroupsController : Controller + { + private readonly ScimSettings _scimSettings; + private readonly IGroupRepository _groupRepository; + private readonly IGroupService _groupService; + private readonly IScimContext _scimContext; + private readonly ILogger _logger; + + public GroupsController( + IGroupRepository groupRepository, + IGroupService groupService, + IOptions scimSettings, + IScimContext scimContext, + ILogger logger) + { + _scimSettings = scimSettings?.Value; + _groupRepository = groupRepository; + _groupService = groupService; + _scimContext = scimContext; + _logger = logger; + } + + [HttpGet("{id}")] + public async Task Get(Guid organizationId, Guid id) + { + var group = await _groupRepository.GetByIdAsync(id); + if (group == null || group.OrganizationId != organizationId) + { + return new NotFoundObjectResult(new ScimErrorResponseModel + { + Status = 404, + Detail = "Group not found." + }); + } + return new ObjectResult(new ScimGroupResponseModel(group)); + } + + [HttpGet("")] + public async Task Get( + Guid organizationId, + [FromQuery] string filter, + [FromQuery] int? count, + [FromQuery] int? startIndex) + { + string nameFilter = null; + string externalIdFilter = null; + if (!string.IsNullOrWhiteSpace(filter)) + { + if (filter.StartsWith("displayName eq ")) + { + nameFilter = filter.Substring(15).Trim('"'); + } + else if (filter.StartsWith("externalId eq ")) + { + externalIdFilter = filter.Substring(14).Trim('"'); + } + } + + var groupList = new List(); + var groups = await _groupRepository.GetManyByOrganizationIdAsync(organizationId); + var totalResults = 0; + if (!string.IsNullOrWhiteSpace(nameFilter)) + { + var group = groups.FirstOrDefault(g => g.Name == nameFilter); + if (group != null) + { + groupList.Add(new ScimGroupResponseModel(group)); + } + totalResults = groupList.Count; + } + else if (!string.IsNullOrWhiteSpace(externalIdFilter)) + { + var group = groups.FirstOrDefault(ou => ou.ExternalId == externalIdFilter); + if (group != null) + { + groupList.Add(new ScimGroupResponseModel(group)); + } + totalResults = groupList.Count; + } + else if (string.IsNullOrWhiteSpace(filter) && startIndex.HasValue && count.HasValue) + { + groupList = groups.OrderBy(g => g.Name) + .Skip(startIndex.Value - 1) + .Take(count.Value) + .Select(g => new ScimGroupResponseModel(g)) + .ToList(); + totalResults = groups.Count; + } + + var result = new ScimListResponseModel + { + Resources = groupList, + ItemsPerPage = count.GetValueOrDefault(groupList.Count), + TotalResults = totalResults, + StartIndex = startIndex.GetValueOrDefault(1), + }; + return new ObjectResult(result); + } + + [HttpPost("")] + public async Task Post(Guid organizationId, [FromBody] ScimGroupRequestModel model) + { + if (string.IsNullOrWhiteSpace(model.DisplayName)) + { + return new BadRequestResult(); + } + + var groups = await _groupRepository.GetManyByOrganizationIdAsync(organizationId); + if (!string.IsNullOrWhiteSpace(model.ExternalId) && groups.Any(g => g.ExternalId == model.ExternalId)) + { + return new ConflictResult(); + } + + var group = model.ToGroup(organizationId); + await _groupService.SaveAsync(group, null); + var response = new ScimGroupResponseModel(group); + return new CreatedResult(Url.Action(nameof(Get), new { group.OrganizationId, group.Id }), response); + } + + [HttpPut("{id}")] + public async Task Put(Guid organizationId, Guid id, [FromBody] ScimGroupRequestModel model) + { + var group = await _groupRepository.GetByIdAsync(id); + if (group == null || group.OrganizationId != organizationId) + { + return new NotFoundObjectResult(new ScimErrorResponseModel + { + Status = 404, + Detail = "Group not found." + }); + } + + group.Name = model.DisplayName; + await _groupService.SaveAsync(group); + return new ObjectResult(new ScimGroupResponseModel(group)); + } + + [HttpPatch("{id}")] + public async Task Patch(Guid organizationId, Guid id, [FromBody] ScimPatchModel model) + { + var group = await _groupRepository.GetByIdAsync(id); + if (group == null || group.OrganizationId != organizationId) + { + return new NotFoundObjectResult(new ScimErrorResponseModel + { + Status = 404, + Detail = "Group not found." + }); + } + + var operationHandled = false; + + var replaceOp = model.Operations?.FirstOrDefault(o => o.Op == "replace"); + if (replaceOp != null) + { + // Replace a list of members + if (replaceOp.Path == "members") + { + var ids = GetOperationValueIds(replaceOp.Value); + await _groupRepository.UpdateUsersAsync(group.Id, ids); + operationHandled = true; + } + // Replace group name + else if (replaceOp.Value.TryGetProperty("displayName", out var displayNameProperty)) + { + group.Name = displayNameProperty.GetString(); + await _groupService.SaveAsync(group); + operationHandled = true; + } + } + + // Add a single member + var addMemberOp = model.Operations?.FirstOrDefault( + o => o.Op == "add" && !string.IsNullOrWhiteSpace(o.Path) && o.Path.StartsWith("members[value eq ")); + if (addMemberOp != null) + { + var addId = GetOperationPathId(addMemberOp.Path); + if (addId.HasValue) + { + var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet(); + orgUserIds.Add(addId.Value); + await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds); + operationHandled = true; + } + } + + // Add a list of members + var addMembersOp = model.Operations?.FirstOrDefault(o => o.Op == "add" && o.Path == "members"); + if (addMembersOp != null) + { + var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet(); + foreach (var v in GetOperationValueIds(addMembersOp.Value)) + { + orgUserIds.Add(v); + } + await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds); + operationHandled = true; + } + + // Remove a single member + var removeMemberOp = model.Operations?.FirstOrDefault( + o => o.Op == "remove" && !string.IsNullOrWhiteSpace(o.Path) && o.Path.StartsWith("members[value eq ")); + if (removeMemberOp != null) + { + var removeId = GetOperationPathId(removeMemberOp.Path); + if (removeId.HasValue) + { + await _groupService.DeleteUserAsync(group, removeId.Value); + operationHandled = true; + } + } + + // Remove a list of members + var removeMembersOp = model.Operations?.FirstOrDefault(o => o.Op == "remove" && o.Path == "members"); + if (removeMembersOp != null) + { + var orgUserIds = (await _groupRepository.GetManyUserIdsByIdAsync(group.Id)).ToHashSet(); + foreach (var v in GetOperationValueIds(removeMembersOp.Value)) + { + orgUserIds.Remove(v); + } + await _groupRepository.UpdateUsersAsync(group.Id, orgUserIds); + operationHandled = true; + } + + if (!operationHandled) + { + _logger.LogWarning("Group patch operation not handled: {0} : ", + string.Join(", ", model.Operations.Select(o => $"{o.Op}:{o.Path}"))); + } + + return new NoContentResult(); + } + + [HttpDelete("{id}")] + public async Task Delete(Guid organizationId, Guid id) + { + var group = await _groupRepository.GetByIdAsync(id); + if (group == null || group.OrganizationId != organizationId) + { + return new NotFoundObjectResult(new ScimErrorResponseModel + { + Status = 404, + Detail = "Group not found." + }); + } + await _groupService.DeleteAsync(group); + return new NoContentResult(); + } + + private List GetOperationValueIds(JsonElement objArray) + { + var ids = new List(); + foreach (var obj in objArray.EnumerateArray()) + { + if (obj.TryGetProperty("value", out var valueProperty)) + { + if (valueProperty.TryGetGuid(out var guid)) + { + ids.Add(guid); + } + } + } + return ids; + } + + private Guid? GetOperationPathId(string path) + { + // Parse Guid from string like: members[value eq "{GUID}"}] + if (Guid.TryParse(path.Substring(18).Replace("\"]", string.Empty), out var id)) + { + return id; + } + return null; + } + } +} diff --git a/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs b/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs new file mode 100644 index 000000000..e6313e4e1 --- /dev/null +++ b/bitwarden_license/src/Scim/Controllers/v2/UsersController.cs @@ -0,0 +1,267 @@ +using Bit.Core.Enums; +using Bit.Core.Models.Data; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Core.Utilities; +using Bit.Scim.Context; +using Bit.Scim.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace Bit.Scim.Controllers.v2 +{ + [Authorize("Scim")] + [Route("v2/{organizationId}/users")] + public class UsersController : Controller + { + private readonly IUserService _userService; + private readonly IUserRepository _userRepository; + private readonly IOrganizationUserRepository _organizationUserRepository; + private readonly IOrganizationService _organizationService; + private readonly IScimContext _scimContext; + private readonly ScimSettings _scimSettings; + private readonly ILogger _logger; + + public UsersController( + IUserService userService, + IUserRepository userRepository, + IOrganizationUserRepository organizationUserRepository, + IOrganizationService organizationService, + IScimContext scimContext, + IOptions scimSettings, + ILogger logger) + { + _userService = userService; + _userRepository = userRepository; + _organizationUserRepository = organizationUserRepository; + _organizationService = organizationService; + _scimContext = scimContext; + _scimSettings = scimSettings?.Value; + _logger = logger; + } + + [HttpGet("{id}")] + public async Task Get(Guid organizationId, Guid id) + { + var orgUser = await _organizationUserRepository.GetDetailsByIdAsync(id); + if (orgUser == null || orgUser.OrganizationId != organizationId) + { + return new NotFoundObjectResult(new ScimErrorResponseModel + { + Status = 404, + Detail = "User not found." + }); + } + return new ObjectResult(new ScimUserResponseModel(orgUser)); + } + + [HttpGet("")] + public async Task Get( + Guid organizationId, + [FromQuery] string filter, + [FromQuery] int? count, + [FromQuery] int? startIndex) + { + string emailFilter = null; + string usernameFilter = null; + string externalIdFilter = null; + if (!string.IsNullOrWhiteSpace(filter)) + { + if (filter.StartsWith("userName eq ")) + { + usernameFilter = filter.Substring(12).Trim('"').ToLowerInvariant(); + if (usernameFilter.Contains("@")) + { + emailFilter = usernameFilter; + } + } + else if (filter.StartsWith("externalId eq ")) + { + externalIdFilter = filter.Substring(14).Trim('"'); + } + } + + var userList = new List { }; + var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId); + var totalResults = 0; + if (!string.IsNullOrWhiteSpace(emailFilter)) + { + var orgUser = orgUsers.FirstOrDefault(ou => ou.Email.ToLowerInvariant() == emailFilter); + if (orgUser != null) + { + userList.Add(new ScimUserResponseModel(orgUser)); + } + totalResults = userList.Count; + } + else if (!string.IsNullOrWhiteSpace(externalIdFilter)) + { + var orgUser = orgUsers.FirstOrDefault(ou => ou.ExternalId == externalIdFilter); + if (orgUser != null) + { + userList.Add(new ScimUserResponseModel(orgUser)); + } + totalResults = userList.Count; + } + else if (string.IsNullOrWhiteSpace(filter) && startIndex.HasValue && count.HasValue) + { + userList = orgUsers.OrderBy(ou => ou.Email) + .Skip(startIndex.Value - 1) + .Take(count.Value) + .Select(ou => new ScimUserResponseModel(ou)) + .ToList(); + totalResults = orgUsers.Count; + } + + var result = new ScimListResponseModel + { + Resources = userList, + ItemsPerPage = count.GetValueOrDefault(userList.Count), + TotalResults = totalResults, + StartIndex = startIndex.GetValueOrDefault(1), + }; + return new ObjectResult(result); + } + + [HttpPost("")] + public async Task Post(Guid organizationId, [FromBody] ScimUserRequestModel model) + { + var email = model.PrimaryEmail?.ToLowerInvariant(); + if (string.IsNullOrWhiteSpace(email)) + { + switch (_scimContext.RequestScimProvider) + { + case ScimProviderType.AzureAd: + email = model.UserName?.ToLowerInvariant(); + break; + default: + break; + } + } + + if (string.IsNullOrWhiteSpace(email) || !model.Active) + { + return new BadRequestResult(); + } + + var orgUsers = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(organizationId); + var orgUserByEmail = orgUsers.FirstOrDefault(ou => ou.Email?.ToLowerInvariant() == email); + if (orgUserByEmail != null) + { + return new ConflictResult(); + } + + string externalId = null; + if (!string.IsNullOrWhiteSpace(model.ExternalId)) + { + externalId = model.ExternalId; + } + else if (!string.IsNullOrWhiteSpace(model.UserName)) + { + externalId = model.UserName; + } + else + { + externalId = CoreHelpers.RandomString(15); + } + + var orgUserByExternalId = orgUsers.FirstOrDefault(ou => ou.ExternalId == externalId); + if (orgUserByExternalId != null) + { + return new ConflictResult(); + } + + var invitedOrgUser = await _organizationService.InviteUserAsync(organizationId, null, email, + OrganizationUserType.User, false, externalId, new List()); + var orgUser = await _organizationUserRepository.GetDetailsByIdAsync(invitedOrgUser.Id); + var response = new ScimUserResponseModel(orgUser); + return new CreatedResult(Url.Action(nameof(Get), new { orgUser.OrganizationId, orgUser.Id }), response); + } + + [HttpPut("{id}")] + public async Task Put(Guid organizationId, Guid id, [FromBody] ScimUserRequestModel model) + { + var orgUser = await _organizationUserRepository.GetByIdAsync(id); + if (orgUser == null || orgUser.OrganizationId != organizationId) + { + return new NotFoundObjectResult(new ScimErrorResponseModel + { + Status = 404, + Detail = "User not found." + }); + } + + if (model.Active && orgUser.Status == OrganizationUserStatusType.Deactivated) + { + await _organizationService.ActivateUserAsync(orgUser, null); + } + else if (!model.Active && orgUser.Status != OrganizationUserStatusType.Deactivated) + { + await _organizationService.DeactivateUserAsync(orgUser, null); + } + + // Have to get full details object for response model + var orgUserDetails = await _organizationUserRepository.GetDetailsByIdAsync(id); + return new ObjectResult(new ScimUserResponseModel(orgUserDetails)); + } + + [HttpPatch("{id}")] + public async Task Patch(Guid organizationId, Guid id, [FromBody] ScimPatchModel model) + { + var orgUser = await _organizationUserRepository.GetByIdAsync(id); + if (orgUser == null || orgUser.OrganizationId != organizationId) + { + return new NotFoundObjectResult(new ScimErrorResponseModel + { + Status = 404, + Detail = "User not found." + }); + } + + var operationHandled = false; + + var replaceOp = model.Operations?.FirstOrDefault(o => o.Op == "replace"); + if (replaceOp != null) + { + if (replaceOp.Value.TryGetProperty("active", out var activeProperty)) + { + var active = activeProperty.GetBoolean(); + if (active && orgUser.Status == OrganizationUserStatusType.Deactivated) + { + await _organizationService.ActivateUserAsync(orgUser, null); + operationHandled = true; + } + else if (!active && orgUser.Status != OrganizationUserStatusType.Deactivated) + { + await _organizationService.DeactivateUserAsync(orgUser, null); + operationHandled = true; + } + } + } + + if (!operationHandled) + { + _logger.LogWarning("User patch operation not handled: {operation} : ", + string.Join(", ", model.Operations.Select(o => $"{o.Op}:{o.Path}"))); + } + + return new NoContentResult(); + } + + [HttpDelete("{id}")] + public async Task Delete(Guid organizationId, Guid id, [FromBody] ScimUserRequestModel model) + { + var orgUser = await _organizationUserRepository.GetByIdAsync(id); + if (orgUser == null || orgUser.OrganizationId != organizationId) + { + return new NotFoundObjectResult(new ScimErrorResponseModel + { + Status = 404, + Detail = "User not found." + }); + } + await _organizationService.DeleteUserAsync(organizationId, id, null); + return new NoContentResult(); + } + } +} diff --git a/bitwarden_license/src/Scim/Dockerfile b/bitwarden_license/src/Scim/Dockerfile new file mode 100644 index 000000000..f63cb82ce --- /dev/null +++ b/bitwarden_license/src/Scim/Dockerfile @@ -0,0 +1,20 @@ +FROM mcr.microsoft.com/dotnet/aspnet:6.0 + +LABEL com.bitwarden.product="bitwarden" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + gosu \ + curl \ + && rm -rf /var/lib/apt/lists/* + +ENV ASPNETCORE_URLS http://+:5000 +WORKDIR /app +EXPOSE 5000 +COPY obj/build-output/publish . +COPY entrypoint.sh / +RUN chmod +x /entrypoint.sh + +HEALTHCHECK CMD curl -f http://localhost:5000/alive || exit 1 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/bitwarden_license/src/Scim/Models/BaseScimGroupModel.cs b/bitwarden_license/src/Scim/Models/BaseScimGroupModel.cs new file mode 100644 index 000000000..06d57bfad --- /dev/null +++ b/bitwarden_license/src/Scim/Models/BaseScimGroupModel.cs @@ -0,0 +1,18 @@ +using Bit.Scim.Utilities; + +namespace Bit.Scim.Models +{ + public abstract class BaseScimGroupModel : BaseScimModel + { + public BaseScimGroupModel(bool initSchema = false) + { + if (initSchema) + { + Schemas = new List { ScimConstants.Scim2SchemaGroup }; + } + } + + public string DisplayName { get; set; } + public string ExternalId { get; set; } + } +} diff --git a/bitwarden_license/src/Scim/Models/BaseScimModel.cs b/bitwarden_license/src/Scim/Models/BaseScimModel.cs new file mode 100644 index 000000000..a2a071786 --- /dev/null +++ b/bitwarden_license/src/Scim/Models/BaseScimModel.cs @@ -0,0 +1,15 @@ +namespace Bit.Scim.Models +{ + public abstract class BaseScimModel + { + public BaseScimModel() + { } + + public BaseScimModel(string schema) + { + Schemas = new List { schema }; + } + + public List Schemas { get; set; } + } +} diff --git a/bitwarden_license/src/Scim/Models/BaseScimUserModel.cs b/bitwarden_license/src/Scim/Models/BaseScimUserModel.cs new file mode 100644 index 000000000..53d94689c --- /dev/null +++ b/bitwarden_license/src/Scim/Models/BaseScimUserModel.cs @@ -0,0 +1,55 @@ +using Bit.Scim.Utilities; + +namespace Bit.Scim.Models +{ + public abstract class BaseScimUserModel : BaseScimModel + { + public BaseScimUserModel(bool initSchema = false) + { + if (initSchema) + { + Schemas = new List { ScimConstants.Scim2SchemaUser }; + } + } + + public string UserName { get; set; } + public NameModel Name { get; set; } + public List Emails { get; set; } + public string PrimaryEmail => Emails?.FirstOrDefault(e => e.Primary)?.Value; + public string DisplayName { get; set; } + public bool Active { get; set; } + public List Groups { get; set; } + public string ExternalId { get; set; } + + public class NameModel + { + public NameModel() { } + + public NameModel(string name) + { + Formatted = name; + } + + public string Formatted { get; set; } + public string GivenName { get; set; } + public string MiddleName { get; set; } + public string FamilyName { get; set; } + } + + public class EmailModel + { + public EmailModel() { } + + public EmailModel(string email) + { + Primary = true; + Value = email; + Type = "work"; + } + + public bool Primary { get; set; } + public string Value { get; set; } + public string Type { get; set; } + } + } +} diff --git a/bitwarden_license/src/Scim/Models/ScimErrorResponseModel.cs b/bitwarden_license/src/Scim/Models/ScimErrorResponseModel.cs new file mode 100644 index 000000000..6055001f5 --- /dev/null +++ b/bitwarden_license/src/Scim/Models/ScimErrorResponseModel.cs @@ -0,0 +1,14 @@ +using Bit.Scim.Utilities; + +namespace Bit.Scim.Models +{ + public class ScimErrorResponseModel : BaseScimModel + { + public ScimErrorResponseModel() + : base(ScimConstants.Scim2SchemaError) + { } + + public string Detail { get; set; } + public int Status { get; set; } + } +} diff --git a/bitwarden_license/src/Scim/Models/ScimGroupRequestModel.cs b/bitwarden_license/src/Scim/Models/ScimGroupRequestModel.cs new file mode 100644 index 000000000..93361066c --- /dev/null +++ b/bitwarden_license/src/Scim/Models/ScimGroupRequestModel.cs @@ -0,0 +1,23 @@ +using Bit.Core.Entities; +using Bit.Core.Utilities; + +namespace Bit.Scim.Models +{ + public class ScimGroupRequestModel : BaseScimGroupModel + { + public ScimGroupRequestModel() + : base(false) + { } + + public Group ToGroup(Guid organizationId) + { + var externalId = string.IsNullOrWhiteSpace(ExternalId) ? CoreHelpers.RandomString(15) : ExternalId; + return new Group + { + Name = DisplayName, + ExternalId = externalId, + OrganizationId = organizationId + }; + } + } +} diff --git a/bitwarden_license/src/Scim/Models/ScimGroupResponseModel.cs b/bitwarden_license/src/Scim/Models/ScimGroupResponseModel.cs new file mode 100644 index 000000000..df5d9b22a --- /dev/null +++ b/bitwarden_license/src/Scim/Models/ScimGroupResponseModel.cs @@ -0,0 +1,26 @@ +using Bit.Core.Entities; + +namespace Bit.Scim.Models +{ + public class ScimGroupResponseModel : BaseScimGroupModel + { + public ScimGroupResponseModel() + : base(true) + { + Meta = new ScimMetaModel("Group"); + } + + public ScimGroupResponseModel(Group group) + : this() + { + Id = group.Id.ToString(); + DisplayName = group.Name; + ExternalId = group.ExternalId; + Meta.Created = group.CreationDate; + Meta.LastModified = group.RevisionDate; + } + + public string Id { get; set; } + public ScimMetaModel Meta { get; private set; } + } +} diff --git a/bitwarden_license/src/Scim/Models/ScimListResponseModel.cs b/bitwarden_license/src/Scim/Models/ScimListResponseModel.cs new file mode 100644 index 000000000..e7b952168 --- /dev/null +++ b/bitwarden_license/src/Scim/Models/ScimListResponseModel.cs @@ -0,0 +1,16 @@ +using Bit.Scim.Utilities; + +namespace Bit.Scim.Models +{ + public class ScimListResponseModel : BaseScimModel + { + public ScimListResponseModel() + : base(ScimConstants.Scim2SchemaListResponse) + { } + + public int TotalResults { get; set; } + public int StartIndex { get; set; } + public int ItemsPerPage { get; set; } + public List Resources { get; set; } + } +} diff --git a/bitwarden_license/src/Scim/Models/ScimMetaModel.cs b/bitwarden_license/src/Scim/Models/ScimMetaModel.cs new file mode 100644 index 000000000..f3d95f5f3 --- /dev/null +++ b/bitwarden_license/src/Scim/Models/ScimMetaModel.cs @@ -0,0 +1,14 @@ +namespace Bit.Scim.Models +{ + public class ScimMetaModel + { + public ScimMetaModel(string resourceType) + { + ResourceType = resourceType; + } + + public string ResourceType { get; set; } + public DateTime? Created { get; set; } + public DateTime? LastModified { get; set; } + } +} diff --git a/bitwarden_license/src/Scim/Models/ScimPatchModel.cs b/bitwarden_license/src/Scim/Models/ScimPatchModel.cs new file mode 100644 index 000000000..d42126765 --- /dev/null +++ b/bitwarden_license/src/Scim/Models/ScimPatchModel.cs @@ -0,0 +1,19 @@ +using System.Text.Json; + +namespace Bit.Scim.Models +{ + public class ScimPatchModel : BaseScimModel + { + public ScimPatchModel() + : base() { } + + public List Operations { get; set; } + + public class OperationModel + { + public string Op { get; set; } + public string Path { get; set; } + public JsonElement Value { get; set; } + } + } +} diff --git a/bitwarden_license/src/Scim/Models/ScimUserRequestModel.cs b/bitwarden_license/src/Scim/Models/ScimUserRequestModel.cs new file mode 100644 index 000000000..17f5e8593 --- /dev/null +++ b/bitwarden_license/src/Scim/Models/ScimUserRequestModel.cs @@ -0,0 +1,9 @@ +namespace Bit.Scim.Models +{ + public class ScimUserRequestModel : BaseScimUserModel + { + public ScimUserRequestModel() + : base(false) + { } + } +} diff --git a/bitwarden_license/src/Scim/Models/ScimUserResponseModel.cs b/bitwarden_license/src/Scim/Models/ScimUserResponseModel.cs new file mode 100644 index 000000000..12401de9d --- /dev/null +++ b/bitwarden_license/src/Scim/Models/ScimUserResponseModel.cs @@ -0,0 +1,29 @@ +using Bit.Core.Models.Data.Organizations.OrganizationUsers; + +namespace Bit.Scim.Models +{ + public class ScimUserResponseModel : BaseScimUserModel + { + public ScimUserResponseModel() + : base(true) + { + Meta = new ScimMetaModel("User"); + Groups = new List(); + } + + public ScimUserResponseModel(OrganizationUserUserDetails orgUser) + : this() + { + Id = orgUser.Id.ToString(); + ExternalId = orgUser.ExternalId; + UserName = orgUser.Email; + DisplayName = orgUser.Name; + Emails = new List { new EmailModel(orgUser.Email) }; + Name = new NameModel(orgUser.Name); + Active = orgUser.Status != Core.Enums.OrganizationUserStatusType.Deactivated; + } + + public string Id { get; set; } + public ScimMetaModel Meta { get; private set; } + } +} diff --git a/bitwarden_license/src/Scim/Program.cs b/bitwarden_license/src/Scim/Program.cs new file mode 100644 index 000000000..f8d6cb15b --- /dev/null +++ b/bitwarden_license/src/Scim/Program.cs @@ -0,0 +1,34 @@ +using Bit.Core.Utilities; +using Serilog.Events; + +namespace Bit.Scim +{ + public class Program + { + public static void Main(string[] args) + { + Host + .CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + webBuilder.ConfigureLogging((hostingContext, logging) => + logging.AddSerilog(hostingContext, e => + { + var context = e.Properties["SourceContext"].ToString(); + + if (e.Properties.ContainsKey("RequestPath") && + !string.IsNullOrWhiteSpace(e.Properties["RequestPath"]?.ToString()) && + (context.Contains(".Server.Kestrel") || context.Contains(".Core.IISHttpServer"))) + { + return false; + } + + return e.Level >= LogEventLevel.Warning; + })); + }) + .Build() + .Run(); + } + } +} diff --git a/bitwarden_license/src/Scim/Properties/launchSettings.json b/bitwarden_license/src/Scim/Properties/launchSettings.json new file mode 100644 index 000000000..a391acb2b --- /dev/null +++ b/bitwarden_license/src/Scim/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:44558/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": false, + "launchUrl": "http://localhost:44558", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Scim": { + "commandName": "Project", + "launchBrowser": false, + "launchUrl": "http://localhost:44558", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:44559" + } + } +} diff --git a/bitwarden_license/src/Scim/Scim.csproj b/bitwarden_license/src/Scim/Scim.csproj new file mode 100644 index 000000000..3387d74e0 --- /dev/null +++ b/bitwarden_license/src/Scim/Scim.csproj @@ -0,0 +1,17 @@ + + + + bitwarden-Scim + false + + + + + + + + + + + + diff --git a/bitwarden_license/src/Scim/ScimSettings.cs b/bitwarden_license/src/Scim/ScimSettings.cs new file mode 100644 index 000000000..5c25dbf37 --- /dev/null +++ b/bitwarden_license/src/Scim/ScimSettings.cs @@ -0,0 +1,6 @@ +namespace Bit.Scim +{ + public class ScimSettings + { + } +} diff --git a/bitwarden_license/src/Scim/Startup.cs b/bitwarden_license/src/Scim/Startup.cs new file mode 100644 index 000000000..96da6632d --- /dev/null +++ b/bitwarden_license/src/Scim/Startup.cs @@ -0,0 +1,113 @@ +using System.Globalization; +using Bit.Core.Context; +using Bit.Core.Settings; +using Bit.Core.Utilities; +using Bit.Scim.Context; +using Bit.Scim.Utilities; +using Bit.SharedWeb.Utilities; +using IdentityModel; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Stripe; + +namespace Bit.Scim +{ + public class Startup + { + public Startup(IWebHostEnvironment env, IConfiguration configuration) + { + CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); + Configuration = configuration; + Environment = env; + } + + public IConfiguration Configuration { get; } + public IWebHostEnvironment Environment { get; set; } + + public void ConfigureServices(IServiceCollection services) + { + // Options + services.AddOptions(); + + // Settings + var globalSettings = services.AddGlobalSettingsServices(Configuration, Environment); + services.Configure(Configuration.GetSection("ScimSettings")); + + // Stripe Billing + StripeConfiguration.ApiKey = globalSettings.Stripe.ApiKey; + StripeConfiguration.MaxNetworkRetries = globalSettings.Stripe.MaxNetworkRetries; + + // Repositories + services.AddSqlServerRepositories(globalSettings); + + // Context + services.AddScoped(); + services.AddScoped(); + + // Authentication + services.AddAuthentication(ApiKeyAuthenticationOptions.DefaultScheme) + .AddScheme( + ApiKeyAuthenticationOptions.DefaultScheme, null); + + services.AddAuthorization(config => + { + config.AddPolicy("Scim", policy => + { + policy.RequireAuthenticatedUser(); + policy.RequireClaim(JwtClaimTypes.Scope, "api.scim"); + }); + }); + + // Identity + services.AddCustomIdentityServices(globalSettings); + + // Services + services.AddBaseServices(globalSettings); + services.AddDefaultServices(globalSettings); + + services.TryAddSingleton(); + + // Mvc + services.AddMvc(config => + { + config.Filters.Add(new LoggingExceptionHandlerFilterAttribute()); + }); + services.Configure(options => options.LowercaseUrls = true); + } + + public void Configure( + IApplicationBuilder app, + IWebHostEnvironment env, + IHostApplicationLifetime appLifetime, + GlobalSettings globalSettings) + { + app.UseSerilog(env, appLifetime, globalSettings); + + // Add general security headers + app.UseMiddleware(); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + // Default Middleware + app.UseDefaultMiddleware(env, globalSettings); + + // Add routing + app.UseRouting(); + + // Add Scim context + app.UseMiddleware(); + + // Add authentication and authorization to the request pipeline. + app.UseAuthentication(); + app.UseAuthorization(); + + // Add current context + app.UseMiddleware(); + + // Add MVC to the request pipeline. + app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute()); + } + } +} diff --git a/bitwarden_license/src/Scim/Utilities/ApiKeyAuthenticationHandler.cs b/bitwarden_license/src/Scim/Utilities/ApiKeyAuthenticationHandler.cs new file mode 100644 index 000000000..e5f75089a --- /dev/null +++ b/bitwarden_license/src/Scim/Utilities/ApiKeyAuthenticationHandler.cs @@ -0,0 +1,83 @@ +using System.Security.Claims; +using System.Text.Encodings.Web; +using Bit.Core.Enums; +using Bit.Core.Repositories; +using Bit.Scim.Context; +using IdentityModel; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Options; + +namespace Bit.Scim.Utilities +{ + public class ApiKeyAuthenticationHandler : AuthenticationHandler + { + private readonly IOrganizationRepository _organizationRepository; + private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository; + private readonly IScimContext _scimContext; + + public ApiKeyAuthenticationHandler( + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + ISystemClock clock, + IOrganizationRepository organizationRepository, + IOrganizationApiKeyRepository organizationApiKeyRepository, + IScimContext scimContext) : + base(options, logger, encoder, clock) + { + _organizationRepository = organizationRepository; + _organizationApiKeyRepository = organizationApiKeyRepository; + _scimContext = scimContext; + } + + protected override async Task HandleAuthenticateAsync() + { + if (!_scimContext.OrganizationId.HasValue || _scimContext.Organization == null) + { + Logger.LogWarning("No organization."); + return AuthenticateResult.Fail("Invalid parameters"); + } + + if (!Request.Headers.TryGetValue("Authorization", out var authHeader) || authHeader.Count != 1) + { + Logger.LogWarning("An API request was received without the Authorization header"); + return AuthenticateResult.Fail("Invalid parameters"); + } + var apiKey = authHeader.ToString(); + if (apiKey.StartsWith("Bearer ")) + { + apiKey = apiKey.Substring(7); + } + + if (!_scimContext.Organization.Enabled || !_scimContext.Organization.UseScim || + _scimContext.ScimConfiguration == null || !_scimContext.ScimConfiguration.Enabled) + { + Logger.LogInformation("Org {organizationId} not able to use Scim.", _scimContext.OrganizationId); + return AuthenticateResult.Fail("Invalid parameters"); + } + + var orgApiKey = (await _organizationApiKeyRepository + .GetManyByOrganizationIdTypeAsync(_scimContext.Organization.Id, OrganizationApiKeyType.Scim)) + .FirstOrDefault(); + if (orgApiKey?.ApiKey != apiKey) + { + Logger.LogWarning("An API request was received with an invalid API key: {apiKey}", apiKey); + return AuthenticateResult.Fail("Invalid parameters"); + } + + Logger.LogInformation("Org {organizationId} authenticated", _scimContext.OrganizationId); + + var claims = new[] + { + new Claim(JwtClaimTypes.ClientId, $"organization.{_scimContext.OrganizationId.Value}"), + new Claim("client_sub", _scimContext.OrganizationId.Value.ToString()), + new Claim(JwtClaimTypes.Scope, "api.scim"), + }; + var identity = new ClaimsIdentity(claims, nameof(ApiKeyAuthenticationHandler)); + var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), + ApiKeyAuthenticationOptions.DefaultScheme); + + return AuthenticateResult.Success(ticket); + } + } +} diff --git a/bitwarden_license/src/Scim/Utilities/ApiKeyAuthenticationOptions.cs b/bitwarden_license/src/Scim/Utilities/ApiKeyAuthenticationOptions.cs new file mode 100644 index 000000000..7d2bb3e81 --- /dev/null +++ b/bitwarden_license/src/Scim/Utilities/ApiKeyAuthenticationOptions.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Authentication; + +namespace Bit.Scim.Utilities +{ + public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions + { + public const string DefaultScheme = "ScimApiKey"; + } +} diff --git a/bitwarden_license/src/Scim/Utilities/ScimConstants.cs b/bitwarden_license/src/Scim/Utilities/ScimConstants.cs new file mode 100644 index 000000000..4c9d11f6c --- /dev/null +++ b/bitwarden_license/src/Scim/Utilities/ScimConstants.cs @@ -0,0 +1,10 @@ +namespace Bit.Scim.Utilities +{ + public static class ScimConstants + { + public const string Scim2SchemaListResponse = "urn:ietf:params:scim:api:messages:2.0:ListResponse"; + public const string Scim2SchemaError = "urn:ietf:params:scim:api:messages:2.0:Error"; + public const string Scim2SchemaUser = "urn:ietf:params:scim:schemas:core:2.0:User"; + public const string Scim2SchemaGroup = "urn:ietf:params:scim:schemas:core:2.0:Group"; + } +} diff --git a/bitwarden_license/src/Scim/Utilities/ScimContextMiddleware.cs b/bitwarden_license/src/Scim/Utilities/ScimContextMiddleware.cs new file mode 100644 index 000000000..9550814de --- /dev/null +++ b/bitwarden_license/src/Scim/Utilities/ScimContextMiddleware.cs @@ -0,0 +1,23 @@ +using Bit.Core.Repositories; +using Bit.Core.Settings; +using Bit.Scim.Context; + +namespace Bit.Scim.Utilities +{ + public class ScimContextMiddleware + { + private readonly RequestDelegate _next; + + public ScimContextMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task Invoke(HttpContext httpContext, IScimContext scimContext, GlobalSettings globalSettings, + IOrganizationRepository organizationRepository, IOrganizationConnectionRepository organizationConnectionRepository) + { + await scimContext.BuildAsync(httpContext, globalSettings, organizationRepository, organizationConnectionRepository); + await _next.Invoke(httpContext); + } + } +} diff --git a/bitwarden_license/src/Scim/appsettings.Development.json b/bitwarden_license/src/Scim/appsettings.Development.json new file mode 100644 index 000000000..32253a93c --- /dev/null +++ b/bitwarden_license/src/Scim/appsettings.Development.json @@ -0,0 +1,35 @@ +{ + "globalSettings": { + "baseServiceUri": { + "vault": "https://localhost:8080", + "api": "http://localhost:4000", + "identity": "http://localhost:33656", + "admin": "http://localhost:62911", + "notifications": "http://localhost:61840", + "sso": "http://localhost:51822", + "internalNotifications": "http://localhost:61840", + "internalAdmin": "http://localhost:62911", + "internalIdentity": "http://localhost:33656", + "internalApi": "http://localhost:4000", + "internalVault": "https://localhost:8080", + "internalSso": "http://localhost:51822", + "internalScim": "http://localhost:44559" + }, + "mail": { + "smtp": { + "host": "localhost", + "port": 10250 + } + }, + "attachment": { + "connectionString": "UseDevelopmentStorage=true", + "baseUrl": "http://localhost:4000/attachments/" + }, + "events": { + "connectionString": "UseDevelopmentStorage=true" + }, + "storage": { + "connectionString": "UseDevelopmentStorage=true" + } + } +} diff --git a/bitwarden_license/src/Scim/appsettings.Production.json b/bitwarden_license/src/Scim/appsettings.Production.json new file mode 100644 index 000000000..d9efbcda1 --- /dev/null +++ b/bitwarden_license/src/Scim/appsettings.Production.json @@ -0,0 +1,42 @@ +{ + "globalSettings": { + "baseServiceUri": { + "vault": "https://vault.bitwarden.com", + "api": "https://api.bitwarden.com", + "identity": "https://identity.bitwarden.com", + "admin": "https://admin.bitwarden.com", + "notifications": "https://notifications.bitwarden.com", + "sso": "https://sso.bitwarden.com", + "internalNotifications": "https://notifications.bitwarden.com", + "internalAdmin": "https://admin.bitwarden.com", + "internalIdentity": "https://identity.bitwarden.com", + "internalApi": "https://api.bitwarden.com", + "internalVault": "https://vault.bitwarden.com", + "internalSso": "https://sso.bitwarden.com", + "internalScim": "https://scim.bitwarden.com" + }, + "braintree": { + "production": true + }, + "bitPay": { + "production": true + } + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + }, + "Console": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Warning", + "System": "Warning", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } + } +} diff --git a/bitwarden_license/src/Scim/appsettings.QA.json b/bitwarden_license/src/Scim/appsettings.QA.json new file mode 100644 index 000000000..f4491a055 --- /dev/null +++ b/bitwarden_license/src/Scim/appsettings.QA.json @@ -0,0 +1,42 @@ +{ + "globalSettings": { + "baseServiceUri": { + "vault": "https://vault.qa.bitwarden.pw", + "api": "https://api.qa.bitwarden.pw", + "identity": "https://identity.qa.bitwarden.pw", + "admin": "https://admin.qa.bitwarden.pw", + "notifications": "https://notifications.qa.bitwarden.pw", + "sso": "https://sso.qa.bitwarden.pw", + "internalNotifications": "https://notifications.qa.bitwarden.pw", + "internalAdmin": "https://admin.qa.bitwarden.pw", + "internalIdentity": "https://identity.qa.bitwarden.pw", + "internalApi": "https://api.qa.bitwarden.pw", + "internalVault": "https://vault.qa.bitwarden.pw", + "internalSso": "https://sso.qa.bitwarden.pw", + "internalScim": "https://scim.qa.bitwarden.pw" + }, + "braintree": { + "production": false + }, + "bitPay": { + "production": false + } + }, + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + }, + "Console": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Debug", + "System": "Debug", + "Microsoft": "Debug", + "Microsoft.Hosting.Lifetime": "Information" + } + } + } +} diff --git a/bitwarden_license/src/Scim/appsettings.json b/bitwarden_license/src/Scim/appsettings.json new file mode 100644 index 000000000..630896a65 --- /dev/null +++ b/bitwarden_license/src/Scim/appsettings.json @@ -0,0 +1,63 @@ +{ + "globalSettings": { + "selfHosted": false, + "siteName": "Bitwarden", + "projectName": "Scim", + "stripe": { + "apiKey": "SECRET" + }, + "sqlServer": { + "connectionString": "SECRET" + }, + "mail": { + "sendGridApiKey": "SECRET", + "amazonConfigSetName": "Email", + "replyToEmail": "no-reply@bitwarden.com" + }, + "identityServer": { + "certificateThumbprint": "SECRET" + }, + "dataProtection": { + "certificateThumbprint": "SECRET" + }, + "storage": { + "connectionString": "SECRET" + }, + "events": { + "connectionString": "SECRET" + }, + "serviceBus": { + "connectionString": "SECRET", + "applicationCacheTopicName": "SECRET" + }, + "documentDb": { + "uri": "SECRET", + "key": "SECRET" + }, + "sentry": { + "dsn": "SECRET" + }, + "notificationHub": { + "connectionString": "SECRET", + "hubName": "SECRET" + }, + "braintree": { + "production": false, + "merchantId": "SECRET", + "publicKey": "SECRET", + "privateKey": "SECRET" + }, + "bitPay": { + "production": false, + "token": "SECRET", + "notificationUrl": "https://bitwarden.com/SECRET" + }, + "amazon": { + "accessKeyId": "SECRET", + "accessKeySecret": "SECRET", + "region": "SECRET" + } + }, + "scimSettings": { + } +} diff --git a/bitwarden_license/src/Scim/build.ps1 b/bitwarden_license/src/Scim/build.ps1 new file mode 100644 index 000000000..21ed14161 --- /dev/null +++ b/bitwarden_license/src/Scim/build.ps1 @@ -0,0 +1,12 @@ +$dir = Split-Path -Parent $MyInvocation.MyCommand.Path + +echo "`n## Building Scim" + +echo "`nBuilding app" +echo ".NET Core version $(dotnet --version)" +echo "Restore" +dotnet restore $dir\Scim.csproj +echo "Clean" +dotnet clean $dir\Scim.csproj -c "Release" -o $dir\obj\Azure\publish +echo "Publish" +dotnet publish $dir\Scim.csproj -c "Release" -o $dir\obj\Azure\publish diff --git a/bitwarden_license/src/Scim/build.sh b/bitwarden_license/src/Scim/build.sh new file mode 100644 index 000000000..b6deb89b4 --- /dev/null +++ b/bitwarden_license/src/Scim/build.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -e + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && "pwd" )" + +echo -e "\n## Building SCIM" + +echo -e "\nBuilding app" +echo ".NET Core version $(dotnet --version)" +echo "Restore" +dotnet restore "$DIR/Scim.csproj" +echo "Clean" +dotnet clean "$DIR/Scim.csproj" -c "Release" -o "$DIR/obj/build-output/publish" +echo "Publish" +dotnet publish "$DIR/Scim.csproj" -c "Release" -o "$DIR/obj/build-output/publish" diff --git a/bitwarden_license/src/Scim/entrypoint.sh b/bitwarden_license/src/Scim/entrypoint.sh new file mode 100644 index 000000000..0d54517bb --- /dev/null +++ b/bitwarden_license/src/Scim/entrypoint.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Setup + +GROUPNAME="bitwarden" +USERNAME="bitwarden" + +LUID=${LOCAL_UID:-0} +LGID=${LOCAL_GID:-0} + +# Step down from host root to well-known nobody/nogroup user + +if [ $LUID -eq 0 ] +then + LUID=65534 +fi +if [ $LGID -eq 0 ] +then + LGID=65534 +fi + +# Create user and group + +groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 || +groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1 +useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 || +usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 +mkhomedir_helper $USERNAME + +# The rest... + +chown -R $USERNAME:$GROUPNAME /app +mkdir -p /etc/bitwarden/core +mkdir -p /etc/bitwarden/logs +mkdir -p /etc/bitwarden/ca-certificates +chown -R $USERNAME:$GROUPNAME /etc/bitwarden + +cp /etc/bitwarden/ca-certificates/*.crt /usr/local/share/ca-certificates/ >/dev/null 2>&1 \ + && update-ca-certificates + +exec gosu $USERNAME:$GROUPNAME dotnet /app/Scim.dll diff --git a/bitwarden_license/src/Scim/packages.lock.json b/bitwarden_license/src/Scim/packages.lock.json new file mode 100644 index 000000000..f1e39e6ad --- /dev/null +++ b/bitwarden_license/src/Scim/packages.lock.json @@ -0,0 +1,2930 @@ +{ + "version": 1, + "dependencies": { + "net6.0": { + "Microsoft.VisualStudio.Web.CodeGeneration.Design": { + "type": "Direct", + "requested": "[5.0.2, )", + "resolved": "5.0.2", + "contentHash": "9eTZV7W+S2iO2AJD03xXyXJZ+Nf71Y25gMXhqyXb8bB63jPfn+VQhV8I1lb6J+NR3jW98m5EB9QBftBSrjgiYQ==", + "dependencies": { + "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": "5.0.2" + } + }, + "AspNetCoreRateLimit": { + "type": "Transitive", + "resolved": "4.0.2", + "contentHash": "FzXAJFgaRjKfnKAVwjEEC7OAGQM5v/I3sQw2tpzmR0yHTCGhUAxZzDuwZiXTk8XLrI6vovzkqKkfKmiDl3nYMg==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.1", + "Microsoft.Extensions.Options": "6.0.0", + "Newtonsoft.Json": "13.0.1" + } + }, + "AutoMapper": { + "type": "Transitive", + "resolved": "11.0.0", + "contentHash": "+596AnKykYCk9RxXCEF4GYuapSebQtFVvIA1oVG1rrRkCLAC7AkWehJ0brCfYUbdDW3v1H/p0W3hob7JoXGjMw==", + "dependencies": { + "Microsoft.CSharp": "4.7.0" + } + }, + "AutoMapper.Extensions.Microsoft.DependencyInjection": { + "type": "Transitive", + "resolved": "11.0.0", + "contentHash": "0asw5WxdCFh2OTi9Gv+oKyH9SzxwYQSnO8TV5Dd0GggovILzJW4UimP26JAcxc3yB5NnC5urooZ1BBs8ElpiBw==", + "dependencies": { + "AutoMapper": "11.0.0", + "Microsoft.Extensions.Options": "6.0.0" + } + }, + "AWSSDK.Core": { + "type": "Transitive", + "resolved": "3.7.10.11", + "contentHash": "B+M7ggPC0FogATRPQxDXL0eTusCQtXulW4zCuX39yiHV8+u9MEXRytcAw0ZA3zFBYYx6ovl9lklho6OQo1DRRQ==" + }, + "AWSSDK.SimpleEmail": { + "type": "Transitive", + "resolved": "3.7.0.150", + "contentHash": "rc/4ZnISfbgTfqz5/BWqMHBAzk4R09qfe1xkdJf2jXo44Zn2X72W8IiLLweBtmNhL7d8Tcf6UCtOHYkFwxHvug==", + "dependencies": { + "AWSSDK.Core": "[3.7.10.11, 4.0.0)" + } + }, + "AWSSDK.SQS": { + "type": "Transitive", + "resolved": "3.7.2.47", + "contentHash": "RPTVBsY333n+aIEqw148Envx9OQkE1/jhjlioNXDP6BrA3fAPN9A+2HoA02c0KSp/sazXYWg8w/kDL8FchH8Dw==", + "dependencies": { + "AWSSDK.Core": "[3.7.10.11, 4.0.0)" + } + }, + "Azure.Core": { + "type": "Transitive", + "resolved": "1.22.0", + "contentHash": "ze/xRCHSSDe5TIk5vBDbVrauW1EN7UIbnBvIBfMH8KSt/I9+/7yPAjTBDgNBk0IwG6WBV+BBHp4IUtS/PGAQwQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "1.1.1", + "System.Diagnostics.DiagnosticSource": "4.6.0", + "System.Memory.Data": "1.0.2", + "System.Numerics.Vectors": "4.5.0", + "System.Text.Encodings.Web": "4.7.2", + "System.Text.Json": "4.7.2", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Azure.Extensions.AspNetCore.DataProtection.Blobs": { + "type": "Transitive", + "resolved": "1.2.1", + "contentHash": "wxvkC6DeWThBtaPbsWdicp5Ltya4J8JuhxmZJDQkhnXG7oihfu8RqBV6w/X1nMieuIOq1qQaGTvjx7nEHHfxSQ==", + "dependencies": { + "Azure.Core": "1.14.0", + "Azure.Storage.Blobs": "12.8.0", + "Microsoft.AspNetCore.DataProtection": "2.1.0" + } + }, + "Azure.Storage.Blobs": { + "type": "Transitive", + "resolved": "12.11.0", + "contentHash": "50eRjIhY7Q1JN7kT2MSawDKCcwSb7uRZUkz00P/BLjSg47gm2hxUYsnJPyvzCHntYMbOWzrvaVQTwYwXabaR5Q==", + "dependencies": { + "Azure.Storage.Common": "12.10.0", + "System.Text.Json": "4.7.2" + } + }, + "Azure.Storage.Common": { + "type": "Transitive", + "resolved": "12.10.0", + "contentHash": "vYkHGzUkdZTace/cDPZLG+Mh/EoPqQuGxDIBOau9D+XWoDPmuUFGk325aXplkFE4JFGpSwoytNYzk/qBCaiHqg==", + "dependencies": { + "Azure.Core": "1.22.0", + "System.IO.Hashing": "6.0.0" + } + }, + "Azure.Storage.Queues": { + "type": "Transitive", + "resolved": "12.9.0", + "contentHash": "jDiyHtsCUCrWNvZW7SjJnJb46UhpdgQrWCbL8aWpapDHlq9LvbvxYpfLh4dfKAz09QiTznLMIU3i+md9+7GzqQ==", + "dependencies": { + "Azure.Storage.Common": "12.10.0", + "System.Memory.Data": "1.0.2", + "System.Text.Json": "4.7.2" + } + }, + "BitPay.Light": { + "type": "Transitive", + "resolved": "1.0.1907", + "contentHash": "QTTIgXakHrRNQPxNyH7bZ7frm0bI8N6gRDtiqVyKG/QYQ+KfjN70xt0zQ0kO0zf8UBaKuwcV5B7vvpXtzR9ijg==", + "dependencies": { + "Newtonsoft.Json": "12.0.2" + } + }, + "Braintree": { + "type": "Transitive", + "resolved": "5.12.0", + "contentHash": "bV2tsVIvBQeKwULT4qPZUWhxSr8mFwyAAcvLDvDpCU0cMYPHzGSahha+ghUdgGMb317BqL34/Od59n2s3MkhOQ==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "System.Xml.XPath.XmlDocument": "4.3.0" + } + }, + "Dapper": { + "type": "Transitive", + "resolved": "2.0.123", + "contentHash": "RDFF4rBLLmbpi6pwkY7q/M6UXHRJEOerplDGE5jwEkP/JGJnBauAClYavNKJPW1yOTWRPIyfj4is3EaJxQXILQ==" + }, + "Fido2": { + "type": "Transitive", + "resolved": "3.0.0-beta2", + "contentHash": "FnNMbK88dyPp0Ww/iMim5g89rSPdqkjQiDiTJJtvxDcEk8JK/eBdTzAl4myNaKS9e8PKrxxddOTrnNja3PHGtQ==", + "dependencies": { + "Fido2.Models": "3.0.0-beta2", + "NSec.Cryptography": "20.2.0", + "System.Formats.Cbor": "5.0.0", + "System.IdentityModel.Tokens.Jwt": "6.6.0" + } + }, + "Fido2.AspNet": { + "type": "Transitive", + "resolved": "3.0.0-beta2", + "contentHash": "qkowZS0WPS26gDG97rwjZObOa/xtFVjSpvWHl3OwWRQ9ZU5xNePXKk2XJWmO2MCQc40idxyEOfA34MMexCHc3w==", + "dependencies": { + "Fido2": "3.0.0-beta2", + "Fido2.Models": "3.0.0-beta2" + } + }, + "Fido2.Models": { + "type": "Transitive", + "resolved": "3.0.0-beta2", + "contentHash": "6ePSMUtqz6lAfDUjDvOONMLugcKiAyz8hzoLSAISk3iDIjBMLMPlZSV3TVZqiY+5SAzC8x61OHNoCODqorucNw==" + }, + "Handlebars.Net": { + "type": "Transitive", + "resolved": "2.1.2", + "contentHash": "p60QyeBYpZmcZdIXRMqs9XySIBaxJ0lj3+QD0EJVr4ybTigOTCumXMMin5dPwjo9At1UwkDZ3gGwa1lmGjG6DA==", + "dependencies": { + "Microsoft.CSharp": "4.7.0" + } + }, + "Humanizer.Core": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "rsYXB7+iUPP8AHgQ8JP2UZI2xK2KhjcdGr9E6zX3CsZaTLCaw8M35vaAJRo1rfxeaZEVMuXeaquLVCkZ7JcZ5Q==", + "dependencies": { + "NETStandard.Library": "1.6.1" + } + }, + "IdentityModel": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "b18wrIx5wnZlMxAX7oVsE+nDtAJ4hajYlH0xPlaRvo4r/fz08K6pPeZvbiqS9nfNbzfIgLFmNX+FL9qR9ZR5PA==", + "dependencies": { + "Newtonsoft.Json": "11.0.2", + "System.Text.Encodings.Web": "4.7.0" + } + }, + "IdentityModel.AspNetCore.OAuth2Introspection": { + "type": "Transitive", + "resolved": "4.0.1", + "contentHash": "ZNdMZMaj9fqR3j50vYsu+1U3QGd6n8+fqwf+a8mCTcmXGor+HgFDfdq0mM34bsmD6uEgAQup7sv2ZW5kR36dbA==", + "dependencies": { + "IdentityModel": "4.0.0" + } + }, + "IdentityServer4": { + "type": "Transitive", + "resolved": "4.1.2", + "contentHash": "blaxxGuOA7v/w1q+fxn97wZ+x2ecG1ZD4mc/N/ZOXMNeFZZhqv+4LF26Gecyik3nWrJPmbMEtQbLmRsKG8k61w==", + "dependencies": { + "IdentityModel": "4.4.0", + "IdentityServer4.Storage": "4.1.2", + "Microsoft.AspNetCore.Authentication.OpenIdConnect": "3.1.0", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.6.0", + "Newtonsoft.Json": "12.0.2" + } + }, + "IdentityServer4.AccessTokenValidation": { + "type": "Transitive", + "resolved": "3.0.1", + "contentHash": "qu/M6UyN4o9NVep7q545Ms7hYAnsQqSdLbN1Fjjrn4m35lyBfeQPSSNzDryAKHbodyWOQfHaOqKEyMEJQ5Rpgw==", + "dependencies": { + "IdentityModel.AspNetCore.OAuth2Introspection": "4.0.1", + "Microsoft.AspNetCore.Authentication.JwtBearer": "3.0.0" + } + }, + "IdentityServer4.Storage": { + "type": "Transitive", + "resolved": "4.1.2", + "contentHash": "KoSffyZyyeCNTIyJiZnCuPakJ1QbCHlpty6gbWUj/7yl+w0PXIchgmmJnJSvddzBb8iZ2xew/vGlxWUIP17P2g==", + "dependencies": { + "IdentityModel": "4.4.0" + } + }, + "libsodium": { + "type": "Transitive", + "resolved": "1.0.18", + "contentHash": "Ajv3AR9Qg/C4SQcE2ONx/UieeKnn5lSvVNc6egC3p6NP6qjZzWJ+Xg2vJURNYjkpHui/KctBwQjMPqpZK8/CHA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1" + } + }, + "linq2db": { + "type": "Transitive", + "resolved": "3.7.0", + "contentHash": "iDous2TbSchtALnTLNXQnprmNZF4GrXas0MBz6ZHWkSdilSJjcf26qFM7Qf98Mny0OXHEmNXG/jtIDhoVJ5KmQ==", + "dependencies": { + "System.ComponentModel.Annotations": "4.7.0" + } + }, + "linq2db.EntityFrameworkCore": { + "type": "Transitive", + "resolved": "6.7.1", + "contentHash": "Bb25vUDyFw3nKnf7KY+bauwKGD0hdM7/syodS+IgHdWlcbH9g7tHxYmMa9+DNuL0yy6DFvP6Q3BkClm7zbQdAw==", + "dependencies": { + "Microsoft.EntityFrameworkCore.Relational": "6.0.0", + "linq2db": "3.7.0" + } + }, + "MailKit": { + "type": "Transitive", + "resolved": "3.2.0", + "contentHash": "5MTpTqmjqT7HPvYbP3HozRZMth5vSaT0ReN0iM3rAM4CgLI/R1qqtLDDNWGnFFIlcNzeJkZQRJJMkv8cgzWBbA==", + "dependencies": { + "MimeKit": "3.2.0" + } + }, + "Microsoft.AspNetCore.Authentication.JwtBearer": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "joDS3+lD1i9qcdFLWP4D316t3bHpezmTNOzbMIf9ZcRPX4QTuiUutZcQn/kZplf3BiLHqwUChZXxPjCAMKaKAQ==", + "dependencies": { + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.10.0" + } + }, + "Microsoft.AspNetCore.Authentication.OpenIdConnect": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "O1cAQYUTU8EfRqwc5/rfTns4E4hKlFlg59fuKRrST+PzsxI6H07KqRN/JjdYhAuVYxF8jPnIGbj+zuc5paOWUw==", + "dependencies": { + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "5.5.0" + } + }, + "Microsoft.AspNetCore.Cryptography.Internal": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "/0FX1OqckMmXAAlsHgBFNymTZuq4nuAOMhiwm6e8CEMi2aOjnMYwiMc7mtvpGTAO0O4C0zwx+iaChxDgvqit2A==" + }, + "Microsoft.AspNetCore.Cryptography.KeyDerivation": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "1Lbwrxg/HRY/nbrkcrB3EUXUYQN8Tkw7Ktgb6/2on2P7ybT5aM59H05gk+OBC8ZTBxwdle9e1tyT3wxEYKw5xw==", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "6.0.4" + } + }, + "Microsoft.AspNetCore.DataProtection": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "G+UoMHL0xiyFh30wkL7Bv/XL6eugTAKYhLPS53k1/Me1bYRwOOw+8VL/q0ppq3/yMzpHX+MkExaCTDlYl48FgA==", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.Internal": "2.1.0", + "Microsoft.AspNetCore.DataProtection.Abstractions": "2.1.0", + "Microsoft.AspNetCore.Hosting.Abstractions": "2.1.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.1.0", + "Microsoft.Extensions.Logging.Abstractions": "2.1.0", + "Microsoft.Extensions.Options": "2.1.0", + "Microsoft.Win32.Registry": "4.5.0", + "System.Security.Cryptography.Xml": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + } + }, + "Microsoft.AspNetCore.DataProtection.Abstractions": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "2+HVDhUqrnV9+EJNEewSy+Gk4hOVPzLPMpFDZI7kuH7NWxtbNkI6A6gT5lO2/kEPMyM8/iLWtohbOwjpC9rHVw==" + }, + "Microsoft.AspNetCore.Hosting.Abstractions": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "1TQgBfd/NPZLR2o/h6l5Cml2ZCF5hsyV4h9WEwWwAIavrbdTnaNozGGcTOd4AOgQvogMM9UM1ajflm9Cwd0jLQ==", + "dependencies": { + "Microsoft.AspNetCore.Hosting.Server.Abstractions": "2.1.0", + "Microsoft.AspNetCore.Http.Abstractions": "2.1.0", + "Microsoft.Extensions.Hosting.Abstractions": "2.1.0" + } + }, + "Microsoft.AspNetCore.Hosting.Server.Abstractions": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "YTKMi2vHX6P+WHEVpW/DS+eFHnwivCSMklkyamcK1ETtc/4j8H3VR0kgW8XIBqukNxhD8k5wYt22P7PhrWSXjQ==", + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.1.0", + "Microsoft.Extensions.Configuration.Abstractions": "2.1.0" + } + }, + "Microsoft.AspNetCore.Html.Abstractions": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "Y4rs5aMEXY8G7wJo5S3EEt6ltqyOTr/qOeZzfn+hw/fuQj5GppGckMY5psGLETo1U9hcT5MmAhaT5xtusM1b5g==", + "dependencies": { + "System.Text.Encodings.Web": "4.5.0" + } + }, + "Microsoft.AspNetCore.Http.Abstractions": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "vbFDyKsSYBnxl3+RABtN79b0vsTcG66fDY8vD6Nqvu9uLtSej70Q5NcbGlnN6bJpZci5orSdgFTHMhBywivDPg==", + "dependencies": { + "Microsoft.AspNetCore.Http.Features": "2.1.0", + "System.Text.Encodings.Web": "4.5.0" + } + }, + "Microsoft.AspNetCore.Http.Features": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "UmkUePxRjsQW0j5euFFscBwjvTu25b8+qIK/2fI3GvcqQ+mkwgbWNAT8b/Gkoei1m2bTWC07lSdutuRDPPLcJA==", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.1.0" + } + }, + "Microsoft.AspNetCore.Razor": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "V54PIyDCFl8COnTp9gezNHpUNHk7F9UnerGeZy3UfbnwYvfzbo+ipqQmSgeoESH8e0JvKhRTyQyZquW2EPtCmg==", + "dependencies": { + "Microsoft.AspNetCore.Html.Abstractions": "2.2.0" + } + }, + "Microsoft.AspNetCore.Razor.Language": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "6yOBBASGfXMx1fY6hyjvG+oM3eR8vovIehDdEZW7jAV4gKlY4xuAvTm7Iw1fEq7KPunh2VrJwo7oRK1XxUn1OQ==" + }, + "Microsoft.AspNetCore.Razor.Runtime": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "7YqK+H61lN6yj9RiQUko7oaOhKtRR9Q/kBcoWNRemhJdTIWOh1OmdvJKzZrMWOlff3BAjejkPQm+0V0qXk+B1w==", + "dependencies": { + "Microsoft.AspNetCore.Html.Abstractions": "2.2.0", + "Microsoft.AspNetCore.Razor": "2.2.0" + } + }, + "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" + } + }, + "Microsoft.Azure.Cosmos": { + "type": "Transitive", + "resolved": "3.24.0", + "contentHash": "QpUe5ho6OzlXwgcJVgAmOR7t3XLC9RI4t8T96RZY61pSOIllPOJdp30L0LwA16tKcqi5r2KayEgWO/MS9fh/6A==", + "dependencies": { + "Azure.Core": "1.3.0", + "Microsoft.Bcl.AsyncInterfaces": "1.0.0", + "Microsoft.Bcl.HashCode": "1.1.0", + "Newtonsoft.Json": "10.0.2", + "System.Buffers": "4.5.1", + "System.Collections.Immutable": "1.7.0", + "System.Configuration.ConfigurationManager": "4.7.0", + "System.Memory": "4.5.4", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3", + "System.Threading.Tasks.Extensions": "4.5.4", + "System.ValueTuple": "4.5.0" + } + }, + "Microsoft.Azure.Cosmos.Table": { + "type": "Transitive", + "resolved": "1.0.8", + "contentHash": "ToeEd1yijM7nQfLYvdFLG//RjKPmfqm45eOm86UAKrxtyGI/CXqP8iL74mzBp6mZ9A/K/ZYA2fVdpH0xHR5Keg==", + "dependencies": { + "Microsoft.Azure.DocumentDB.Core": "2.11.2", + "Microsoft.OData.Core": "7.6.4", + "Newtonsoft.Json": "10.0.2" + } + }, + "Microsoft.Azure.DocumentDB.Core": { + "type": "Transitive", + "resolved": "2.11.2", + "contentHash": "cA8eWrTFbYrkHrz095x4CUGb7wqQgA1slzFZCYexhNwz6Zcn3v+S1yvWMGwGRmRjT0MKU9tYdFWgLfT0OjSycw==", + "dependencies": { + "NETStandard.Library": "1.6.0", + "Newtonsoft.Json": "9.0.1", + "System.Collections.Immutable": "1.3.0", + "System.Collections.NonGeneric": "4.0.1", + "System.Collections.Specialized": "4.0.1", + "System.Diagnostics.TraceSource": "4.0.0", + "System.Dynamic.Runtime": "4.0.11", + "System.Linq.Queryable": "4.0.1", + "System.Net.Http": "4.3.4", + "System.Net.NameResolution": "4.0.0", + "System.Net.NetworkInformation": "4.1.0", + "System.Net.Requests": "4.0.11", + "System.Net.Security": "4.3.2", + "System.Net.WebHeaderCollection": "4.0.1", + "System.Runtime.Serialization.Primitives": "4.1.1", + "System.Security.SecureString": "4.0.0" + } + }, + "Microsoft.Azure.NotificationHubs": { + "type": "Transitive", + "resolved": "4.1.0", + "contentHash": "C2SssjX3e6/HIo1OCImQDDVOn64d1+gkgEmgxJryzkwixyivJHWH2YIgxZs33pyzVQcZWx5PR2tqLkQ7riSq8Q==", + "dependencies": { + "Microsoft.Extensions.Caching.Memory": "3.1.8", + "Newtonsoft.Json": "12.0.3" + } + }, + "Microsoft.Azure.ServiceBus": { + "type": "Transitive", + "resolved": "5.2.0", + "contentHash": "wyZNJggyFNtKxd+HgvcTiuRYuTjDGi+pgE4RcBvFbfvNiarKr5AOlE4Ne7on1eUJZuMuEa19wN5dj694HlP60A==", + "dependencies": { + "Microsoft.Azure.Amqp": "2.4.11", + "Microsoft.Azure.Services.AppAuthentication": "[1.0.3, 2.0.0)", + "Newtonsoft.Json": "10.0.3", + "System.Diagnostics.DiagnosticSource": "4.5.1", + "System.IdentityModel.Tokens.Jwt": "5.4.0" + } + }, + "Microsoft.Azure.Services.AppAuthentication": { + "type": "Transitive", + "resolved": "1.0.3", + "contentHash": "ywpQaK1klu1IoX4VUf+TBmU4kR71aWNI6O5rEIJU8z28L2xhJhnIm7k2Nf1Zu/PygeuOtt5g0QPCk5+lLltbeQ==", + "dependencies": { + "Microsoft.IdentityModel.Clients.ActiveDirectory": "3.14.2", + "NETStandard.Library": "1.6.1", + "System.Diagnostics.Process": "4.3.0" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "yuvf07qFWFqtK3P/MRkEKLhn5r2UbSpVueRziSqj0yJQIKFwG1pq9mOayK3zE5qZCTs0CbrwL9M6R8VwqyGy2w==" + }, + "Microsoft.Bcl.HashCode": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "J2G1k+u5unBV+aYcwxo94ip16Rkp65pgWFb0R6zwJipzWNMgvqlWeuI7/+R+e8bob66LnSG+llLJ+z8wI94cHg==" + }, + "Microsoft.CodeAnalysis.Analyzers": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "ojG5pGAhTPmjxRGTNvuszO3H8XPZqksDwr9xLd4Ae/JBjZZdl6GuoLk7uLMf+o7yl5wO0TAqoWcEKkEWqrZE5g==" + }, + "Microsoft.CodeAnalysis.Common": { + "type": "Transitive", + "resolved": "3.8.0", + "contentHash": "8YTZ7GpsbTdC08DITx7/kwV0k4SC6cbBAFqc13cOm5vKJZcEIAh51tNSyGSkWisMgYCr96B2wb5Zri1bsla3+g==", + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.0.0", + "System.Collections.Immutable": "5.0.0", + "System.Memory": "4.5.4", + "System.Reflection.Metadata": "5.0.0", + "System.Runtime.CompilerServices.Unsafe": "4.7.1", + "System.Text.Encoding.CodePages": "4.5.1", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Microsoft.CodeAnalysis.CSharp": { + "type": "Transitive", + "resolved": "3.8.0", + "contentHash": "hKqFCUSk9TIMBDjiYMF8/ZfK9p9mzpU+slM73CaCHu4ctfkoqJGHLQhyT8wvrYsIg+ufrUWBF8hcJYmyr5rc5Q==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "[3.8.0]" + } + }, + "Microsoft.CodeAnalysis.CSharp.Workspaces": { + "type": "Transitive", + "resolved": "3.8.0", + "contentHash": "rdEBvPWqe/IIscsnp7OkZ4tQin8khxBcSLyV9tU+sHdw9uW9U0GKL+Dv2rD4voC1bZBaO18Hp+m4Vkyfmaz0OA==", + "dependencies": { + "Humanizer.Core": "2.2.0", + "Microsoft.CodeAnalysis.CSharp": "[3.8.0]", + "Microsoft.CodeAnalysis.Common": "[3.8.0]", + "Microsoft.CodeAnalysis.Workspaces.Common": "[3.8.0]" + } + }, + "Microsoft.CodeAnalysis.Razor": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "s4u/6z/MQ35y/egrXf4WgJlUZf5GGvuba9mZ700dH4XxLBrA9Fw9kFZ8uymoATry7hwz5owvFhBVo+2VnoiGRg==", + "dependencies": { + "Microsoft.AspNetCore.Razor.Language": "5.0.0", + "Microsoft.CodeAnalysis.CSharp": "3.7.0", + "Microsoft.CodeAnalysis.Common": "3.7.0" + } + }, + "Microsoft.CodeAnalysis.Workspaces.Common": { + "type": "Transitive", + "resolved": "3.8.0", + "contentHash": "GPYVydsmOmScOWDJA1LFky7/MkoXpx1JI3lZJShxC+bvVUvL9zVKE8WDZMLsYJ5MAbry2xkZftdfeMpZ+kvLDQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "1.1.1", + "Microsoft.CodeAnalysis.Common": "[3.8.0]", + "System.Composition": "1.0.31" + } + }, + "Microsoft.CSharp": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA==" + }, + "Microsoft.EntityFrameworkCore": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "gTh3SJsF5WNjEmG32kYc3U4tjeTIv55QOrwHAJcF/xtrIVMteDHMArGC35N0dw86WFY0v8yFkKYKOIOln4jkfQ==", + "dependencies": { + "Microsoft.EntityFrameworkCore.Abstractions": "6.0.4", + "Microsoft.EntityFrameworkCore.Analyzers": "6.0.4", + "Microsoft.Extensions.Caching.Memory": "6.0.1", + "Microsoft.Extensions.DependencyInjection": "6.0.0", + "Microsoft.Extensions.Logging": "6.0.0", + "System.Collections.Immutable": "6.0.0", + "System.Diagnostics.DiagnosticSource": "6.0.0" + } + }, + "Microsoft.EntityFrameworkCore.Abstractions": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "jycTQF0FUJp10cGWBmtsyFhQNeISU9CltDRKCaNiX4QRSEFzgRgaFN4vAFK0T+G5etmXugyddijE4NWCGtgznQ==" + }, + "Microsoft.EntityFrameworkCore.Analyzers": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "t12WodVyGGP2CuLo7R1qwcawHY5zlg+GiQzvkceZpsjcFJVyTFFBFDPg1isBtzurLzWsl+G3z5fVXeic90mPxg==" + }, + "Microsoft.EntityFrameworkCore.Relational": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "E867NbEXYRTElBF5ff+1AN5Awa1jkORy/Rrm0ueibaTAV5uw89LsLoH6yTe+b9urZTWMHtLfGd1RDdNjk8+KzA==", + "dependencies": { + "Microsoft.EntityFrameworkCore": "6.0.4", + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" + } + }, + "Microsoft.Extensions.Caching.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "bcz5sSFJbganH0+YrfvIjJDIcKNW7TL07C4d1eTmXy/wOt52iz4LVogJb6pazs7W0+74j0YpXFErvp++Aq5Bsw==", + "dependencies": { + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Caching.Memory": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "B4y+Cev05eMcjf1na0v9gza6GUtahXbtY1JCypIgx3B4Ea/KAgsWyXEmW4q6zMbmTMtKzmPVk09rvFJirvMwTg==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "6.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0", + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Caching.Redis": { + "type": "Transitive", + "resolved": "2.2.0", + "contentHash": "cb21miiGDVjlNl8TRBKIi7OEFdlKuV8d4ZoYqFOhKdZhzo7Sv+b8Puy3NLW3y/g+UDclt7FTh+Za7ykurtaVMQ==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "2.2.0", + "Microsoft.Extensions.Options": "2.2.0", + "StackExchange.Redis.StrongName": "1.2.6" + } + }, + "Microsoft.Extensions.Configuration": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "tq2wXyh3fL17EMF2bXgRhU7JrbO3on93MRKYxzz4JzzvuGSA1l0W3GI9/tl8EO89TH+KWEymP7bcFway6z9fXg==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==", + "dependencies": { + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "IznHHzGUtrdpuQqIUdmzF6TYPcsYHONhHh3o9dGp39sX/9Zfmt476UnhvU0UhXgJnXXAikt/MpN6AuSLCCMdEQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "2.0.0" + } + }, + "Microsoft.Extensions.Configuration.EnvironmentVariables": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "pnyXV1LFOsYjGveuC07xp0YHIyGq7jRq5Ncb5zrrIieMLWVwgMyYxcOH0jTnBedDT4Gh1QinSqsjqzcieHk1og==", + "dependencies": { + "Microsoft.Extensions.Configuration": "6.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" + } + }, + "Microsoft.Extensions.Configuration.FileExtensions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "V4Dth2cYMZpw3HhGw9XUDIijpI6gN+22LDt0AhufIgOppCUfpWX4483OmN+dFXRJkJLc8Tv0Q8QK+1ingT2+KQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "6.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", + "Microsoft.Extensions.FileProviders.Physical": "6.0.0", + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Configuration.Json": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "GJGery6QytCzS/BxJ96klgG9in3uH26KcUBbiVG/coNDXCRq6LGVVlUT4vXq34KPuM+R2av+LeYdX9h4IZOCUg==", + "dependencies": { + "Microsoft.Extensions.Configuration": "6.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "6.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", + "System.Text.Json": "6.0.0" + } + }, + "Microsoft.Extensions.Configuration.UserSecrets": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "Fy8yr4V6obi7ZxvKYI1i85jqtwMq8tqyxQVZpRSkgeA8enqy/KvBIMdcuNdznlxQMZa72mvbHqb7vbg4Pyx95w==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", + "Microsoft.Extensions.Configuration.Json": "6.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", + "Microsoft.Extensions.FileProviders.Physical": "6.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg==" + }, + "Microsoft.Extensions.DependencyModel": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "Iaectmzg9Dc4ZbKX/FurrRjgO/I8rTumL5UU+Uube6vZuGetcnXoIgTA94RthFWePhdMVm8MMhVFJZdbzMsdyQ==", + "dependencies": { + "System.Text.Json": "4.6.0" + } + }, + "Microsoft.Extensions.FileProviders.Abstractions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==", + "dependencies": { + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.FileProviders.Physical": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "QvkL7l0nM8udt3gfyu0Vw8bbCXblxaKOl7c2oBfgGy4LCURRaL9XWZX1FWJrQc43oMokVneVxH38iz+bY1sbhg==", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "6.0.0", + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.FileSystemGlobbing": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "ip8jnL1aPiaPeKINCqaTEbvBFDmVx9dXQEBZ2HOBRXPD1eabGNqP/bKlsIcp7U2lGxiXd5xIhoFcmY8nM4Hdiw==" + }, + "Microsoft.Extensions.Hosting.Abstractions": { + "type": "Transitive", + "resolved": "3.1.8", + "contentHash": "7ZJUKwPipkDvuv2KJPZ3r01wp2AWNMiYH+61i0dL89F7QICknjKpWgLKLpTSUYFgl77S3b4264I6i4HzDdrb2A==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "3.1.8", + "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.8", + "Microsoft.Extensions.FileProviders.Abstractions": "3.1.8", + "Microsoft.Extensions.Logging.Abstractions": "3.1.8" + } + }, + "Microsoft.Extensions.Identity.Core": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "8vBsyGkA8ZI3lZvm1nf+9ynRC/TzPD+UtbdgTlKk+cz+AW5I41LrK8f/adGej5uXgprOA2DMjZw33vZG6vyXxA==", + "dependencies": { + "Microsoft.AspNetCore.Cryptography.KeyDerivation": "6.0.4", + "Microsoft.Extensions.Logging": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0" + } + }, + "Microsoft.Extensions.Identity.Stores": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "linRCnWBfnqg8qjrd9u/KMISy8O4a6X/GRhpHXU0ar654YQw9LJ/Ht+psx8QLqSX5EsCBbBCZzuamatH2FWIyQ==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "6.0.0", + "Microsoft.Extensions.Identity.Core": "6.0.4", + "Microsoft.Extensions.Logging": "6.0.0" + } + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "6.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Logging.Abstractions": "6.0.0", + "Microsoft.Extensions.Options": "6.0.0", + "System.Diagnostics.DiagnosticSource": "6.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "dzB2Cgg+JmrouhjkcQGzSFjjvpwlq353i8oBQO2GWNjCXSzhbtBRUf28HSauWe7eib3wYOdb3tItdjRwAdwCSg==" + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0", + "Microsoft.Extensions.Primitives": "6.0.0" + } + }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "Y/lGICwO27fCkQRK3tZseVzFjZaxfGmui990E67sB4MuiPzdJHnJDS/BeYWrHShSSBgCl4KyKRx4ux686fftPg==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "2.0.0", + "Microsoft.Extensions.Configuration.Binder": "2.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.0.0", + "Microsoft.Extensions.Options": "2.0.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "Microsoft.IdentityModel.Clients.ActiveDirectory": { + "type": "Transitive", + "resolved": "3.14.2", + "contentHash": "TNsJJMiRnkeby1ovThVoV9yFsPWjAdluwOA+Nf0LtSsBVVrKQv8Qp4kYOgyNwMVj+pDwbhXISySk+4HyHVWNZQ==", + "dependencies": { + "NETStandard.Library": "1.6.0", + "System.Runtime.Serialization.Json": "4.0.2", + "System.Runtime.Serialization.Primitives": "4.1.1" + } + }, + "Microsoft.IdentityModel.JsonWebTokens": { + "type": "Transitive", + "resolved": "6.10.0", + "contentHash": "0qjS31rN1MQTc46tAYbzmMTSRfdV5ndZxSjYxIGqKSidd4wpNJfNII/pdhU5Fx8olarQoKL9lqqYw4yNOIwT0Q==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "6.10.0" + } + }, + "Microsoft.IdentityModel.Logging": { + "type": "Transitive", + "resolved": "6.10.0", + "contentHash": "zbcwV6esnNzhZZ/VP87dji6VrUBLB5rxnZBkDMqNYpyG+nrBnBsbm4PUYLCBMUflHCM9EMLDG0rLnqqT+l0ldA==" + }, + "Microsoft.IdentityModel.Protocols": { + "type": "Transitive", + "resolved": "6.10.0", + "contentHash": "DFyXD0xylP+DknCT3hzJ7q/Q5qRNu0hO/gCU90O0ATdR0twZmlcuY9RNYaaDofXKVbzcShYNCFCGle2G/o8mkg==", + "dependencies": { + "Microsoft.IdentityModel.Logging": "6.10.0", + "Microsoft.IdentityModel.Tokens": "6.10.0" + } + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect": { + "type": "Transitive", + "resolved": "6.10.0", + "contentHash": "LVvMXAWPbPeEWTylDrxunlHH2wFyE4Mv0L4gZrJHC4HTESbWHquKZb/y/S8jgiQEDycOP0PDQvbG4RR/tr2TVQ==", + "dependencies": { + "Microsoft.IdentityModel.Protocols": "6.10.0", + "System.IdentityModel.Tokens.Jwt": "6.10.0" + } + }, + "Microsoft.IdentityModel.Tokens": { + "type": "Transitive", + "resolved": "6.10.0", + "contentHash": "qbf1NslutDB4oLrriYTJpy7oB1pbh2ej2lEHd2IPDQH9C74ysOdhU5wAC7KoXblldbo7YsNR2QYFOqQM/b0Rsg==", + "dependencies": { + "Microsoft.CSharp": "4.5.0", + "Microsoft.IdentityModel.Logging": "6.10.0", + "System.Security.Cryptography.Cng": "4.5.0" + } + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "2.1.2", + "contentHash": "mOJy3M0UN+LUG21dLGMxaWZEP6xYpQEpLuvuEQBaownaX4YuhH6NmNUlN9si+vNkAS6dwJ//N1O4DmLf2CikVg==" + }, + "Microsoft.NETCore.Targets": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" + }, + "Microsoft.OData.Core": { + "type": "Transitive", + "resolved": "7.6.4", + "contentHash": "/EjnJezMBjXf8OjcShhGzPY7pOO0CopgoZGhS6xsP3t2uhC+O72IBHgtQ7F3v1rRXWVtJwLGhzE1GfJUlx3c4Q==", + "dependencies": { + "Microsoft.OData.Edm": "[7.6.4]", + "Microsoft.Spatial": "[7.6.4]" + } + }, + "Microsoft.OData.Edm": { + "type": "Transitive", + "resolved": "7.6.4", + "contentHash": "MSSmA6kIfpgFTtNpOnnayoSj/6KSzHC1U9KOjF7cTA1PG4tZ7rIMi1pvjFc8CmYEvP4cxGl/+vrCn+HpK26HTQ==" + }, + "Microsoft.Spatial": { + "type": "Transitive", + "resolved": "7.6.4", + "contentHash": "3mB+Frn4LU4yb5ie9R752QiRn0Hvp9PITkSRofV/Lzm9EyLM87Fy9ziqgz75O/c712dh6GxuypMSBUGmNFwMeA==" + }, + "Microsoft.VisualStudio.Web.CodeGeneration": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "YUah81QG5q/ViVbr1BZcTbDLNJ5/k84fr+xx3/IoDVJR8KEUm89HmPAGM+FMMyWOjit+CIVpyOq7yEmRBBWXxQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "5.0.0", + "Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore": "5.0.2" + } + }, + "Microsoft.VisualStudio.Web.CodeGeneration.Contracts": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "34v6AkkRJykgFq7rHwNbzXBsLFquevLuegM9XDQl2j+wyOfj+ql1++jUR1WdZoPkv04WoM09mD47S3lMzJmHrQ==", + "dependencies": { + "Newtonsoft.Json": "11.0.2", + "System.Collections.Immutable": "1.7.0" + } + }, + "Microsoft.VisualStudio.Web.CodeGeneration.Core": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "R7mrxvTtv/MiEH42OtHYi/3L0A/vaAH8mwg+3yAyQtVuy6v9CeeVyL30lfTQ7EYV4ezUmuQKFwfjcU6PP0/KSQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "5.0.0", + "Microsoft.VisualStudio.Web.CodeGeneration.Templating": "5.0.2", + "Newtonsoft.Json": "11.0.2" + } + }, + "Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "f9XeBRS9ICosrCpbO9jnAVMd/ISLhaZgx388XNBjigiyBJuq577J6tQgQWZA8PQTiPj6MKe9HVIW2GnKXDiUrQ==", + "dependencies": { + "Microsoft.VisualStudio.Web.CodeGeneration.Core": "5.0.2" + } + }, + "Microsoft.VisualStudio.Web.CodeGeneration.Templating": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "P3z/JZTGP5DhSc8ik4xrimWuCZ2ZaEZ6q7WGgfgmSVibfXxwh2Oo+dtdkiXwq8MNlkrcP0AZAo3+1wowYUzluA==", + "dependencies": { + "Microsoft.AspNetCore.Razor.Language": "5.0.0", + "Microsoft.AspNetCore.Razor.Runtime": "2.2.0", + "Microsoft.CodeAnalysis.CSharp": "3.8.0", + "Microsoft.CodeAnalysis.Razor": "5.0.0", + "Microsoft.VisualStudio.Web.CodeGeneration.Utils": "5.0.2" + } + }, + "Microsoft.VisualStudio.Web.CodeGeneration.Utils": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "4zViWGIFeKsGxDmc5xpn2G8kWs2FSHiLOolw85ZPHihDXc2jiFKp7qjA3SRt8U23kR3zeb0vZiFlETxgTHwAUA==", + "dependencies": { + "Microsoft.CodeAnalysis.CSharp.Workspaces": "3.8.0", + "Microsoft.VisualStudio.Web.CodeGeneration.Contracts": "5.0.2", + "Newtonsoft.Json": "11.0.2" + } + }, + "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { + "type": "Transitive", + "resolved": "5.0.2", + "contentHash": "W4Uk2y0oja+4E+XP5d5OFu+ViTEtlqm3a6nYuuC3tjA+lTK6dLaMf0G6WnO4BO18i0kM0l49XjTwwXd5XpjnAQ==", + "dependencies": { + "Microsoft.VisualStudio.Web.CodeGeneration": "5.0.2" + } + }, + "Microsoft.Win32.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "KSrRMb5vNi0CWSGG1++id2ZOs/1QhRqROt+qgbEAdQuGjGrFcl4AOl4/exGPUYz2wUnU42nvJqon1T3U0kPXLA==", + "dependencies": { + "System.Security.AccessControl": "4.7.0", + "System.Security.Principal.Windows": "4.7.0" + } + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "hqTM5628jSsQiv+HGpiq3WKBl2c8v1KZfby2J6Pr7pEPlK9waPdgEO6b8A/+/xn/yZ9ulv8HuqK71ONy2tg67A==" + }, + "MimeKit": { + "type": "Transitive", + "resolved": "3.2.0", + "contentHash": "l9YHMBhBUwY7qQHUp8fw0EvjcbmhN4Iggz6MdjqIShBf42+0nJTa5gu0kuupCOPuiARc9ZaS9c9f0gKz4OnxKw==", + "dependencies": { + "Portable.BouncyCastle": "1.9.0", + "System.Security.Cryptography.Pkcs": "6.0.0" + } + }, + "MySqlConnector": { + "type": "Transitive", + "resolved": "2.1.2", + "contentHash": "JVokQTUNN3WHAu9Vw8ieeq1dXTFokJiig5P0VJ4f439UxRrsPo6SaVWC8Zdm6mkPeQFhZ0/9afdWa02EY/1j/w==" + }, + "NETStandard.Library": { + "type": "Transitive", + "resolved": "1.6.1", + "contentHash": "WcSp3+vP+yHNgS8EV5J7pZ9IRpeDuARBPN28by8zqff1wJQXm26PVU8L3/fYLBJVU7BtDyqNVWq2KlCVvSSR4A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.Win32.Primitives": "4.3.0", + "System.AppContext": "4.3.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Console": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Calendars": "4.3.0", + "System.IO": "4.3.0", + "System.IO.Compression": "4.3.0", + "System.IO.Compression.ZipFile": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.Net.Http": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Net.Sockets": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.InteropServices.RuntimeInformation": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Timer": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0", + "System.Xml.XDocument": "4.3.0" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "SJMlOmFHr32oOzVXeHmarGaBKkhi0wHVN/rzuu2tUSJ4Qx2AkHCpr9R/DhLWwDiklqgzFU++9wkFyGJxbx/zzg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "Npgsql.EntityFrameworkCore.PostgreSQL": { + "type": "Transitive", + "resolved": "6.0.4", + "contentHash": "fzgRmBd3nAFvKt/L70sJfFWAdobtwDEeOzOzruJq9og97O8/5B96inQOAgOpYyaUjPYpS4ZS5/bxm3vnOJ0+pQ==", + "dependencies": { + "Microsoft.EntityFrameworkCore": "6.0.4", + "Microsoft.EntityFrameworkCore.Abstractions": "6.0.4", + "Microsoft.EntityFrameworkCore.Relational": "6.0.4", + "Npgsql": "6.0.4" + } + }, + "NSec.Cryptography": { + "type": "Transitive", + "resolved": "20.2.0", + "contentHash": "NxzHaDQm3JfH+9VQdLI1bC4h/ZTKPo5o/4BEscBu4KK0Yv35sB87hSRuzpr09VahxY5ZpJfE2tHyK4u27jfiyQ==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.7.0", + "libsodium": "[1.0.18, 1.0.19)" + } + }, + "Otp.NET": { + "type": "Transitive", + "resolved": "1.2.2", + "contentHash": "2hrZfkbzeWJ3tNXXt/1beg4IY+nS4F3gIfh4NVFvW0f6Pj51hGpiJ4prBz7Dmrr4ZYrA96rTERVGieZ4xYm7jA==" + }, + "Pomelo.EntityFrameworkCore.MySql": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "sFIo5e9RmQoCTEvH6EeSV8ptmX3dw/6XgyD8R93X/i7A9+XCeG9KTjSNjrszVjVOtCu/eyvYqqcv2uZ/BHhlYA==", + "dependencies": { + "Microsoft.EntityFrameworkCore.Relational": "[6.0.1, 7.0.0)", + "Microsoft.Extensions.DependencyInjection": "6.0.0", + "MySqlConnector": "2.1.2" + } + }, + "Portable.BouncyCastle": { + "type": "Transitive", + "resolved": "1.9.0", + "contentHash": "eZZBCABzVOek+id9Xy04HhmgykF0wZg9wpByzrWN7q8qEI0Qen9b7tfd7w8VA3dOeesumMG7C5ZPy0jk7PSRHw==" + }, + "Quartz": { + "type": "Transitive", + "resolved": "3.4.0", + "contentHash": "N8350OAlQhd8zKg0ARFikGjh3bfAW/CF/KVxu2fTIlAALB/oC1eg54n/QAPYR5ryHuYyDr5G8/Qa4k+D/7OFRQ==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "2.1.1", + "System.Configuration.ConfigurationManager": "4.7.0", + "System.Diagnostics.DiagnosticSource": "4.7.1" + } + }, + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "7VSGO0URRKoMEAq0Sc9cRz8mb6zbyx/BZDEWhgPdzzpmFhkam3fJ1DAGWFXBI4nGlma+uPKpfuMQP5LXRnOH5g==" + }, + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "0oAaTAm6e2oVH+/Zttt0cuhGaePQYKII1dY8iaqP7CvOpVKgLybKRFvQjXR2LtxXOXTVPNv14j0ot8uV+HrUmw==" + }, + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "G24ibsCNi5Kbz0oXWynBoRgtGvsw5ZSVEWjv13/KiCAM8C6wz9zzcCniMeQFIkJ2tasjo2kXlvlBZhplL51kGg==" + }, + "runtime.native.System": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Data.SqlClient.sni": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "9kyFSIdN3T0qjDQ2R0HRXYIhS3l5psBzQi6qqhdLz+SzFyEy4sVxNOke+yyYv8Cu8rPER12c3RDjLT8wF3WBYQ==", + "dependencies": { + "runtime.win-arm64.runtime.native.System.Data.SqlClient.sni": "4.4.0", + "runtime.win-x64.runtime.native.System.Data.SqlClient.sni": "4.4.0", + "runtime.win-x86.runtime.native.System.Data.SqlClient.sni": "4.4.0" + } + }, + "runtime.native.System.IO.Compression": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "INBPonS5QPEgn7naufQFXJEp3zX6L4bwHgJ/ZH78aBTpeNfQMtf7C6VrAFhlq2xxWBveIOWyFzQjJ8XzHMhdOQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Net.Security": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "M2nN92ePS8BgQ2oi6Jj3PlTUzadYSIWLdZrHY1n1ZcW9o4wAQQ6W+aQ2lfq1ysZQfVCgDwY58alUdowrzezztg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==", + "dependencies": { + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0" + } + }, + "runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "QR1OwtwehHxSeQvZKXe+iSd+d3XZNkEcuWMFYa2i0aG1l+lR739HPicKMlTbJst3spmeekDVBUS7SeS26s4U/g==", + "dependencies": { + "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" + } + }, + "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "I+GNKGg2xCHueRd1m9PzeEW7WLbNNLznmTuEi8/vZX71HudUbx1UTwlGkiwMri7JLl8hGaIAWnA/GONhu+LOyQ==" + }, + "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "1Z3TAq1ytS1IBRtPXJvEUZdVsfWfeNEhBkbiOCGEl9wwAfsjP2lz3ZFDx5tq8p60/EqbS0HItG5piHuB71RjoA==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ==" + }, + "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "6mU/cVmmHtQiDXhnzUImxIcDL48GbTk+TsptXyJA+MIOG9LRjPoAQC/qBFB7X+UNyK86bmvGwC8t+M66wsYC8w==" + }, + "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "vjwG0GGcTW/PPg6KVud8F9GLWYuAV1rrw1BKAqY0oh4jcUqg15oYF1+qkGR2x2ZHM4DQnWKQ7cJgYbfncz/lYg==" + }, + "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "7KMFpTkHC/zoExs+PwP8jDCWcrK9H6L7soowT80CUx3e+nxP/AFnq0AQAW5W76z2WYbLAYCRyPfwYFG6zkvQRw==" + }, + "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "xrlmRCnKZJLHxyyLIqkZjNXqgxnKdZxfItrPkjI+6pkRo5lHX8YvSZlWrSI5AVwLMi4HbNWP7064hcAWeZKp5w==" + }, + "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg==" + }, + "runtime.win-arm64.runtime.native.System.Data.SqlClient.sni": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "LbrynESTp3bm5O/+jGL8v0Qg5SJlTV08lpIpFesXjF6uGNMWqFnUQbYBJwZTeua6E/Y7FIM1C54Ey1btLWupdg==" + }, + "runtime.win-x64.runtime.native.System.Data.SqlClient.sni": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "38ugOfkYJqJoX9g6EYRlZB5U2ZJH51UP8ptxZgdpS07FgOEToV+lS11ouNK2PM12Pr6X/PpT5jK82G3DwH/SxQ==" + }, + "runtime.win-x86.runtime.native.System.Data.SqlClient.sni": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "YhEdSQUsTx+C8m8Bw7ar5/VesXvCFMItyZF7G1AUY+OM0VPZUOeAVpJ4Wl6fydBGUYZxojTDR3I6Bj/+BPkJNA==" + }, + "SendGrid": { + "type": "Transitive", + "resolved": "9.27.0", + "contentHash": "kMyXRQ8hmN2bG3tYZ7T31Ufl1kXkpuP5+WBh1BJ32WY31DTnBTCVGURoIqfbTo/tRuQfAYLxra6C8cQGN6kk+A==", + "dependencies": { + "Newtonsoft.Json": "9.0.1", + "starkbank-ecdsa": "[1.3.3, 2.0.0)" + } + }, + "Sentry": { + "type": "Transitive", + "resolved": "3.16.0", + "contentHash": "Pkw4+51EDUQ0X02jdCZIpaM2Q4UO06VKGDE+dYYNxgvOirRXGKTKxRk4NPKJTLSTNl+2JyT9HoE7C6BTlYhLOw==" + }, + "Sentry.Serilog": { + "type": "Transitive", + "resolved": "3.16.0", + "contentHash": "GFTVfQdOFqZ9Vmo8EEZTx1EQMDRJjka/4v2CwxnAUh+sqHDICga4eOm4AyGzDBbE4s9iAHMgMUCceIqo+7z84w==", + "dependencies": { + "Sentry": "3.16.0", + "Serilog": "2.10.0" + } + }, + "Serilog": { + "type": "Transitive", + "resolved": "2.10.0", + "contentHash": "+QX0hmf37a0/OZLxM3wL7V6/ADvC1XihXN4Kq/p6d8lCPfgkRdiuhbWlMaFjR9Av0dy5F0+MBeDmDdRZN/YwQA==" + }, + "Serilog.AspNetCore": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "/JO/txIxRR61x1UXQAgUzG2Sx05o1QHCkokVBWrKzmAoDu+p5EtCAj7L/TVVg7Ezhh3GPiZ0JI9OJCmRO9tSRw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "5.0.0", + "Microsoft.Extensions.Logging": "5.0.0", + "Serilog": "2.10.0", + "Serilog.Extensions.Hosting": "4.2.0", + "Serilog.Formatting.Compact": "1.1.0", + "Serilog.Settings.Configuration": "3.3.0", + "Serilog.Sinks.Console": "4.0.1", + "Serilog.Sinks.Debug": "2.0.0", + "Serilog.Sinks.File": "5.0.0" + } + }, + "Serilog.Extensions.Hosting": { + "type": "Transitive", + "resolved": "4.2.0", + "contentHash": "gT2keceCmPQR9EX0VpXQZvUgELdfE7yqJ7MOxBhm3WLCblcvRgswEOOTgok/DHObbM15A3V/DtF3VdVDQPIZzQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.8", + "Microsoft.Extensions.Hosting.Abstractions": "3.1.8", + "Microsoft.Extensions.Logging.Abstractions": "3.1.8", + "Serilog": "2.10.0", + "Serilog.Extensions.Logging": "3.1.0" + } + }, + "Serilog.Extensions.Logging": { + "type": "Transitive", + "resolved": "3.1.0", + "contentHash": "IWfem7wfrFbB3iw1OikqPFNPEzfayvDuN4WP7Ue1AVFskalMByeWk3QbtUXQR34SBkv1EbZ3AySHda/ErDgpcg==", + "dependencies": { + "Microsoft.Extensions.Logging": "2.0.0", + "Serilog": "2.9.0" + } + }, + "Serilog.Extensions.Logging.File": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "usO0qr4v9VCMBWiTJ1nQmAbPNCt40FrkDol6CpfCXbsxGZS/hH+YCueF7vvPQ32ATI0GWcMWiKRdjXEE7/HxTQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "2.0.0", + "Microsoft.Extensions.Configuration.Binder": "2.0.0", + "Serilog": "2.5.0", + "Serilog.Extensions.Logging": "2.0.2", + "Serilog.Formatting.Compact": "1.0.0", + "Serilog.Sinks.Async": "1.1.0", + "Serilog.Sinks.RollingFile": "3.3.0" + } + }, + "Serilog.Formatting.Compact": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "pNroKVjo+rDqlxNG5PXkRLpfSCuDOBY0ri6jp9PLe505ljqwhwZz8ospy2vWhQlFu5GkIesh3FcDs4n7sWZODA==", + "dependencies": { + "Serilog": "2.8.0" + } + }, + "Serilog.Settings.Configuration": { + "type": "Transitive", + "resolved": "3.3.0", + "contentHash": "7GNudISZwqaT902hqEL2OFGTZeUFWfnrNLupJkOqeF41AR3GjcxX+Hwb30xb8gG2/CDXsCMVfF8o0+8KY0fJNg==", + "dependencies": { + "Microsoft.Extensions.DependencyModel": "3.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "2.0.0", + "Serilog": "2.10.0" + } + }, + "Serilog.Sinks.Async": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "xll0Kanz2BkCxuv+F3p1WXr47jdsVM0GU1n1LZvK+18QiRZ/WGFNxSNw9EMKFV5ED5gr7MUpAe6PCMNL1HGUMA==", + "dependencies": { + "Serilog": "2.1.0", + "System.Collections.Concurrent": "4.0.12" + } + }, + "Serilog.Sinks.AzureCosmosDB": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "Im2/ZqjXQIpsd727qEo5Pq+br0MiNVuTvI40Yk7736tgjCpEx+omPHv4+c4fEAxnOP2kL9Ge6UoDFoDw3cjF2A==", + "dependencies": { + "Microsoft.Azure.Cosmos": "3.24.0", + "Microsoft.CSharp": "4.7.0", + "Newtonsoft.Json": "13.0.1", + "Serilog": "2.10.0", + "Serilog.Sinks.PeriodicBatching": "2.3.1" + } + }, + "Serilog.Sinks.Console": { + "type": "Transitive", + "resolved": "4.0.1", + "contentHash": "apLOvSJQLlIbKlbx+Y2UDHSP05kJsV7mou+fvJoRGs/iR+jC22r8cuFVMjjfVxz/AD4B2UCltFhE1naRLXwKNw==", + "dependencies": { + "Serilog": "2.10.0" + } + }, + "Serilog.Sinks.Debug": { + "type": "Transitive", + "resolved": "2.0.0", + "contentHash": "Y6g3OBJ4JzTyyw16fDqtFcQ41qQAydnEvEqmXjhwhgjsnG/FaJ8GUqF5ldsC/bVkK8KYmqrPhDO+tm4dF6xx4A==", + "dependencies": { + "Serilog": "2.10.0" + } + }, + "Serilog.Sinks.File": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==", + "dependencies": { + "Serilog": "2.10.0" + } + }, + "Serilog.Sinks.PeriodicBatching": { + "type": "Transitive", + "resolved": "2.3.1", + "contentHash": "LVYvqpqjSTD8dhfxRnzpxTs8/ys3V2q01MvaY3r0eKsDgpKK1U1y/5N6gFHgiesbxG0V+O5IWdz4+c1DzoNyOQ==", + "dependencies": { + "Serilog": "2.0.0" + } + }, + "Serilog.Sinks.RollingFile": { + "type": "Transitive", + "resolved": "3.3.0", + "contentHash": "2lT5X1r3GH4P0bRWJfhA7etGl8Q2Ipw9AACvtAHWRUSpYZ42NGVyHoVs2ALBZ/cAkkS+tA4jl80Zie144eLQPg==", + "dependencies": { + "Serilog.Sinks.File": "3.2.0", + "System.IO": "4.1.0", + "System.IO.FileSystem.Primitives": "4.0.1", + "System.Runtime.InteropServices": "4.1.0", + "System.Text.Encoding.Extensions": "4.0.11" + } + }, + "Serilog.Sinks.SyslogMessages": { + "type": "Transitive", + "resolved": "2.0.6", + "contentHash": "V2Yq2GEbk7taEPbpBLFzLXhrHrUzKf4sQu/zLrANU8XIoUn/Mr08M2E8PrcrWVXCj0R4xLMWYe0Z1sxOrMF3IA==", + "dependencies": { + "Serilog": "2.5.0", + "Serilog.Sinks.PeriodicBatching": "2.3.0" + } + }, + "StackExchange.Redis.StrongName": { + "type": "Transitive", + "resolved": "1.2.6", + "contentHash": "UFmT1/JYu1PLiRwkyvEPVHk/tVTJa8Ka2rb9yzidzDoQARvhBVRpaWUeaP81373v54jupDBvAoGHGl0EY/HphQ==", + "dependencies": { + "NETStandard.Library": "1.6.1", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Collections.NonGeneric": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.IO.Compression": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.Linq": "4.3.0", + "System.Net.NameResolution": "4.3.0", + "System.Net.Security": "4.3.0", + "System.Net.Sockets": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices.RuntimeInformation": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Thread": "4.3.0", + "System.Threading.ThreadPool": "4.3.0", + "System.Threading.Timer": "4.3.0" + } + }, + "starkbank-ecdsa": { + "type": "Transitive", + "resolved": "1.3.3", + "contentHash": "OblOaKb1enXn+dSp7tsx9yjwV+/BEKM9jFhshIkZTwCk7LuTFTp+wSon6rFzuPiIiTGtvVWQNUw2slHjGktJog==" + }, + "Stripe.net": { + "type": "Transitive", + "resolved": "39.107.0", + "contentHash": "cp/t6YzMTTPHopf7D7XFe7sPe5jE3QrVaPuA//xQWTbvTwBryOofTosyREq7OLqkvQ9olEHMNbHAkKIjM7vhsg==", + "dependencies": { + "Newtonsoft.Json": "12.0.3", + "System.Configuration.ConfigurationManager": "6.0.0" + } + }, + "System.AppContext": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "fKC+rmaLfeIzUhagxY17Q9siv/sPrjjKcfNg1Ic8IlQkZLipo8ljcaZQu4VtI4Jqbzjc2VTjzGLF6WmsRXAEgA==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Collections": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Collections.Concurrent": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Collections.Immutable": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Collections.NonGeneric": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "prtjIEMhGUnQq6RnPEYLpFt8AtLbp9yq2zxOSrY7KJJZrw25Fi97IzBqY7iqssbM61Ek5b8f3MG/sG1N2sN5KA==", + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Collections.Specialized": { + "type": "Transitive", + "resolved": "4.0.1", + "contentHash": "/HKQyVP0yH1I0YtK7KJL/28snxHNH/bi+0lgk/+MbURF6ULhAE31MDI+NZDerNWu264YbxklXCCygISgm+HMug==", + "dependencies": { + "System.Collections.NonGeneric": "4.0.1", + "System.Globalization": "4.0.11", + "System.Globalization.Extensions": "4.0.1", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Threading": "4.0.11" + } + }, + "System.ComponentModel.Annotations": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "0YFqjhp/mYkDGpU0Ye1GjE53HMp9UVfGN7seGpAMttAC0C40v5gw598jCgpbBLMmCo0E5YRLBv5Z2doypO49ZQ==" + }, + "System.Composition": { + "type": "Transitive", + "resolved": "1.0.31", + "contentHash": "I+D26qpYdoklyAVUdqwUBrEIckMNjAYnuPJy/h9dsQItpQwVREkDFs4b4tkBza0kT2Yk48Lcfsv2QQ9hWsh9Iw==", + "dependencies": { + "System.Composition.AttributedModel": "1.0.31", + "System.Composition.Convention": "1.0.31", + "System.Composition.Hosting": "1.0.31", + "System.Composition.Runtime": "1.0.31", + "System.Composition.TypedParts": "1.0.31" + } + }, + "System.Composition.AttributedModel": { + "type": "Transitive", + "resolved": "1.0.31", + "contentHash": "NHWhkM3ZkspmA0XJEsKdtTt1ViDYuojgSND3yHhTzwxepiwqZf+BCWuvCbjUt4fe0NxxQhUDGJ5km6sLjo9qnQ==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Composition.Convention": { + "type": "Transitive", + "resolved": "1.0.31", + "contentHash": "GLjh2Ju71k6C0qxMMtl4efHa68NmWeIUYh4fkUI8xbjQrEBvFmRwMDFcylT8/PR9SQbeeL48IkFxU/+gd0nYEQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Composition.AttributedModel": "1.0.31", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Globalization": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Composition.Hosting": { + "type": "Transitive", + "resolved": "1.0.31", + "contentHash": "fN1bT4RX4vUqjbgoyuJFVUizAl2mYF5VAb+bVIxIYZSSc0BdnX+yGAxcavxJuDDCQ1K+/mdpgyEFc8e9ikjvrg==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Composition.Runtime": "1.0.31", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Globalization": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Composition.Runtime": { + "type": "Transitive", + "resolved": "1.0.31", + "contentHash": "0LEJN+2NVM89CE4SekDrrk5tHV5LeATltkp+9WNYrR+Huiyt0vaCqHbbHtVAjPyeLWIc8dOz/3kthRBj32wGQg==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Globalization": "4.3.0", + "System.Linq": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Composition.TypedParts": { + "type": "Transitive", + "resolved": "1.0.31", + "contentHash": "0Zae/FtzeFgDBBuILeIbC/T9HMYbW4olAmi8XqqAGosSOWvXfiQLfARZEhiGd0LVXaYgXr0NhxiU1LldRP1fpQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Composition.AttributedModel": "1.0.31", + "System.Composition.Hosting": "1.0.31", + "System.Composition.Runtime": "1.0.31", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Globalization": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "7T+m0kDSlIPTHIkPMIu6m6tV6qsMqJpvQWW2jIc2qi7sn40qxFo0q+7mEQAhMPXZHMKnWrnv47ntGlM/ejvw3g==", + "dependencies": { + "System.Security.Cryptography.ProtectedData": "6.0.0", + "System.Security.Permissions": "6.0.0" + } + }, + "System.Console": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "DHDrIxiqk1h03m6khKWV2X8p/uvN79rgSqpilL6uzpmSfxfU5ng8VcPtW4qsDsQDHiTv6IPV9TmD5M/vElPNLg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Data.SqlClient": { + "type": "Transitive", + "resolved": "4.8.3", + "contentHash": "yERfVLXAY0QbylAgaGLByYN0hFxX28aeEQ0hUgJO+Ntn1AfmWl5HHUoYJA0Yl9HhIUUJHVaS/Sw/RLZr5aaC+A==", + "dependencies": { + "Microsoft.Win32.Registry": "4.7.0", + "System.Security.Principal.Windows": "4.7.0", + "runtime.native.System.Data.SqlClient.sni": "4.7.0" + } + }, + "System.Diagnostics.Debug": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Diagnostics.Process": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "J0wOX07+QASQblsfxmIMFc9Iq7KTXYL3zs2G/Xc704Ylv3NpuVdo6gij6V3PGiptTxqsK0K7CdXenRvKUnkA2g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.Win32.Primitives": "4.3.0", + "Microsoft.Win32.Registry": "4.3.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Thread": "4.3.0", + "System.Threading.ThreadPool": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, + "System.Diagnostics.Tools": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "UUvkJfSYJMM6x527dJg2VyWPSRqIVB0Z7dbjHst1zmwTXz5CcXSYJFWRpuigfbO1Lf7yfZiIaEUesfnl/g5EyA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Diagnostics.TraceSource": { + "type": "Transitive", + "resolved": "4.0.0", + "contentHash": "6WVCczFZKXwpWpzd/iJkYnsmWTSFFiU24Xx/YdHXBcu+nFI/ehTgeqdJQFbtRPzbrO3KtRNjvkhtj4t5/WwWsA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1", + "System.Collections": "4.0.11", + "System.Diagnostics.Debug": "4.0.11", + "System.Globalization": "4.0.11", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Threading": "4.0.11", + "runtime.native.System": "4.0.0" + } + }, + "System.Diagnostics.Tracing": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "NfuoKUiP2nUWwKZN6twGqXioIe1zVD0RIj2t976A+czLHr2nY454RwwXs6JU9Htc6mwqL6Dn/nEL3dpVf2jOhg==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "6.0.0" + } + }, + "System.Dynamic.Runtime": { + "type": "Transitive", + "resolved": "4.0.11", + "contentHash": "db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==", + "dependencies": { + "System.Collections": "4.0.11", + "System.Diagnostics.Debug": "4.0.11", + "System.Globalization": "4.0.11", + "System.Linq": "4.1.0", + "System.Linq.Expressions": "4.1.0", + "System.ObjectModel": "4.0.12", + "System.Reflection": "4.1.0", + "System.Reflection.Emit": "4.0.1", + "System.Reflection.Emit.ILGeneration": "4.0.1", + "System.Reflection.Primitives": "4.0.1", + "System.Reflection.TypeExtensions": "4.1.0", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Threading": "4.0.11" + } + }, + "System.Formats.Asn1": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "T6fD00dQ3NTbPDy31m4eQUwKW84s03z0N2C8HpOklyeaDgaJPa/TexP4/SkORMSOwc7WhKifnA6Ya33AkzmafA==" + }, + "System.Formats.Cbor": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "OJ8UXNyYIvu22ZrMHDBcnBvs3l6w2wEWUSwgPf2gimUrdoKJC4pcg963kiYAA9kvs8HYLQKQ+2Arr7pm19aZ4A==" + }, + "System.Globalization": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Calendars": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Globalization.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0" + } + }, + "System.IdentityModel.Tokens.Jwt": { + "type": "Transitive", + "resolved": "6.10.0", + "contentHash": "C+Q5ORsFycRkRuvy/Xd0Pv5xVpmWSAvQYZAGs7VQogmkqlLhvfZXTgBIlHqC3cxkstSoLJAYx6xZB7foQ2y5eg==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "6.10.0", + "Microsoft.IdentityModel.Tokens": "6.10.0" + } + }, + "System.IO": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.Compression": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "YHndyoiV90iu4iKG115ibkhrG+S3jBm8Ap9OwoUAzO5oPDAWcr0SFwQFm0HjM8WkEZWo0zvLTyLmbvTkW1bXgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Buffers": "4.3.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.IO.Compression": "4.3.0" + } + }, + "System.IO.Compression.ZipFile": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "G4HwjEsgIwy3JFBduZ9quBkAu+eUwjIdJleuNSgmUojbH6O3mlvEIme+GHx/cLlTAPcrnnL7GqvB9pTlWRfhOg==", + "dependencies": { + "System.Buffers": "4.3.0", + "System.IO": "4.3.0", + "System.IO.Compression": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.IO.FileSystem": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.IO.FileSystem.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "Rfm2jYCaUeGysFEZjDe7j1R4x6Z6BzumS/vUT5a1AA/AWJuGX71PoGB0RmpyX3VmrGqVnAwtfMn39OHR8Y/5+g==" + }, + "System.Linq": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Linq.Expressions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Linq.Queryable": { + "type": "Transitive", + "resolved": "4.0.1", + "contentHash": "Yn/WfYe9RoRfmSLvUt2JerP0BTGGykCZkQPgojaxgzF2N0oPo+/AhB8TXOpdCcNlrG3VRtsamtK2uzsp3cqRVw==", + "dependencies": { + "System.Collections": "4.0.11", + "System.Diagnostics.Debug": "4.0.11", + "System.Linq": "4.1.0", + "System.Linq.Expressions": "4.1.0", + "System.Reflection": "4.1.0", + "System.Reflection.Extensions": "4.0.1", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==" + }, + "System.Memory.Data": { + "type": "Transitive", + "resolved": "1.0.2", + "contentHash": "JGkzeqgBsiZwKJZ1IxPNsDFZDhUvuEdX8L8BDC8N3KOj+6zMcNU28CNN59TpZE/VJYy9cP+5M+sbxtWJx3/xtw==", + "dependencies": { + "System.Text.Encodings.Web": "4.7.2", + "System.Text.Json": "4.6.0" + } + }, + "System.Net.Http": { + "type": "Transitive", + "resolved": "4.3.4", + "contentHash": "aOa2d51SEbmM+H+Csw7yJOuNZoHkrP2XnAurye5HWYgGVVU54YZDvsLUYRv6h18X3sPnjNCANmN7ZhIPiqMcjA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.1", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.DiagnosticSource": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Extensions": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" + } + }, + "System.Net.NameResolution": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "AFYl08R7MrsrEjqpQWTZWBadqXyTzNDaWpMqyxhb0d6sGhV6xMDKueuBXlLL30gz+DIRY6MpdgnHWlCh5wmq9w==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Principal.Windows": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, + "System.Net.NetworkInformation": { + "type": "Transitive", + "resolved": "4.1.0", + "contentHash": "Q0rfeiW6QsiZuicGjrFA7cRr2+kXex0JIljTTxzI09GIftB8k+aNL31VsQD1sI2g31cw7UGDTgozA/FgeNSzsQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1", + "Microsoft.Win32.Primitives": "4.0.1", + "System.Collections": "4.0.11", + "System.Diagnostics.Tracing": "4.1.0", + "System.Globalization": "4.0.11", + "System.IO": "4.1.0", + "System.IO.FileSystem": "4.0.1", + "System.IO.FileSystem.Primitives": "4.0.1", + "System.Linq": "4.1.0", + "System.Net.Primitives": "4.0.11", + "System.Net.Sockets": "4.1.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.Principal.Windows": "4.0.0", + "System.Threading": "4.0.11", + "System.Threading.Overlapped": "4.0.1", + "System.Threading.Tasks": "4.0.11", + "System.Threading.Thread": "4.0.0", + "System.Threading.ThreadPool": "4.0.10", + "runtime.native.System": "4.0.0" + } + }, + "System.Net.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Net.Requests": { + "type": "Transitive", + "resolved": "4.0.11", + "contentHash": "vxGt7C0cZixN+VqoSW4Yakc1Y9WknmxauDqzxgpw/FnBdz4kQNN51l4wxdXX5VY1xjqy//+G+4CvJWp1+f+y6Q==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.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.IO": "4.1.0", + "System.Net.Http": "4.1.0", + "System.Net.Primitives": "4.0.11", + "System.Net.WebHeaderCollection": "4.0.1", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Threading": "4.0.11", + "System.Threading.Tasks": "4.0.11" + } + }, + "System.Net.Security": { + "type": "Transitive", + "resolved": "4.3.2", + "contentHash": "xT2jbYpbBo3ha87rViHoTA6WdvqOAW37drmqyx/6LD8p7HEPT2qgdxoimRzWtPg8Jh4X5G9BV2seeTv4x6FYlA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.Win32.Primitives": "4.3.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Diagnostics.Tracing": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Extensions": "4.3.0", + "System.IO": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Claims": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Security.Cryptography.X509Certificates": "4.3.0", + "System.Security.Principal": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.ThreadPool": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Security": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" + } + }, + "System.Net.Sockets": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "m6icV6TqQOAdgt5N/9I5KNpjom/5NFtkmGseEH+AK/hny8XrytLH3+b5M8zL/Ycg3fhIocFpUMyl/wpFnVRvdw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Net.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Net.WebHeaderCollection": { + "type": "Transitive", + "resolved": "4.0.1", + "contentHash": "XX2TIAN+wBSAIV51BU2FvvXMdstUa8b0FBSZmDWjZdwUMmggQSifpTOZ5fNH20z9ZCg2fkV1L5SsZnpO2RQDRQ==", + "dependencies": { + "System.Collections": "4.0.11", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "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", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.ObjectModel": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Private.DataContractSerialization": { + "type": "Transitive", + "resolved": "4.1.1", + "contentHash": "lcqFBUaCZxPiUkA4dlSOoPZGtZsAuuElH2XHgLwGLxd7ZozWetV5yiz0qGAV2AUYOqw97MtZBjbLMN16Xz4vXA==", + "dependencies": { + "System.Collections": "4.0.11", + "System.Collections.Concurrent": "4.0.12", + "System.Diagnostics.Debug": "4.0.11", + "System.Globalization": "4.0.11", + "System.IO": "4.1.0", + "System.Linq": "4.1.0", + "System.Reflection": "4.1.0", + "System.Reflection.Emit.ILGeneration": "4.0.1", + "System.Reflection.Emit.Lightweight": "4.0.1", + "System.Reflection.Extensions": "4.0.1", + "System.Reflection.Primitives": "4.0.1", + "System.Reflection.TypeExtensions": "4.1.0", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Runtime.Serialization.Primitives": "4.1.1", + "System.Text.Encoding": "4.0.11", + "System.Text.Encoding.Extensions": "4.0.11", + "System.Text.RegularExpressions": "4.1.0", + "System.Threading": "4.0.11", + "System.Threading.Tasks": "4.0.11", + "System.Xml.ReaderWriter": "4.0.11", + "System.Xml.XmlDocument": "4.0.1", + "System.Xml.XmlSerializer": "4.0.11" + } + }, + "System.Reflection": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", + "dependencies": { + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.ILGeneration": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.Lightweight": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" + }, + "System.Reflection.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.TypeExtensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Runtime.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.Handles": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Runtime.InteropServices": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Runtime.InteropServices.RuntimeInformation": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==", + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0" + } + }, + "System.Runtime.Numerics": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", + "dependencies": { + "System.Globalization": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Runtime.Serialization.Json": { + "type": "Transitive", + "resolved": "4.0.2", + "contentHash": "+7DIJhnKYgCzUgcLbVTtRQb2l1M0FP549XFlFkQM5lmNiUBl44AfNbx4bz61xA8PzLtlYwfmif4JJJW7MPPnjg==", + "dependencies": { + "System.IO": "4.1.0", + "System.Private.DataContractSerialization": "4.1.1", + "System.Runtime": "4.1.0" + } + }, + "System.Runtime.Serialization.Primitives": { + "type": "Transitive", + "resolved": "4.1.1", + "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", + "dependencies": { + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0" + } + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "AUADIc0LIEQe7MzC+I0cl0rAT8RrTAKFHl53yHjEUzNVIaUlhFY11vc2ebiVJzVBuOzun6F7FBA+8KAbGTTedQ==" + }, + "System.Security.Claims": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "P/+BR/2lnc4PNDHt/TPBAWHVMLMRHsyYZbU1NphW4HIWzCggz8mJbTQQ3MKljFE7LS3WagmVFuBgoLcFzYXlkA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Security.Principal": "4.3.0" + } + }, + "System.Security.Cryptography.Algorithms": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.Apple": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Cng": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "WG3r7EyjUe9CMPFSs6bty5doUqT+q9pbI80hlNzo2SkPkZ4VTuZkGWjpp77JB8+uaL4DFPRdBsAY+DX3dBK92A==" + }, + "System.Security.Cryptography.Csp": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Security.Cryptography.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Collections.Concurrent": "4.3.0", + "System.Linq": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.OpenSsl": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==", + "dependencies": { + "System.Collections": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Pkcs": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "elM3x+xSRhzQysiqo85SbidJJ2YbZlnvmh+53TuSZHsD7dNuuEWser+9EFtY+rYupBwkq2avc6ZCO3/6qACgmg==", + "dependencies": { + "System.Formats.Asn1": "6.0.0" + } + }, + "System.Security.Cryptography.Primitives": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", + "dependencies": { + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "rp1gMNEZpvx9vP0JW0oHLxlf8oSiQgtno77Y4PLUBjSiDYoD77Y8uXHr1Ea5XG4/pIKhqAdxZ8v8OTUtqo9PeQ==" + }, + "System.Security.Cryptography.X509Certificates": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.Globalization.Calendars": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Runtime.Numerics": "4.3.0", + "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Cng": "4.3.0", + "System.Security.Cryptography.Csp": "4.3.0", + "System.Security.Cryptography.Encoding": "4.3.0", + "System.Security.Cryptography.OpenSsl": "4.3.0", + "System.Security.Cryptography.Primitives": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "runtime.native.System": "4.3.0", + "runtime.native.System.Net.Http": "4.3.0", + "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" + } + }, + "System.Security.Cryptography.Xml": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "i2Jn6rGXR63J0zIklImGRkDIJL4b1NfPSEbIVHBlqoIb12lfXIigCbDRpDmIEzwSo/v1U5y/rYJdzZYSyCWxvg==", + "dependencies": { + "System.Security.Cryptography.Pkcs": "4.5.0", + "System.Security.Permissions": "4.5.0" + } + }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "T/uuc7AklkDoxmcJ7LGkyX1CcSviZuLCa4jg3PekfJ7SU0niF0IVTXwUiNVP9DSpzou2PpxJ+eNY2IfDM90ZCg==", + "dependencies": { + "System.Security.AccessControl": "6.0.0", + "System.Windows.Extensions": "6.0.0" + } + }, + "System.Security.Principal": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "I1tkfQlAoMM2URscUtpcRo/hX0jinXx6a/KUtEQoz3owaYwl3qwsO8cbzYVVnjxrzxjHo3nJC+62uolgeGIS9A==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" + }, + "System.Security.SecureString": { + "type": "Transitive", + "resolved": "4.0.0", + "contentHash": "sqzq9GD6/b0yqPuMpgIKBuoLf4VKAj8oAfh4kXSzPaN6eoKY3hRi9C5L27uip25qlU+BGPfb0xh2Rmbwc4jFVA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Handles": "4.0.1", + "System.Runtime.InteropServices": "4.1.0", + "System.Security.Cryptography.Primitives": "4.0.0", + "System.Text.Encoding": "4.0.11", + "System.Threading": "4.0.11" + } + }, + "System.Text.Encoding": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Text.Encoding.CodePages": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "4J2JQXbftjPMppIHJ7IC+VXQ9XfEagN92vZZNoG12i+zReYlim5dMoXFC1Zzg7tsnKDM7JPo5bYfFK4Jheq44w==", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.1.2", + "System.Runtime.CompilerServices.Unsafe": "4.5.2" + } + }, + "System.Text.Encoding.Extensions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0" + } + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "zaJsHfESQvJ11vbXnNlkrR46IaMULk/gHxYsJphzSF+07kTjPHv+Oc14w6QEOfo3Q4hqLJgStUaYB9DBl0TmWg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "6.0.0" + } + }, + "System.Text.RegularExpressions": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Threading": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Overlapped": { + "type": "Transitive", + "resolved": "4.0.1", + "contentHash": "f7aLuLkBoCQM2kng7zqLFBXz9Gk48gDK8lk1ih9rH/1arJJzZK9gJwNvPDhL6Ps/l6rwOr8jw+4FCHL0KKWiEg==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Handles": "4.0.1" + } + }, + "System.Threading.Tasks": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" + }, + "System.Threading.Thread": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "System.Threading.ThreadPool": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "k/+g4b7vjdd4aix83sTgC9VG6oXYKAktSfNIJUNGxPEj7ryEOfzHHhfnmsZvjxawwcD9HyWXKCXmPjX8U4zeSw==", + "dependencies": { + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0" + } + }, + "System.Threading.Timer": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "Z6YfyYTCg7lOZjJzBjONJTFKGN9/NIYKSxhU5GRd+DTwHSZyvWp1xuI5aR+dLg+ayyC5Xv57KiY4oJ0tMO89fQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0" + } + }, + "System.ValueTuple": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==" + }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "IXoJOXIqc39AIe+CIR7koBtRGMiCt/LPM3lI+PELtDIy9XdyeSrwXFdWV9dzJ2Awl0paLWUaknLxFQ5HpHZUog==", + "dependencies": { + "System.Drawing.Common": "6.0.0" + } + }, + "System.Xml.ReaderWriter": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "GrprA+Z0RUXaR4N7/eW71j1rgMnEnEVlgii49GZyAjTH7uliMnrOU3HNFBr6fEDBCJCIdlVNq9hHbaDR621XBA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.IO.FileSystem": "4.3.0", + "System.IO.FileSystem.Primitives": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Text.Encoding.Extensions": "4.3.0", + "System.Text.RegularExpressions": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "System.Threading.Tasks.Extensions": "4.3.0" + } + }, + "System.Xml.XDocument": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "5zJ0XDxAIg8iy+t4aMnQAu0MqVbqyvfoUVl1yDV61xdo3Vth45oA2FoY4pPkxYAH5f8ixpmTqXeEIya95x0aCQ==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Diagnostics.Tools": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0" + } + }, + "System.Xml.XmlDocument": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "lJ8AxvkX7GQxpC6GFCeBj8ThYVyQczx2+f/cWHJU8tjS7YfI6Cv6bon70jVEgs2CiFbmmM8b9j1oZVx0dSI2Ww==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0" + } + }, + "System.Xml.XmlSerializer": { + "type": "Transitive", + "resolved": "4.0.11", + "contentHash": "FrazwwqfIXTfq23mfv4zH+BjqkSFNaNFBtjzu3I9NRmG8EELYyrv/fJnttCIwRMFRR/YKXF1hmsMmMEnl55HGw==", + "dependencies": { + "System.Collections": "4.0.11", + "System.Globalization": "4.0.11", + "System.IO": "4.1.0", + "System.Linq": "4.1.0", + "System.Reflection": "4.1.0", + "System.Reflection.Emit": "4.0.1", + "System.Reflection.Emit.ILGeneration": "4.0.1", + "System.Reflection.Extensions": "4.0.1", + "System.Reflection.Primitives": "4.0.1", + "System.Reflection.TypeExtensions": "4.1.0", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Text.RegularExpressions": "4.1.0", + "System.Threading": "4.0.11", + "System.Xml.ReaderWriter": "4.0.11", + "System.Xml.XmlDocument": "4.0.1" + } + }, + "System.Xml.XPath": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "v1JQ5SETnQusqmS3RwStF7vwQ3L02imIzl++sewmt23VGygix04pEH+FCj1yWb+z4GDzKiljr1W7Wfvrx0YwgA==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0" + } + }, + "System.Xml.XPath.XmlDocument": { + "type": "Transitive", + "resolved": "4.3.0", + "contentHash": "A/uxsWi/Ifzkmd4ArTLISMbfFs6XpRPsXZonrIqyTY70xi8t+mDtvSM5Os0RqyRDobjMBwIDHDL4NOIbkDwf7A==", + "dependencies": { + "System.Collections": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0", + "System.Xml.ReaderWriter": "4.3.0", + "System.Xml.XPath": "4.3.0", + "System.Xml.XmlDocument": "4.3.0" + } + }, + "YubicoDotNetClient": { + "type": "Transitive", + "resolved": "1.2.0", + "contentHash": "uP5F3Ko1gqZi3lwS2R/jAAwhBxXs/6PKDpS6FdQjsBA5qmF0hQmbtfxM6QHTXOMoWbUtfetG7+LtgmG8T5zDIg==", + "dependencies": { + "NETStandard.Library": "1.6.1" + } + }, + "core": { + "type": "Project", + "dependencies": { + "AWSSDK.SQS": "3.7.2.47", + "AWSSDK.SimpleEmail": "3.7.0.150", + "AspNetCoreRateLimit": "4.0.2", + "Azure.Extensions.AspNetCore.DataProtection.Blobs": "1.2.1", + "Azure.Storage.Blobs": "12.11.0", + "Azure.Storage.Queues": "12.9.0", + "BitPay.Light": "1.0.1907", + "Braintree": "5.12.0", + "Fido2.AspNet": "3.0.0-beta2", + "Handlebars.Net": "2.1.2", + "IdentityServer4": "4.1.2", + "IdentityServer4.AccessTokenValidation": "3.0.1", + "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.Extensions.Caching.Redis": "2.2.0", + "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": "39.107.0", + "YubicoDotNetClient": "1.2.0" + } + }, + "infrastructure.dapper": { + "type": "Project", + "dependencies": { + "Core": "2022.6.0", + "Dapper": "2.0.123", + "System.Data.SqlClient": "4.8.3" + } + }, + "infrastructure.entityframework": { + "type": "Project", + "dependencies": { + "AutoMapper.Extensions.Microsoft.DependencyInjection": "11.0.0", + "Core": "2022.6.0", + "Microsoft.EntityFrameworkCore.Relational": "6.0.4", + "Npgsql.EntityFrameworkCore.PostgreSQL": "6.0.4", + "Pomelo.EntityFrameworkCore.MySql": "6.0.1", + "linq2db.EntityFrameworkCore": "6.7.1" + } + }, + "sharedweb": { + "type": "Project", + "dependencies": { + "Core": "2022.6.0", + "Infrastructure.Dapper": "2022.6.0", + "Infrastructure.EntityFramework": "2022.6.0" + } + } + } + } +} \ No newline at end of file diff --git a/bitwarden_license/src/Sso/appsettings.Development.json b/bitwarden_license/src/Sso/appsettings.Development.json index f516c57b2..d45377822 100644 --- a/bitwarden_license/src/Sso/appsettings.Development.json +++ b/bitwarden_license/src/Sso/appsettings.Development.json @@ -12,7 +12,8 @@ "internalIdentity": "http://localhost:33656", "internalApi": "http://localhost:4000", "internalVault": "https://localhost:8080", - "internalSso": "http://localhost:51822" + "internalSso": "http://localhost:51822", + "internalScim": "http://localhost:44559" }, "events": { "connectionString": "UseDevelopmentStorage=true" diff --git a/bitwarden_license/src/Sso/appsettings.Production.json b/bitwarden_license/src/Sso/appsettings.Production.json index 54786119f..d2009cb3b 100644 --- a/bitwarden_license/src/Sso/appsettings.Production.json +++ b/bitwarden_license/src/Sso/appsettings.Production.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.bitwarden.com", "internalApi": "https://api.bitwarden.com", "internalVault": "https://vault.bitwarden.com", - "internalSso": "https://sso.bitwarden.com" + "internalSso": "https://sso.bitwarden.com", + "internalScim": "https://scim.bitwarden.com" }, "braintree": { "production": true diff --git a/bitwarden_license/src/Sso/appsettings.QA.json b/bitwarden_license/src/Sso/appsettings.QA.json index e2a020c07..b1d71196c 100644 --- a/bitwarden_license/src/Sso/appsettings.QA.json +++ b/bitwarden_license/src/Sso/appsettings.QA.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.qa.bitwarden.pw", "internalApi": "https://api.qa.bitwarden.pw", "internalVault": "https://vault.qa.bitwarden.pw", - "internalSso": "https://sso.qa.bitwarden.pw" + "internalSso": "https://sso.qa.bitwarden.pw", + "internalScim": "https://scim.qa.bitwarden.pw" }, "braintree": { "production": false diff --git a/bitwarden_license/src/Sso/appsettings.SelfHosted.json b/bitwarden_license/src/Sso/appsettings.SelfHosted.json index 0fab07f9f..37faf24b5 100644 --- a/bitwarden_license/src/Sso/appsettings.SelfHosted.json +++ b/bitwarden_license/src/Sso/appsettings.SelfHosted.json @@ -12,7 +12,8 @@ "internalIdentity": null, "internalApi": null, "internalVault": null, - "internalSso": null + "internalSso": null, + "internalScim": null } } } diff --git a/dev/setup_secrets.ps1 b/dev/setup_secrets.ps1 index c3c717a92..e9903bf4d 100644 --- a/dev/setup_secrets.ps1 +++ b/dev/setup_secrets.ps1 @@ -25,6 +25,7 @@ $projects = @{ Identity = "../src/Identity" Notifications = "../src/Notifications" Sso = "../bitwarden_license/src/Sso" + Scim = "../bitwarden_license/src/Scim" } foreach ($key in $projects.keys) { diff --git a/src/Admin/Models/OrganizationEditModel.cs b/src/Admin/Models/OrganizationEditModel.cs index cc7d6b62a..bf0d6c8d5 100644 --- a/src/Admin/Models/OrganizationEditModel.cs +++ b/src/Admin/Models/OrganizationEditModel.cs @@ -32,6 +32,7 @@ namespace Bit.Admin.Models UsePolicies = org.UsePolicies; UseSso = org.UseSso; UseKeyConnector = org.UseKeyConnector; + UseScim = org.UseScim; UseGroups = org.UseGroups; UseDirectory = org.UseDirectory; UseEvents = org.UseEvents; @@ -94,6 +95,8 @@ namespace Bit.Admin.Models public bool UseApi { get; set; } [Display(Name = "Reset Password")] public bool UseResetPassword { get; set; } + [Display(Name = "SCIM")] + public bool UseScim { get; set; } [Display(Name = "Self Host")] public bool SelfHost { get; set; } [Display(Name = "Users Get Premium")] @@ -126,6 +129,7 @@ namespace Bit.Admin.Models existingOrganization.UsePolicies = UsePolicies; existingOrganization.UseSso = UseSso; existingOrganization.UseKeyConnector = UseKeyConnector; + existingOrganization.UseScim = UseScim; existingOrganization.UseGroups = UseGroups; existingOrganization.UseDirectory = UseDirectory; existingOrganization.UseEvents = UseEvents; diff --git a/src/Admin/Views/Organizations/Edit.cshtml b/src/Admin/Views/Organizations/Edit.cshtml index c154ea245..10b42484b 100644 --- a/src/Admin/Views/Organizations/Edit.cshtml +++ b/src/Admin/Views/Organizations/Edit.cshtml @@ -32,6 +32,7 @@ document.getElementById('@(nameof(Model.UseApi))').checked = true; document.getElementById('@(nameof(Model.SelfHost))').checked = false; document.getElementById('@(nameof(Model.UseResetPassword))').checked = false; + document.getElementById('@(nameof(Model.UseScim))').checked = false; // Licensing document.getElementById('@(nameof(Model.LicenseKey))').value = '@Model.RandomLicenseKey'; document.getElementById('@(nameof(Model.ExpirationDate))').value = '@Model.FourteenDayExpirationDate'; @@ -65,6 +66,7 @@ document.getElementById('@(nameof(Model.UseApi))').checked = true; document.getElementById('@(nameof(Model.SelfHost))').checked = true; document.getElementById('@(nameof(Model.UseResetPassword))').checked = true; + document.getElementById('@(nameof(Model.UseScim))').checked = true; // Licensing document.getElementById('@(nameof(Model.LicenseKey))').value = '@Model.RandomLicenseKey'; document.getElementById('@(nameof(Model.ExpirationDate))').value = '@Model.FourteenDayExpirationDate'; @@ -219,6 +221,10 @@ +
+ + +
diff --git a/src/Admin/appsettings.Development.json b/src/Admin/appsettings.Development.json index 7f6bac5ff..645b9020d 100644 --- a/src/Admin/appsettings.Development.json +++ b/src/Admin/appsettings.Development.json @@ -12,7 +12,8 @@ "internalIdentity": "http://localhost:33656", "internalApi": "http://localhost:4000", "internalVault": "https://localhost:8080", - "internalSso": "http://localhost:51822" + "internalSso": "http://localhost:51822", + "internalScim": "http://localhost:44559" }, "mail": { "smtp": { diff --git a/src/Admin/appsettings.Production.json b/src/Admin/appsettings.Production.json index e3b014855..9f797f311 100644 --- a/src/Admin/appsettings.Production.json +++ b/src/Admin/appsettings.Production.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.bitwarden.com", "internalApi": "https://api.bitwarden.com", "internalVault": "https://vault.bitwarden.com", - "internalSso": "https://sso.bitwarden.com" + "internalSso": "https://sso.bitwarden.com", + "internalScim": "https://scim.bitwarden.com" }, "braintree": { "production": true diff --git a/src/Admin/appsettings.QA.json b/src/Admin/appsettings.QA.json index 3052e58e2..748372bc9 100644 --- a/src/Admin/appsettings.QA.json +++ b/src/Admin/appsettings.QA.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.qa.bitwarden.pw", "internalApi": "https://api.qa.bitwarden.pw", "internalVault": "https://vault.qa.bitwarden.pw", - "internalSso": "https://sso.qa.bitwarden.pw" + "internalSso": "https://sso.qa.bitwarden.pw", + "internalScim": "https://scim.qa.bitwarden.pw" }, "braintree": { "production": false diff --git a/src/Admin/appsettings.SelfHosted.json b/src/Admin/appsettings.SelfHosted.json index 0fab07f9f..37faf24b5 100644 --- a/src/Admin/appsettings.SelfHosted.json +++ b/src/Admin/appsettings.SelfHosted.json @@ -12,7 +12,8 @@ "internalIdentity": null, "internalApi": null, "internalVault": null, - "internalSso": null + "internalSso": null, + "internalScim": null } } } diff --git a/src/Api/Controllers/OrganizationConnectionsController.cs b/src/Api/Controllers/OrganizationConnectionsController.cs index 2302116aa..83f7a6ed7 100644 --- a/src/Api/Controllers/OrganizationConnectionsController.cs +++ b/src/Api/Controllers/OrganizationConnectionsController.cs @@ -9,13 +9,11 @@ using Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Settings; -using Bit.Core.Utilities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Bit.Api.Controllers { - [SelfHosted(SelfHostedOnly = true)] [Authorize("Application")] [Route("organizations/connections")] public class OrganizationConnectionsController : Controller @@ -57,10 +55,10 @@ namespace Bit.Api.Controllers { if (!await HasPermissionAsync(model?.OrganizationId)) { - throw new BadRequestException("Only the owner of an organization can create a connection."); + throw new BadRequestException($"You do not have permission to create a connection of type {model.Type}."); } - if (await HasConnectionTypeAsync(model)) + if (await HasConnectionTypeAsync(model, null, model.Type)) { throw new BadRequestException($"The requested organization already has a connection of type {model.Type}. Only one of each connection type may exist per organization."); } @@ -68,15 +66,9 @@ namespace Bit.Api.Controllers switch (model.Type) { case OrganizationConnectionType.CloudBillingSync: - var typedModel = new OrganizationConnectionRequestModel(model); - var license = await _licensingService.ReadOrganizationLicenseAsync(model.OrganizationId); - if (!_licensingService.VerifyLicense(license)) - { - throw new BadRequestException("Cannot verify license file."); - } - typedModel.ParsedConfig.CloudOrganizationId = license.Id; - var connection = await _createOrganizationConnectionCommand.CreateAsync(typedModel.ToData()); - return new OrganizationConnectionResponseModel(connection, typeof(BillingSyncConfig)); + return await CreateOrUpdateOrganizationConnectionAsync(null, model, ValidateBillingSyncConfig); + case OrganizationConnectionType.Scim: + return await CreateOrUpdateOrganizationConnectionAsync(null, model); default: throw new BadRequestException($"Unknown Organization connection Type: {model.Type}"); } @@ -91,12 +83,12 @@ namespace Bit.Api.Controllers throw new NotFoundException(); } - if (!await HasPermissionAsync(model?.OrganizationId)) + if (!await HasPermissionAsync(model?.OrganizationId, model?.Type)) { - throw new BadRequestException("Only the owner of an organization can update a connection."); + throw new BadRequestException("You do not have permission to update this connection."); } - if (await HasConnectionTypeAsync(model, organizationConnectionId)) + if (await HasConnectionTypeAsync(model, organizationConnectionId, model.Type)) { throw new BadRequestException($"The requested organization already has a connection of type {model.Type}. Only one of each connection type may exist per organization."); } @@ -104,11 +96,9 @@ namespace Bit.Api.Controllers switch (model.Type) { case OrganizationConnectionType.CloudBillingSync: - var typedModel = new OrganizationConnectionRequestModel(model); - // We don't allow overwriting or changing the CloudOrganizationId so save it from the existing connection - typedModel.ParsedConfig.CloudOrganizationId = existingOrganizationConnection.GetConfig().CloudOrganizationId; - var connection = await _updateOrganizationConnectionCommand.UpdateAsync(typedModel.ToData(organizationConnectionId)); - return new OrganizationConnectionResponseModel(connection, typeof(BillingSyncConfig)); + return await CreateOrUpdateOrganizationConnectionAsync(organizationConnectionId, model); + case OrganizationConnectionType.Scim: + return await CreateOrUpdateOrganizationConnectionAsync(organizationConnectionId, model); default: throw new BadRequestException($"Unkown Organization connection Type: {model.Type}"); } @@ -117,22 +107,27 @@ namespace Bit.Api.Controllers [HttpGet("{organizationId}/{type}")] public async Task GetConnection(Guid organizationId, OrganizationConnectionType type) { - if (!await HasPermissionAsync(organizationId)) + if (!await HasPermissionAsync(organizationId, type)) { - throw new BadRequestException("Only the owner of an organization can retrieve a connection."); + throw new BadRequestException($"You do not have permission to retrieve a connection of type {type}."); } - var connections = await GetConnectionsAsync(organizationId); + var connections = await GetConnectionsAsync(organizationId, type); var connection = connections.FirstOrDefault(c => c.Type == type); switch (type) { case OrganizationConnectionType.CloudBillingSync: + if (!_globalSettings.SelfHosted) + { + throw new BadRequestException($"Cannot get a {type} connection outside of a self-hosted instance."); + } return new OrganizationConnectionResponseModel(connection, typeof(BillingSyncConfig)); + case OrganizationConnectionType.Scim: + return new OrganizationConnectionResponseModel(connection, typeof(ScimConfig)); default: throw new BadRequestException($"Unkown Organization connection Type: {type}"); } - } [HttpDelete("{organizationConnectionId}")] @@ -146,25 +141,70 @@ namespace Bit.Api.Controllers throw new NotFoundException(); } - if (!await HasPermissionAsync(connection.OrganizationId)) + if (!await HasPermissionAsync(connection.OrganizationId, connection.Type)) { - throw new BadRequestException("Only the owner of an organization can remove a connection."); + throw new BadRequestException($"You do not have permission to remove this connection of type {connection.Type}."); } await _deleteOrganizationConnectionCommand.DeleteAsync(connection); } - private async Task> GetConnectionsAsync(Guid organizationId) => - await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(organizationId, OrganizationConnectionType.CloudBillingSync); + private async Task> GetConnectionsAsync(Guid organizationId, OrganizationConnectionType type) => + await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(organizationId, type); - private async Task HasConnectionTypeAsync(OrganizationConnectionRequestModel model, Guid? connectionId = null) + private async Task HasConnectionTypeAsync(OrganizationConnectionRequestModel model, Guid? connectionId, + OrganizationConnectionType type) { - var existingConnections = await GetConnectionsAsync(model.OrganizationId); + var existingConnections = await GetConnectionsAsync(model.OrganizationId, type); return existingConnections.Any(c => c.Type == model.Type && (!connectionId.HasValue || c.Id != connectionId.Value)); } - private async Task HasPermissionAsync(Guid? organizationId) => - organizationId.HasValue && await _currentContext.OrganizationOwner(organizationId.Value); + private async Task HasPermissionAsync(Guid? organizationId, OrganizationConnectionType? type = null) + { + if (!organizationId.HasValue) + { + return false; + } + return type switch + { + OrganizationConnectionType.Scim => await _currentContext.ManageScim(organizationId.Value), + _ => await _currentContext.OrganizationOwner(organizationId.Value), + }; + } + + private async Task ValidateBillingSyncConfig(OrganizationConnectionRequestModel typedModel) + { + if (!_globalSettings.SelfHosted) + { + throw new BadRequestException($"Cannot create a {typedModel.Type} connection outside of a self-hosted instance."); + } + var license = await _licensingService.ReadOrganizationLicenseAsync(typedModel.OrganizationId); + if (!_licensingService.VerifyLicense(license)) + { + throw new BadRequestException("Cannot verify license file."); + } + typedModel.ParsedConfig.CloudOrganizationId = license.Id; + } + + private async Task CreateOrUpdateOrganizationConnectionAsync( + Guid? organizationConnectionId, + OrganizationConnectionRequestModel model, + Func, Task> validateAction = null) + where T : new() + { + var typedModel = new OrganizationConnectionRequestModel(model); + if (validateAction != null) + { + await validateAction(typedModel); + } + + var data = typedModel.ToData(organizationConnectionId); + var connection = organizationConnectionId.HasValue + ? await _updateOrganizationConnectionCommand.UpdateAsync(data) + : await _createOrganizationConnectionCommand.CreateAsync(data); + + return new OrganizationConnectionResponseModel(connection, typeof(T)); + } } } diff --git a/src/Api/Controllers/OrganizationsController.cs b/src/Api/Controllers/OrganizationsController.cs index da73ab9e6..7a5b26d9e 100644 --- a/src/Api/Controllers/OrganizationsController.cs +++ b/src/Api/Controllers/OrganizationsController.cs @@ -493,7 +493,7 @@ namespace Bit.Api.Controllers public async Task ApiKey(string id, [FromBody] OrganizationApiKeyRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await HasApiKeyAccessAsync(orgIdGuid, model.Type)) { throw new NotFoundException(); } @@ -504,9 +504,9 @@ namespace Bit.Api.Controllers throw new NotFoundException(); } - if (model.Type == OrganizationApiKeyType.BillingSync) + if (model.Type == OrganizationApiKeyType.BillingSync || model.Type == OrganizationApiKeyType.Scim) { - // Non-enterprise orgs should not be able to create or view an apikey of billing sync key type + // Non-enterprise orgs should not be able to create or view an apikey of billing sync/scim key types var plan = StaticStore.GetPlan(organization.PlanType); if (plan.Product != ProductType.Enterprise) { @@ -523,7 +523,8 @@ namespace Bit.Api.Controllers throw new UnauthorizedAccessException(); } - if (!await _userService.VerifySecretAsync(user, model.Secret)) + if (model.Type != OrganizationApiKeyType.Scim + && !await _userService.VerifySecretAsync(user, model.Secret)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); @@ -535,15 +536,15 @@ namespace Bit.Api.Controllers } } - [HttpGet("{id}/api-key-information")] - public async Task> ApiKeyInformation(Guid id) + [HttpGet("{id}/api-key-information/{type?}")] + public async Task> ApiKeyInformation(Guid id, OrganizationApiKeyType? type) { - if (!await _currentContext.OrganizationOwner(id)) + if (!await HasApiKeyAccessAsync(id, type)) { throw new NotFoundException(); } - var apiKeys = await _organizationApiKeyRepository.GetManyByOrganizationIdTypeAsync(id); + var apiKeys = await _organizationApiKeyRepository.GetManyByOrganizationIdTypeAsync(id, type); return new ListResponseModel( apiKeys.Select(k => new OrganizationApiKeyInformation(k))); @@ -553,7 +554,7 @@ namespace Bit.Api.Controllers public async Task RotateApiKey(string id, [FromBody] OrganizationApiKeyRequestModel model) { var orgIdGuid = new Guid(id); - if (!await _currentContext.OrganizationOwner(orgIdGuid)) + if (!await HasApiKeyAccessAsync(orgIdGuid, model.Type)) { throw new NotFoundException(); } @@ -573,7 +574,8 @@ namespace Bit.Api.Controllers throw new UnauthorizedAccessException(); } - if (!await _userService.VerifySecretAsync(user, model.Secret)) + if (model.Type != OrganizationApiKeyType.Scim + && !await _userService.VerifySecretAsync(user, model.Secret)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); @@ -586,6 +588,15 @@ namespace Bit.Api.Controllers } } + private async Task HasApiKeyAccessAsync(Guid orgId, OrganizationApiKeyType? type) + { + return type switch + { + OrganizationApiKeyType.Scim => await _currentContext.ManageScim(orgId), + _ => await _currentContext.OrganizationOwner(orgId), + }; + } + [HttpGet("{id}/tax")] [SelfHosted(NotSelfHostedOnly = true)] public async Task GetTaxInfo(string id) diff --git a/src/Api/Models/Response/Organizations/OrganizationResponseModel.cs b/src/Api/Models/Response/Organizations/OrganizationResponseModel.cs index 81b9c3d9a..eab23bee9 100644 --- a/src/Api/Models/Response/Organizations/OrganizationResponseModel.cs +++ b/src/Api/Models/Response/Organizations/OrganizationResponseModel.cs @@ -35,6 +35,7 @@ namespace Bit.Api.Models.Response.Organizations UsePolicies = organization.UsePolicies; UseSso = organization.UseSso; UseKeyConnector = organization.UseKeyConnector; + UseScim = organization.UseScim; UseGroups = organization.UseGroups; UseDirectory = organization.UseDirectory; UseEvents = organization.UseEvents; @@ -66,6 +67,7 @@ namespace Bit.Api.Models.Response.Organizations public bool UsePolicies { get; set; } public bool UseSso { get; set; } public bool UseKeyConnector { get; set; } + public bool UseScim { get; set; } public bool UseGroups { get; set; } public bool UseDirectory { get; set; } public bool UseEvents { get; set; } diff --git a/src/Api/Models/Response/ProfileOrganizationResponseModel.cs b/src/Api/Models/Response/ProfileOrganizationResponseModel.cs index cb41f8b35..969dbbaf1 100644 --- a/src/Api/Models/Response/ProfileOrganizationResponseModel.cs +++ b/src/Api/Models/Response/ProfileOrganizationResponseModel.cs @@ -17,6 +17,7 @@ namespace Bit.Api.Models.Response UsePolicies = organization.UsePolicies; UseSso = organization.UseSso; UseKeyConnector = organization.UseKeyConnector; + UseScim = organization.UseScim; UseGroups = organization.UseGroups; UseDirectory = organization.UseDirectory; UseEvents = organization.UseEvents; @@ -63,6 +64,7 @@ namespace Bit.Api.Models.Response public bool UsePolicies { get; set; } public bool UseSso { get; set; } public bool UseKeyConnector { get; set; } + public bool UseScim { get; set; } public bool UseGroups { get; set; } public bool UseDirectory { get; set; } public bool UseEvents { get; set; } diff --git a/src/Api/Models/Response/ProfileProviderOrganizationResponseModel.cs b/src/Api/Models/Response/ProfileProviderOrganizationResponseModel.cs index bb8d0af36..c2d7858b5 100644 --- a/src/Api/Models/Response/ProfileProviderOrganizationResponseModel.cs +++ b/src/Api/Models/Response/ProfileProviderOrganizationResponseModel.cs @@ -13,6 +13,7 @@ namespace Bit.Api.Models.Response UsePolicies = organization.UsePolicies; UseSso = organization.UseSso; UseKeyConnector = organization.UseKeyConnector; + UseScim = organization.UseScim; UseGroups = organization.UseGroups; UseDirectory = organization.UseDirectory; UseEvents = organization.UseEvents; diff --git a/src/Api/appsettings.Development.json b/src/Api/appsettings.Development.json index cdf5a7748..2f33d87ae 100644 --- a/src/Api/appsettings.Development.json +++ b/src/Api/appsettings.Development.json @@ -12,7 +12,8 @@ "internalIdentity": "http://localhost:33656", "internalApi": "http://localhost:4000", "internalVault": "https://localhost:8080", - "internalSso": "http://localhost:51822" + "internalSso": "http://localhost:51822", + "internalScim": "http://localhost:44559" }, "mail": { "smtp": { diff --git a/src/Api/appsettings.Production.json b/src/Api/appsettings.Production.json index d8ffaf659..d9efbcda1 100644 --- a/src/Api/appsettings.Production.json +++ b/src/Api/appsettings.Production.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.bitwarden.com", "internalApi": "https://api.bitwarden.com", "internalVault": "https://vault.bitwarden.com", - "internalSso": "https://sso.bitwarden.com" + "internalSso": "https://sso.bitwarden.com", + "internalScim": "https://scim.bitwarden.com" }, "braintree": { "production": true diff --git a/src/Api/appsettings.QA.json b/src/Api/appsettings.QA.json index 6bf7bb0a5..f4491a055 100644 --- a/src/Api/appsettings.QA.json +++ b/src/Api/appsettings.QA.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.qa.bitwarden.pw", "internalApi": "https://api.qa.bitwarden.pw", "internalVault": "https://vault.qa.bitwarden.pw", - "internalSso": "https://sso.qa.bitwarden.pw" + "internalSso": "https://sso.qa.bitwarden.pw", + "internalScim": "https://scim.qa.bitwarden.pw" }, "braintree": { "production": false diff --git a/src/Api/appsettings.SelfHosted.json b/src/Api/appsettings.SelfHosted.json index 0fab07f9f..37faf24b5 100644 --- a/src/Api/appsettings.SelfHosted.json +++ b/src/Api/appsettings.SelfHosted.json @@ -12,7 +12,8 @@ "internalIdentity": null, "internalApi": null, "internalVault": null, - "internalSso": null + "internalSso": null, + "internalScim": null } } } diff --git a/src/Billing/appsettings.Development.json b/src/Billing/appsettings.Development.json index 7dfdd763f..32253a93c 100644 --- a/src/Billing/appsettings.Development.json +++ b/src/Billing/appsettings.Development.json @@ -12,7 +12,8 @@ "internalIdentity": "http://localhost:33656", "internalApi": "http://localhost:4000", "internalVault": "https://localhost:8080", - "internalSso": "http://localhost:51822" + "internalSso": "http://localhost:51822", + "internalScim": "http://localhost:44559" }, "mail": { "smtp": { diff --git a/src/Billing/appsettings.Production.json b/src/Billing/appsettings.Production.json index b8edf7259..819986181 100644 --- a/src/Billing/appsettings.Production.json +++ b/src/Billing/appsettings.Production.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.bitwarden.com", "internalApi": "https://api.bitwarden.com", "internalVault": "https://vault.bitwarden.com", - "internalSso": "https://sso.bitwarden.com" + "internalSso": "https://sso.bitwarden.com", + "internalScim": "https://scim.bitwarden.com" }, "braintree": { "production": true diff --git a/src/Billing/appsettings.QA.json b/src/Billing/appsettings.QA.json index 52506fe02..496eedc19 100644 --- a/src/Billing/appsettings.QA.json +++ b/src/Billing/appsettings.QA.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.qa.bitwarden.pw", "internalApi": "https://api.qa.bitwarden.pw", "internalVault": "https://vault.qa.bitwarden.pw", - "internalSso": "https://sso.qa.bitwarden.pw" + "internalSso": "https://sso.qa.bitwarden.pw", + "internalScim": "https://scim.qa.bitwarden.pw" }, "braintree": { "production": false diff --git a/src/Core/Context/CurrentContext.cs b/src/Core/Context/CurrentContext.cs index c6d4ca00a..47effcab1 100644 --- a/src/Core/Context/CurrentContext.cs +++ b/src/Core/Context/CurrentContext.cs @@ -344,6 +344,12 @@ namespace Bit.Core.Context && (o.Permissions?.ManageSso ?? false)) ?? false); } + public async Task ManageScim(Guid orgId) + { + return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId + && (o.Permissions?.ManageScim ?? false)) ?? false); + } + public async Task ManageUsers(Guid orgId) { return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId @@ -469,7 +475,8 @@ namespace Bit.Core.Context ManagePolicies = hasClaim("managepolicies"), ManageSso = hasClaim("managesso"), ManageUsers = hasClaim("manageusers"), - ManageResetPassword = hasClaim("manageresetpassword") + ManageResetPassword = hasClaim("manageresetpassword"), + ManageScim = hasClaim("managescim"), }; } diff --git a/src/Core/Context/ICurrentContext.cs b/src/Core/Context/ICurrentContext.cs index 3d0b8c855..d82ad12e4 100644 --- a/src/Core/Context/ICurrentContext.cs +++ b/src/Core/Context/ICurrentContext.cs @@ -47,6 +47,7 @@ namespace Bit.Core.Context Task ManagePolicies(Guid orgId); Task ManageSso(Guid orgId); Task ManageUsers(Guid orgId); + Task ManageScim(Guid orgId); Task ManageResetPassword(Guid orgId); Task ManageBilling(Guid orgId); Task ProviderUserForOrgAsync(Guid orgId); diff --git a/src/Core/Entities/Organization.cs b/src/Core/Entities/Organization.cs index 19ed28091..818db3230 100644 --- a/src/Core/Entities/Organization.cs +++ b/src/Core/Entities/Organization.cs @@ -37,6 +37,7 @@ namespace Bit.Core.Entities public bool UsePolicies { get; set; } public bool UseSso { get; set; } public bool UseKeyConnector { get; set; } + public bool UseScim { get; set; } public bool UseGroups { get; set; } public bool UseDirectory { get; set; } public bool UseEvents { get; set; } diff --git a/src/Core/Enums/OrganizationApiKeyType.cs b/src/Core/Enums/OrganizationApiKeyType.cs index fe294a7d2..153079cf2 100644 --- a/src/Core/Enums/OrganizationApiKeyType.cs +++ b/src/Core/Enums/OrganizationApiKeyType.cs @@ -2,7 +2,8 @@ { public enum OrganizationApiKeyType : byte { - Default, - BillingSync, + Default = 0, + BillingSync = 1, + Scim = 2, } } diff --git a/src/Core/Enums/OrganizationConnectionType.cs b/src/Core/Enums/OrganizationConnectionType.cs index bfa9a2215..e998e5532 100644 --- a/src/Core/Enums/OrganizationConnectionType.cs +++ b/src/Core/Enums/OrganizationConnectionType.cs @@ -3,5 +3,6 @@ public enum OrganizationConnectionType : byte { CloudBillingSync = 1, + Scim = 2, } } diff --git a/src/Core/Enums/ScimProviderType.cs b/src/Core/Enums/ScimProviderType.cs new file mode 100644 index 000000000..18039c87c --- /dev/null +++ b/src/Core/Enums/ScimProviderType.cs @@ -0,0 +1,13 @@ +namespace Bit.Core.Enums +{ + public enum ScimProviderType : byte + { + Default = 0, + AzureAd = 1, + Okta = 2, + OneLogin = 3, + JumpCloud = 4, + GoogleWorkspace = 5, + Rippling = 6, + } +} diff --git a/src/Core/Models/Business/OrganizationLicense.cs b/src/Core/Models/Business/OrganizationLicense.cs index f9fe2eccd..8f394c7ab 100644 --- a/src/Core/Models/Business/OrganizationLicense.cs +++ b/src/Core/Models/Business/OrganizationLicense.cs @@ -34,6 +34,7 @@ namespace Bit.Core.Models.Business UsePolicies = org.UsePolicies; UseSso = org.UseSso; UseKeyConnector = org.UseKeyConnector; + UseScim = org.UseScim; UseGroups = org.UseGroups; UseEvents = org.UseEvents; UseDirectory = org.UseDirectory; @@ -105,6 +106,7 @@ namespace Bit.Core.Models.Business public bool UsePolicies { get; set; } public bool UseSso { get; set; } public bool UseKeyConnector { get; set; } + public bool UseScim { get; set; } public bool UseGroups { get; set; } public bool UseEvents { get; set; } public bool UseDirectory { get; set; } @@ -129,10 +131,10 @@ namespace Bit.Core.Models.Business /// /// Represents the current version of the license format. Should be updated whenever new fields are added. /// - private const int CURRENT_LICENSE_FILE_VERSION = 8; + private const int CURRENT_LICENSE_FILE_VERSION = 10; private bool ValidLicenseVersion { - get => Version is >= 1 and <= 9; + get => Version is >= 1 and <= 10; } public byte[] GetDataBytes(bool forHash = false) @@ -162,6 +164,8 @@ namespace Bit.Core.Models.Business (Version >= 8 || !p.Name.Equals(nameof(UseResetPassword))) && // UseKeyConnector was added in Version 9 (Version >= 9 || !p.Name.Equals(nameof(UseKeyConnector))) && + // UseScim was added in Version 10 + (Version >= 10 || !p.Name.Equals(nameof(UseScim))) && ( !forHash || ( @@ -270,6 +274,11 @@ namespace Bit.Core.Models.Business valid = organization.UseKeyConnector == UseKeyConnector; } + if (valid && Version >= 10) + { + valid = organization.UseScim == UseScim; + } + return valid; } else diff --git a/src/Core/Models/Data/Organizations/OrganizationAbility.cs b/src/Core/Models/Data/Organizations/OrganizationAbility.cs index c70b03c49..6ec693185 100644 --- a/src/Core/Models/Data/Organizations/OrganizationAbility.cs +++ b/src/Core/Models/Data/Organizations/OrganizationAbility.cs @@ -17,6 +17,7 @@ namespace Bit.Core.Models.Data.Organizations Enabled = organization.Enabled; UseSso = organization.UseSso; UseKeyConnector = organization.UseKeyConnector; + UseScim = organization.UseScim; UseResetPassword = organization.UseResetPassword; } @@ -28,6 +29,7 @@ namespace Bit.Core.Models.Data.Organizations public bool Enabled { get; set; } public bool UseSso { get; set; } public bool UseKeyConnector { get; set; } + public bool UseScim { get; set; } public bool UseResetPassword { get; set; } } } diff --git a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs index 258b5e726..554e99e6c 100644 --- a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs +++ b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs @@ -8,6 +8,7 @@ public bool UsePolicies { get; set; } public bool UseSso { get; set; } public bool UseKeyConnector { get; set; } + public bool UseScim { get; set; } public bool UseGroups { get; set; } public bool UseDirectory { get; set; } public bool UseEvents { get; set; } diff --git a/src/Core/Models/Data/Permissions.cs b/src/Core/Models/Data/Permissions.cs index 501968dfd..5cb0149a3 100644 --- a/src/Core/Models/Data/Permissions.cs +++ b/src/Core/Models/Data/Permissions.cs @@ -21,6 +21,7 @@ namespace Bit.Core.Models.Data public bool ManageSso { get; set; } public bool ManageUsers { get; set; } public bool ManageResetPassword { get; set; } + public bool ManageScim { get; set; } [JsonIgnore] public List<(bool Permission, string ClaimName)> ClaimsMap => new() @@ -38,6 +39,7 @@ namespace Bit.Core.Models.Data (ManageSso, "managesso"), (ManageUsers, "manageusers"), (ManageResetPassword, "manageresetpassword"), + (ManageScim, "managescim"), }; } } diff --git a/src/Core/Models/Data/Provider/ProviderUserOrganizationDetails.cs b/src/Core/Models/Data/Provider/ProviderUserOrganizationDetails.cs index ee34d0081..ab19931b6 100644 --- a/src/Core/Models/Data/Provider/ProviderUserOrganizationDetails.cs +++ b/src/Core/Models/Data/Provider/ProviderUserOrganizationDetails.cs @@ -10,6 +10,7 @@ namespace Bit.Core.Models.Data public bool UsePolicies { get; set; } public bool UseSso { get; set; } public bool UseKeyConnector { get; set; } + public bool UseScim { get; set; } public bool UseGroups { get; set; } public bool UseDirectory { get; set; } public bool UseEvents { get; set; } diff --git a/src/Core/Models/OrganizationConnectionConfigs/ScimConfig.cs b/src/Core/Models/OrganizationConnectionConfigs/ScimConfig.cs new file mode 100644 index 000000000..a7eeb632b --- /dev/null +++ b/src/Core/Models/OrganizationConnectionConfigs/ScimConfig.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; +using Bit.Core.Enums; + +namespace Bit.Core.Models.OrganizationConnectionConfigs +{ + public class ScimConfig + { + public bool Enabled { get; set; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public ScimProviderType? ScimProvider { get; set; } + } +} diff --git a/src/Core/Models/StaticStore/Plan.cs b/src/Core/Models/StaticStore/Plan.cs index 2bed65c7f..98686f5ab 100644 --- a/src/Core/Models/StaticStore/Plan.cs +++ b/src/Core/Models/StaticStore/Plan.cs @@ -34,6 +34,7 @@ namespace Bit.Core.Models.StaticStore public bool HasApi { get; set; } public bool HasSso { get; set; } public bool HasKeyConnector { get; set; } + public bool HasScim { get; set; } public bool HasResetPassword { get; set; } public bool UsersGetPremium { get; set; } diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index f7314d0e7..ca1913c4e 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -6,6 +6,7 @@ using Bit.Core.Exceptions; using Bit.Core.Models.Business; using Bit.Core.Models.Data; using Bit.Core.Models.Data.Organizations.Policies; +using Bit.Core.Models.OrganizationConnectionConfigs; using Bit.Core.Repositories; using Bit.Core.Settings; using Bit.Core.Utilities; @@ -39,6 +40,7 @@ namespace Bit.Core.Services private readonly IGlobalSettings _globalSettings; private readonly ITaxRateRepository _taxRateRepository; private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository; + private readonly IOrganizationConnectionRepository _organizationConnectionRepository; private readonly ICurrentContext _currentContext; private readonly ILogger _logger; @@ -66,6 +68,7 @@ namespace Bit.Core.Services IGlobalSettings globalSettings, ITaxRateRepository taxRateRepository, IOrganizationApiKeyRepository organizationApiKeyRepository, + IOrganizationConnectionRepository organizationConnectionRepository, ICurrentContext currentContext, ILogger logger) { @@ -91,6 +94,7 @@ namespace Bit.Core.Services _globalSettings = globalSettings; _taxRateRepository = taxRateRepository; _organizationApiKeyRepository = organizationApiKeyRepository; + _organizationConnectionRepository = organizationConnectionRepository; _currentContext = currentContext; _logger = logger; } @@ -266,6 +270,17 @@ namespace Bit.Core.Services } } + if (!newPlan.HasScim && organization.UseScim) + { + var scimConnections = await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(organization.Id, + OrganizationConnectionType.Scim); + if (scimConnections != null && scimConnections.Any(c => c.GetConfig()?.Enabled == true)) + { + throw new BadRequestException("Your new plan does not allow the SCIM feature. " + + "Disable your SCIM configuration."); + } + } + // TODO: Check storage? string paymentIntentClientSecret = null; @@ -304,6 +319,7 @@ namespace Bit.Core.Services organization.UseApi = newPlan.HasApi; organization.UseSso = newPlan.HasSso; organization.UseKeyConnector = newPlan.HasKeyConnector; + organization.UseScim = newPlan.HasScim; organization.UseResetPassword = newPlan.HasResetPassword; organization.SelfHost = newPlan.HasSelfHost; organization.UsersGetPremium = newPlan.UsersGetPremium || upgrade.PremiumAccessAddon; @@ -702,6 +718,7 @@ namespace Bit.Core.Services UsePolicies = license.UsePolicies, UseSso = license.UseSso, UseKeyConnector = license.UseKeyConnector, + UseScim = license.UseScim, UseGroups = license.UseGroups, UseDirectory = license.UseDirectory, UseEvents = license.UseEvents, @@ -902,6 +919,17 @@ namespace Bit.Core.Services } } + if (!license.UseScim && organization.UseScim) + { + var scimConnections = await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(organization.Id, + OrganizationConnectionType.Scim); + if (scimConnections != null && scimConnections.Any(c => c.GetConfig()?.Enabled == true)) + { + throw new BadRequestException("Your new plan does not allow the SCIM feature. " + + "Disable your SCIM configuration."); + } + } + if (!license.UseResetPassword && organization.UseResetPassword) { var resetPasswordPolicy = @@ -933,6 +961,7 @@ namespace Bit.Core.Services organization.UsePolicies = license.UsePolicies; organization.UseSso = license.UseSso; organization.UseKeyConnector = license.UseKeyConnector; + organization.UseScim = license.UseScim; organization.UseResetPassword = license.UseResetPassword; organization.SelfHost = license.SelfHost; organization.UsersGetPremium = license.UsersGetPremium; diff --git a/src/Core/Settings/GlobalSettings.cs b/src/Core/Settings/GlobalSettings.cs index f927fd463..b79a5250d 100644 --- a/src/Core/Settings/GlobalSettings.cs +++ b/src/Core/Settings/GlobalSettings.cs @@ -117,12 +117,14 @@ private string _admin; private string _notifications; private string _sso; + private string _scim; private string _internalApi; private string _internalIdentity; private string _internalAdmin; private string _internalNotifications; private string _internalSso; private string _internalVault; + private string _internalScim; public BaseServiceUriSettings(GlobalSettings globalSettings) { @@ -157,6 +159,11 @@ get => _globalSettings.BuildExternalUri(_sso, "sso"); set => _sso = value; } + public string Scim + { + get => _globalSettings.BuildExternalUri(_scim, "scim"); + set => _scim = value; + } public string InternalNotifications { @@ -188,6 +195,11 @@ get => _globalSettings.BuildInternalUri(_internalSso, "sso"); set => _internalSso = value; } + public string InternalScim + { + get => _globalSettings.BuildInternalUri(_scim, "scim"); + set => _internalScim = value; + } } public class SqlSettings diff --git a/src/Core/Settings/IBaseServiceUriSettings.cs b/src/Core/Settings/IBaseServiceUriSettings.cs index 9a4373e91..0dfdaf0b9 100644 --- a/src/Core/Settings/IBaseServiceUriSettings.cs +++ b/src/Core/Settings/IBaseServiceUriSettings.cs @@ -10,11 +10,13 @@ namespace Bit.Core.Settings public string Admin { get; set; } public string Notifications { get; set; } public string Sso { get; set; } + public string Scim { get; set; } public string InternalNotifications { get; set; } public string InternalAdmin { get; set; } public string InternalIdentity { get; set; } public string InternalApi { get; set; } public string InternalVault { get; set; } public string InternalSso { get; set; } + public string InternalScim { get; set; } } } diff --git a/src/Core/Utilities/StaticStore.cs b/src/Core/Utilities/StaticStore.cs index fd5f3ce9e..0b8cb61bf 100644 --- a/src/Core/Utilities/StaticStore.cs +++ b/src/Core/Utilities/StaticStore.cs @@ -414,6 +414,7 @@ namespace Bit.Core.Utilities HasApi = true, HasSso = true, HasKeyConnector = true, + HasScim = true, HasResetPassword = true, UsersGetPremium = true, @@ -453,6 +454,7 @@ namespace Bit.Core.Utilities HasSelfHost = true, HasSso = true, HasKeyConnector = true, + HasScim = true, HasResetPassword = true, UsersGetPremium = true, diff --git a/src/Events/appsettings.Development.json b/src/Events/appsettings.Development.json index df8bd6bfa..4f264b51a 100644 --- a/src/Events/appsettings.Development.json +++ b/src/Events/appsettings.Development.json @@ -12,7 +12,8 @@ "internalIdentity": "http://localhost:33656", "internalApi": "http://localhost:4000", "internalVault": "https://localhost:8080", - "internalSso": "http://localhost:51822" + "internalSso": "http://localhost:51822", + "internalScim": "http://localhost:44559" }, "events": { "connectionString": "UseDevelopmentStorage=true" diff --git a/src/Events/appsettings.Production.json b/src/Events/appsettings.Production.json index 95162be32..010f02f8c 100644 --- a/src/Events/appsettings.Production.json +++ b/src/Events/appsettings.Production.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.bitwarden.com", "internalApi": "https://api.bitwarden.com", "internalVault": "https://vault.bitwarden.com", - "internalSso": "https://sso.bitwarden.com" + "internalSso": "https://sso.bitwarden.com", + "internalScim": "https://scim.bitwarden.com" } }, "Logging": { diff --git a/src/Events/appsettings.QA.json b/src/Events/appsettings.QA.json index 4b49e70dc..3ad6a9cae 100644 --- a/src/Events/appsettings.QA.json +++ b/src/Events/appsettings.QA.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.qa.bitwarden.pw", "internalApi": "https://api.qa.bitwarden.pw", "internalVault": "https://vault.qa.bitwarden.pw", - "internalSso": "https://sso.qa.bitwarden.pw" + "internalSso": "https://sso.qa.bitwarden.pw", + "internalScim": "https://scim.qa.bitwarden.pw" } }, "Logging": { diff --git a/src/Events/appsettings.SelfHosted.json b/src/Events/appsettings.SelfHosted.json index 0fab07f9f..37faf24b5 100644 --- a/src/Events/appsettings.SelfHosted.json +++ b/src/Events/appsettings.SelfHosted.json @@ -12,7 +12,8 @@ "internalIdentity": null, "internalApi": null, "internalVault": null, - "internalSso": null + "internalSso": null, + "internalScim": null } } } diff --git a/src/Identity/appsettings.Production.json b/src/Identity/appsettings.Production.json index b0cfe28c4..af92ef704 100644 --- a/src/Identity/appsettings.Production.json +++ b/src/Identity/appsettings.Production.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.bitwarden.com", "internalApi": "https://api.bitwarden.com", "internalVault": "https://vault.bitwarden.com", - "internalSso": "https://sso.bitwarden.com" + "internalSso": "https://sso.bitwarden.com", + "internalScim": "https://scim.bitwarden.com" }, "braintree": { "production": true diff --git a/src/Identity/appsettings.QA.json b/src/Identity/appsettings.QA.json index b06d80a7c..4717a1310 100644 --- a/src/Identity/appsettings.QA.json +++ b/src/Identity/appsettings.QA.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.qa.bitwarden.pw", "internalApi": "https://api.qa.bitwarden.pw", "internalVault": "https://vault.qa.bitwarden.pw", - "internalSso": "https://sso.qa.bitwarden.pw" + "internalSso": "https://sso.qa.bitwarden.pw", + "internalScim": "https://scim.qa.bitwarden.pw" }, "braintree": { "production": false diff --git a/src/Identity/appsettings.SelfHosted.json b/src/Identity/appsettings.SelfHosted.json index 5efd8d651..cb31ead15 100644 --- a/src/Identity/appsettings.SelfHosted.json +++ b/src/Identity/appsettings.SelfHosted.json @@ -12,7 +12,8 @@ "internalIdentity": null, "internalApi": null, "internalVault": null, - "internalSso": null + "internalSso": null, + "internalScim": null }, "captcha": { "maximumFailedLoginAttempts": 0 diff --git a/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs b/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs index d97a6493e..259deb2e1 100644 --- a/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs +++ b/src/Infrastructure.EntityFramework/EntityFrameworkServiceCollectionExtensions.cs @@ -23,6 +23,8 @@ namespace Bit.Infrastructure.EntityFramework if (provider == SupportedDatabaseProviders.Postgres) { options.UseNpgsql(connectionString); + // Handle NpgSql Legacy Support for `timestamp without timezone` issue + AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); } else if (provider == SupportedDatabaseProviders.MySql) { diff --git a/src/Infrastructure.EntityFramework/Repositories/OrganizationRepository.cs b/src/Infrastructure.EntityFramework/Repositories/OrganizationRepository.cs index ce08935a4..b12ff65bf 100644 --- a/src/Infrastructure.EntityFramework/Repositories/OrganizationRepository.cs +++ b/src/Infrastructure.EntityFramework/Repositories/OrganizationRepository.cs @@ -83,6 +83,8 @@ namespace Bit.Infrastructure.EntityFramework.Repositories Using2fa = e.Use2fa && e.TwoFactorProviders != null, UseSso = e.UseSso, UseKeyConnector = e.UseKeyConnector, + UseResetPassword = e.UseResetPassword, + UseScim = e.UseScim, }).ToListAsync(); } } diff --git a/src/Infrastructure.EntityFramework/Repositories/Queries/OrganizationUserOrganizationDetailsViewQuery.cs b/src/Infrastructure.EntityFramework/Repositories/Queries/OrganizationUserOrganizationDetailsViewQuery.cs index 5d82ee718..f39bb6218 100644 --- a/src/Infrastructure.EntityFramework/Repositories/Queries/OrganizationUserOrganizationDetailsViewQuery.cs +++ b/src/Infrastructure.EntityFramework/Repositories/Queries/OrganizationUserOrganizationDetailsViewQuery.cs @@ -31,6 +31,7 @@ namespace Bit.Infrastructure.EntityFramework.Repositories.Queries UsePolicies = x.o.UsePolicies, UseSso = x.o.UseSso, UseKeyConnector = x.o.UseKeyConnector, + UseScim = x.o.UseScim, UseGroups = x.o.UseGroups, UseDirectory = x.o.UseDirectory, UseEvents = x.o.UseEvents, diff --git a/src/Infrastructure.EntityFramework/Repositories/Queries/ProviderUserOrganizationDetailsViewQuery.cs b/src/Infrastructure.EntityFramework/Repositories/Queries/ProviderUserOrganizationDetailsViewQuery.cs index 187426dfb..8f3e71861 100644 --- a/src/Infrastructure.EntityFramework/Repositories/Queries/ProviderUserOrganizationDetailsViewQuery.cs +++ b/src/Infrastructure.EntityFramework/Repositories/Queries/ProviderUserOrganizationDetailsViewQuery.cs @@ -20,6 +20,7 @@ namespace Bit.Infrastructure.EntityFramework.Repositories.Queries UsePolicies = x.o.UsePolicies, UseSso = x.o.UseSso, UseKeyConnector = x.o.UseKeyConnector, + UseScim = x.o.UseScim, UseGroups = x.o.UseGroups, UseDirectory = x.o.UseDirectory, UseEvents = x.o.UseEvents, diff --git a/src/Notifications/appsettings.Development.json b/src/Notifications/appsettings.Development.json index 11958effe..3a915e28a 100644 --- a/src/Notifications/appsettings.Development.json +++ b/src/Notifications/appsettings.Development.json @@ -12,7 +12,8 @@ "internalIdentity": "http://localhost:33656", "internalApi": "http://localhost:4000", "internalVault": "https://localhost:8080", - "internalSso": "http://localhost:51822" + "internalSso": "http://localhost:51822", + "internalScim": "http://localhost:44559" }, "notifications": { "connectionString": "UseDevelopmentStorage=true" diff --git a/src/Notifications/appsettings.Production.json b/src/Notifications/appsettings.Production.json index 95162be32..010f02f8c 100644 --- a/src/Notifications/appsettings.Production.json +++ b/src/Notifications/appsettings.Production.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.bitwarden.com", "internalApi": "https://api.bitwarden.com", "internalVault": "https://vault.bitwarden.com", - "internalSso": "https://sso.bitwarden.com" + "internalSso": "https://sso.bitwarden.com", + "internalScim": "https://scim.bitwarden.com" } }, "Logging": { diff --git a/src/Notifications/appsettings.QA.json b/src/Notifications/appsettings.QA.json index 4b49e70dc..3ad6a9cae 100644 --- a/src/Notifications/appsettings.QA.json +++ b/src/Notifications/appsettings.QA.json @@ -12,7 +12,8 @@ "internalIdentity": "https://identity.qa.bitwarden.pw", "internalApi": "https://api.qa.bitwarden.pw", "internalVault": "https://vault.qa.bitwarden.pw", - "internalSso": "https://sso.qa.bitwarden.pw" + "internalSso": "https://sso.qa.bitwarden.pw", + "internalScim": "https://scim.qa.bitwarden.pw" } }, "Logging": { diff --git a/src/Notifications/appsettings.SelfHosted.json b/src/Notifications/appsettings.SelfHosted.json index 0fab07f9f..37faf24b5 100644 --- a/src/Notifications/appsettings.SelfHosted.json +++ b/src/Notifications/appsettings.SelfHosted.json @@ -12,7 +12,8 @@ "internalIdentity": null, "internalApi": null, "internalVault": null, - "internalSso": null + "internalSso": null, + "internalScim": null } } } diff --git a/src/Sql/dbo/Stored Procedures/Organization_Create.sql b/src/Sql/dbo/Stored Procedures/Organization_Create.sql index 51c2eaf26..7fcd6d77d 100644 --- a/src/Sql/dbo/Stored Procedures/Organization_Create.sql +++ b/src/Sql/dbo/Stored Procedures/Organization_Create.sql @@ -40,7 +40,8 @@ @RevisionDate DATETIME2(7), @OwnersNotifiedOfAutoscaling DATETIME2(7), @MaxAutoscaleSeats INT, - @UseKeyConnector BIT = 0 + @UseKeyConnector BIT = 0, + @UseScim BIT = 0 AS BEGIN SET NOCOUNT ON @@ -88,7 +89,8 @@ BEGIN [RevisionDate], [OwnersNotifiedOfAutoscaling], [MaxAutoscaleSeats], - [UseKeyConnector] + [UseKeyConnector], + [UseScim] ) VALUES ( @@ -133,6 +135,7 @@ BEGIN @RevisionDate, @OwnersNotifiedOfAutoscaling, @MaxAutoscaleSeats, - @UseKeyConnector + @UseKeyConnector, + @UseScim ) END \ No newline at end of file diff --git a/src/Sql/dbo/Stored Procedures/Organization_ReadAbilities.sql b/src/Sql/dbo/Stored Procedures/Organization_ReadAbilities.sql index cf5219f08..26bec3895 100644 --- a/src/Sql/dbo/Stored Procedures/Organization_ReadAbilities.sql +++ b/src/Sql/dbo/Stored Procedures/Organization_ReadAbilities.sql @@ -16,6 +16,7 @@ BEGIN [UsersGetPremium], [UseSso], [UseKeyConnector], + [UseScim], [UseResetPassword], [Enabled] FROM diff --git a/src/Sql/dbo/Stored Procedures/Organization_Update.sql b/src/Sql/dbo/Stored Procedures/Organization_Update.sql index 2339518af..e86ed75c0 100644 --- a/src/Sql/dbo/Stored Procedures/Organization_Update.sql +++ b/src/Sql/dbo/Stored Procedures/Organization_Update.sql @@ -40,7 +40,8 @@ @RevisionDate DATETIME2(7), @OwnersNotifiedOfAutoscaling DATETIME2(7), @MaxAutoscaleSeats INT, - @UseKeyConnector BIT = 0 + @UseKeyConnector BIT = 0, + @UseScim BIT = 0 AS BEGIN SET NOCOUNT ON @@ -88,7 +89,8 @@ BEGIN [RevisionDate] = @RevisionDate, [OwnersNotifiedOfAutoscaling] = @OwnersNotifiedOfAutoscaling, [MaxAutoscaleSeats] = @MaxAutoscaleSeats, - [UseKeyConnector] = @UseKeyConnector + [UseKeyConnector] = @UseKeyConnector, + [UseScim] = @UseScim WHERE [Id] = @Id END diff --git a/src/Sql/dbo/Tables/Organization.sql b/src/Sql/dbo/Tables/Organization.sql index 3985c85d6..c30045738 100644 --- a/src/Sql/dbo/Tables/Organization.sql +++ b/src/Sql/dbo/Tables/Organization.sql @@ -41,6 +41,7 @@ [OwnersNotifiedOfAutoscaling] DATETIME2(7) NULL, [MaxAutoscaleSeats] INT NULL, [UseKeyConnector] BIT NOT NULL, + [UseScim] BIT NOT NULL CONSTRAINT [DF_Organization_UseScim] DEFAULT (0), CONSTRAINT [PK_Organization] PRIMARY KEY CLUSTERED ([Id] ASC) ); diff --git a/src/Sql/dbo/Views/OrganizationUserOrganizationDetailsView.sql b/src/Sql/dbo/Views/OrganizationUserOrganizationDetailsView.sql index 288ae8612..b990a4569 100644 --- a/src/Sql/dbo/Views/OrganizationUserOrganizationDetailsView.sql +++ b/src/Sql/dbo/Views/OrganizationUserOrganizationDetailsView.sql @@ -8,6 +8,7 @@ SELECT O.[UsePolicies], O.[UseSso], O.[UseKeyConnector], + O.[UseScim], O.[UseGroups], O.[UseDirectory], O.[UseEvents], diff --git a/src/Sql/dbo/Views/ProviderUserProviderOrganizationDetailsView.sql b/src/Sql/dbo/Views/ProviderUserProviderOrganizationDetailsView.sql index 27daa4800..1217ee122 100644 --- a/src/Sql/dbo/Views/ProviderUserProviderOrganizationDetailsView.sql +++ b/src/Sql/dbo/Views/ProviderUserProviderOrganizationDetailsView.sql @@ -8,6 +8,7 @@ SELECT O.[UsePolicies], O.[UseSso], O.[UseKeyConnector], + O.[UseScim], O.[UseGroups], O.[UseDirectory], O.[UseEvents], diff --git a/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs b/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs index b3743f9fd..c4c413670 100644 --- a/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs +++ b/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs @@ -50,11 +50,15 @@ namespace Bit.Api.Test.Controllers [Theory] [BitAutoData] - public async Task CreateConnection_RequiresOwnerPermissions(SutProvider sutProvider) + public async Task CreateConnection_CloudBillingSync_RequiresOwnerPermissions(SutProvider sutProvider) { - var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.CreateConnection(null)); + var model = new OrganizationConnectionRequestModel + { + Type = OrganizationConnectionType.CloudBillingSync, + }; + var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.CreateConnection(model)); - Assert.Contains("Only the owner of an organization can create a connection.", exception.Message); + Assert.Contains($"You do not have permission to create a connection of type", exception.Message); } [Theory] @@ -116,6 +120,7 @@ namespace Bit.Api.Test.Controllers var typedModel = new OrganizationConnectionRequestModel(model); typedModel.ParsedConfig.CloudOrganizationId = cloudOrgId; + sutProvider.GetDependency().SelfHosted.Returns(true); sutProvider.GetDependency().CreateAsync(default) .ReturnsForAnyArgs(typedModel.ToData(Guid.NewGuid()).ToEntity()); sutProvider.GetDependency().OrganizationOwner(model.OrganizationId).Returns(true); @@ -143,17 +148,40 @@ namespace Bit.Api.Test.Controllers var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateConnection(default, null)); - Assert.Contains("Only the owner of an organization can update a connection.", exception.Message); + Assert.Contains("You do not have permission to update this connection.", exception.Message); } [Theory] - [BitMemberAutoData(nameof(ConnectionTypes))] - public async Task UpdateConnection_OnlyOneConnectionOfEachType(OrganizationConnectionType type, + [BitAutoData(OrganizationConnectionType.CloudBillingSync)] + public async Task UpdateConnection_BillingSync_OnlyOneConnectionOfEachType(OrganizationConnectionType type, OrganizationConnection existing1, OrganizationConnection existing2, BillingSyncConfig config, SutProvider sutProvider) { + existing1.Type = existing2.Type = type; existing1.Config = JsonSerializer.Serialize(config); - var typedModel = RequestModelFromEntity(existing1); + var typedModel = RequestModelFromEntity(existing1); + + sutProvider.GetDependency().OrganizationOwner(typedModel.OrganizationId).Returns(true); + + var orgConnectionRepository = sutProvider.GetDependency(); + orgConnectionRepository.GetByIdAsync(existing1.Id).Returns(existing1); + orgConnectionRepository.GetByIdAsync(existing2.Id).Returns(existing2); + orgConnectionRepository.GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type).Returns(new[] { existing1, existing2 }); + + var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateConnection(existing1.Id, typedModel)); + + Assert.Contains($"The requested organization already has a connection of type {typedModel.Type}. Only one of each connection type may exist per organization.", exception.Message); + } + + [Theory] + [BitAutoData(OrganizationConnectionType.Scim)] + public async Task UpdateConnection_Scim_OnlyOneConnectionOfEachType(OrganizationConnectionType type, + OrganizationConnection existing1, OrganizationConnection existing2, ScimConfig config, + SutProvider sutProvider) + { + existing1.Type = existing2.Type = type; + existing1.Config = JsonSerializer.Serialize(config); + var typedModel = RequestModelFromEntity(existing1); sutProvider.GetDependency().OrganizationOwner(typedModel.OrganizationId).Returns(true); @@ -161,7 +189,11 @@ namespace Bit.Api.Test.Controllers .GetByIdAsync(existing1.Id) .Returns(existing1); - sutProvider.GetDependency().GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type).Returns(new[] { existing1, existing2 }); + sutProvider.GetDependency().ManageScim(typedModel.OrganizationId).Returns(true); + + sutProvider.GetDependency() + .GetByOrganizationIdTypeAsync(typedModel.OrganizationId, type) + .Returns(new[] { existing1, existing2 }); var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateConnection(existing1.Id, typedModel)); @@ -180,11 +212,16 @@ namespace Bit.Api.Test.Controllers }); updated.Config = JsonSerializer.Serialize(config); updated.Id = existing.Id; - var model = RequestModelFromEntity(updated); + updated.Type = OrganizationConnectionType.CloudBillingSync; + var model = RequestModelFromEntity(updated); sutProvider.GetDependency().OrganizationOwner(model.OrganizationId).Returns(true); - sutProvider.GetDependency().GetByOrganizationIdTypeAsync(model.OrganizationId, model.Type).Returns(new[] { existing }); - sutProvider.GetDependency().UpdateAsync(default).ReturnsForAnyArgs(updated); + sutProvider.GetDependency() + .GetByOrganizationIdTypeAsync(model.OrganizationId, model.Type) + .Returns(new[] { existing }); + sutProvider.GetDependency() + .UpdateAsync(default) + .ReturnsForAnyArgs(updated); sutProvider.GetDependency() .GetByIdAsync(existing.Id) .Returns(existing); @@ -211,7 +248,7 @@ namespace Bit.Api.Test.Controllers var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.GetConnection(connectionId, OrganizationConnectionType.CloudBillingSync)); - Assert.Contains("Only the owner of an organization can retrieve a connection.", exception.Message); + Assert.Contains("You do not have permission to retrieve a connection of type", exception.Message); } [Theory] @@ -221,7 +258,10 @@ namespace Bit.Api.Test.Controllers { connection.Config = JsonSerializer.Serialize(config); - sutProvider.GetDependency().GetByOrganizationIdTypeAsync(connection.OrganizationId, connection.Type).Returns(new[] { connection }); + sutProvider.GetDependency().SelfHosted.Returns(true); + sutProvider.GetDependency() + .GetByOrganizationIdTypeAsync(connection.OrganizationId, connection.Type) + .Returns(new[] { connection }); sutProvider.GetDependency().OrganizationOwner(connection.OrganizationId).Returns(true); var expected = new OrganizationConnectionResponseModel(connection, typeof(BillingSyncConfig)); @@ -247,7 +287,7 @@ namespace Bit.Api.Test.Controllers var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.DeleteConnection(connection.Id)); - Assert.Contains("Only the owner of an organization can remove a connection.", exception.Message); + Assert.Contains("You do not have permission to remove this connection of type", exception.Message); } [Theory] @@ -263,7 +303,8 @@ namespace Bit.Api.Test.Controllers await sutProvider.GetDependency().DeleteAsync(connection); } - private static OrganizationConnectionRequestModel RequestModelFromEntity(OrganizationConnection entity) + private static OrganizationConnectionRequestModel RequestModelFromEntity(OrganizationConnection entity) + where T : new() { return new(new OrganizationConnectionRequestModel() { diff --git a/test/Core.Test/Helpers/Factories.cs b/test/Core.Test/Helpers/Factories.cs index 8db0e8135..48bf06b77 100644 --- a/test/Core.Test/Helpers/Factories.cs +++ b/test/Core.Test/Helpers/Factories.cs @@ -13,6 +13,7 @@ namespace Bit.Core.Test.Helpers.Factories var globalSettings = GlobalSettingsFactory.GlobalSettings; if (!string.IsNullOrWhiteSpace(GlobalSettingsFactory.GlobalSettings.PostgreSql?.ConnectionString)) { + AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); Options.Add(new DbContextOptionsBuilder().UseNpgsql(globalSettings.PostgreSql.ConnectionString).Options); } if (!string.IsNullOrWhiteSpace(GlobalSettingsFactory.GlobalSettings.MySql?.ConnectionString)) diff --git a/test/Core.Test/Models/PermissionsTests.cs b/test/Core.Test/Models/PermissionsTests.cs index a45a23972..c8522eaa2 100644 --- a/test/Core.Test/Models/PermissionsTests.cs +++ b/test/Core.Test/Models/PermissionsTests.cs @@ -23,7 +23,8 @@ namespace Bit.Core.Test.Models "\"managePolicies\": false,", "\"manageSso\": false,", "\"manageUsers\": false,", - "\"manageResetPassword\": false", + "\"manageResetPassword\": false,", + "\"manageScim\": false", "}"); [Fact] @@ -44,6 +45,7 @@ namespace Bit.Core.Test.Models ManageSso = false, ManageUsers = false, ManageResetPassword = false, + ManageScim = false, }; // minify expected json diff --git a/test/Core.Test/Repositories/EntityFramework/EqualityComparers/OrganizationCompare.cs b/test/Core.Test/Repositories/EntityFramework/EqualityComparers/OrganizationCompare.cs index 7383e43e3..ca7ef7318 100644 --- a/test/Core.Test/Repositories/EntityFramework/EqualityComparers/OrganizationCompare.cs +++ b/test/Core.Test/Repositories/EntityFramework/EqualityComparers/OrganizationCompare.cs @@ -25,6 +25,7 @@ namespace Bit.Core.Test.Repositories.EntityFramework.EqualityComparers x.UsePolicies.Equals(y.UsePolicies) && x.UseSso.Equals(y.UseSso) && x.UseKeyConnector.Equals(y.UseKeyConnector) && + x.UseScim.Equals(y.UseScim) && x.UseGroups.Equals(y.UseGroups) && x.UseDirectory.Equals(y.UseDirectory) && x.UseEvents.Equals(y.UseEvents) && diff --git a/test/Identity.IntegrationTest/Endpoints/IdentityServerTests.cs b/test/Identity.IntegrationTest/Endpoints/IdentityServerTests.cs index a62413bac..1d7d0dd8d 100644 --- a/test/Identity.IntegrationTest/Endpoints/IdentityServerTests.cs +++ b/test/Identity.IntegrationTest/Endpoints/IdentityServerTests.cs @@ -237,6 +237,8 @@ namespace Bit.Identity.IntegrationTest.Endpoints public async Task TokenEndpoint_GrantTypeClientCredentials_AsOrganization_Success(Organization organization, OrganizationApiKey organizationApiKey) { var orgRepo = _factory.Services.GetRequiredService(); + organization.Enabled = true; + organization.UseApi = true; organization = await orgRepo.CreateAsync(organization); organizationApiKey.OrganizationId = organization.Id; organizationApiKey.Type = OrganizationApiKeyType.Default; diff --git a/util/Migrator/DbScripts/2022-06-24_00_UseScimFlag.sql b/util/Migrator/DbScripts/2022-06-24_00_UseScimFlag.sql new file mode 100644 index 000000000..7f3ea5ab4 --- /dev/null +++ b/util/Migrator/DbScripts/2022-06-24_00_UseScimFlag.sql @@ -0,0 +1,373 @@ +IF COL_LENGTH('[dbo].[Organization]', 'UseScim') IS NULL + BEGIN + ALTER TABLE + [dbo].[Organization] + ADD + [UseScim] BIT NOT NULL CONSTRAINT [DF_Organization_UseScim] DEFAULT (0); + END +GO + +CREATE OR ALTER VIEW [dbo].[OrganizationUserOrganizationDetailsView] +AS +SELECT + OU.[UserId], + OU.[OrganizationId], + O.[Name], + O.[Enabled], + O.[UsePolicies], + O.[UseSso], + O.[UseKeyConnector], + O.[UseScim], + O.[UseGroups], + O.[UseDirectory], + O.[UseEvents], + O.[UseTotp], + O.[Use2fa], + O.[UseApi], + O.[UseResetPassword], + O.[SelfHost], + O.[UsersGetPremium], + O.[Seats], + O.[MaxCollections], + O.[MaxStorageGb], + O.[Identifier], + OU.[Key], + OU.[ResetPasswordKey], + O.[PublicKey], + O.[PrivateKey], + OU.[Status], + OU.[Type], + SU.[ExternalId] SsoExternalId, + OU.[Permissions], + PO.[ProviderId], + P.[Name] ProviderName, + SS.[Data] SsoConfig +FROM + [dbo].[OrganizationUser] OU +INNER JOIN + [dbo].[Organization] O ON O.[Id] = OU.[OrganizationId] +LEFT JOIN + [dbo].[SsoUser] SU ON SU.[UserId] = OU.[UserId] AND SU.[OrganizationId] = OU.[OrganizationId] +LEFT JOIN + [dbo].[ProviderOrganization] PO ON PO.[OrganizationId] = O.[Id] +LEFT JOIN + [dbo].[Provider] P ON P.[Id] = PO.[ProviderId] +LEFT JOIN + [dbo].[SsoConfig] SS ON SS.[OrganizationId] = OU.[OrganizationId] +GO + +CREATE OR ALTER VIEW [dbo].[ProviderUserProviderOrganizationDetailsView] +AS +SELECT + PU.[UserId], + PO.[OrganizationId], + O.[Name], + O.[Enabled], + O.[UsePolicies], + O.[UseSso], + O.[UseKeyConnector], + O.[UseScim], + O.[UseGroups], + O.[UseDirectory], + O.[UseEvents], + O.[UseTotp], + O.[Use2fa], + O.[UseApi], + O.[UseResetPassword], + O.[SelfHost], + O.[UsersGetPremium], + O.[Seats], + O.[MaxCollections], + O.[MaxStorageGb], + O.[Identifier], + PO.[Key], + O.[PublicKey], + O.[PrivateKey], + PU.[Status], + PU.[Type], + PO.[ProviderId], + PU.[Id] ProviderUserId, + P.[Name] ProviderName +FROM + [dbo].[ProviderUser] PU +INNER JOIN + [dbo].[ProviderOrganization] PO ON PO.[ProviderId] = PU.[ProviderId] +INNER JOIN + [dbo].[Organization] O ON O.[Id] = PO.[OrganizationId] +INNER JOIN + [dbo].[Provider] P ON P.[Id] = PU.[ProviderId] +GO + +CREATE OR ALTER PROCEDURE [dbo].[Organization_Create] + @Id UNIQUEIDENTIFIER OUTPUT, + @Identifier NVARCHAR(50), + @Name NVARCHAR(50), + @BusinessName NVARCHAR(50), + @BusinessAddress1 NVARCHAR(50), + @BusinessAddress2 NVARCHAR(50), + @BusinessAddress3 NVARCHAR(50), + @BusinessCountry VARCHAR(2), + @BusinessTaxNumber NVARCHAR(30), + @BillingEmail NVARCHAR(256), + @Plan NVARCHAR(50), + @PlanType TINYINT, + @Seats INT, + @MaxCollections SMALLINT, + @UsePolicies BIT, + @UseSso BIT, + @UseGroups BIT, + @UseDirectory BIT, + @UseEvents BIT, + @UseTotp BIT, + @Use2fa BIT, + @UseApi BIT, + @UseResetPassword BIT, + @SelfHost BIT, + @UsersGetPremium BIT, + @Storage BIGINT, + @MaxStorageGb SMALLINT, + @Gateway TINYINT, + @GatewayCustomerId VARCHAR(50), + @GatewaySubscriptionId VARCHAR(50), + @ReferenceData VARCHAR(MAX), + @Enabled BIT, + @LicenseKey VARCHAR(100), + @PublicKey VARCHAR(MAX), + @PrivateKey VARCHAR(MAX), + @TwoFactorProviders NVARCHAR(MAX), + @ExpirationDate DATETIME2(7), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @OwnersNotifiedOfAutoscaling DATETIME2(7), + @MaxAutoscaleSeats INT, + @UseKeyConnector BIT = 0, + @UseScim BIT = 0 +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[Organization] + ( + [Id], + [Identifier], + [Name], + [BusinessName], + [BusinessAddress1], + [BusinessAddress2], + [BusinessAddress3], + [BusinessCountry], + [BusinessTaxNumber], + [BillingEmail], + [Plan], + [PlanType], + [Seats], + [MaxCollections], + [UsePolicies], + [UseSso], + [UseGroups], + [UseDirectory], + [UseEvents], + [UseTotp], + [Use2fa], + [UseApi], + [UseResetPassword], + [SelfHost], + [UsersGetPremium], + [Storage], + [MaxStorageGb], + [Gateway], + [GatewayCustomerId], + [GatewaySubscriptionId], + [ReferenceData], + [Enabled], + [LicenseKey], + [PublicKey], + [PrivateKey], + [TwoFactorProviders], + [ExpirationDate], + [CreationDate], + [RevisionDate], + [OwnersNotifiedOfAutoscaling], + [MaxAutoscaleSeats], + [UseKeyConnector], + [UseScim] + ) + VALUES + ( + @Id, + @Identifier, + @Name, + @BusinessName, + @BusinessAddress1, + @BusinessAddress2, + @BusinessAddress3, + @BusinessCountry, + @BusinessTaxNumber, + @BillingEmail, + @Plan, + @PlanType, + @Seats, + @MaxCollections, + @UsePolicies, + @UseSso, + @UseGroups, + @UseDirectory, + @UseEvents, + @UseTotp, + @Use2fa, + @UseApi, + @UseResetPassword, + @SelfHost, + @UsersGetPremium, + @Storage, + @MaxStorageGb, + @Gateway, + @GatewayCustomerId, + @GatewaySubscriptionId, + @ReferenceData, + @Enabled, + @LicenseKey, + @PublicKey, + @PrivateKey, + @TwoFactorProviders, + @ExpirationDate, + @CreationDate, + @RevisionDate, + @OwnersNotifiedOfAutoscaling, + @MaxAutoscaleSeats, + @UseKeyConnector, + @UseScim + ) +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[Organization_Update] + @Id UNIQUEIDENTIFIER, + @Identifier NVARCHAR(50), + @Name NVARCHAR(50), + @BusinessName NVARCHAR(50), + @BusinessAddress1 NVARCHAR(50), + @BusinessAddress2 NVARCHAR(50), + @BusinessAddress3 NVARCHAR(50), + @BusinessCountry VARCHAR(2), + @BusinessTaxNumber NVARCHAR(30), + @BillingEmail NVARCHAR(256), + @Plan NVARCHAR(50), + @PlanType TINYINT, + @Seats INT, + @MaxCollections SMALLINT, + @UsePolicies BIT, + @UseSso BIT, + @UseGroups BIT, + @UseDirectory BIT, + @UseEvents BIT, + @UseTotp BIT, + @Use2fa BIT, + @UseApi BIT, + @UseResetPassword BIT, + @SelfHost BIT, + @UsersGetPremium BIT, + @Storage BIGINT, + @MaxStorageGb SMALLINT, + @Gateway TINYINT, + @GatewayCustomerId VARCHAR(50), + @GatewaySubscriptionId VARCHAR(50), + @ReferenceData VARCHAR(MAX), + @Enabled BIT, + @LicenseKey VARCHAR(100), + @PublicKey VARCHAR(MAX), + @PrivateKey VARCHAR(MAX), + @TwoFactorProviders NVARCHAR(MAX), + @ExpirationDate DATETIME2(7), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @OwnersNotifiedOfAutoscaling DATETIME2(7), + @MaxAutoscaleSeats INT, + @UseKeyConnector BIT = 0, + @UseScim BIT = 0 +AS +BEGIN + SET NOCOUNT ON + + UPDATE + [dbo].[Organization] + SET + [Identifier] = @Identifier, + [Name] = @Name, + [BusinessName] = @BusinessName, + [BusinessAddress1] = @BusinessAddress1, + [BusinessAddress2] = @BusinessAddress2, + [BusinessAddress3] = @BusinessAddress3, + [BusinessCountry] = @BusinessCountry, + [BusinessTaxNumber] = @BusinessTaxNumber, + [BillingEmail] = @BillingEmail, + [Plan] = @Plan, + [PlanType] = @PlanType, + [Seats] = @Seats, + [MaxCollections] = @MaxCollections, + [UsePolicies] = @UsePolicies, + [UseSso] = @UseSso, + [UseGroups] = @UseGroups, + [UseDirectory] = @UseDirectory, + [UseEvents] = @UseEvents, + [UseTotp] = @UseTotp, + [Use2fa] = @Use2fa, + [UseApi] = @UseApi, + [UseResetPassword] = @UseResetPassword, + [SelfHost] = @SelfHost, + [UsersGetPremium] = @UsersGetPremium, + [Storage] = @Storage, + [MaxStorageGb] = @MaxStorageGb, + [Gateway] = @Gateway, + [GatewayCustomerId] = @GatewayCustomerId, + [GatewaySubscriptionId] = @GatewaySubscriptionId, + [ReferenceData] = @ReferenceData, + [Enabled] = @Enabled, + [LicenseKey] = @LicenseKey, + [PublicKey] = @PublicKey, + [PrivateKey] = @PrivateKey, + [TwoFactorProviders] = @TwoFactorProviders, + [ExpirationDate] = @ExpirationDate, + [CreationDate] = @CreationDate, + [RevisionDate] = @RevisionDate, + [OwnersNotifiedOfAutoscaling] = @OwnersNotifiedOfAutoscaling, + [MaxAutoscaleSeats] = @MaxAutoscaleSeats, + [UseKeyConnector] = @UseKeyConnector, + [UseScim] = @UseScim + WHERE + [Id] = @Id +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[Organization_ReadAbilities] +AS +BEGIN + SET NOCOUNT ON + + SELECT + [Id], + [UseEvents], + [Use2fa], + CASE + WHEN [Use2fa] = 1 AND [TwoFactorProviders] IS NOT NULL AND [TwoFactorProviders] != '{}' THEN + 1 + ELSE + 0 + END AS [Using2fa], + [UsersGetPremium], + [UseSso], + [UseKeyConnector], + [UseScim], + [UseResetPassword], + [Enabled] + FROM + [dbo].[Organization] +END +GO + +-- Enable Existing Enterprise Customers to use SCIM +UPDATE [dbo].[Organization] +SET [UseScim] = 1 +WHERE [PlanType] IN (10, 11) -- New Enterprise Annual/Monthly (not 2019) + AND [UseScim] = 0; +GO diff --git a/util/MySqlMigrations/Migrations/20220707163017_UseScimFlag.Designer.cs b/util/MySqlMigrations/Migrations/20220707163017_UseScimFlag.Designer.cs new file mode 100644 index 000000000..423082836 --- /dev/null +++ b/util/MySqlMigrations/Migrations/20220707163017_UseScimFlag.Designer.cs @@ -0,0 +1,1596 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20220707163017_UseScimFlag")] + partial class UseScimFlag + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Attachments") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Favorites") + .HasColumnType("longtext"); + + b.Property("Folders") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Reprompt") + .HasColumnType("tinyint unsigned"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("HidePasswords") + .HasColumnType("tinyint(1)"); + + b.Property("ReadOnly") + .HasColumnType("tinyint(1)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("GranteeId") + .HasColumnType("char(36)"); + + b.Property("GrantorId") + .HasColumnType("char(36)"); + + b.Property("KeyEncrypted") + .HasColumnType("longtext"); + + b.Property("LastNotificationDate") + .HasColumnType("datetime(6)"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("WaitTimeDays") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ActingUserId") + .HasColumnType("char(36)"); + + b.Property("CipherId") + .HasColumnType("char(36)"); + + b.Property("CollectionId") + .HasColumnType("char(36)"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("DeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("InstallationId") + .HasColumnType("char(36)"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("PolicyId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("ProviderOrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderUserId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ConsumedDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("int"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("datetime(6)"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PlanType") + .HasColumnType("tinyint unsigned"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Seats") + .HasColumnType("int"); + + b.Property("SelfHost") + .HasColumnType("tinyint(1)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("Use2fa") + .HasColumnType("tinyint(1)"); + + b.Property("UseApi") + .HasColumnType("tinyint(1)"); + + b.Property("UseDirectory") + .HasColumnType("tinyint(1)"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.Property("UseGroups") + .HasColumnType("tinyint(1)"); + + b.Property("UseKeyConnector") + .HasColumnType("tinyint(1)"); + + b.Property("UsePolicies") + .HasColumnType("tinyint(1)"); + + b.Property("UseResetPassword") + .HasColumnType("tinyint(1)"); + + b.Property("UseScim") + .HasColumnType("tinyint(1)"); + + b.Property("UseSso") + .HasColumnType("tinyint(1)"); + + b.Property("UseTotp") + .HasColumnType("tinyint(1)"); + + b.Property("UsersGetPremium") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Config") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("LastSyncDate") + .HasColumnType("datetime(6)"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("tinyint unsigned"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("ToDelete") + .HasColumnType("tinyint(1)"); + + b.Property("ValidUntil") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ResetPasswordKey") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .HasColumnType("longtext"); + + b.Property("BusinessAddress1") + .HasColumnType("longtext"); + + b.Property("BusinessAddress2") + .HasColumnType("longtext"); + + b.Property("BusinessAddress3") + .HasColumnType("longtext"); + + b.Property("BusinessCountry") + .HasColumnType("longtext"); + + b.Property("BusinessName") + .HasColumnType("longtext"); + + b.Property("BusinessTaxNumber") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("UseEvents") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Settings") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasColumnType("longtext"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ProviderId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCount") + .HasColumnType("int"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletionDate") + .HasColumnType("datetime(6)"); + + b.Property("Disabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("HideEmail") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MaxAccessCount") + .HasColumnType("int"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("Active") + .HasColumnType("tinyint(1)"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Rate") + .HasColumnType("decimal(65,30)"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("PaymentMethodType") + .HasColumnType("tinyint unsigned"); + + b.Property("Refunded") + .HasColumnType("tinyint(1)"); + + b.Property("RefundedAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccountRevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailVerified") + .HasColumnType("tinyint(1)"); + + b.Property("EquivalentDomains") + .HasColumnType("longtext"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("longtext"); + + b.Property("FailedLoginCount") + .HasColumnType("int"); + + b.Property("ForcePasswordReset") + .HasColumnType("tinyint(1)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Kdf") + .HasColumnType("tinyint unsigned"); + + b.Property("KdfIterations") + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("LastFailedLoginDate") + .HasColumnType("datetime(6)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Premium") + .HasColumnType("tinyint(1)"); + + b.Property("PremiumExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RenewalReminderDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("varchar(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UsesKeyConnector") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/MySqlMigrations/Migrations/20220707163017_UseScimFlag.cs b/util/MySqlMigrations/Migrations/20220707163017_UseScimFlag.cs new file mode 100644 index 000000000..4c2998612 --- /dev/null +++ b/util/MySqlMigrations/Migrations/20220707163017_UseScimFlag.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations +{ + public partial class UseScimFlag : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UseScim", + table: "Organization", + type: "tinyint(1)", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "UseScim", + table: "Organization"); + } + } +} diff --git a/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs b/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs index 491d8edb9..471b285a4 100644 --- a/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs +++ b/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs @@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +#nullable disable + namespace Bit.MySqlMigrations.Migrations { [DbContext(typeof(DatabaseContext))] @@ -14,8 +16,8 @@ namespace Bit.MySqlMigrations.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("Relational:MaxIdentifierLength", 64) - .HasAnnotation("ProductVersion", "5.0.12"); + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => { @@ -61,7 +63,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Cipher"); + b.ToTable("Cipher", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => @@ -89,7 +91,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("Collection"); + b.ToTable("Collection", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => @@ -104,7 +106,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("CipherId"); - b.ToTable("CollectionCipher"); + b.ToTable("CollectionCipher", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => @@ -188,7 +190,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Device"); + b.ToTable("Device", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => @@ -236,7 +238,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("GrantorId"); - b.ToTable("EmergencyAccess"); + b.ToTable("EmergencyAccess", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => @@ -295,7 +297,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasKey("Id"); - b.ToTable("Event"); + b.ToTable("Event", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => @@ -319,7 +321,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Folder"); + b.ToTable("Folder", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => @@ -362,7 +364,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasKey("Key"); - b.ToTable("Grant"); + b.ToTable("Grant", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => @@ -394,7 +396,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("Group"); + b.ToTable("Group", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => @@ -414,7 +416,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("GroupUser"); + b.ToTable("GroupUser", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => @@ -438,7 +440,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasKey("Id"); - b.ToTable("Installation"); + b.ToTable("Installation", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => @@ -573,6 +575,9 @@ namespace Bit.MySqlMigrations.Migrations b.Property("UseResetPassword") .HasColumnType("tinyint(1)"); + b.Property("UseScim") + .HasColumnType("tinyint(1)"); + b.Property("UseSso") .HasColumnType("tinyint(1)"); @@ -584,7 +589,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasKey("Id"); - b.ToTable("Organization"); + b.ToTable("Organization", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => @@ -609,7 +614,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("OrganizationApiKey"); + b.ToTable("OrganizationApiKey", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => @@ -633,7 +638,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("OrganizationConnection"); + b.ToTable("OrganizationConnection", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => @@ -676,7 +681,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("SponsoringOrganizationId"); - b.ToTable("OrganizationSponsorship"); + b.ToTable("OrganizationSponsorship", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => @@ -728,7 +733,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("OrganizationUser"); + b.ToTable("OrganizationUser", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => @@ -758,7 +763,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("Policy"); + b.ToTable("Policy", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => @@ -807,7 +812,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasKey("Id"); - b.ToTable("Provider"); + b.ToTable("Provider", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => @@ -839,7 +844,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("ProviderId"); - b.ToTable("ProviderOrganization"); + b.ToTable("ProviderOrganization", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => @@ -880,7 +885,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("ProviderUser"); + b.ToTable("ProviderUser", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => @@ -937,7 +942,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Send"); + b.ToTable("Send", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => @@ -965,7 +970,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("SsoConfig"); + b.ToTable("SsoConfig", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => @@ -993,7 +998,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("SsoUser"); + b.ToTable("SsoUser", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => @@ -1022,7 +1027,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasKey("Id"); - b.ToTable("TaxRate"); + b.ToTable("TaxRate", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => @@ -1071,7 +1076,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Transaction"); + b.ToTable("Transaction", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => @@ -1200,7 +1205,7 @@ namespace Bit.MySqlMigrations.Migrations b.HasKey("Id"); - b.ToTable("User"); + b.ToTable("User", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => diff --git a/util/MySqlMigrations/Scripts/2022-07-07_00_UseScimFlag.sql b/util/MySqlMigrations/Scripts/2022-07-07_00_UseScimFlag.sql new file mode 100644 index 000000000..5499952df --- /dev/null +++ b/util/MySqlMigrations/Scripts/2022-07-07_00_UseScimFlag.sql @@ -0,0 +1,17 @@ +START TRANSACTION; + +ALTER TABLE `OrganizationUser` MODIFY COLUMN `Status` smallint NOT NULL; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20220608191914_DeactivatedUserStatus', '6.0.4'); + +COMMIT; + +START TRANSACTION; + +ALTER TABLE `Organization` ADD `UseScim` tinyint(1) NOT NULL DEFAULT FALSE; + +INSERT INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) +VALUES ('20220707163017_UseScimFlag', '6.0.4'); + +COMMIT; \ No newline at end of file diff --git a/util/PostgresMigrations/Migrations/20220707162231_UseScimFlag.Designer.cs b/util/PostgresMigrations/Migrations/20220707162231_UseScimFlag.Designer.cs new file mode 100644 index 000000000..68feb2cd7 --- /dev/null +++ b/util/PostgresMigrations/Migrations/20220707162231_UseScimFlag.Designer.cs @@ -0,0 +1,1607 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20220707162231_UseScimFlag")] + partial class UseScimFlag + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:postgresIndetermanisticCollation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Attachments") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletedDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Favorites") + .HasColumnType("text"); + + b.Property("Folders") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Reprompt") + .HasColumnType("smallint"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GranteeId") + .HasColumnType("uuid"); + + b.Property("GrantorId") + .HasColumnType("uuid"); + + b.Property("KeyEncrypted") + .HasColumnType("text"); + + b.Property("LastNotificationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("WaitTimeDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActingUserId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("Date") + .HasColumnType("timestamp without time zone"); + + b.Property("DeviceType") + .HasColumnType("smallint"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("InstallationId") + .HasColumnType("uuid"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("PolicyId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("ProviderOrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderUserId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedDate") + .HasColumnType("timestamp without time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.HasIndex("UserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("integer"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("timestamp without time zone"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PlanType") + .HasColumnType("smallint"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Seats") + .HasColumnType("integer"); + + b.Property("SelfHost") + .HasColumnType("boolean"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("Use2fa") + .HasColumnType("boolean"); + + b.Property("UseApi") + .HasColumnType("boolean"); + + b.Property("UseDirectory") + .HasColumnType("boolean"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.Property("UseGroups") + .HasColumnType("boolean"); + + b.Property("UseKeyConnector") + .HasColumnType("boolean"); + + b.Property("UsePolicies") + .HasColumnType("boolean"); + + b.Property("UseResetPassword") + .HasColumnType("boolean"); + + b.Property("UseScim") + .HasColumnType("boolean"); + + b.Property("UseSso") + .HasColumnType("boolean"); + + b.Property("UseTotp") + .HasColumnType("boolean"); + + b.Property("UsersGetPremium") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Config") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastSyncDate") + .HasColumnType("timestamp without time zone"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("smallint"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("uuid"); + + b.Property("ToDelete") + .HasColumnType("boolean"); + + b.Property("ValidUntil") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ResetPasswordKey") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasColumnType("text"); + + b.Property("BusinessAddress1") + .HasColumnType("text"); + + b.Property("BusinessAddress2") + .HasColumnType("text"); + + b.Property("BusinessAddress3") + .HasColumnType("text"); + + b.Property("BusinessCountry") + .HasColumnType("text"); + + b.Property("BusinessName") + .HasColumnType("text"); + + b.Property("BusinessTaxNumber") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCount") + .HasColumnType("integer"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Disabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("HideEmail") + .HasColumnType("boolean"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MaxAccessCount") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("PaymentMethodType") + .HasColumnType("smallint"); + + b.Property("Refunded") + .HasColumnType("boolean"); + + b.Property("RefundedAmount") + .HasColumnType("numeric"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountRevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("EmailVerified") + .HasColumnType("boolean"); + + b.Property("EquivalentDomains") + .HasColumnType("text"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("text"); + + b.Property("FailedLoginCount") + .HasColumnType("integer"); + + b.Property("ForcePasswordReset") + .HasColumnType("boolean"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Kdf") + .HasColumnType("smallint"); + + b.Property("KdfIterations") + .HasColumnType("integer"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("LastFailedLoginDate") + .HasColumnType("timestamp without time zone"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Premium") + .HasColumnType("boolean"); + + b.Property("PremiumExpirationDate") + .HasColumnType("timestamp without time zone"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RenewalReminderDate") + .HasColumnType("timestamp without time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp without time zone"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("boolean"); + + b.Property("UsesKeyConnector") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("CollectionUsers") + .HasForeignKey("UserId"); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", null) + .WithMany("GroupUsers") + .HasForeignKey("UserId"); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("CollectionUsers"); + + b.Navigation("Folders"); + + b.Navigation("GroupUsers"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/PostgresMigrations/Migrations/20220707162231_UseScimFlag.cs b/util/PostgresMigrations/Migrations/20220707162231_UseScimFlag.cs new file mode 100644 index 000000000..6a71e38fb --- /dev/null +++ b/util/PostgresMigrations/Migrations/20220707162231_UseScimFlag.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations +{ + public partial class UseScimFlag : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UseScim", + table: "Organization", + type: "boolean", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "UseScim", + table: "Organization"); + } + } +} diff --git a/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs b/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs index 818dcffd5..cdef656ac 100644 --- a/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs +++ b/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs @@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +#nullable disable + namespace Bit.PostgresMigrations.Migrations { [DbContext(typeof(DatabaseContext))] @@ -16,9 +18,10 @@ namespace Bit.PostgresMigrations.Migrations #pragma warning disable 612, 618 modelBuilder .HasAnnotation("Npgsql:CollationDefinition:postgresIndetermanisticCollation", "en-u-ks-primary,en-u-ks-primary,icu,False") - .HasAnnotation("Relational:MaxIdentifierLength", 63) - .HasAnnotation("ProductVersion", "5.0.12") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasAnnotation("ProductVersion", "6.0.4") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => { @@ -64,7 +67,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Cipher"); + b.ToTable("Cipher", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => @@ -92,7 +95,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("Collection"); + b.ToTable("Collection", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => @@ -107,7 +110,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("CipherId"); - b.ToTable("CollectionCipher"); + b.ToTable("CollectionCipher", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => @@ -191,7 +194,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Device"); + b.ToTable("Device", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => @@ -239,7 +242,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("GrantorId"); - b.ToTable("EmergencyAccess"); + b.ToTable("EmergencyAccess", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => @@ -298,7 +301,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasKey("Id"); - b.ToTable("Event"); + b.ToTable("Event", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => @@ -322,7 +325,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Folder"); + b.ToTable("Folder", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => @@ -365,7 +368,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasKey("Key"); - b.ToTable("Grant"); + b.ToTable("Grant", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => @@ -397,7 +400,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("Group"); + b.ToTable("Group", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => @@ -417,7 +420,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("GroupUser"); + b.ToTable("GroupUser", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => @@ -441,7 +444,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasKey("Id"); - b.ToTable("Installation"); + b.ToTable("Installation", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => @@ -577,6 +580,9 @@ namespace Bit.PostgresMigrations.Migrations b.Property("UseResetPassword") .HasColumnType("boolean"); + b.Property("UseScim") + .HasColumnType("boolean"); + b.Property("UseSso") .HasColumnType("boolean"); @@ -588,7 +594,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasKey("Id"); - b.ToTable("Organization"); + b.ToTable("Organization", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => @@ -613,7 +619,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("OrganizationApiKey"); + b.ToTable("OrganizationApiKey", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => @@ -637,7 +643,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("OrganizationConnection"); + b.ToTable("OrganizationConnection", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => @@ -680,7 +686,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("SponsoringOrganizationId"); - b.ToTable("OrganizationSponsorship"); + b.ToTable("OrganizationSponsorship", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => @@ -717,7 +723,7 @@ namespace Bit.PostgresMigrations.Migrations b.Property("RevisionDate") .HasColumnType("timestamp without time zone"); - b.Property("Status") + b.Property("Status") .HasColumnType("smallint"); b.Property("Type") @@ -732,7 +738,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("OrganizationUser"); + b.ToTable("OrganizationUser", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => @@ -762,7 +768,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("Policy"); + b.ToTable("Policy", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => @@ -811,7 +817,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasKey("Id"); - b.ToTable("Provider"); + b.ToTable("Provider", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => @@ -843,7 +849,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("ProviderId"); - b.ToTable("ProviderOrganization"); + b.ToTable("ProviderOrganization", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => @@ -884,7 +890,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("ProviderUser"); + b.ToTable("ProviderUser", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => @@ -941,15 +947,16 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Send"); + b.ToTable("Send", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("CreationDate") .HasColumnType("timestamp without time zone"); @@ -970,15 +977,16 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("OrganizationId"); - b.ToTable("SsoConfig"); + b.ToTable("SsoConfig", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("bigint") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); b.Property("CreationDate") .HasColumnType("timestamp without time zone"); @@ -1000,7 +1008,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("SsoUser"); + b.ToTable("SsoUser", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => @@ -1029,7 +1037,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasKey("Id"); - b.ToTable("TaxRate"); + b.ToTable("TaxRate", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => @@ -1078,7 +1086,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasIndex("UserId"); - b.ToTable("Transaction"); + b.ToTable("Transaction", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => @@ -1208,7 +1216,7 @@ namespace Bit.PostgresMigrations.Migrations b.HasKey("Id"); - b.ToTable("User"); + b.ToTable("User", (string)null); }); modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => diff --git a/util/PostgresMigrations/Scripts/2022-05-24_00_DeviceUnknownVerification.psql b/util/PostgresMigrations/Scripts/2022-05-24_00_DeviceUnknownVerification.psql index dbe25b304..5b534dcf5 100644 --- a/util/PostgresMigrations/Scripts/2022-05-24_00_DeviceUnknownVerification.psql +++ b/util/PostgresMigrations/Scripts/2022-05-24_00_DeviceUnknownVerification.psql @@ -1,6 +1,6 @@ START TRANSACTION; -ALTER TABLE "User" ADD "UnknownDeviceVerificationEnabled" boolean NOT NULL DEFAULT 1; +ALTER TABLE "User" ADD "UnknownDeviceVerificationEnabled" boolean NOT NULL DEFAULT true; INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") VALUES ('20220524170740_DeviceUnknownVerification', '5.0.12'); diff --git a/util/PostgresMigrations/Scripts/2022-07-07_00_UseScimFlag.psql b/util/PostgresMigrations/Scripts/2022-07-07_00_UseScimFlag.psql new file mode 100644 index 000000000..642f4fb6a --- /dev/null +++ b/util/PostgresMigrations/Scripts/2022-07-07_00_UseScimFlag.psql @@ -0,0 +1,8 @@ +START TRANSACTION; + +ALTER TABLE "Organization" ADD "UseScim" boolean NOT NULL DEFAULT FALSE; + +INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion") +VALUES ('20220707162231_UseScimFlag', '6.0.4'); + +COMMIT; diff --git a/util/Setup/Configuration.cs b/util/Setup/Configuration.cs index 6c030cdd5..e0062b522 100644 --- a/util/Setup/Configuration.cs +++ b/util/Setup/Configuration.cs @@ -103,6 +103,9 @@ namespace Bit.Setup [Description("Enable Key Connector (https://bitwarden.com/help/article/deploy-key-connector)")] public bool EnableKeyConnector { get; set; } = false; + [Description("Enable SCIM")] + public bool EnableScim { get; set; } = false; + [YamlIgnore] public string Domain { diff --git a/util/Setup/DockerComposeBuilder.cs b/util/Setup/DockerComposeBuilder.cs index 29dff8065..d007ffe1c 100644 --- a/util/Setup/DockerComposeBuilder.cs +++ b/util/Setup/DockerComposeBuilder.cs @@ -48,6 +48,7 @@ } MssqlDataDockerVolume = context.Config.DatabaseDockerVolume; EnableKeyConnector = context.Config.EnableKeyConnector; + EnableScim = context.Config.EnableScim; HttpPort = context.Config.HttpPort; HttpsPort = context.Config.HttpsPort; if (!string.IsNullOrWhiteSpace(context.CoreVersion)) @@ -67,6 +68,7 @@ public string ComposeVersion { get; set; } = "3"; public bool MssqlDataDockerVolume { get; set; } public bool EnableKeyConnector { get; set; } + public bool EnableScim { get; set; } public string HttpPort { get; set; } public string HttpsPort { get; set; } public bool HasPort => !string.IsNullOrWhiteSpace(HttpPort) || !string.IsNullOrWhiteSpace(HttpsPort); diff --git a/util/Setup/NginxConfigBuilder.cs b/util/Setup/NginxConfigBuilder.cs index c9c0c2623..f2ad08ced 100644 --- a/util/Setup/NginxConfigBuilder.cs +++ b/util/Setup/NginxConfigBuilder.cs @@ -68,6 +68,7 @@ Captcha = context.Config.Captcha; Ssl = context.Config.Ssl; EnableKeyConnector = context.Config.EnableKeyConnector; + EnableScim = context.Config.EnableScim; Domain = context.Config.Domain; Url = context.Config.Url; RealIps = context.Config.RealIps; @@ -116,6 +117,7 @@ public bool Captcha { get; set; } public bool Ssl { get; set; } public bool EnableKeyConnector { get; set; } + public bool EnableScim { get; set; } public string Domain { get; set; } public string Url { get; set; } public string CertificatePath { get; set; } diff --git a/util/Setup/Templates/DockerCompose.hbs b/util/Setup/Templates/DockerCompose.hbs index f38e239ed..8a3879ce6 100644 --- a/util/Setup/Templates/DockerCompose.hbs +++ b/util/Setup/Templates/DockerCompose.hbs @@ -211,6 +211,23 @@ services: - default - public {{/if}} +{{#if EnableScim}} + + scim: + image: bitwarden/scim:{{{CoreVersion}}} + container_name: bitwarden-scim + restart: always + volumes: + - ../ca-certificates:/etc/bitwarden/ca-certificates + - ../logs/api:/etc/bitwarden/logs + env_file: + - global.env + - ../env/uid.env + - ../env/global.override.env + networks: + - default + - public +{{/if}} {{#if MssqlDataDockerVolume}} volumes: diff --git a/util/Setup/Templates/NginxConfig.hbs b/util/Setup/Templates/NginxConfig.hbs index 5c395141e..e708ae7b0 100644 --- a/util/Setup/Templates/NginxConfig.hbs +++ b/util/Setup/Templates/NginxConfig.hbs @@ -104,7 +104,7 @@ server { location = /captcha-connector.html { proxy_pass http://web:5000/captcha-connector.html; } - + location = /captcha-mobile-connector.html { proxy_pass http://web:5000/captcha-mobile-connector.html; } @@ -168,4 +168,10 @@ server { proxy_pass http://key-connector:5000/; } {{/if}} +{{#if EnableScim}} + + location /scim/ { + proxy_pass http://scim:5000/; + } +{{/if}} }