mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-12 11:04:25 +00:00
fix: management api remove otp (#1010)
* fix: management api remove otp * add postinstall * remove mgmt otp Co-authored-by: Max Peintner <max@caos.ch>
This commit is contained in:
parent
855725c3c0
commit
75bf0409c4
@ -17,6 +17,16 @@
|
|||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{ 'USER.MFA.TABLEACTIONS' | translate }} </th>
|
||||||
|
<td mat-cell *matCellDef="let mfa">
|
||||||
|
<button matTooltip="{{'ACTIONS.REMOVE' | translate}}" color="warn" mat-icon-button
|
||||||
|
(click)="deleteMFA(mfa.type)">
|
||||||
|
<i class="las la-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;">
|
<tr class="highlight" mat-row *matRowDef="let row; columns: displayedColumns;">
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
import { MatTable, MatTableDataSource } from '@angular/material/table';
|
import { MatTable, MatTableDataSource } from '@angular/material/table';
|
||||||
import { BehaviorSubject, Observable } from 'rxjs';
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||||
import { MFAState, MfaType, UserMultiFactor, UserView } from 'src/app/proto/generated/management_pb';
|
import { MFAState, MfaType, UserMultiFactor, UserView } from 'src/app/proto/generated/management_pb';
|
||||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||||
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
|
||||||
export interface MFAItem {
|
export interface MFAItem {
|
||||||
@ -17,7 +20,7 @@ export interface MFAItem {
|
|||||||
styleUrls: ['./user-mfa.component.scss'],
|
styleUrls: ['./user-mfa.component.scss'],
|
||||||
})
|
})
|
||||||
export class UserMfaComponent implements OnInit, OnDestroy {
|
export class UserMfaComponent implements OnInit, OnDestroy {
|
||||||
public displayedColumns: string[] = ['type', 'state'];
|
public displayedColumns: string[] = ['type', 'state', 'actions'];
|
||||||
@Input() private user!: UserView.AsObject;
|
@Input() private user!: UserView.AsObject;
|
||||||
public mfaSubject: BehaviorSubject<UserMultiFactor.AsObject[]> = new BehaviorSubject<UserMultiFactor.AsObject[]>([]);
|
public mfaSubject: BehaviorSubject<UserMultiFactor.AsObject[]> = new BehaviorSubject<UserMultiFactor.AsObject[]>([]);
|
||||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
@ -31,7 +34,7 @@ export class UserMfaComponent implements OnInit, OnDestroy {
|
|||||||
public MFAState: any = MFAState;
|
public MFAState: any = MFAState;
|
||||||
|
|
||||||
public error: string = '';
|
public error: string = '';
|
||||||
constructor(private mgmtUserService: ManagementService) { }
|
constructor(private mgmtUserService: ManagementService, private dialog: MatDialog, private toast: ToastService) { }
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
this.getOTP();
|
this.getOTP();
|
||||||
@ -50,4 +53,34 @@ export class UserMfaComponent implements OnInit, OnDestroy {
|
|||||||
this.error = error.message;
|
this.error = error.message;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public deleteMFA(type: MfaType): void {
|
||||||
|
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||||
|
data: {
|
||||||
|
confirmKey: 'ACTIONS.DELETE',
|
||||||
|
cancelKey: 'ACTIONS.CANCEL',
|
||||||
|
titleKey: 'USER.MFA.DIALOG.OTP_DELETE_TITLE',
|
||||||
|
descriptionKey: 'USER.MFA.DIALOG.OTP_DELETE_DESCRIPTION',
|
||||||
|
},
|
||||||
|
width: '400px',
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe(resp => {
|
||||||
|
if (resp) {
|
||||||
|
if (type === MfaType.MFATYPE_OTP) {
|
||||||
|
this.mgmtUserService.removeMfaOTP(this.user.id).then(() => {
|
||||||
|
this.toast.showInfo('USER.TOAST.OTPREMOVED', true);
|
||||||
|
|
||||||
|
const index = this.dataSource.data.findIndex(mfa => mfa.type === type);
|
||||||
|
if (index > -1) {
|
||||||
|
this.dataSource.data.splice(index, 1);
|
||||||
|
}
|
||||||
|
this.getOTP();
|
||||||
|
}).catch(error => {
|
||||||
|
this.toast.showError(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,6 +677,12 @@ export class ManagementService {
|
|||||||
return this.grpcService.mgmt.getUserMfas(req);
|
return this.grpcService.mgmt.getUserMfas(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public removeMfaOTP(id: string): Promise<Empty> {
|
||||||
|
const req = new UserID();
|
||||||
|
req.setId(id);
|
||||||
|
return this.grpcService.mgmt.removeMfaOTP(req);
|
||||||
|
}
|
||||||
|
|
||||||
public SaveUserProfile(
|
public SaveUserProfile(
|
||||||
id: string,
|
id: string,
|
||||||
firstName?: string,
|
firstName?: string,
|
||||||
|
@ -221,6 +221,11 @@ func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*m
|
|||||||
return &management.UserMultiFactors{Mfas: mfasFromModel(mfas)}, nil
|
return &management.UserMultiFactors{Mfas: mfasFromModel(mfas)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) RemoveMfaOTP(ctx context.Context, userID *management.UserID) (*empty.Empty, error) {
|
||||||
|
err := s.user.RemoveOTP(ctx, userID.Id)
|
||||||
|
return &empty.Empty{}, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) SearchUserMemberships(ctx context.Context, in *management.UserMembershipSearchRequest) (*management.UserMembershipSearchResponse, error) {
|
func (s *Server) SearchUserMemberships(ctx context.Context, in *management.UserMembershipSearchRequest) (*management.UserMembershipSearchResponse, error) {
|
||||||
request := userMembershipSearchRequestsToModel(in)
|
request := userMembershipSearchRequestsToModel(in)
|
||||||
request.AppendUserIDQuery(in.UserId)
|
request.AppendUserIDQuery(in.UserId)
|
||||||
|
@ -223,6 +223,10 @@ func (repo *UserRepo) UserMfas(ctx context.Context, userID string) ([]*usr_model
|
|||||||
return []*usr_model.MultiFactor{{Type: usr_model.MfaTypeOTP, State: user.OTPState}}, nil
|
return []*usr_model.MultiFactor{{Type: usr_model.MfaTypeOTP, State: user.OTPState}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *UserRepo) RemoveOTP(ctx context.Context, userID string) error {
|
||||||
|
return repo.UserEvents.RemoveOTP(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
func (repo *UserRepo) SetOneTimePassword(ctx context.Context, password *usr_model.Password) (*usr_model.Password, error) {
|
func (repo *UserRepo) SetOneTimePassword(ctx context.Context, password *usr_model.Password) (*usr_model.Password, error) {
|
||||||
policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
|
||||||
if err != nil && caos_errs.IsNotFound(err) {
|
if err != nil && caos_errs.IsNotFound(err) {
|
||||||
|
@ -31,6 +31,7 @@ type UserRepository interface {
|
|||||||
ChangeProfile(ctx context.Context, profile *model.Profile) (*model.Profile, error)
|
ChangeProfile(ctx context.Context, profile *model.Profile) (*model.Profile, error)
|
||||||
|
|
||||||
UserMfas(ctx context.Context, userID string) ([]*model.MultiFactor, error)
|
UserMfas(ctx context.Context, userID string) ([]*model.MultiFactor, error)
|
||||||
|
RemoveOTP(ctx context.Context, userID string) error
|
||||||
|
|
||||||
SearchExternalIDPs(ctx context.Context, request *model.ExternalIDPSearchRequest) (*model.ExternalIDPSearchResponse, error)
|
SearchExternalIDPs(ctx context.Context, request *model.ExternalIDPSearchRequest) (*model.ExternalIDPSearchResponse, error)
|
||||||
RemoveExternalIDP(ctx context.Context, externalIDP *model.ExternalIDP) error
|
RemoveExternalIDP(ctx context.Context, externalIDP *model.ExternalIDP) error
|
||||||
|
@ -388,6 +388,16 @@ rpc GetUserByID(UserID) returns (UserView) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpc RemoveMfaOTP(UserID) returns (google.protobuf.Empty) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
delete: "/users/{id}/mfas/otp"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (caos.zitadel.utils.v1.auth_option) = {
|
||||||
|
permission: "user.write"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Sends an Notification (Email/SMS) with a password reset Link
|
// Sends an Notification (Email/SMS) with a password reset Link
|
||||||
rpc SendSetPasswordNotification(SetPasswordNotificationRequest) returns (google.protobuf.Empty) {
|
rpc SendSetPasswordNotification(SetPasswordNotificationRequest) returns (google.protobuf.Empty) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
|
Loading…
Reference in New Issue
Block a user