Continue moving SCIM userId refs to orgMembershipId

This commit is contained in:
Tuan Dang
2024-04-28 19:09:12 -07:00
parent 80da2a19aa
commit a7af3a48d9
13 changed files with 205 additions and 134 deletions

View File

@@ -2,4 +2,5 @@
frontend/src/views/Project/MembersPage/components/IdentityTab/components/IdentityRoleForm/IdentityRbacSection.tsx:generic-api-key:206
frontend/src/views/Project/MembersPage/components/IdentityTab/components/IdentityRoleForm/SpecificPrivilegeSection.tsx:generic-api-key:304
frontend/src/views/Project/MembersPage/components/MemberListTab/MemberRoleForm/MemberRbacSection.tsx:generic-api-key:206
frontend/src/views/Project/MembersPage/components/MemberListTab/MemberRoleForm/SpecificPrivilegeSection.tsx:generic-api-key:292
frontend/src/views/Project/MembersPage/components/MemberListTab/MemberRoleForm/SpecificPrivilegeSection.tsx:generic-api-key:292
docs/self-hosting/configuration/envars.mdx:generic-api-key:106

View File

@@ -152,8 +152,9 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log("GET /Users req.query: ", req.query);
const users = await req.server.services.scim.listScimUsers({
offset: req.query.startIndex,
startIndex: req.query.startIndex,
limit: req.query.count,
filter: req.query.filter,
orgId: req.permission.orgId
@@ -163,11 +164,11 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/Users/:userId",
url: "/Users/:orgMembershipId",
method: "GET",
schema: {
params: z.object({
userId: z.string().trim()
orgMembershipId: z.string().trim()
}),
response: {
201: z.object({
@@ -192,8 +193,9 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log(`GET /Users/${req.params.orgMembershipId}`);
const user = await req.server.services.scim.getScimUser({
userId: req.params.userId,
orgMembershipId: req.params.orgMembershipId,
orgId: req.permission.orgId
});
return user;
@@ -246,6 +248,8 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log("POST /Users req.body: ", req.body);
const primaryEmail = req.body.emails?.find((email) => email.primary)?.value;
const user = await req.server.services.scim.createScimUser({
@@ -261,11 +265,11 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/Users/:userId",
url: "/Users/:orgMembershipId",
method: "DELETE",
schema: {
params: z.object({
userId: z.string().trim()
orgMembershipId: z.string().trim()
}),
response: {
200: z.object({})
@@ -273,8 +277,9 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log(`DELETE /Users/${req.params.orgMembershipId}`);
const user = await req.server.services.scim.deleteScimUser({
userId: req.params.userId,
orgMembershipId: req.params.orgMembershipId,
orgId: req.permission.orgId
});
@@ -319,6 +324,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log("POST /Groups req.body: ", req.body);
const group = await req.server.services.scim.createScimGroup({
orgId: req.permission.orgId,
...req.body
@@ -359,6 +365,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log("GET /Groups req.query: ", req.query);
const groups = await req.server.services.scim.listScimGroups({
orgId: req.permission.orgId,
offset: req.query.startIndex,
@@ -395,6 +402,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log(`GET /Groups/${req.params.groupId}`);
const group = await req.server.services.scim.getScimGroup({
groupId: req.params.groupId,
orgId: req.permission.orgId
@@ -440,6 +448,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log(`PUT /Groups/${req.params.groupId} req.body: `, req.body);
const group = await req.server.services.scim.updateScimGroupNamePut({
groupId: req.params.groupId,
orgId: req.permission.orgId,
@@ -501,6 +510,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log(`PATCH /Groups/${req.params.groupId} req.body: `, req.body);
const group = await req.server.services.scim.updateScimGroupNamePatch({
groupId: req.params.groupId,
orgId: req.permission.orgId,
@@ -524,6 +534,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log(`DELETE /Groups/${req.params.groupId}`);
const group = await req.server.services.scim.deleteScimGroup({
groupId: req.params.groupId,
orgId: req.permission.orgId
@@ -534,11 +545,11 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/Users/:userId",
url: "/Users/:orgMembershipId",
method: "PUT",
schema: {
params: z.object({
userId: z.string().trim()
orgMembershipId: z.string().trim()
}),
body: z.object({
schemas: z.array(z.string()),
@@ -574,8 +585,9 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
handler: async (req) => {
console.log(`PUT /Users/${req.params.orgMembershipId} req.body: `, req.body);
const user = await req.server.services.scim.replaceScimUser({
userId: req.params.userId,
orgMembershipId: req.params.orgMembershipId,
orgId: req.permission.orgId,
active: req.body.active
});

View File

@@ -31,7 +31,7 @@ import { TProjectKeyDALFactory } from "@app/services/project-key/project-key-dal
import { TUserDALFactory } from "@app/services/user/user-dal";
import { normalizeUsername } from "@app/services/user/user-fns";
import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal";
import { TUserAliasType } from "@app/services/user-alias/user-alias-types";
import { UserAliasType } from "@app/services/user-alias/user-alias-types";
import { TLicenseServiceFactory } from "../license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
@@ -395,7 +395,7 @@ export const ldapConfigServiceFactory = ({
let userAlias = await userAliasDAL.findOne({
externalId,
orgId,
aliasType: TUserAliasType.LDAP
aliasType: UserAliasType.LDAP
});
const organization = await orgDAL.findOrgById(orgId);
@@ -449,7 +449,7 @@ export const ldapConfigServiceFactory = ({
{
userId: newUser.id,
username,
aliasType: TUserAliasType.LDAP,
aliasType: UserAliasType.LDAP,
externalId,
emails,
orgId
@@ -564,7 +564,7 @@ export const ldapConfigServiceFactory = ({
organizationId: organization.id,
organizationSlug: organization.slug,
authMethod: AuthMethod.LDAP,
authType: TUserAliasType.LDAP,
authType: UserAliasType.LDAP,
isUserCompleted,
...(relayState
? {

View File

@@ -17,8 +17,8 @@ export const getDefaultOnPremFeatures = () => {
customAlerts: false,
auditLogs: false,
auditLogsRetentionDays: 0,
samlSSO: true,
scim: true,
samlSSO: false,
scim: false,
ldap: false,
groups: false,
status: null,

View File

@@ -24,10 +24,10 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
customAlerts: false,
auditLogs: false,
auditLogsRetentionDays: 0,
samlSSO: true,
scim: true,
ldap: true,
groups: true,
samlSSO: false,
scim: false,
ldap: false,
groups: false,
status: null,
trial_end: null,
has_used_trial: true,

View File

@@ -40,8 +40,8 @@ export type TFeatureSet = {
customAlerts: false;
auditLogs: false;
auditLogsRetentionDays: 0;
samlSSO: true;
scim: true;
samlSSO: false;
scim: false;
ldap: false;
groups: false;
status: null;

View File

@@ -27,7 +27,7 @@ import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membe
import { TUserDALFactory } from "@app/services/user/user-dal";
import { normalizeUsername } from "@app/services/user/user-fns";
import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal";
import { TUserAliasType } from "@app/services/user-alias/user-alias-types";
import { UserAliasType } from "@app/services/user-alias/user-alias-types";
import { TLicenseServiceFactory } from "../license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
@@ -326,7 +326,7 @@ export const samlConfigServiceFactory = ({
const userAlias = await userAliasDAL.findOne({
externalId,
orgId,
aliasType: TUserAliasType.SAML
aliasType: UserAliasType.SAML
});
const organization = await orgDAL.findOrgById(orgId);
@@ -385,7 +385,7 @@ export const samlConfigServiceFactory = ({
await userAliasDAL.create(
{
userId: newUser.id,
aliasType: TUserAliasType.SAML,
aliasType: UserAliasType.SAML,
externalId,
emails: email ? [email] : [],
orgId
@@ -421,7 +421,7 @@ export const samlConfigServiceFactory = ({
organizationId: organization.id,
organizationSlug: organization.slug,
authMethod: authProvider,
authType: TUserAliasType.SAML,
authType: UserAliasType.SAML,
isUserCompleted,
...(relayState
? {

View File

@@ -2,31 +2,31 @@ import { TListScimGroups, TListScimUsers, TScimGroup, TScimUser } from "./scim-t
export const buildScimUserList = ({
scimUsers,
offset,
startIndex,
limit
}: {
scimUsers: TScimUser[];
offset: number;
startIndex: number;
limit: number;
}): TListScimUsers => {
return {
Resources: scimUsers,
itemsPerPage: limit,
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
startIndex: offset,
startIndex,
totalResults: scimUsers.length
};
};
export const buildScimUser = ({
userId,
orgMembershipId,
username,
email,
firstName,
lastName,
active
}: {
userId: string;
orgMembershipId: string;
username: string;
email?: string | null;
firstName: string;
@@ -35,7 +35,7 @@ export const buildScimUser = ({
}): TScimUser => {
const scimUser = {
schemas: ["urn:ietf:params:scim:schemas:core:2.0:User"],
id: userId,
id: orgMembershipId,
userName: username,
displayName: `${firstName} ${lastName}`,
name: {

View File

@@ -2,7 +2,7 @@ import { ForbiddenError } from "@casl/ability";
import slugify from "@sindresorhus/slugify";
import jwt from "jsonwebtoken";
import { OrgMembershipRole, OrgMembershipStatus, TableName, TGroups } from "@app/db/schemas";
import { OrgMembershipRole, OrgMembershipStatus, TableName, TGroups, TOrgMemberships, TUsers } from "@app/db/schemas";
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns";
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
@@ -11,16 +11,20 @@ import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ScimRequestError, UnauthorizedError } from "@app/lib/errors";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { TOrgPermission } from "@app/lib/types";
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
import { AuthTokenType } from "@app/services/auth/auth-type";
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
import { TOrgDALFactory } from "@app/services/org/org-dal";
import { deleteOrgMembership } from "@app/services/org/org-fns";
import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TProjectBotDALFactory } from "@app/services/project-bot/project-bot-dal";
import { TProjectKeyDALFactory } from "@app/services/project-key/project-key-dal";
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
import { TUserDALFactory } from "@app/services/user/user-dal";
import { normalizeUsername } from "@app/services/user/user-fns";
import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal";
import { UserAliasType } from "@app/services/user-alias/user-alias-types";
import { TLicenseServiceFactory } from "../license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
@@ -47,11 +51,16 @@ import {
type TScimServiceFactoryDep = {
scimDAL: Pick<TScimDALFactory, "create" | "find" | "findById" | "deleteById">;
userDAL: Pick<TUserDALFactory, "find" | "findOne" | "create" | "transaction" | "findUserEncKeyByUserIdsBatch">;
userDAL: Pick<
TUserDALFactory,
"find" | "findOne" | "create" | "transaction" | "findUserEncKeyByUserIdsBatch" | "findById"
>;
userAliasDAL: TUserAliasDALFactory; // TODO: pick
orgDAL: Pick<
TOrgDALFactory,
"createMembership" | "findById" | "findMembership" | "deleteMembershipById" | "transaction"
"createMembership" | "findById" | "findMembership" | "deleteMembershipById" | "transaction" | "updateMembershipById"
>;
orgMembershipDAL: TOrgMembershipDALFactory; // TODO: Pick
projectDAL: Pick<TProjectDALFactory, "find" | "findProjectGhostUser">;
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find" | "delete">;
groupDAL: Pick<
@@ -64,7 +73,7 @@ type TScimServiceFactoryDep = {
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
smtpService: TSmtpService;
smtpService: Pick<TSmtpService, "sendMail">;
};
export type TScimServiceFactory = ReturnType<typeof scimServiceFactory>;
@@ -75,7 +84,9 @@ export const scimServiceFactory = ({
licenseService,
scimDAL,
userDAL,
userAliasDAL,
orgDAL,
orgMembershipDAL,
projectDAL,
projectMembershipDAL,
groupDAL,
@@ -162,8 +173,13 @@ export const scimServiceFactory = ({
};
// SCIM server endpoints
const listScimUsers = async ({ offset, limit, filter, orgId }: TListScimUsersDTO): Promise<TListScimUsers> => {
console.log("listScimUsers"); // done
const listScimUsers = async ({ startIndex, limit, filter, orgId }: TListScimUsersDTO): Promise<TListScimUsers> => {
console.log("listScimUsers args: ", {
startIndex,
limit,
filter,
orgId
}); // done
const org = await orgDAL.findById(orgId);
if (!org.scimEnabled)
@@ -181,11 +197,11 @@ export const scimServiceFactory = ({
attributeName = "email";
}
return { [attributeName]: parsedValue };
return { [attributeName]: parsedValue.replace(/"/g, "") };
};
const findOpts = {
...(offset && { offset }),
...(startIndex && { offset: startIndex - 1 }),
...(limit && { limit })
};
@@ -197,11 +213,9 @@ export const scimServiceFactory = ({
findOpts
);
console.log("orgDAL.findMembership users: ", users);
const scimUsers = users.map(({ id, username, firstName, lastName, email }) =>
buildScimUser({
userId: id ?? "",
orgMembershipId: id ?? "",
username,
firstName: firstName ?? "",
lastName: lastName ?? "",
@@ -212,17 +226,20 @@ export const scimServiceFactory = ({
return buildScimUserList({
scimUsers,
offset,
startIndex,
limit
});
};
const getScimUser = async ({ userId, orgId }: TGetScimUserDTO) => {
console.log("getScimUser"); // done
const getScimUser = async ({ orgMembershipId, orgId }: TGetScimUserDTO) => {
console.log("getScimUser args: ", {
orgMembershipId,
orgId
}); // done
const [membership] = await orgDAL
.findMembership({
userId,
[`${TableName.OrgMembership}.orgId` as "id"]: orgId
[`${TableName.OrgMembership}.id` as "id"]: orgMembershipId,
[`${TableName.OrgMembership}.orgId` as "orgId"]: orgId
})
.catch(() => {
throw new ScimRequestError({
@@ -246,7 +263,7 @@ export const scimServiceFactory = ({
console.log("getScimUser membership: ", membership);
return buildScimUser({
userId: membership.id,
orgMembershipId: membership.id,
username: membership.username,
email: membership.email ?? "",
firstName: membership.firstName as string,
@@ -256,7 +273,14 @@ export const scimServiceFactory = ({
};
const createScimUser = async ({ username, email, firstName, lastName, orgId }: TCreateScimUserDTO) => {
console.log("createScimUser"); // TODO: update implementation to always create a new user and be based on orgMembershipId
// do we get external ID or not?
console.log("createScimUser args: ", {
username,
email,
firstName,
lastName,
orgId
});
const org = await orgDAL.findById(orgId);
if (!org)
@@ -271,67 +295,85 @@ export const scimServiceFactory = ({
status: 403
});
let user = await userDAL.findOne({
username
const appCfg = getConfig();
const userAlias = await userAliasDAL.findOne({
externalId: username,
orgId,
aliasType: UserAliasType.SAML
});
if (user) {
await userDAL.transaction(async (tx) => {
const [orgMembership] = await orgDAL.findMembership(
const { user: createdUser, orgMembership: createdOrgMembership } = await userDAL.transaction(async (tx) => {
let user: TUsers;
let orgMembership: TOrgMemberships;
if (userAlias) {
user = await userDAL.findById(userAlias.userId, tx);
orgMembership = await orgMembershipDAL.findOne(
{
userId: user.id,
[`${TableName.OrgMembership}.orgId` as "id"]: orgId
},
{ tx }
);
if (orgMembership)
throw new ScimRequestError({
detail: "User already exists in the database",
status: 409
});
if (!orgMembership) {
await orgDAL.createMembership(
{
userId: user.id,
orgId,
inviteEmail: email,
role: OrgMembershipRole.Member,
status: OrgMembershipStatus.Invited
},
tx
);
}
});
} else {
user = await userDAL.transaction(async (tx) => {
const newUser = await userDAL.create(
{
username,
email,
firstName,
lastName,
authMethods: [AuthMethod.EMAIL],
isGhost: false
orgId
},
tx
);
await orgDAL.createMembership(
if (!orgMembership) {
orgMembership = await orgMembershipDAL.create(
{
userId: userAlias.userId,
inviteEmail: email,
orgId,
role: OrgMembershipRole.Member,
status: user.isAccepted ? OrgMembershipStatus.Accepted : OrgMembershipStatus.Invited // if user is fully completed, then set status to accepted, otherwise set it to invited so we can update it later
},
tx
);
} else if (orgMembership.status === OrgMembershipStatus.Invited && user.isAccepted) {
orgMembership = await orgMembershipDAL.updateById(
orgMembership.id,
{
status: OrgMembershipStatus.Accepted
},
tx
);
}
} else {
const uniqueUsername = await normalizeUsername(username, userDAL);
user = await userDAL.create(
{
username: uniqueUsername,
email,
isEmailVerified: appCfg.TRUST_SAML_EMAILS,
firstName,
lastName,
authMethods: [],
isGhost: false
},
tx
);
await userAliasDAL.create(
{
userId: user.id,
aliasType: UserAliasType.SAML,
externalId: username,
emails: email ? [email] : [],
orgId
},
tx
);
orgMembership = await orgMembershipDAL.create(
{
userId: user.id,
inviteEmail: email,
orgId,
userId: newUser.id,
role: OrgMembershipRole.Member,
status: OrgMembershipStatus.Invited
},
tx
);
return newUser;
});
}
}
const appCfg = getConfig();
return { user, orgMembership };
});
if (email) {
await smtpService.sendMail({
@@ -346,11 +388,11 @@ export const scimServiceFactory = ({
}
return buildScimUser({
userId: user.id,
username: user.username,
firstName: user.firstName as string,
lastName: user.lastName as string,
email: user.email ?? "",
orgMembershipId: createdOrgMembership.id,
username: createdUser.username,
firstName: createdUser.firstName as string,
lastName: createdUser.lastName as string,
email: createdUser.email ?? "",
active: true
});
};
@@ -406,7 +448,7 @@ export const scimServiceFactory = ({
}
return buildScimUser({
userId: membership.id,
orgMembershipId: membership.id,
username: membership.username,
email: membership.email,
firstName: membership.firstName as string,
@@ -415,12 +457,16 @@ export const scimServiceFactory = ({
});
};
const replaceScimUser = async ({ userId, active, orgId }: TReplaceScimUserDTO) => {
console.log("replaceScimUser"); // done
const replaceScimUser = async ({ orgMembershipId, active, orgId }: TReplaceScimUserDTO) => {
console.log("replaceScimUser args: ", {
orgMembershipId,
orgId,
active
}); // done
const [membership] = await orgDAL
.findMembership({
userId,
[`${TableName.OrgMembership}.orgId` as "id"]: orgId
[`${TableName.OrgMembership}.id` as "id"]: orgMembershipId,
[`${TableName.OrgMembership}.orgId` as "orgId"]: orgId
})
.catch(() => {
throw new ScimRequestError({
@@ -453,7 +499,7 @@ export const scimServiceFactory = ({
}
return buildScimUser({
userId: membership.id,
orgMembershipId: membership.id,
username: membership.username,
email: membership.email,
firstName: membership.firstName as string,
@@ -462,19 +508,15 @@ export const scimServiceFactory = ({
});
};
const deleteScimUser = async ({ userId, orgId }: TDeleteScimUserDTO) => {
console.log("deleteScimUser"); // done
const [membership] = await orgDAL
.findMembership({
userId,
[`${TableName.OrgMembership}.orgId` as "id"]: orgId
})
.catch(() => {
throw new ScimRequestError({
detail: "User not found",
status: 404
});
});
const deleteScimUser = async ({ orgMembershipId, orgId }: TDeleteScimUserDTO) => {
console.log("deleteScimUser args: ", {
orgMembershipId,
orgId
}); // done
const [membership] = await orgDAL.findMembership({
[`${TableName.OrgMembership}.id` as "id"]: orgMembershipId,
[`${TableName.OrgMembership}.orgId` as "orgId"]: orgId
});
if (!membership)
throw new ScimRequestError({
@@ -593,12 +635,19 @@ export const scimServiceFactory = ({
return { group, newMembers: [] };
});
const orgMemberships = await orgDAL.findMembership({
orgId,
$in: {
userId: newGroup.newMembers.map((member) => member.id)
}
});
return buildScimGroup({
groupId: newGroup.group.id,
name: newGroup.group.name,
members: newGroup.newMembers.map((member) => ({
value: member.id,
display: `${member.firstName} ${member.lastName}`
members: orgMemberships.map(({ id, firstName, lastName }) => ({
value: id,
display: `${firstName} ${lastName}`
}))
});
};
@@ -627,15 +676,20 @@ export const scimServiceFactory = ({
groupId: group.id
});
const orgMemberships = await orgDAL.findMembership({
orgId,
$in: {
userId: users.filter((user) => user.isPartOfGroup).map((user) => user.id)
}
});
return buildScimGroup({
groupId: group.id,
name: group.name,
members: users
.filter((user) => user.isPartOfGroup)
.map((user) => ({
value: user.id,
display: `${user.firstName} ${user.lastName}`
}))
members: orgMemberships.map(({ id, firstName, lastName }) => ({
value: id,
display: `${firstName} ${lastName}`
}))
});
};

View File

@@ -12,7 +12,7 @@ export type TDeleteScimTokenDTO = {
// SCIM server endpoint types
export type TListScimUsersDTO = {
offset: number;
startIndex: number;
limit: number;
filter?: string;
orgId: string;
@@ -27,7 +27,7 @@ export type TListScimUsers = {
};
export type TGetScimUserDTO = {
userId: string;
orgMembershipId: string;
orgId: string;
};
@@ -54,13 +54,13 @@ export type TUpdateScimUserDTO = {
};
export type TReplaceScimUserDTO = {
userId: string;
orgMembershipId: string;
active: boolean;
orgId: string;
};
export type TDeleteScimUserDTO = {
userId: string;
orgMembershipId: string;
orgId: string;
};

View File

@@ -292,7 +292,9 @@ export const registerRoutes = async (
licenseService,
scimDAL,
userDAL,
userAliasDAL,
orgDAL,
orgMembershipDAL,
projectDAL,
projectMembershipDAL,
groupDAL,

View File

@@ -34,6 +34,8 @@ export const deleteOrgMembership = async ({
tx
);
// TODO: delete associated aliases
return orgMembership;
});

View File

@@ -1,4 +1,4 @@
export enum TUserAliasType {
export enum UserAliasType {
LDAP = "ldap",
SAML = "saml"
}