EC-265 - Initial stubs for SCIM config UI
This commit is contained in:
parent
af8f83980f
commit
664b8dc13e
|
@ -86,6 +86,9 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy {
|
|||
case this.organization.canManageSso:
|
||||
route = "manage/sso";
|
||||
break;
|
||||
case this.organization.canManageScim:
|
||||
route = "manage/scim";
|
||||
break;
|
||||
case this.organization.canAccessEventLogs:
|
||||
route = "manage/events";
|
||||
break;
|
||||
|
|
|
@ -52,6 +52,14 @@
|
|||
>
|
||||
{{ "eventLogs" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
routerLink="scim"
|
||||
class="list-group-item"
|
||||
routerLinkActive="active"
|
||||
*ngIf="organization.canManageScim && accessScim"
|
||||
>
|
||||
{{ "singleSignOn" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -14,6 +14,7 @@ export class ManageComponent implements OnInit {
|
|||
accessGroups = false;
|
||||
accessEvents = false;
|
||||
accessSso = false;
|
||||
accessScim = false;
|
||||
|
||||
constructor(private route: ActivatedRoute, private organizationService: OrganizationService) {}
|
||||
|
||||
|
@ -24,6 +25,7 @@ export class ManageComponent implements OnInit {
|
|||
this.accessSso = this.organization.useSso;
|
||||
this.accessEvents = this.organization.useEvents;
|
||||
this.accessGroups = this.organization.useGroups;
|
||||
this.accessScim = this.organization.useScim;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ const permissions = {
|
|||
Permissions.ManageUsers,
|
||||
Permissions.ManagePolicies,
|
||||
Permissions.ManageSso,
|
||||
Permissions.ManageScim,
|
||||
],
|
||||
tools: [Permissions.AccessImportExport, Permissions.AccessReports],
|
||||
settings: [Permissions.ManageOrganization],
|
||||
|
|
|
@ -5165,5 +5165,9 @@
|
|||
"example": "My Email"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scim": {
|
||||
"message": "SCIM Provisioning",
|
||||
"description": "This text, 'SCIM', is an acronymn and should not be translated."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
<div class="page-header d-flex">
|
||||
<h1>{{ "scim" | i18n }}</h1>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="loading">
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin text-muted"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||
</ng-container>
|
||||
|
||||
<form #form (ngSubmit)="submit()" [appApiAction]="formPromise" *ngIf="!loading">
|
||||
<p><!-- TODO: Need to fill in this component, just a placeholder for now --></p>
|
||||
</form>
|
|
@ -0,0 +1,63 @@
|
|||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { OrganizationService } from "@bitwarden/common/abstractions/organization.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
import { OrganizationApiKeyType } from "@bitwarden/common/enums/organizationApiKeyType";
|
||||
import { OrganizationConnectionType } from "@bitwarden/common/enums/organizationConnectionType";
|
||||
import { ScimConfigApi } from "@bitwarden/common/models/api/scimConfigApi";
|
||||
import { Organization } from "@bitwarden/common/models/domain/organization";
|
||||
|
||||
@Component({
|
||||
selector: "app-org-manage-scim",
|
||||
templateUrl: "scim.component.html",
|
||||
})
|
||||
export class ScimComponent implements OnInit {
|
||||
loading = true;
|
||||
organizationId: string;
|
||||
organization: Organization;
|
||||
formPromise: Promise<any>;
|
||||
|
||||
endpointUrl: string;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private apiService: ApiService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private organizationService: OrganizationService
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organizationId = params.organizationId;
|
||||
await this.load();
|
||||
});
|
||||
}
|
||||
|
||||
async load() {
|
||||
this.organization = await this.organizationService.get(this.organizationId);
|
||||
//TODO: Load the SCIM configuration (connection) and API Key
|
||||
this.endpointUrl = "https://example.com/callback/scim";
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
async submit() {
|
||||
//this.validateForm();
|
||||
|
||||
//TODO: POST data update to server and update display
|
||||
//this.formPromise = POST;
|
||||
|
||||
try {
|
||||
//const response = await this.formPromise;
|
||||
//this.populateForm(response);
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("scimSettingsSaved"));
|
||||
} catch {
|
||||
// Logged by appApiAction, do nothing
|
||||
}
|
||||
|
||||
this.formPromise = null;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import { OrganizationLayoutComponent } from "src/app/organizations/layouts/organ
|
|||
import { ManageComponent } from "src/app/organizations/manage/manage.component";
|
||||
import { NavigationPermissionsService } from "src/app/organizations/services/navigation-permissions.service";
|
||||
|
||||
import { ScimComponent } from "./manage/scim.component";
|
||||
import { SsoComponent } from "./manage/sso.component";
|
||||
|
||||
const routes: Routes = [
|
||||
|
@ -33,6 +34,14 @@ const routes: Routes = [
|
|||
permissions: [Permissions.ManageSso],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "scim",
|
||||
component: ScimComponent,
|
||||
canActivate: [PermissionsGuard],
|
||||
data: {
|
||||
permissions: [Permissions.ManageScim],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { OrganizationApiKeyType } from "../enums/organizationApiKeyType";
|
||||
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
|
||||
import { PolicyType } from "../enums/policyType";
|
||||
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
|
||||
|
@ -569,7 +570,8 @@ export abstract class ApiService {
|
|||
request: OrganizationApiKeyRequest
|
||||
) => Promise<ApiKeyResponse>;
|
||||
getOrganizationApiKeyInformation: (
|
||||
id: string
|
||||
id: string,
|
||||
type?: OrganizationApiKeyType
|
||||
) => Promise<ListResponse<OrganizationApiKeyInformationResponse>>;
|
||||
postOrganizationRotateApiKey: (
|
||||
id: string,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export enum OrganizationApiKeyType {
|
||||
Default = 0,
|
||||
BillingSync = 1,
|
||||
Scim = 2,
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export enum OrganizationConnectionType {
|
||||
CloudBillingSync = 1,
|
||||
Scim = 2,
|
||||
}
|
||||
|
|
|
@ -25,4 +25,5 @@ export enum Permissions {
|
|||
DeleteAssignedCollections,
|
||||
ManageSso,
|
||||
ManageBilling,
|
||||
ManageScim,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
export enum ScimProviderType {
|
||||
AzureAd = 0,
|
||||
Okta = 1,
|
||||
OneLogin = 2,
|
||||
JumpCloud = 3,
|
||||
GoogleWorkspace = 4,
|
||||
Rippling = 5,
|
||||
}
|
|
@ -25,6 +25,7 @@ export class PermissionsApi extends BaseResponse {
|
|||
managePolicies: boolean;
|
||||
manageUsers: boolean;
|
||||
manageResetPassword: boolean;
|
||||
manageScim: boolean;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
|
@ -51,5 +52,6 @@ export class PermissionsApi extends BaseResponse {
|
|||
this.managePolicies = this.getResponseProperty("ManagePolicies");
|
||||
this.manageUsers = this.getResponseProperty("ManageUsers");
|
||||
this.manageResetPassword = this.getResponseProperty("ManageResetPassword");
|
||||
this.manageScim = this.getResponseProperty("ManageScim");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import { ScimProviderType } from "@bitwarden/common/enums/scimProviderType";
|
||||
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
export class ScimConfigApi extends BaseResponse {
|
||||
enabled: boolean;
|
||||
scimProvider: ScimProviderType;
|
||||
|
||||
constructor(data: any) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.enabled = this.getResponseProperty("Enabled");
|
||||
this.scimProvider = this.getResponseProperty("ScimProvider");
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ export class OrganizationData {
|
|||
useApi: boolean;
|
||||
useSso: boolean;
|
||||
useKeyConnector: boolean;
|
||||
useScim: boolean;
|
||||
useResetPassword: boolean;
|
||||
selfHost: boolean;
|
||||
usersGetPremium: boolean;
|
||||
|
@ -58,6 +59,7 @@ export class OrganizationData {
|
|||
this.useApi = response.useApi;
|
||||
this.useSso = response.useSso;
|
||||
this.useKeyConnector = response.useKeyConnector;
|
||||
this.useScim = response.useScim;
|
||||
this.useResetPassword = response.useResetPassword;
|
||||
this.selfHost = response.selfHost;
|
||||
this.usersGetPremium = response.usersGetPremium;
|
||||
|
|
|
@ -20,6 +20,7 @@ export class Organization {
|
|||
useApi: boolean;
|
||||
useSso: boolean;
|
||||
useKeyConnector: boolean;
|
||||
useScim: boolean;
|
||||
useResetPassword: boolean;
|
||||
selfHost: boolean;
|
||||
usersGetPremium: boolean;
|
||||
|
@ -63,6 +64,7 @@ export class Organization {
|
|||
this.useApi = obj.useApi;
|
||||
this.useSso = obj.useSso;
|
||||
this.useKeyConnector = obj.useKeyConnector;
|
||||
this.useScim = obj.useScim;
|
||||
this.useResetPassword = obj.useResetPassword;
|
||||
this.selfHost = obj.selfHost;
|
||||
this.usersGetPremium = obj.usersGetPremium;
|
||||
|
@ -173,6 +175,10 @@ export class Organization {
|
|||
return this.isAdmin || this.permissions.manageSso;
|
||||
}
|
||||
|
||||
get canManageScim() {
|
||||
return this.isAdmin || this.permissions.manageScim;
|
||||
}
|
||||
|
||||
get canManagePolicies() {
|
||||
return this.isAdmin || this.permissions.managePolicies;
|
||||
}
|
||||
|
@ -207,6 +213,7 @@ export class Organization {
|
|||
(permissions.includes(Permissions.ManageUsers) && this.canManageUsers) ||
|
||||
(permissions.includes(Permissions.ManageUsersPassword) && this.canManageUsersPassword) ||
|
||||
(permissions.includes(Permissions.ManageSso) && this.canManageSso) ||
|
||||
(permissions.includes(Permissions.ManageScim) && this.canManageScim) ||
|
||||
(permissions.includes(Permissions.ManageBilling) && this.canManageBilling);
|
||||
|
||||
return specifiedPermissions && (this.enabled || this.isOwner);
|
||||
|
|
|
@ -17,6 +17,7 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
|||
useApi: boolean;
|
||||
useSso: boolean;
|
||||
useKeyConnector: boolean;
|
||||
useScim: boolean;
|
||||
useResetPassword: boolean;
|
||||
selfHost: boolean;
|
||||
usersGetPremium: boolean;
|
||||
|
@ -57,6 +58,7 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
|||
this.useApi = this.getResponseProperty("UseApi");
|
||||
this.useSso = this.getResponseProperty("UseSso");
|
||||
this.useKeyConnector = this.getResponseProperty("UseKeyConnector") ?? false;
|
||||
this.useScim = this.getResponseProperty("UseScim") ?? false;
|
||||
this.useResetPassword = this.getResponseProperty("UseResetPassword");
|
||||
this.selfHost = this.getResponseProperty("SelfHost");
|
||||
this.usersGetPremium = this.getResponseProperty("UsersGetPremium");
|
||||
|
|
|
@ -4,6 +4,7 @@ import { EnvironmentService } from "../abstractions/environment.service";
|
|||
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
|
||||
import { TokenService } from "../abstractions/token.service";
|
||||
import { DeviceType } from "../enums/deviceType";
|
||||
import { OrganizationApiKeyType } from "../enums/organizationApiKeyType";
|
||||
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
|
||||
import { PolicyType } from "../enums/policyType";
|
||||
import { Utils } from "../misc/utils";
|
||||
|
@ -1840,15 +1841,14 @@ export class ApiService implements ApiServiceAbstraction {
|
|||
}
|
||||
|
||||
async getOrganizationApiKeyInformation(
|
||||
id: string
|
||||
id: string,
|
||||
type: OrganizationApiKeyType = null
|
||||
): Promise<ListResponse<OrganizationApiKeyInformationResponse>> {
|
||||
const r = await this.send(
|
||||
"GET",
|
||||
"/organizations/" + id + "/api-key-information",
|
||||
null,
|
||||
true,
|
||||
true
|
||||
);
|
||||
const uri =
|
||||
type === null
|
||||
? "/organizations/" + id + "/api-key-information"
|
||||
: "/organizations/" + id + "/api-key-information/" + type;
|
||||
const r = await this.send("GET", uri, null, true, true);
|
||||
return new ListResponse(r, OrganizationApiKeyInformationResponse);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue