1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 15:42:48 -05:00

[EC-261] SCIM (#2105)

* scim project stub

* some scim models and v2 controllers

* implement some v2 scim endpoints

* fix spacing

* api key auth

* EC-261 - SCIM Org API Key and connection type config

* EC-261 - Fix lint errors/formatting

* updates for okta implementation testing

* fix var ref

* updates from testing with Okta

* implement scim context via provider parsing

* support single and list of ids for add/remove groups

* log ops not handled

* touch up scim context

* group list filtering

* EC-261 - Additional SCIM provider types

* EC-265 - UseScim flag and license update

* EC-265 - SCIM provider type of default (0)

* EC-265 - Add Scim URL and update connection validation

* EC-265 - Model validation and cleanup for SCIM keys

* implement scim org connection

* EC-265 - Ensure ServiceUrl is not persisted to DB

* EC-265 - Exclude provider type from DB if not configured

* EC-261 - EF Migrations for SCIM

* add docker builds for scim

* EC-261 - Fix failing permissions tests

* EC-261 - Fix unit tests and pgsql migrations

* Formatting fixes from linter

* EC-265 - Remove service URL from scim config

* EC-265 - Fix unit tests, removed wayward validation

* EC-265 - Require self-hosted for billing sync org conn

* EC-265 - Fix formatting issues - whitespace

* EC-261 - PR feedback and cleanup

* scim constants rename

* no scim settings right now

* update project name

* delete package lock

* update appsettings configs for scim

* use default scim provider for context

Co-authored-by: Kyle Spearrin <kyle.spearrin@gmail.com>
This commit is contained in:
Chad Scharf
2022-07-14 15:58:48 -04:00
committed by GitHub
parent c5852db6ed
commit 19b8d8281a
117 changed files with 8553 additions and 169 deletions

View File

@ -344,6 +344,12 @@ namespace Bit.Core.Context
&& (o.Permissions?.ManageSso ?? false)) ?? false);
}
public async Task<bool> ManageScim(Guid orgId)
{
return await OrganizationAdmin(orgId) || (Organizations?.Any(o => o.Id == orgId
&& (o.Permissions?.ManageScim ?? false)) ?? false);
}
public async Task<bool> 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"),
};
}

View File

@ -47,6 +47,7 @@ namespace Bit.Core.Context
Task<bool> ManagePolicies(Guid orgId);
Task<bool> ManageSso(Guid orgId);
Task<bool> ManageUsers(Guid orgId);
Task<bool> ManageScim(Guid orgId);
Task<bool> ManageResetPassword(Guid orgId);
Task<bool> ManageBilling(Guid orgId);
Task<bool> ProviderUserForOrgAsync(Guid orgId);

View File

@ -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; }

View File

@ -2,7 +2,8 @@
{
public enum OrganizationApiKeyType : byte
{
Default,
BillingSync,
Default = 0,
BillingSync = 1,
Scim = 2,
}
}

View File

@ -3,5 +3,6 @@
public enum OrganizationConnectionType : byte
{
CloudBillingSync = 1,
Scim = 2,
}
}

View File

@ -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,
}
}

View File

@ -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
/// <summary>
/// Represents the current version of the license format. Should be updated whenever new fields are added.
/// </summary>
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

View File

@ -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; }
}
}

View File

@ -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; }

View File

@ -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"),
};
}
}

View File

@ -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; }

View File

@ -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; }
}
}

View File

@ -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; }

View File

@ -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<OrganizationService> _logger;
@ -66,6 +68,7 @@ namespace Bit.Core.Services
IGlobalSettings globalSettings,
ITaxRateRepository taxRateRepository,
IOrganizationApiKeyRepository organizationApiKeyRepository,
IOrganizationConnectionRepository organizationConnectionRepository,
ICurrentContext currentContext,
ILogger<OrganizationService> 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<ScimConfig>()?.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<ScimConfig>()?.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;

View File

@ -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

View File

@ -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; }
}
}

View File

@ -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,