mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 05:27:52 +00:00
Continue making progress on SCIM groups
This commit is contained in:
@@ -206,7 +206,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
schema: {
|
schema: {
|
||||||
body: z.object({
|
body: z.object({
|
||||||
schemas: z.array(z.string()),
|
schemas: z.array(z.string()),
|
||||||
userName: z.string().trim().email(),
|
userName: z.string().trim(),
|
||||||
name: z.object({
|
name: z.object({
|
||||||
familyName: z.string().trim(),
|
familyName: z.string().trim(),
|
||||||
givenName: z.string().trim()
|
givenName: z.string().trim()
|
||||||
@@ -227,7 +227,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
200: z.object({
|
200: z.object({
|
||||||
schemas: z.array(z.string()),
|
schemas: z.array(z.string()),
|
||||||
id: z.string().trim(),
|
id: z.string().trim(),
|
||||||
userName: z.string().trim().email(),
|
userName: z.string().trim(),
|
||||||
name: z.object({
|
name: z.object({
|
||||||
familyName: z.string().trim(),
|
familyName: z.string().trim(),
|
||||||
givenName: z.string().trim()
|
givenName: z.string().trim()
|
||||||
@@ -260,6 +260,28 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/Users/:userId",
|
||||||
|
method: "DELETE",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
userId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const user = await req.server.services.scim.deleteScimUser({
|
||||||
|
userId: req.params.userId,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
url: "/Groups",
|
url: "/Groups",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -267,7 +289,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
schemas: z.array(z.string()),
|
schemas: z.array(z.string()),
|
||||||
displayName: z.string().trim(),
|
displayName: z.string().trim(),
|
||||||
members: z.array(z.any()).length(0)
|
members: z.array(z.any()).length(0).optional() // okta-specific
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
@@ -292,6 +314,47 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/Groups",
|
||||||
|
method: "GET",
|
||||||
|
schema: {
|
||||||
|
querystring: z.object({
|
||||||
|
startIndex: z.coerce.number().default(1),
|
||||||
|
count: z.coerce.number().default(20),
|
||||||
|
filter: z.string().trim().optional()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
Resources: z.array(
|
||||||
|
z.object({
|
||||||
|
schemas: z.array(z.string()),
|
||||||
|
id: z.string().trim(),
|
||||||
|
displayName: z.string().trim(),
|
||||||
|
members: z.array(z.any()).length(0),
|
||||||
|
meta: z.object({
|
||||||
|
resourceType: z.string().trim()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
),
|
||||||
|
itemsPerPage: z.number(),
|
||||||
|
schemas: z.array(z.string()),
|
||||||
|
startIndex: z.number(),
|
||||||
|
totalResults: z.number()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const groups = await req.server.services.scim.listScimGroups({
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
offset: req.query.startIndex,
|
||||||
|
limit: req.query.count
|
||||||
|
});
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
url: "/Groups/:groupId",
|
url: "/Groups/:groupId",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@@ -358,7 +421,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
|
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const group = await req.server.services.scim.updateScimGroupName({
|
const group = await req.server.services.scim.updateScimGroupNamePut({
|
||||||
groupId: req.params.groupId,
|
groupId: req.params.groupId,
|
||||||
orgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
displayName: req.body.displayName
|
displayName: req.body.displayName
|
||||||
@@ -368,6 +431,69 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
url: "/Groups/:groupId",
|
||||||
|
method: "PATCH",
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
groupId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
schemas: z.array(z.string()),
|
||||||
|
Operations: z.array(
|
||||||
|
z.union([
|
||||||
|
z.object({
|
||||||
|
op: z.literal("replace"),
|
||||||
|
value: z.object({
|
||||||
|
id: z.string().trim(),
|
||||||
|
displayName: z.string().trim()
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
op: z.literal("remove"),
|
||||||
|
path: z.string().trim()
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
op: z.literal("add"),
|
||||||
|
value: z.object({
|
||||||
|
value: z.string().trim(),
|
||||||
|
display: z.string().trim().optional()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
schemas: z.array(z.string()),
|
||||||
|
id: z.string().trim(),
|
||||||
|
displayName: z.string().trim(),
|
||||||
|
members: z.array(
|
||||||
|
z.object({
|
||||||
|
value: z.string(),
|
||||||
|
display: z.string()
|
||||||
|
})
|
||||||
|
),
|
||||||
|
meta: z.object({
|
||||||
|
resourceType: z.string().trim()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
|
||||||
|
handler: async (req) => {
|
||||||
|
console.log("PATCH /Groups/:groupId req.body: ", req.body);
|
||||||
|
console.log("PATCH /Groups/:groupId req.body: ", req.body.Operations[0]);
|
||||||
|
const group = await req.server.services.scim.updateScimGroupNamePatch({
|
||||||
|
groupId: req.params.groupId,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
operations: req.body.Operations
|
||||||
|
});
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
url: "/Groups/:groupId",
|
url: "/Groups/:groupId",
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
|
|||||||
@@ -1,15 +1,35 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { TableName, TGroups } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
import { buildFindFilter, ormify, selectAllTableCols, TFindFilter, TFindOpt } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TGroupDALFactory = ReturnType<typeof groupDALFactory>;
|
export type TGroupDALFactory = ReturnType<typeof groupDALFactory>;
|
||||||
|
|
||||||
export const groupDALFactory = (db: TDbClient) => {
|
export const groupDALFactory = (db: TDbClient) => {
|
||||||
const groupOrm = ormify(db, TableName.Groups);
|
const groupOrm = ormify(db, TableName.Groups);
|
||||||
|
|
||||||
|
const findGroups = async (filter: TFindFilter<TGroups>, { offset, limit, sort, tx }: TFindOpt<TGroups> = {}) => {
|
||||||
|
try {
|
||||||
|
const query = (tx || db)(TableName.Groups)
|
||||||
|
// eslint-disable-next-line
|
||||||
|
.where(buildFindFilter(filter))
|
||||||
|
.select(selectAllTableCols(TableName.Groups));
|
||||||
|
|
||||||
|
if (limit) void query.limit(limit);
|
||||||
|
if (offset) void query.limit(offset);
|
||||||
|
if (sort) {
|
||||||
|
void query.orderBy(sort.map(([column, order, nulls]) => ({ column: column as string, order, nulls })));
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await query;
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
throw new DatabaseError({ error: err, name: "Find groups" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const findByOrgId = async (orgId: string, tx?: Knex) => {
|
const findByOrgId = async (orgId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const docs = await (tx || db)(TableName.Groups)
|
const docs = await (tx || db)(TableName.Groups)
|
||||||
@@ -78,6 +98,7 @@ export const groupDALFactory = (db: TDbClient) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
findGroups,
|
||||||
findByOrgId,
|
findByOrgId,
|
||||||
findAllGroupMembers,
|
findAllGroupMembers,
|
||||||
...groupOrm
|
...groupOrm
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TListScimUsers, TScimUser } from "./scim-types";
|
import { TListScimGroups, TListScimUsers, TScimGroup, TScimUser } from "./scim-types";
|
||||||
|
|
||||||
export const buildScimUserList = ({
|
export const buildScimUserList = ({
|
||||||
scimUsers,
|
scimUsers,
|
||||||
@@ -63,6 +63,24 @@ export const buildScimUser = ({
|
|||||||
return scimUser;
|
return scimUser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const buildScimGroupList = ({
|
||||||
|
scimGroups,
|
||||||
|
offset,
|
||||||
|
limit
|
||||||
|
}: {
|
||||||
|
scimGroups: TScimGroup[];
|
||||||
|
offset: number;
|
||||||
|
limit: number;
|
||||||
|
}): TListScimGroups => {
|
||||||
|
return {
|
||||||
|
Resources: scimGroups,
|
||||||
|
itemsPerPage: limit,
|
||||||
|
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
||||||
|
startIndex: offset,
|
||||||
|
totalResults: scimGroups.length
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const buildScimGroup = ({
|
export const buildScimGroup = ({
|
||||||
groupId,
|
groupId,
|
||||||
name,
|
name,
|
||||||
@@ -74,14 +92,15 @@ export const buildScimGroup = ({
|
|||||||
value: string;
|
value: string;
|
||||||
display: string;
|
display: string;
|
||||||
}[];
|
}[];
|
||||||
}) => {
|
}): TScimGroup => {
|
||||||
const scimGroup = {
|
const scimGroup = {
|
||||||
schemas: ["urn:ietf:params:scim:schemas:core:2.0:Group"],
|
schemas: ["urn:ietf:params:scim:schemas:core:2.0:Group"],
|
||||||
id: groupId,
|
id: groupId,
|
||||||
displayName: name,
|
displayName: name,
|
||||||
members,
|
members,
|
||||||
meta: {
|
meta: {
|
||||||
resourceType: "Group"
|
resourceType: "Group",
|
||||||
|
location: null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
|
|
||||||
import { OrgMembershipRole, OrgMembershipStatus, TableName } from "@app/db/schemas";
|
import { OrgMembershipRole, OrgMembershipStatus, TableName, TGroups } from "@app/db/schemas";
|
||||||
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
||||||
import { TScimDALFactory } from "@app/ee/services/scim/scim-dal";
|
import { TScimDALFactory } from "@app/ee/services/scim/scim-dal";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
@@ -20,20 +20,23 @@ import { TUserDALFactory } from "@app/services/user/user-dal";
|
|||||||
import { TLicenseServiceFactory } from "../license/license-service";
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||||
import { buildScimGroup, buildScimUser, buildScimUserList } from "./scim-fns";
|
import { buildScimGroup, buildScimGroupList, buildScimUser, buildScimUserList } from "./scim-fns";
|
||||||
import {
|
import {
|
||||||
TCreateScimGroupDTO,
|
TCreateScimGroupDTO,
|
||||||
TCreateScimTokenDTO,
|
TCreateScimTokenDTO,
|
||||||
TCreateScimUserDTO,
|
TCreateScimUserDTO,
|
||||||
TDeleteScimGroupDTO,
|
TDeleteScimGroupDTO,
|
||||||
TDeleteScimTokenDTO,
|
TDeleteScimTokenDTO,
|
||||||
|
TDeleteScimUserDTO,
|
||||||
TGetScimGroupDTO,
|
TGetScimGroupDTO,
|
||||||
TGetScimUserDTO,
|
TGetScimUserDTO,
|
||||||
|
TListScimGroupsDTO,
|
||||||
TListScimUsers,
|
TListScimUsers,
|
||||||
TListScimUsersDTO,
|
TListScimUsersDTO,
|
||||||
TReplaceScimUserDTO,
|
TReplaceScimUserDTO,
|
||||||
TScimTokenJwtPayload,
|
TScimTokenJwtPayload,
|
||||||
TUpdateScimGroupNameDTO,
|
TUpdateScimGroupNamePatchDTO,
|
||||||
|
TUpdateScimGroupNamePutDTO,
|
||||||
TUpdateScimUserDTO
|
TUpdateScimUserDTO
|
||||||
} from "./scim-types";
|
} from "./scim-types";
|
||||||
|
|
||||||
@@ -46,7 +49,7 @@ type TScimServiceFactoryDep = {
|
|||||||
>;
|
>;
|
||||||
projectDAL: Pick<TProjectDALFactory, "find">;
|
projectDAL: Pick<TProjectDALFactory, "find">;
|
||||||
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find" | "delete">;
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find" | "delete">;
|
||||||
groupDAL: Pick<TGroupDALFactory, "create" | "findOne" | "findAllGroupMembers" | "update" | "delete">;
|
groupDAL: Pick<TGroupDALFactory, "create" | "findOne" | "findAllGroupMembers" | "update" | "delete" | "findGroups">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
smtpService: TSmtpService;
|
smtpService: TSmtpService;
|
||||||
@@ -432,7 +435,80 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteScimUser = async ({ userId, orgId }: TDeleteScimUserDTO) => {
|
||||||
|
const [membership] = await orgDAL
|
||||||
|
.findMembership({
|
||||||
|
userId,
|
||||||
|
[`${TableName.OrgMembership}.orgId` as "id"]: orgId
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
throw new ScimRequestError({
|
||||||
|
detail: "User not found",
|
||||||
|
status: 404
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership)
|
||||||
|
throw new ScimRequestError({
|
||||||
|
detail: "User not found",
|
||||||
|
status: 404
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!membership.scimEnabled) {
|
||||||
|
throw new ScimRequestError({
|
||||||
|
detail: "SCIM is disabled for the organization",
|
||||||
|
status: 403
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await deleteOrgMembership({
|
||||||
|
orgMembershipId: membership.id,
|
||||||
|
orgId: membership.orgId,
|
||||||
|
orgDAL,
|
||||||
|
projectDAL,
|
||||||
|
projectMembershipDAL
|
||||||
|
});
|
||||||
|
|
||||||
|
return {}; // intentionally return empty object upon success
|
||||||
|
};
|
||||||
|
|
||||||
|
const listScimGroups = async ({ orgId, offset, limit }: TListScimGroupsDTO) => {
|
||||||
|
const org = await orgDAL.findById(orgId);
|
||||||
|
|
||||||
|
if (!org.scimEnabled)
|
||||||
|
throw new ScimRequestError({
|
||||||
|
detail: "SCIM is disabled for the organization",
|
||||||
|
status: 403
|
||||||
|
});
|
||||||
|
|
||||||
|
const groups = await groupDAL.findGroups({
|
||||||
|
orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
const scimGroups = groups.map((group) =>
|
||||||
|
buildScimGroup({
|
||||||
|
groupId: group.id,
|
||||||
|
name: group.name,
|
||||||
|
members: []
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return buildScimGroupList({
|
||||||
|
scimGroups,
|
||||||
|
offset,
|
||||||
|
limit
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const createScimGroup = async ({ displayName, orgId }: TCreateScimGroupDTO) => {
|
const createScimGroup = async ({ displayName, orgId }: TCreateScimGroupDTO) => {
|
||||||
|
const org = await orgDAL.findById(orgId);
|
||||||
|
|
||||||
|
if (!org.scimEnabled)
|
||||||
|
throw new ScimRequestError({
|
||||||
|
detail: "SCIM is disabled for the organization",
|
||||||
|
status: 403
|
||||||
|
});
|
||||||
|
|
||||||
const group = await groupDAL.create({
|
const group = await groupDAL.create({
|
||||||
name: displayName,
|
name: displayName,
|
||||||
slug: slugify(`${displayName}-${alphaNumericNanoId(4)}`),
|
slug: slugify(`${displayName}-${alphaNumericNanoId(4)}`),
|
||||||
@@ -474,7 +550,7 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateScimGroupName = async ({ groupId, orgId, displayName }: TUpdateScimGroupNameDTO) => {
|
const updateScimGroupNamePut = async ({ groupId, orgId, displayName }: TUpdateScimGroupNamePutDTO) => {
|
||||||
const [group] = await groupDAL.update(
|
const [group] = await groupDAL.update(
|
||||||
{
|
{
|
||||||
id: groupId,
|
id: groupId,
|
||||||
@@ -499,6 +575,62 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: add support for add/remove op
|
||||||
|
const updateScimGroupNamePatch = async ({ groupId, orgId, operations }: TUpdateScimGroupNamePatchDTO) => {
|
||||||
|
const org = await orgDAL.findById(orgId);
|
||||||
|
|
||||||
|
if (!org.scimEnabled)
|
||||||
|
throw new ScimRequestError({
|
||||||
|
detail: "SCIM is disabled for the organization",
|
||||||
|
status: 403
|
||||||
|
});
|
||||||
|
|
||||||
|
let group: TGroups | undefined;
|
||||||
|
for await (const operation of operations) {
|
||||||
|
switch (operation.op) {
|
||||||
|
case "replace": {
|
||||||
|
await groupDAL.update(
|
||||||
|
{
|
||||||
|
id: groupId,
|
||||||
|
orgId
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: operation.value.displayName
|
||||||
|
}
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "add": {
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "remove": {
|
||||||
|
// TODO
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
throw new ScimRequestError({
|
||||||
|
detail: "Invalid Operation",
|
||||||
|
status: 400
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!group) {
|
||||||
|
throw new ScimRequestError({
|
||||||
|
detail: "Group Not Found",
|
||||||
|
status: 404
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildScimGroup({
|
||||||
|
groupId: group.id,
|
||||||
|
name: group.name,
|
||||||
|
members: []
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const deleteScimGroup = async ({ groupId, orgId }: TDeleteScimGroupDTO) => {
|
const deleteScimGroup = async ({ groupId, orgId }: TDeleteScimGroupDTO) => {
|
||||||
const [group] = await groupDAL.delete({
|
const [group] = await groupDAL.delete({
|
||||||
id: groupId,
|
id: groupId,
|
||||||
@@ -547,10 +679,13 @@ export const scimServiceFactory = ({
|
|||||||
createScimUser,
|
createScimUser,
|
||||||
updateScimUser,
|
updateScimUser,
|
||||||
replaceScimUser,
|
replaceScimUser,
|
||||||
|
deleteScimUser,
|
||||||
|
listScimGroups,
|
||||||
createScimGroup,
|
createScimGroup,
|
||||||
getScimGroup,
|
getScimGroup,
|
||||||
deleteScimGroup,
|
deleteScimGroup,
|
||||||
updateScimGroupName,
|
updateScimGroupNamePut,
|
||||||
|
updateScimGroupNamePatch,
|
||||||
fnValidateScimToken
|
fnValidateScimToken
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,6 +59,25 @@ export type TReplaceScimUserDTO = {
|
|||||||
orgId: string;
|
orgId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TDeleteScimUserDTO = {
|
||||||
|
userId: string;
|
||||||
|
orgId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TListScimGroupsDTO = {
|
||||||
|
offset: number;
|
||||||
|
limit: number;
|
||||||
|
orgId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TListScimGroups = {
|
||||||
|
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"];
|
||||||
|
totalResults: number;
|
||||||
|
Resources: TScimGroup[];
|
||||||
|
itemsPerPage: number;
|
||||||
|
startIndex: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type TCreateScimGroupDTO = {
|
export type TCreateScimGroupDTO = {
|
||||||
displayName: string;
|
displayName: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
@@ -69,12 +88,39 @@ export type TGetScimGroupDTO = {
|
|||||||
orgId: string;
|
orgId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TUpdateScimGroupNameDTO = {
|
export type TUpdateScimGroupNamePutDTO = {
|
||||||
groupId: string;
|
groupId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TUpdateScimGroupNamePatchDTO = {
|
||||||
|
groupId: string;
|
||||||
|
orgId: string;
|
||||||
|
operations: (TRemoveOp | TReplaceOp | TAddOp)[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type TReplaceOp = {
|
||||||
|
op: "replace";
|
||||||
|
value: {
|
||||||
|
id: string;
|
||||||
|
displayName: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
type TRemoveOp = {
|
||||||
|
op: "remove";
|
||||||
|
path: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TAddOp = {
|
||||||
|
op: "add";
|
||||||
|
value: {
|
||||||
|
value: string;
|
||||||
|
display?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export type TDeleteScimGroupDTO = {
|
export type TDeleteScimGroupDTO = {
|
||||||
groupId: string;
|
groupId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
@@ -107,3 +153,17 @@ export type TScimUser = {
|
|||||||
location: null;
|
location: null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TScimGroup = {
|
||||||
|
schemas: string[];
|
||||||
|
id: string;
|
||||||
|
displayName: string;
|
||||||
|
members: {
|
||||||
|
value: string;
|
||||||
|
display: string;
|
||||||
|
}[];
|
||||||
|
meta: {
|
||||||
|
resourceType: string;
|
||||||
|
location: null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Prerequisites:
|
|||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Create a SCIM token in Infisical">
|
<Step title="Create a SCIM token in Infisical">
|
||||||
In Infisical, head to your Organization Settings > Authentication > SCIM Configuration and
|
In Infisical, head to your Organization Settings > Authentication > SCIM Configuration and
|
||||||
press the **Enable SCIM provisioning** toggle to allow JumpCloud to provision/deprovision users for your organization.
|
press the **Enable SCIM provisioning** toggle to allow JumpCloud to provision/deprovision users and user groups for your organization.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ Prerequisites:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
Now JumpCloud can provision/deprovision users to/from your organization in Infisical.
|
Now JumpCloud can provision/deprovision users and user groups to/from your organization in Infisical.
|
||||||
</Step>
|
</Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Prerequisites:
|
|||||||
<Steps>
|
<Steps>
|
||||||
<Step title="Create a SCIM token in Infisical">
|
<Step title="Create a SCIM token in Infisical">
|
||||||
In Infisical, head to your Organization Settings > Authentication > SCIM Configuration and
|
In Infisical, head to your Organization Settings > Authentication > SCIM Configuration and
|
||||||
press the **Enable SCIM provisioning** toggle to allow Okta to provision/deprovision users for your organization.
|
press the **Enable SCIM provisioning** toggle to allow Okta to provision/deprovision users and user groups for your organization.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ Prerequisites:
|
|||||||
|
|
||||||
- SCIM connector base URL: Input the **SCIM URL** from Step 1.
|
- SCIM connector base URL: Input the **SCIM URL** from Step 1.
|
||||||
- Unique identifier field for users: Input `email`.
|
- Unique identifier field for users: Input `email`.
|
||||||
- Supported provisioning actions: Select **Push New Users** and **Push Profile Updates**.
|
- Supported provisioning actions: Select **Push New Users**, **Push Profile Updates**, and **Push Groups**.
|
||||||
- Authentication Mode: `HTTP Header`.
|
- Authentication Mode: `HTTP Header`.
|
||||||
|
|
||||||

|

|
||||||
@@ -55,7 +55,7 @@ Prerequisites:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
Now Okta can provision/deprovision users to/from your organization in Infisical.
|
Now Okta can provision/deprovision users and user groups to/from your organization in Infisical.
|
||||||
</Step>
|
</Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ description: "Learn how to provision users for Infisical via SCIM."
|
|||||||
then you should contact [email protected] to purchase an enterprise license to use it.
|
then you should contact [email protected] to purchase an enterprise license to use it.
|
||||||
</Info>
|
</Info>
|
||||||
|
|
||||||
You can configure your organization in Infisical to have members be provisioned/deprovisioned using [SCIM](https://scim.cloud/#Implementations2) via providers like Okta, Azure, JumpCloud, etc.
|
You can configure your organization in Infisical to have users and user groups be provisioned/deprovisioned using [SCIM](https://scim.cloud/#Implementations2) via providers like Okta, Azure, JumpCloud, etc.
|
||||||
|
|
||||||
- Provisioning: The SCIM provider pushes user information to Infisical. If the user exists in Infisical, Infisical sends an email invitation to add them to the relevant organization in Infisical; if not, Infisical initializes a new user and sends them an email invitation to finish setting up their account in the organization.
|
- Provisioning: The SCIM provider pushes user information to Infisical. If the user exists in Infisical, Infisical sends an email invitation to add them to the relevant organization in Infisical; if not, Infisical initializes a new user and sends them an email invitation to finish setting up their account in the organization.
|
||||||
- Deprovisioning: The SCIM provider instructs Infisical to remove user(s) from an organization in Infisical.
|
- Deprovisioning: The SCIM provider instructs Infisical to remove user(s) from an organization in Infisical.
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 308 KiB After Width: | Height: | Size: 323 KiB |
Reference in New Issue
Block a user