1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-03 00:52:49 -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

@ -493,7 +493,7 @@ namespace Bit.Api.Controllers
public async Task<ApiKeyResponseModel> 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<ListResponseModel<OrganizationApiKeyInformation>> ApiKeyInformation(Guid id)
[HttpGet("{id}/api-key-information/{type?}")]
public async Task<ListResponseModel<OrganizationApiKeyInformation>> 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<OrganizationApiKeyInformation>(
apiKeys.Select(k => new OrganizationApiKeyInformation(k)));
@ -553,7 +554,7 @@ namespace Bit.Api.Controllers
public async Task<ApiKeyResponseModel> 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<bool> 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<TaxInfoResponseModel> GetTaxInfo(string id)