fix role mapping + create role if doesn't exit

This commit is contained in:
Hugo Renard 2022-04-25 12:42:30 +02:00
parent c957b152b7
commit 4cc01ed771
Signed by: hougo
GPG key ID: 3A285FD470209C59
7 changed files with 96 additions and 17 deletions

View file

@ -18,6 +18,7 @@ import { EmptyRequestError } from "../errors/EmptyRequestError";
import { EmptyResponseError } from "../errors/EmptyResponseError";
import { JsonParseError } from "../errors/JsonParseError";
import { SCIMError, SCIMErrorType } from "../scim/Error";
import { handleRcError } from "./common/endpoint";
import { Context } from "./Context";
type ApiEndpointMethod = (
@ -41,6 +42,7 @@ export abstract class ScimEndpoint extends ApiEndpoint {
public post: ApiEndpointMethod | undefined;
public put: ApiEndpointMethod | undefined;
public delete: ApiEndpointMethod | undefined;
protected handleError = handleRcError;
constructor(app: IApp) {
super(app);
@ -91,19 +93,6 @@ export abstract class ScimEndpoint extends ApiEndpoint {
}
}
protected handleError(o: any) {
if (!o.success) {
if (o.error?.includes("already in use")) {
throw new ConflictError(
o.error.includes("@") ? "email" : "username",
);
}
if (o.error?.includes("not found")) {
}
throw new Error(o.error);
}
}
private wrapMethod(name: string): ApiEndpointMethod | undefined {
const method = this[`_${name}`];
if (method === undefined || typeof method !== "function") {

View file

@ -2,6 +2,7 @@ import { HttpStatusCode } from "@rocket.chat/apps-engine/definition/accessors";
import { IApiResponse } from "@rocket.chat/apps-engine/definition/api";
import { SCIMError, SCIMErrorType } from "../scim/Error";
import { SCIMUser } from "../scim/User";
import { findOrCreateRole } from "./common/user";
import { Context } from "./Context";
import { IScimEndpoint, ScimEndpoint } from "./ScimEndpoint";
@ -27,6 +28,7 @@ export class UserEndpoint extends ScimEndpoint implements IScimEndpoint {
u.roles.push({ value: "admin" });
}
}
const roles = await findOrCreateRole(ctx, u);
const o = await ctx.rc.user.update({
userId: ctx.id(),
data: {
@ -35,7 +37,7 @@ export class UserEndpoint extends ScimEndpoint implements IScimEndpoint {
username: u.userName,
active: u.active,
verified: true,
roles: u.roles.map((x) => x.value),
roles,
customFields: {
scimExternalId: u.externalId,
},

View file

@ -3,6 +3,7 @@ import { IApiResponse } from "@rocket.chat/apps-engine/definition/api";
import crypto = require("crypto");
import { SCIMListResponse } from "../scim/ListResponse";
import { SCIMUser } from "../scim/User";
import { findOrCreateRole } from "./common/user";
import { Context } from "./Context";
import { IScimEndpoint, ScimEndpoint } from "./ScimEndpoint";
@ -28,12 +29,13 @@ export class UsersEndpoint extends ScimEndpoint implements IScimEndpoint {
public async _post(ctx: Context): Promise<IApiResponse> {
const u = SCIMUser.fromPlain(ctx.content());
const roles = await findOrCreateRole(ctx, u);
const o = await ctx.rc.user.create({
email: u.getEmail(),
name: u.displayName || u.userName,
username: u.userName,
password: crypto.randomBytes(64).toString("base64").slice(0, 64),
roles: u.roles.map((x) => x.value),
roles,
verified: true,
customFields: {
scimExternalId: u.externalId,

View file

@ -0,0 +1,14 @@
import { ConflictError } from "../../errors/ConflictError";
export function handleRcError(o: any) {
if (!o.success) {
if (o.error?.includes("already in use")) {
throw new ConflictError(
o.error.includes("@") ? "email" : "username",
);
}
if (o.error?.includes("not found")) {
}
throw new Error(o.error);
}
}

View file

@ -0,0 +1,25 @@
import { SCIMUser } from "../../scim/User";
import { Context } from "../Context";
import { handleRcError } from "./endpoint";
export async function findOrCreateRole(
ctx: Context,
user: SCIMUser,
): Promise<Array<string>> {
const listResp = await ctx.rc.role.list();
handleRcError(listResp);
const rcRoles = listResp.roles;
const roles = await Promise.all(
user.roles.map(async ({ value }) => {
let rcRole = rcRoles.find((x) => x.name === value);
if (!rcRole) {
const r = await ctx.rc.role.create({ name: value });
handleRcError(r);
rcRoles.push(r.role);
rcRole = r.role;
}
return rcRole._id;
}),
);
return roles;
}

View file

@ -7,6 +7,7 @@ import {
} from "@rocket.chat/apps-engine/definition/accessors";
import { EmptyResponseError } from "../errors/EmptyResponseError";
import { JsonParseError } from "../errors/JsonParseError";
import { RcSdkRole } from "./RcSdkRole";
import { RcSdkTeam } from "./RcSdkTeam";
import { RcSdkUser } from "./RcSdkUser";
@ -18,6 +19,7 @@ type RequestCallback = (
export class RcSdk {
public user: RcSdkUser;
public team: RcSdkTeam;
public role: RcSdkRole;
private readonly baseUrl = "http://localhost:3000/api/v1";
private readonly http: IHttp;
private readonly read: IRead;
@ -29,10 +31,11 @@ export class RcSdk {
this.logger = logger;
this.user = new RcSdkUser(this);
this.team = new RcSdkTeam(this);
this.role = new RcSdkRole(this);
}
public get(url: string, content?: any): Promise<any> {
return this.request(this.http.get, url, content);
public get(url: string, content?: any): Promise<any> {
return this.request(this.http.get, url, content);
}
public post(url: string, content?: any): Promise<any> {

44
src/rc-sdk/RcSdkRole.ts Normal file
View file

@ -0,0 +1,44 @@
import { RcSdk } from "./RcSdk";
interface IRoleCreate {
name: string;
scope?: string;
description?: boolean;
}
export interface IRole {
_id: string;
name: string;
scope?: string;
description?: boolean;
createdAt: string;
_updatedAt?: string;
}
interface IRoleListResponse {
roles: Array<IRole>;
count: number;
success: boolean;
error?: string;
}
interface IRoleResponse {
role: IRole;
success: boolean;
error?: string;
}
export class RcSdkRole {
private sdk: RcSdk;
constructor(sdk: RcSdk) {
this.sdk = sdk;
}
public list(): Promise<IRoleListResponse> {
return this.sdk.get(`roles.list`);
}
public create(body: IRoleCreate): Promise<IRoleResponse> {
return this.sdk.post(`roles.create`, body);
}
}