mirror of
https://github.com/bitwarden/browser.git
synced 2024-09-27 04:03:00 +02:00
[SM-378] Enable SM on a user basis (#4497)
* Add support for giving individual users access to secrets manager
This commit is contained in:
parent
29cc94ed70
commit
2757fcee86
@ -42,6 +42,7 @@ export class UserAdminService {
|
||||
request.type = user.type;
|
||||
request.collections = user.collections;
|
||||
request.groups = user.groups;
|
||||
request.accessSecretsManager = user.accessSecretsManager;
|
||||
|
||||
await this.organizationUserService.putOrganizationUser(user.organizationId, user.id, request);
|
||||
}
|
||||
@ -54,6 +55,7 @@ export class UserAdminService {
|
||||
request.type = user.type;
|
||||
request.collections = user.collections;
|
||||
request.groups = user.groups;
|
||||
request.accessSecretsManager = user.accessSecretsManager;
|
||||
|
||||
await this.organizationUserService.postOrganizationUserInvite(user.organizationId, request);
|
||||
}
|
||||
@ -79,6 +81,7 @@ export class UserAdminService {
|
||||
readOnly: c.readOnly,
|
||||
}));
|
||||
view.groups = u.groups;
|
||||
view.accessSecretsManager = u.accessSecretsManager;
|
||||
|
||||
return view;
|
||||
});
|
||||
|
@ -16,4 +16,6 @@ export class OrganizationUserAdminView {
|
||||
|
||||
collections: CollectionAccessSelectionView[] = [];
|
||||
groups: string[] = [];
|
||||
|
||||
accessSecretsManager: boolean;
|
||||
}
|
||||
|
@ -253,6 +253,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="canUseSecretsManager">
|
||||
<h3 class="mt-4">
|
||||
{{ "secretsManagerBeta" | i18n }}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
appA11yTitle="{{ 'learnMore' | i18n }}"
|
||||
href="https://bitwarden.com/help/secrets-manager"
|
||||
>
|
||||
<i class="bwi bwi-question-circle" aria-hidden="true"></i>
|
||||
</a>
|
||||
</h3>
|
||||
<p class="tw-text-muted">{{ "secretsManagerBetaDesc" | i18n }}</p>
|
||||
<bit-form-control>
|
||||
<input type="checkbox" bitCheckbox formControlName="accessSecretsManager" />
|
||||
<bit-label>
|
||||
{{ "userAccessSecretsManager" | i18n }}
|
||||
</bit-label>
|
||||
</bit-form-control>
|
||||
</ng-container>
|
||||
</bit-tab>
|
||||
<bit-tab *ngIf="organization.useGroups" [label]="'groups' | i18n">
|
||||
<div class="tw-mb-6">
|
||||
|
@ -69,6 +69,7 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
|
||||
organizationUserType = OrganizationUserType;
|
||||
canUseCustomPermissions: boolean;
|
||||
PermissionMode = PermissionMode;
|
||||
canUseSecretsManager: boolean;
|
||||
|
||||
protected organization: Organization;
|
||||
protected collectionAccessItems: AccessItemView[] = [];
|
||||
@ -78,6 +79,7 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
|
||||
emails: ["", [Validators.required, commaSeparatedEmails]],
|
||||
type: OrganizationUserType.User,
|
||||
accessAllCollections: false,
|
||||
accessSecretsManager: false,
|
||||
access: [[] as AccessItemValue[]],
|
||||
groups: [[] as AccessItemValue[]],
|
||||
});
|
||||
@ -158,6 +160,7 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
|
||||
.subscribe(({ organization, collections, userDetails, groups }) => {
|
||||
this.organization = organization;
|
||||
this.canUseCustomPermissions = organization.useCustomPermissions;
|
||||
this.canUseSecretsManager = organization.useSecretsManager;
|
||||
|
||||
this.collectionAccessItems = [].concat(
|
||||
collections.map((c) => mapCollectionToAccessItemView(c))
|
||||
@ -226,6 +229,7 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
|
||||
type: userDetails.type,
|
||||
accessAllCollections: userDetails.accessAll,
|
||||
access: accessSelections,
|
||||
accessSecretsManager: userDetails.accessSecretsManager,
|
||||
groups: groupAccessSelections,
|
||||
});
|
||||
}
|
||||
@ -324,6 +328,7 @@ export class MemberDialogComponent implements OnInit, OnDestroy {
|
||||
.filter((v) => v.type === AccessItemType.Collection)
|
||||
.map(convertToSelectionView);
|
||||
userView.groups = this.formGroup.value.groups.map((m) => m.id);
|
||||
userView.accessSecretsManager = this.formGroup.value.accessSecretsManager;
|
||||
|
||||
if (this.editMode) {
|
||||
await this.userService.save(userView);
|
||||
|
@ -6146,5 +6146,14 @@
|
||||
},
|
||||
"changeKdfLoggedOutWarning": {
|
||||
"message": "Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour. We recommend exporting your vault before changing your encryption settings to prevent data loss."
|
||||
},
|
||||
"secretsManagerBeta": {
|
||||
"message": "Secrets Manager Beta"
|
||||
},
|
||||
"secretsManagerBetaDesc": {
|
||||
"message": "Enable user access to the Secrets Manager at no charge during the Beta program."
|
||||
},
|
||||
"userAccessSecretsManager": {
|
||||
"message": "This user can access the Secrets Manager Beta"
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ export class OrganizationUserInviteRequest {
|
||||
emails: string[] = [];
|
||||
type: OrganizationUserType;
|
||||
accessAll: boolean;
|
||||
accessSecretsManager: boolean;
|
||||
collections: SelectionReadOnlyRequest[] = [];
|
||||
groups: string[];
|
||||
permissions: PermissionsApi;
|
||||
|
@ -5,6 +5,7 @@ import { SelectionReadOnlyRequest } from "../../../models/request/selection-read
|
||||
export class OrganizationUserUpdateRequest {
|
||||
type: OrganizationUserType;
|
||||
accessAll: boolean;
|
||||
accessSecretsManager: boolean;
|
||||
collections: SelectionReadOnlyRequest[] = [];
|
||||
groups: string[] = [];
|
||||
permissions: PermissionsApi;
|
||||
|
@ -11,6 +11,7 @@ export class OrganizationUserResponse extends BaseResponse {
|
||||
type: OrganizationUserType;
|
||||
status: OrganizationUserStatusType;
|
||||
accessAll: boolean;
|
||||
accessSecretsManager: boolean;
|
||||
permissions: PermissionsApi;
|
||||
resetPasswordEnrolled: boolean;
|
||||
collections: SelectionReadOnlyResponse[] = [];
|
||||
@ -24,6 +25,7 @@ export class OrganizationUserResponse extends BaseResponse {
|
||||
this.status = this.getResponseProperty("Status");
|
||||
this.permissions = new PermissionsApi(this.getResponseProperty("Permissions"));
|
||||
this.accessAll = this.getResponseProperty("AccessAll");
|
||||
this.accessSecretsManager = this.getResponseProperty("AccessSecretsManager");
|
||||
this.resetPasswordEnrolled = this.getResponseProperty("ResetPasswordEnrolled");
|
||||
|
||||
const collections = this.getResponseProperty("Collections");
|
||||
|
@ -45,6 +45,7 @@ export class OrganizationData {
|
||||
familySponsorshipLastSyncDate?: Date;
|
||||
familySponsorshipValidUntil?: Date;
|
||||
familySponsorshipToDelete?: boolean;
|
||||
accessSecretsManager: boolean;
|
||||
|
||||
constructor(response: ProfileOrganizationResponse) {
|
||||
this.id = response.id;
|
||||
@ -86,5 +87,6 @@ export class OrganizationData {
|
||||
this.familySponsorshipLastSyncDate = response.familySponsorshipLastSyncDate;
|
||||
this.familySponsorshipValidUntil = response.familySponsorshipValidUntil;
|
||||
this.familySponsorshipToDelete = response.familySponsorshipToDelete;
|
||||
this.accessSecretsManager = response.accessSecretsManager;
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ export class Organization {
|
||||
familySponsorshipLastSyncDate?: Date;
|
||||
familySponsorshipValidUntil?: Date;
|
||||
familySponsorshipToDelete?: boolean;
|
||||
accessSecretsManager: boolean;
|
||||
|
||||
constructor(obj?: OrganizationData) {
|
||||
if (obj == null) {
|
||||
@ -93,6 +94,7 @@ export class Organization {
|
||||
this.familySponsorshipLastSyncDate = obj.familySponsorshipLastSyncDate;
|
||||
this.familySponsorshipValidUntil = obj.familySponsorshipValidUntil;
|
||||
this.familySponsorshipToDelete = obj.familySponsorshipToDelete;
|
||||
this.accessSecretsManager = obj.accessSecretsManager;
|
||||
}
|
||||
|
||||
get canAccess() {
|
||||
@ -199,7 +201,7 @@ export class Organization {
|
||||
}
|
||||
|
||||
get canAccessSecretsManager() {
|
||||
return this.useSecretsManager;
|
||||
return this.useSecretsManager && this.accessSecretsManager;
|
||||
}
|
||||
|
||||
static fromJSON(json: Jsonify<Organization>) {
|
||||
|
@ -46,6 +46,7 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
familySponsorshipLastSyncDate?: Date;
|
||||
familySponsorshipValidUntil?: Date;
|
||||
familySponsorshipToDelete?: boolean;
|
||||
accessSecretsManager: boolean;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@ -99,5 +100,6 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
this.familySponsorshipValidUntil = new Date(familySponsorshipValidUntilString);
|
||||
}
|
||||
this.familySponsorshipToDelete = this.getResponseProperty("FamilySponsorshipToDelete");
|
||||
this.accessSecretsManager = this.getResponseProperty("AccessSecretsManager");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user