mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 08:26:29 +00:00
Minor UX adjustments to SCIM
This commit is contained in:
@@ -9,7 +9,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
try {
|
try {
|
||||||
const strBody = body instanceof Buffer ? body.toString() : body;
|
const strBody = body instanceof Buffer ? body.toString() : body;
|
||||||
|
|
||||||
const json: unknown = JSON.parse(strBody); // TODO: update
|
const json: unknown = JSON.parse(strBody);
|
||||||
done(null, json);
|
done(null, json);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const error = err as Error;
|
const error = err as Error;
|
||||||
@@ -294,13 +294,6 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
familyName: z.string().trim(),
|
familyName: z.string().trim(),
|
||||||
givenName: z.string().trim()
|
givenName: z.string().trim()
|
||||||
}),
|
}),
|
||||||
// emails: z.array(
|
|
||||||
// z.object({
|
|
||||||
// primary: z.boolean(),
|
|
||||||
// value: z.string().email(),
|
|
||||||
// type: z.string().trim()
|
|
||||||
// })
|
|
||||||
// ),
|
|
||||||
displayName: z.string().trim(),
|
displayName: z.string().trim(),
|
||||||
active: z.boolean()
|
active: z.boolean()
|
||||||
}),
|
}),
|
||||||
@@ -335,20 +328,4 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
|
|||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// server.route({
|
|
||||||
// url: "/Users/:userId",
|
|
||||||
// method: "DELETE",
|
|
||||||
// schema: {
|
|
||||||
// body: z.object({}),
|
|
||||||
// response: {
|
|
||||||
// 200: z.object({})
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// onRequest: verifyAuth([AuthMode.SCIM_TOKEN]),
|
|
||||||
// handler: () => {
|
|
||||||
// // TODO: update a user's profile
|
|
||||||
// return {};
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import { TOrgPermission } from "@app/lib/types";
|
|||||||
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
||||||
import { deleteOrgMembership } from "@app/services/org/org-fns";
|
import { deleteOrgMembership } from "@app/services/org/org-fns";
|
||||||
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
|
||||||
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
|
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
|
||||||
import { TUserDALFactory } from "@app/services/user/user-dal";
|
import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||||
|
|
||||||
@@ -29,10 +31,14 @@ import {
|
|||||||
} from "./scim-types";
|
} from "./scim-types";
|
||||||
|
|
||||||
type TScimServiceFactoryDep = {
|
type TScimServiceFactoryDep = {
|
||||||
// TODO: pick types
|
scimDAL: Pick<TScimDALFactory, "create" | "find" | "findById" | "deleteById">;
|
||||||
scimDAL: TScimDALFactory; // TODO: pick
|
userDAL: Pick<TUserDALFactory, "findOne" | "create" | "transaction">;
|
||||||
userDAL: TUserDALFactory; // TODO: pick
|
orgDAL: Pick<
|
||||||
orgDAL: TOrgDALFactory; // TODO: pick
|
TOrgDALFactory,
|
||||||
|
"createMembership" | "findById" | "findMembership" | "deleteMembershipById" | "transaction"
|
||||||
|
>;
|
||||||
|
projectDAL: Pick<TProjectDALFactory, "find">;
|
||||||
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find" | "delete">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
smtpService: TSmtpService;
|
smtpService: TSmtpService;
|
||||||
@@ -45,6 +51,8 @@ export const scimServiceFactory = ({
|
|||||||
scimDAL,
|
scimDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
|
projectDAL,
|
||||||
|
projectMembershipDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
smtpService
|
smtpService
|
||||||
}: TScimServiceFactoryDep) => {
|
}: TScimServiceFactoryDep) => {
|
||||||
@@ -325,7 +333,9 @@ export const scimServiceFactory = ({
|
|||||||
await deleteOrgMembership({
|
await deleteOrgMembership({
|
||||||
orgMembershipId: membership.id,
|
orgMembershipId: membership.id,
|
||||||
orgId: membership.orgId,
|
orgId: membership.orgId,
|
||||||
orgDAL
|
orgDAL,
|
||||||
|
projectDAL,
|
||||||
|
projectMembershipDAL
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +378,9 @@ export const scimServiceFactory = ({
|
|||||||
await deleteOrgMembership({
|
await deleteOrgMembership({
|
||||||
orgMembershipId: membership.id,
|
orgMembershipId: membership.id,
|
||||||
orgId: membership.orgId,
|
orgId: membership.orgId,
|
||||||
orgDAL
|
orgDAL,
|
||||||
|
projectDAL,
|
||||||
|
projectMembershipDAL
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -219,6 +219,8 @@ export const registerRoutes = async (
|
|||||||
scimDAL,
|
scimDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
|
projectDAL,
|
||||||
|
projectMembershipDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
smtpService
|
smtpService
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,21 +1,41 @@
|
|||||||
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
||||||
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
|
||||||
|
|
||||||
type TDeleteOrgMembership = {
|
type TDeleteOrgMembership = {
|
||||||
orgMembershipId: string;
|
orgMembershipId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
orgDAL: TOrgDALFactory;
|
orgDAL: Pick<TOrgDALFactory, "findMembership" | "deleteMembershipById" | "transaction">;
|
||||||
|
projectDAL: Pick<TProjectDALFactory, "find">;
|
||||||
|
projectMembershipDAL: Pick<TProjectMembershipDALFactory, "find" | "delete">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deleteOrgMembership = async ({ orgMembershipId, orgId, orgDAL }: TDeleteOrgMembership) => {
|
export const deleteOrgMembership = async ({
|
||||||
// TODO: improve this implementation
|
orgMembershipId,
|
||||||
|
orgId,
|
||||||
|
orgDAL,
|
||||||
|
projectDAL,
|
||||||
|
projectMembershipDAL
|
||||||
|
}: TDeleteOrgMembership) => {
|
||||||
|
const membership = await orgDAL.transaction(async (tx) => {
|
||||||
|
// delete org membership
|
||||||
|
const orgMembership = await orgDAL.deleteMembershipById(orgMembershipId, orgId, tx);
|
||||||
|
|
||||||
// delete
|
const projects = await projectDAL.find({ orgId }, { tx });
|
||||||
const m2 = await orgDAL.transaction(async (tx) => {
|
|
||||||
const m1 = await orgDAL.deleteMembershipById(orgMembershipId, orgId, tx);
|
// delete associated project memberships
|
||||||
// const [deletedMembership] = await projectMembershipDAL.delete({ projectId, id: membershipId }, tx);
|
await projectMembershipDAL.delete(
|
||||||
// delete project memberships
|
{
|
||||||
return m1;
|
$in: {
|
||||||
|
projectId: projects.map((project) => project.id)
|
||||||
|
},
|
||||||
|
userId: orgMembership.userId as string
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
return orgMembership;
|
||||||
});
|
});
|
||||||
|
|
||||||
return m2;
|
return membership;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
import { organizationKeys } from "@app/hooks/api/organization/queries";
|
||||||
|
|
||||||
const ssoConfigKeys = {
|
const ssoConfigKeys = {
|
||||||
getSSOConfig: (orgId: string) => [{ orgId }, "organization-saml-sso"] as const
|
getSSOConfig: (orgId: string) => [{ orgId }, "organization-saml-sso"] as const
|
||||||
@@ -82,8 +83,12 @@ export const useUpdateSSOConfig = () => {
|
|||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
onSuccess(_, dto) {
|
onSuccess(_, { organizationId, isActive }) {
|
||||||
queryClient.invalidateQueries(ssoConfigKeys.getSSOConfig(dto.organizationId));
|
if (isActive === false) {
|
||||||
|
queryClient.invalidateQueries(organizationKeys.getUserOrganizations);
|
||||||
|
}
|
||||||
|
|
||||||
|
queryClient.invalidateQueries(ssoConfigKeys.getSSOConfig(organizationId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
+6
@@ -81,6 +81,12 @@ const SIMPLE_PERMISSION_OPTIONS = [
|
|||||||
subtitle: "Define organization level SSO requirements",
|
subtitle: "Define organization level SSO requirements",
|
||||||
icon: faSignIn,
|
icon: faSignIn,
|
||||||
formName: "sso"
|
formName: "sso"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "SCIM",
|
||||||
|
subtitle: "Define organization level SCIM requirements",
|
||||||
|
icon: faUsers,
|
||||||
|
formName: "scim"
|
||||||
}
|
}
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
|||||||
+1
@@ -34,6 +34,7 @@ export const formSchema = z.object({
|
|||||||
"incident-contact": generalPermissionSchema,
|
"incident-contact": generalPermissionSchema,
|
||||||
"secret-scanning": generalPermissionSchema,
|
"secret-scanning": generalPermissionSchema,
|
||||||
sso: generalPermissionSchema,
|
sso: generalPermissionSchema,
|
||||||
|
scim: generalPermissionSchema,
|
||||||
billing: generalPermissionSchema,
|
billing: generalPermissionSchema,
|
||||||
identity: generalPermissionSchema
|
identity: generalPermissionSchema
|
||||||
})
|
})
|
||||||
|
|||||||
+3
-3
@@ -10,14 +10,14 @@ import {
|
|||||||
useOrganization,
|
useOrganization,
|
||||||
useSubscription
|
useSubscription
|
||||||
} from "@app/context";
|
} from "@app/context";
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
|
||||||
import { useLogoutUser, useUpdateOrg } from "@app/hooks/api";
|
import { useLogoutUser, useUpdateOrg } from "@app/hooks/api";
|
||||||
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
export const OrgGeneralAuthSection = () => {
|
export const OrgGeneralAuthSection = () => {
|
||||||
const { createNotification } = useNotificationContext();
|
const { createNotification } = useNotificationContext();
|
||||||
const { currentOrg } = useOrganization();
|
const { currentOrg } = useOrganization();
|
||||||
const { subscription } = useSubscription();
|
const { subscription } = useSubscription();
|
||||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([
|
||||||
"upgradePlan"
|
"upgradePlan"
|
||||||
] as const);
|
] as const);
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ export const OrgGeneralAuthSection = () => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
createNotification({
|
createNotification({
|
||||||
text: `Failed to ${value ? "enforce" : "un-enforce"} org-level auth`,
|
text: (err as { response: { data: { message: string; }}}).response.data.message,
|
||||||
type: "error"
|
type: "error"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-21
@@ -11,12 +11,12 @@ import {
|
|||||||
import {
|
import {
|
||||||
OrgPermissionActions,
|
OrgPermissionActions,
|
||||||
OrgPermissionSubjects,
|
OrgPermissionSubjects,
|
||||||
useSubscription,
|
useOrganization,
|
||||||
useOrganization
|
useSubscription} from "@app/context";
|
||||||
} from "@app/context";
|
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
|
||||||
import { ScimTokenModal } from "./ScimTokenModal";
|
|
||||||
import { useUpdateOrg } from "@app/hooks/api";
|
import { useUpdateOrg } from "@app/hooks/api";
|
||||||
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
|
import { ScimTokenModal } from "./ScimTokenModal";
|
||||||
|
|
||||||
export const OrgScimSection = () => {
|
export const OrgScimSection = () => {
|
||||||
const { createNotification } = useNotificationContext();
|
const { createNotification } = useNotificationContext();
|
||||||
@@ -56,9 +56,8 @@ export const OrgScimSection = () => {
|
|||||||
type: "success"
|
type: "success"
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
|
||||||
createNotification({
|
createNotification({
|
||||||
text: `Failed to ${value ? "enable" : "disable"} SCIM provisioning`,
|
text: (err as { response: { data: { message: string; }}}).response.data.message,
|
||||||
type: "error"
|
type: "error"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -82,20 +81,22 @@ export const OrgScimSection = () => {
|
|||||||
</OrgPermissionCan>
|
</OrgPermissionCan>
|
||||||
</div>
|
</div>
|
||||||
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Scim}>
|
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Scim}>
|
||||||
<Switch
|
{(isAllowed) => (
|
||||||
id="enable-scim"
|
<Switch
|
||||||
onCheckedChange={(value) => {
|
id="enable-scim"
|
||||||
if (subscription?.scim) {
|
onCheckedChange={(value) => {
|
||||||
handleEnableSCIMToggle(value)
|
if (subscription?.scim) {
|
||||||
} else {
|
handleEnableSCIMToggle(value)
|
||||||
handlePopUpOpen("upgradePlan");
|
} else {
|
||||||
}
|
handlePopUpOpen("upgradePlan");
|
||||||
}}
|
}
|
||||||
isChecked={currentOrg?.scimEnabled ?? false}
|
}}
|
||||||
isDisabled={false}
|
isChecked={currentOrg?.scimEnabled ?? false}
|
||||||
>
|
isDisabled={!isAllowed}
|
||||||
Enable SCIM Provisioning
|
>
|
||||||
</Switch>
|
Enable SCIM Provisioning
|
||||||
|
</Switch>
|
||||||
|
)}
|
||||||
</OrgPermissionCan>
|
</OrgPermissionCan>
|
||||||
<ScimTokenModal
|
<ScimTokenModal
|
||||||
popUp={popUp}
|
popUp={popUp}
|
||||||
|
|||||||
Reference in New Issue
Block a user