bitwarden-estensione-browser/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.ts

167 lines
5.9 KiB
TypeScript

import { Component, OnInit } from "@angular/core";
import { UntypedFormBuilder, FormControl } from "@angular/forms";
import { ActivatedRoute } from "@angular/router";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
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 { OrganizationApiKeyRequest } from "@bitwarden/common/models/request/organizationApiKeyRequest";
import { OrganizationConnectionRequest } from "@bitwarden/common/models/request/organizationConnectionRequest";
import { ScimConfigRequest } from "@bitwarden/common/models/request/scimConfigRequest";
import { ApiKeyResponse } from "@bitwarden/common/models/response/apiKeyResponse";
import { OrganizationConnectionResponse } from "@bitwarden/common/models/response/organizationConnectionResponse";
@Component({
selector: "app-org-manage-scim",
templateUrl: "scim.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class ScimComponent implements OnInit {
loading = true;
organizationId: string;
existingConnectionId: string;
formPromise: Promise<OrganizationConnectionResponse<ScimConfigApi>>;
rotatePromise: Promise<ApiKeyResponse>;
enabled = new FormControl(false);
showScimSettings = false;
formData = this.formBuilder.group({
endpointUrl: new FormControl({ value: "", disabled: true }),
clientSecret: new FormControl({ value: "", disabled: true }),
});
constructor(
private formBuilder: UntypedFormBuilder,
private route: ActivatedRoute,
private apiService: ApiService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private environmentService: EnvironmentService,
private organizationApiService: OrganizationApiServiceAbstraction
) {}
async ngOnInit() {
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
await this.load();
});
}
async load() {
const connection = await this.apiService.getOrganizationConnection(
this.organizationId,
OrganizationConnectionType.Scim,
ScimConfigApi
);
await this.setConnectionFormValues(connection);
}
async loadApiKey() {
const apiKeyRequest = new OrganizationApiKeyRequest();
apiKeyRequest.type = OrganizationApiKeyType.Scim;
apiKeyRequest.masterPasswordHash = "N/A";
const apiKeyResponse = await this.organizationApiService.getOrCreateApiKey(
this.organizationId,
apiKeyRequest
);
this.formData.setValue({
endpointUrl: this.getScimEndpointUrl(),
clientSecret: apiKeyResponse.apiKey,
});
}
async copyScimUrl() {
this.platformUtilsService.copyToClipboard(this.getScimEndpointUrl());
}
async rotateScimKey() {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("rotateScimKeyWarning"),
this.i18nService.t("rotateScimKey"),
this.i18nService.t("rotateKey"),
this.i18nService.t("cancel"),
"warning"
);
if (!confirmed) {
return false;
}
const request = new OrganizationApiKeyRequest();
request.type = OrganizationApiKeyType.Scim;
request.masterPasswordHash = "N/A";
this.rotatePromise = this.organizationApiService.rotateApiKey(this.organizationId, request);
try {
const response = await this.rotatePromise;
this.formData.setValue({
endpointUrl: this.getScimEndpointUrl(),
clientSecret: response.apiKey,
});
this.platformUtilsService.showToast("success", null, this.i18nService.t("scimApiKeyRotated"));
} catch {
// Logged by appApiAction, do nothing
}
this.rotatePromise = null;
}
async copyScimKey() {
this.platformUtilsService.copyToClipboard(this.formData.get("clientSecret").value);
}
async submit() {
try {
const request = new OrganizationConnectionRequest(
this.organizationId,
OrganizationConnectionType.Scim,
true,
new ScimConfigRequest(this.enabled.value)
);
if (this.existingConnectionId == null) {
this.formPromise = this.apiService.createOrganizationConnection(request, ScimConfigApi);
} else {
this.formPromise = this.apiService.updateOrganizationConnection(
request,
ScimConfigApi,
this.existingConnectionId
);
}
const response = (await this.formPromise) as OrganizationConnectionResponse<ScimConfigApi>;
await this.setConnectionFormValues(response);
this.platformUtilsService.showToast("success", null, this.i18nService.t("scimSettingsSaved"));
} catch (e) {
// Logged by appApiAction, do nothing
}
this.formPromise = null;
}
getScimEndpointUrl() {
return this.environmentService.getScimUrl() + "/" + this.organizationId;
}
private async setConnectionFormValues(connection: OrganizationConnectionResponse<ScimConfigApi>) {
this.existingConnectionId = connection?.id;
if (connection !== null && connection.config?.enabled) {
this.showScimSettings = true;
this.enabled.setValue(true);
this.formData.setValue({
endpointUrl: this.getScimEndpointUrl(),
clientSecret: "",
});
await this.loadApiKey();
} else {
this.showScimSettings = false;
this.enabled.setValue(false);
}
this.loading = false;
}
}