From 3641875b2477d04dcbbbacefcdf9dbc6ae7ae71e Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Tue, 27 Feb 2024 11:36:35 -0800 Subject: [PATCH] Update LDAP permissioning, styling of org auth section --- .../ldap-config/ldap-config-service.ts | 6 +- .../ee/services/permission/org-permission.ts | 7 +++ .../src/context/OrgPermissionContext/types.ts | 2 + .../OrgRoleModifySection.tsx | 6 ++ .../OrgRoleModifySection.utils.ts | 1 + .../components/OrgAuthTab/OrgLDAPSection.tsx | 56 +++++++++---------- .../components/OrgAuthTab/OrgSCIMSection.tsx | 6 +- .../components/OrgAuthTab/OrgSSOSection.tsx | 45 +++------------ 8 files changed, 59 insertions(+), 70 deletions(-) diff --git a/backend/src/ee/services/ldap-config/ldap-config-service.ts b/backend/src/ee/services/ldap-config/ldap-config-service.ts index 0036f519d..b78a2b138 100644 --- a/backend/src/ee/services/ldap-config/ldap-config-service.ts +++ b/backend/src/ee/services/ldap-config/ldap-config-service.ts @@ -61,7 +61,7 @@ export const ldapConfigServiceFactory = ({ caCert }: TCreateLdapCfgDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap); const plan = await licenseService.getPlan(orgId); if (!plan.ldap) @@ -154,7 +154,7 @@ export const ldapConfigServiceFactory = ({ caCert }: TUpdateLdapCfgDTO) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Ldap); const plan = await licenseService.getPlan(orgId); if (!plan.ldap) @@ -274,7 +274,7 @@ export const ldapConfigServiceFactory = ({ const getLdapCfgWithPermissionCheck = async ({ actor, actorId, orgId, actorOrgId }: TOrgPermission) => { const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Ldap); return getLdapCfg({ orgId }); diff --git a/backend/src/ee/services/permission/org-permission.ts b/backend/src/ee/services/permission/org-permission.ts index e527f1a4a..30b601c2c 100644 --- a/backend/src/ee/services/permission/org-permission.ts +++ b/backend/src/ee/services/permission/org-permission.ts @@ -17,6 +17,7 @@ export enum OrgPermissionSubjects { IncidentAccount = "incident-contact", Sso = "sso", Scim = "scim", + Ldap = "ldap", Billing = "billing", SecretScanning = "secret-scanning", Identity = "identity" @@ -31,6 +32,7 @@ export type OrgPermissionSet = | [OrgPermissionActions, OrgPermissionSubjects.IncidentAccount] | [OrgPermissionActions, OrgPermissionSubjects.Sso] | [OrgPermissionActions, OrgPermissionSubjects.Scim] + | [OrgPermissionActions, OrgPermissionSubjects.Ldap] | [OrgPermissionActions, OrgPermissionSubjects.SecretScanning] | [OrgPermissionActions, OrgPermissionSubjects.Billing] | [OrgPermissionActions, OrgPermissionSubjects.Identity]; @@ -76,6 +78,11 @@ const buildAdminPermission = () => { can(OrgPermissionActions.Edit, OrgPermissionSubjects.Scim); can(OrgPermissionActions.Delete, OrgPermissionSubjects.Scim); + can(OrgPermissionActions.Read, OrgPermissionSubjects.Ldap); + can(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap); + can(OrgPermissionActions.Edit, OrgPermissionSubjects.Ldap); + can(OrgPermissionActions.Delete, OrgPermissionSubjects.Ldap); + can(OrgPermissionActions.Read, OrgPermissionSubjects.Billing); can(OrgPermissionActions.Create, OrgPermissionSubjects.Billing); can(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing); diff --git a/frontend/src/context/OrgPermissionContext/types.ts b/frontend/src/context/OrgPermissionContext/types.ts index 8a7393a17..8127cb772 100644 --- a/frontend/src/context/OrgPermissionContext/types.ts +++ b/frontend/src/context/OrgPermissionContext/types.ts @@ -15,6 +15,7 @@ export enum OrgPermissionSubjects { IncidentAccount = "incident-contact", Scim = "scim", Sso = "sso", + Ldap = "ldap", Billing = "billing", SecretScanning = "secret-scanning", Identity = "identity" @@ -29,6 +30,7 @@ export type OrgPermissionSet = | [OrgPermissionActions, OrgPermissionSubjects.IncidentAccount] | [OrgPermissionActions, OrgPermissionSubjects.Scim] | [OrgPermissionActions, OrgPermissionSubjects.Sso] + | [OrgPermissionActions, OrgPermissionSubjects.Ldap] | [OrgPermissionActions, OrgPermissionSubjects.SecretScanning] | [OrgPermissionActions, OrgPermissionSubjects.Billing] | [OrgPermissionActions, OrgPermissionSubjects.Identity]; diff --git a/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleModifySection/OrgRoleModifySection.tsx b/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleModifySection/OrgRoleModifySection.tsx index 406bd569e..106da7047 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleModifySection/OrgRoleModifySection.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleModifySection/OrgRoleModifySection.tsx @@ -82,6 +82,12 @@ const SIMPLE_PERMISSION_OPTIONS = [ icon: faSignIn, formName: "sso" }, + { + title: "LDAP", + subtitle: "Define organization level LDAP requirements", + icon: faSignIn, + formName: "ldap" + }, { title: "SCIM", subtitle: "Define organization level SCIM requirements", diff --git a/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleModifySection/OrgRoleModifySection.utils.ts b/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleModifySection/OrgRoleModifySection.utils.ts index 415fa68df..f5e535a18 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleModifySection/OrgRoleModifySection.utils.ts +++ b/frontend/src/views/Org/MembersPage/components/OrgRoleTabSection/OrgRoleModifySection/OrgRoleModifySection.utils.ts @@ -35,6 +35,7 @@ export const formSchema = z.object({ "secret-scanning": generalPermissionSchema, sso: generalPermissionSchema, scim: generalPermissionSchema, + ldap: generalPermissionSchema, billing: generalPermissionSchema, identity: generalPermissionSchema }) diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgLDAPSection.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgLDAPSection.tsx index 5f2970170..c1ac93db8 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgLDAPSection.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgLDAPSection.tsx @@ -3,11 +3,16 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { OrgPermissionCan } from "@app/components/permissions"; -import { Button, Switch } from "@app/components/v2"; +import { + Button, + Switch, + UpgradePlanModal +} from "@app/components/v2"; import { OrgPermissionActions, OrgPermissionSubjects, useOrganization, + useSubscription } from "@app/context"; import { useCreateLDAPConfig, @@ -20,18 +25,24 @@ import { LDAPModal } from "./LDAPModal"; export const OrgLDAPSection = (): JSX.Element => { const { currentOrg } = useOrganization(); + const { subscription } = useSubscription(); const { createNotification } = useNotificationContext(); const { data, isLoading } = useGetLDAPConfig(currentOrg?.id ?? ""); const { mutateAsync } = useUpdateLDAPConfig(); const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ - "addLDAP" + "addLDAP", + "upgradePlan" ] as const); const { mutateAsync: createMutateAsync } = useCreateLDAPConfig(); - const handleSamlSSOToggle = async (value: boolean) => { // TODO: rename to LDAP toggle + const handleLDAPToggle = async (value: boolean) => { try { if (!currentOrg?.id) return; + if (!subscription?.ldap) { + handlePopUpOpen("upgradePlan"); + return; + } await mutateAsync({ organizationId: currentOrg?.id, @@ -53,7 +64,7 @@ export const OrgLDAPSection = (): JSX.Element => { const addLDAPBtnClick = async () => { try { - if (currentOrg) { + if (subscription?.ldap && currentOrg) { if (!data) { // case: LDAP is not configured // -> initialize empty LDAP configuration @@ -68,6 +79,8 @@ export const OrgLDAPSection = (): JSX.Element => { } handlePopUpOpen("addLDAP"); + } else { + handlePopUpOpen("upgradePlan"); } } catch (err) { console.error(err); @@ -77,9 +90,9 @@ export const OrgLDAPSection = (): JSX.Element => { return (
-

LDAP Configuration

+

LDAP

{!isLoading && ( - + {(isAllowed) => ( )} @@ -95,43 +108,30 @@ export const OrgLDAPSection = (): JSX.Element => {
{data && (
- + {(isAllowed) => ( handleSamlSSOToggle(value)} + onCheckedChange={(value) => handleLDAPToggle(value)} isChecked={data ? data.isActive : false} isDisabled={!isAllowed} > - Enable LDAP + Enable )}
)} -
-

URL

-

{data && data.url !== "" ? data.url : "-"}

-
-
-

Bind DN

-

{data && data.bindDN !== "" ? data.bindDN : "-"}

-
-
-

Bind Pass

-

- {data && data.bindPass !== "" ? "*".repeat(data.bindPass.length) : "-"} -

-
-
-

Search Base / User DN

-

{data && data.searchBase !== "" ? data.searchBase : "-"}

-
+ handlePopUpToggle("upgradePlan", isOpen)} + text="You can use LDAP authentication if you switch to Infisical's Enterprise plan." + />
); }; \ No newline at end of file diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx index 041518d9f..bb1f4ff94 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSCIMSection.tsx @@ -66,7 +66,7 @@ export const OrgScimSection = () => { return (
-

SCIM Configuration

+

SCIM

{(isAllowed) => ( )} @@ -94,7 +94,7 @@ export const OrgScimSection = () => { isChecked={currentOrg?.scimEnabled ?? false} isDisabled={!isAllowed} > - Enable SCIM Provisioning + Enable )} diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSSOSection.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSSOSection.tsx index 23900708d..9f03bdc7f 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSSOSection.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgAuthTab/OrgSSOSection.tsx @@ -1,6 +1,5 @@ import { faPlus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { format } from "date-fns"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { OrgPermissionCan } from "@app/components/permissions"; @@ -16,12 +15,6 @@ import { usePopUp } from "@app/hooks/usePopUp"; import { SSOModal } from "./SSOModal"; -const ssoAuthProviderMap: { [key: string]: string } = { - "okta-saml": "Okta SAML", - "azure-saml": "Azure SAML", - "jumpcloud-saml": "JumpCloud SAML" -}; - export const OrgSSOSection = (): JSX.Element => { const { currentOrg } = useOrganization(); const { subscription } = useSubscription(); @@ -38,6 +31,11 @@ export const OrgSSOSection = (): JSX.Element => { const handleSamlSSOToggle = async (value: boolean) => { try { if (!currentOrg?.id) return; + + if (!subscription?.samlSSO) { + handlePopUpOpen("upgradePlan"); + return; + } await mutateAsync({ organizationId: currentOrg?.id, @@ -85,7 +83,7 @@ export const OrgSSOSection = (): JSX.Element => { return (
-

SAML SSO Configuration

+

SAML

{!isLoading && ( {(isAllowed) => ( @@ -95,13 +93,13 @@ export const OrgSSOSection = (): JSX.Element => { isDisabled={!isAllowed} leftIcon={} > - {data ? "Update SAML SSO" : "Set up SAML SSO"} + Configure )} )}
- {data && ( + {/* {data && ( */}
{(isAllowed) => ( @@ -111,36 +109,11 @@ export const OrgSSOSection = (): JSX.Element => { isChecked={data ? data.isActive : false} isDisabled={!isAllowed} > - Enable SAML SSO + Enable )}
- )} -
-

SSO identifier

-

{data && data.id !== "" ? data.id : "-"}

-
-
-

Type

-

- {data && data.authProvider !== "" ? ssoAuthProviderMap[data.authProvider] : "-"} -

-
-
-

Entrypoint

-

- {data && data.entryPoint !== "" ? data.entryPoint : "-"} -

-
-
-

Issuer

-

{data && data.issuer !== "" ? data.issuer : "-"}

-
-
-

Last Logged In

-

{data?.lastUsed ? format(new Date(data?.lastUsed), "yyyy-MM-dd HH:mm:ss") : "-"}

-