Add accessToSecrets to service account lists (#5749)

This commit is contained in:
Thomas Avery 2023-08-03 10:06:18 -05:00 committed by GitHub
parent 5756aa851b
commit 6c68b46acb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 79 additions and 29 deletions

View File

@ -5,3 +5,7 @@ export class ServiceAccountView {
creationDate: string;
revisionDate: string;
}
export class ServiceAccountSecretsDetailsView extends ServiceAccountView {
accessToSecrets: number;
}

View File

@ -130,7 +130,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
orgId$,
this.serviceAccountService.serviceAccount$.pipe(startWith(null)),
]).pipe(
switchMap(([orgId]) => this.serviceAccountService.getServiceAccounts(orgId)),
switchMap(([orgId]) => this.serviceAccountService.getServiceAccounts(orgId, false)),
share()
);

View File

@ -16,3 +16,12 @@ export class ServiceAccountResponse extends BaseResponse {
this.revisionDate = this.getResponseProperty("RevisionDate");
}
}
export class ServiceAccountSecretsDetailsResponse extends ServiceAccountResponse {
accessToSecrets: number;
constructor(response: any) {
super(response);
this.accessToSecrets = this.getResponseProperty("AccessToSecrets");
}
}

View File

@ -8,11 +8,17 @@ import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { ServiceAccountView } from "../models/view/service-account.view";
import {
ServiceAccountSecretsDetailsView,
ServiceAccountView,
} from "../models/view/service-account.view";
import { BulkOperationStatus } from "../shared/dialogs/bulk-status-dialog.component";
import { ServiceAccountRequest } from "./models/requests/service-account.request";
import { ServiceAccountResponse } from "./models/responses/service-account.response";
import {
ServiceAccountResponse,
ServiceAccountSecretsDetailsResponse,
} from "./models/responses/service-account.response";
@Injectable({
providedIn: "root",
@ -28,16 +34,24 @@ export class ServiceAccountService {
private encryptService: EncryptService
) {}
async getServiceAccounts(organizationId: string): Promise<ServiceAccountView[]> {
async getServiceAccounts(
organizationId: string,
includeAccessToSecrets?: boolean
): Promise<ServiceAccountSecretsDetailsView[]> {
const params = new URLSearchParams();
if (includeAccessToSecrets) {
params.set("includeAccessToSecrets", "true");
}
const r = await this.apiService.send(
"GET",
"/organizations/" + organizationId + "/service-accounts",
"/organizations/" + organizationId + "/service-accounts?" + params.toString(),
null,
true,
true
);
const results = new ListResponse(r, ServiceAccountResponse);
return await this.createServiceAccountViews(organizationId, results.data);
const results = new ListResponse(r, ServiceAccountSecretsDetailsResponse);
return await this.createServiceAccountSecretsDetailsViews(organizationId, results.data);
}
async getByServiceAccountId(
@ -127,21 +141,39 @@ export class ServiceAccountService {
serviceAccountView.organizationId = serviceAccountResponse.organizationId;
serviceAccountView.creationDate = serviceAccountResponse.creationDate;
serviceAccountView.revisionDate = serviceAccountResponse.revisionDate;
serviceAccountView.name = await this.encryptService.decryptToUtf8(
new EncString(serviceAccountResponse.name),
organizationKey
);
serviceAccountView.name = serviceAccountResponse.name
? await this.encryptService.decryptToUtf8(
new EncString(serviceAccountResponse.name),
organizationKey
)
: null;
return serviceAccountView;
}
private async createServiceAccountViews(
private async createServiceAccountSecretsDetailsView(
organizationKey: SymmetricCryptoKey,
response: ServiceAccountSecretsDetailsResponse
): Promise<ServiceAccountSecretsDetailsView> {
const view = new ServiceAccountSecretsDetailsView();
view.id = response.id;
view.organizationId = response.organizationId;
view.creationDate = response.creationDate;
view.revisionDate = response.revisionDate;
view.accessToSecrets = response.accessToSecrets;
view.name = response.name
? await this.encryptService.decryptToUtf8(new EncString(response.name), organizationKey)
: null;
return view;
}
private async createServiceAccountSecretsDetailsViews(
organizationId: string,
serviceAccountResponses: ServiceAccountResponse[]
): Promise<ServiceAccountView[]> {
serviceAccountResponses: ServiceAccountSecretsDetailsResponse[]
): Promise<ServiceAccountSecretsDetailsView[]> {
const orgKey = await this.getOrganizationKey(organizationId);
return await Promise.all(
serviceAccountResponses.map(async (s: ServiceAccountResponse) => {
return await this.createServiceAccountView(orgKey, s);
serviceAccountResponses.map(async (s: ServiceAccountSecretsDetailsResponse) => {
return await this.createServiceAccountSecretsDetailsView(orgKey, s);
})
);
}

View File

@ -64,8 +64,7 @@
</a>
</td>
<td bitCell>
<!-- TODO add number of secrets once mapping is implemented-->
<span> 0 </span>
<span> {{ serviceAccount.accessToSecrets }} </span>
</td>
<td bitCell>{{ serviceAccount.revisionDate | date : "medium" }}</td>
<td bitCell>

View File

@ -6,25 +6,28 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { TableDataSource } from "@bitwarden/components";
import { ServiceAccountView } from "../models/view/service-account.view";
import {
ServiceAccountSecretsDetailsView,
ServiceAccountView,
} from "../models/view/service-account.view";
@Component({
selector: "sm-service-accounts-list",
templateUrl: "./service-accounts-list.component.html",
})
export class ServiceAccountsListComponent implements OnDestroy {
protected dataSource = new TableDataSource<ServiceAccountView>();
protected dataSource = new TableDataSource<ServiceAccountSecretsDetailsView>();
@Input()
get serviceAccounts(): ServiceAccountView[] {
get serviceAccounts(): ServiceAccountSecretsDetailsView[] {
return this._serviceAccounts;
}
set serviceAccounts(serviceAccounts: ServiceAccountView[]) {
set serviceAccounts(serviceAccounts: ServiceAccountSecretsDetailsView[]) {
this.selection.clear();
this._serviceAccounts = serviceAccounts;
this.dataSource.data = serviceAccounts;
}
private _serviceAccounts: ServiceAccountView[];
private _serviceAccounts: ServiceAccountSecretsDetailsView[];
@Input()
set search(search: string) {
@ -72,8 +75,8 @@ export class ServiceAccountsListComponent implements OnDestroy {
}
}
delete(serviceAccount: ServiceAccountView) {
this.deleteServiceAccountsEvent.emit([serviceAccount]);
delete(serviceAccount: ServiceAccountSecretsDetailsView) {
this.deleteServiceAccountsEvent.emit([serviceAccount as ServiceAccountView]);
}
bulkDeleteServiceAccounts() {

View File

@ -4,7 +4,10 @@ import { combineLatest, Observable, startWith, switchMap } from "rxjs";
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
import { ServiceAccountView } from "../models/view/service-account.view";
import {
ServiceAccountSecretsDetailsView,
ServiceAccountView,
} from "../models/view/service-account.view";
import { AccessPolicyService } from "../shared/access-policies/access-policy.service";
import {
@ -23,7 +26,7 @@ import { ServiceAccountService } from "./service-account.service";
templateUrl: "./service-accounts.component.html",
})
export class ServiceAccountsComponent implements OnInit {
protected serviceAccounts$: Observable<ServiceAccountView[]>;
protected serviceAccounts$: Observable<ServiceAccountSecretsDetailsView[]>;
protected search: string;
private organizationId: string;
@ -78,7 +81,7 @@ export class ServiceAccountsComponent implements OnInit {
);
}
private async getServiceAccounts(): Promise<ServiceAccountView[]> {
return await this.serviceAccountService.getServiceAccounts(this.organizationId);
private async getServiceAccounts(): Promise<ServiceAccountSecretsDetailsView[]> {
return await this.serviceAccountService.getServiceAccounts(this.organizationId, true);
}
}