mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-14 00:19:16 +01:00
feat: implement a way to purge scim users
This commit is contained in:
parent
bf71d397a9
commit
e203d26f64
@ -272,6 +272,10 @@ class UserStore implements IUserStore {
|
|||||||
await this.activeUsers().del();
|
await this.activeUsers().del();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteScimUsers(): Promise<void> {
|
||||||
|
await this.db(TABLE).whereNotNull('scim_id').del();
|
||||||
|
}
|
||||||
|
|
||||||
async count(): Promise<number> {
|
async count(): Promise<number> {
|
||||||
return this.activeUsers()
|
return this.activeUsers()
|
||||||
.count('*')
|
.count('*')
|
||||||
|
@ -441,6 +441,26 @@ export default class UserAdminController extends Controller {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//add a method to delete all scim users
|
||||||
|
this.route({
|
||||||
|
method: 'delete',
|
||||||
|
path: '/scim-users',
|
||||||
|
handler: this.deleteScimUsers,
|
||||||
|
permission: ADMIN,
|
||||||
|
middleware: [
|
||||||
|
openApiService.validPath({
|
||||||
|
tags: ['Users'],
|
||||||
|
operationId: 'deleteScimUsers',
|
||||||
|
summary: 'Delete all SCIM users',
|
||||||
|
description: 'Deletes all users managed by SCIM',
|
||||||
|
responses: {
|
||||||
|
200: emptyResponse,
|
||||||
|
...getStandardResponses(401, 403),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async resetUserPassword(
|
async resetUserPassword(
|
||||||
@ -766,4 +786,10 @@ export default class UserAdminController extends Controller {
|
|||||||
Boolean((await this.userService.getUser(id)).scimId)
|
Boolean((await this.userService.getUser(id)).scimId)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteScimUsers(req: IAuthRequest, res: Response): Promise<void> {
|
||||||
|
const { audit } = req;
|
||||||
|
await this.userService.deleteScimUsers(audit);
|
||||||
|
res.status(200).send();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import type SessionService from './session-service';
|
|||||||
import type { IUnleashStores } from '../types/stores';
|
import type { IUnleashStores } from '../types/stores';
|
||||||
import PasswordUndefinedError from '../error/password-undefined';
|
import PasswordUndefinedError from '../error/password-undefined';
|
||||||
import {
|
import {
|
||||||
|
ScimUsersDeleted,
|
||||||
UserCreatedEvent,
|
UserCreatedEvent,
|
||||||
UserDeletedEvent,
|
UserDeletedEvent,
|
||||||
UserUpdatedEvent,
|
UserUpdatedEvent,
|
||||||
@ -398,6 +399,17 @@ class UserService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteScimUsers(auditUser: IAuditUser): Promise<void> {
|
||||||
|
await this.store.deleteScimUsers();
|
||||||
|
|
||||||
|
await this.eventService.storeEvent(
|
||||||
|
new ScimUsersDeleted({
|
||||||
|
data: null,
|
||||||
|
auditUser,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async loginUser(
|
async loginUser(
|
||||||
usernameOrEmail: string,
|
usernameOrEmail: string,
|
||||||
password: string,
|
password: string,
|
||||||
|
@ -217,6 +217,8 @@ export const RELEASE_PLAN_MILESTONE_STARTED =
|
|||||||
'release-plan-milestone-started' as const;
|
'release-plan-milestone-started' as const;
|
||||||
|
|
||||||
export const USER_PREFERENCE_UPDATED = 'user-preference-updated' as const;
|
export const USER_PREFERENCE_UPDATED = 'user-preference-updated' as const;
|
||||||
|
export const SCIM_USERS_DELETED = 'scim-users-deleted' as const;
|
||||||
|
export const SCIM_GROUPS_DELETED = 'scim-groups-deleted' as const;
|
||||||
|
|
||||||
export const IEventTypes = [
|
export const IEventTypes = [
|
||||||
APPLICATION_CREATED,
|
APPLICATION_CREATED,
|
||||||
@ -372,6 +374,8 @@ export const IEventTypes = [
|
|||||||
RELEASE_PLAN_REMOVED,
|
RELEASE_PLAN_REMOVED,
|
||||||
RELEASE_PLAN_MILESTONE_STARTED,
|
RELEASE_PLAN_MILESTONE_STARTED,
|
||||||
USER_PREFERENCE_UPDATED,
|
USER_PREFERENCE_UPDATED,
|
||||||
|
SCIM_USERS_DELETED,
|
||||||
|
SCIM_GROUPS_DELETED,
|
||||||
] as const;
|
] as const;
|
||||||
export type IEventType = (typeof IEventTypes)[number];
|
export type IEventType = (typeof IEventTypes)[number];
|
||||||
|
|
||||||
@ -1608,6 +1612,30 @@ export class UserDeletedEvent extends BaseEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ScimUsersDeleted extends BaseEvent {
|
||||||
|
readonly data: any;
|
||||||
|
|
||||||
|
constructor(eventData: {
|
||||||
|
data: any;
|
||||||
|
auditUser: IAuditUser;
|
||||||
|
}) {
|
||||||
|
super(SCIM_USERS_DELETED, eventData.auditUser);
|
||||||
|
this.data = eventData.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScimGroupsDeleted extends BaseEvent {
|
||||||
|
readonly data: any;
|
||||||
|
|
||||||
|
constructor(eventData: {
|
||||||
|
data: any;
|
||||||
|
auditUser: IAuditUser;
|
||||||
|
}) {
|
||||||
|
super(SCIM_GROUPS_DELETED, eventData.auditUser);
|
||||||
|
this.data = eventData.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class TagTypeCreatedEvent extends BaseEvent {
|
export class TagTypeCreatedEvent extends BaseEvent {
|
||||||
readonly data: any;
|
readonly data: any;
|
||||||
|
|
||||||
|
@ -40,4 +40,5 @@ export interface IUserStore extends Store<IUser, number> {
|
|||||||
count(): Promise<number>;
|
count(): Promise<number>;
|
||||||
countRecentlyDeleted(): Promise<number>;
|
countRecentlyDeleted(): Promise<number>;
|
||||||
countServiceAccounts(): Promise<number>;
|
countServiceAccounts(): Promise<number>;
|
||||||
|
deleteScimUsers(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
4
src/test/fixtures/fake-user-store.ts
vendored
4
src/test/fixtures/fake-user-store.ts
vendored
@ -159,6 +159,10 @@ class UserStoreMock implements IUserStore {
|
|||||||
return Promise.resolve(undefined);
|
return Promise.resolve(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteScimUsers(): Promise<void> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
upsert(user: ICreateUser): Promise<IUser> {
|
upsert(user: ICreateUser): Promise<IUser> {
|
||||||
this.data.splice(this.data.findIndex((u) => u.email === user.email));
|
this.data.splice(this.data.findIndex((u) => u.email === user.email));
|
||||||
const userToReturn = {
|
const userToReturn = {
|
||||||
|
Loading…
Reference in New Issue
Block a user