From e0dc2dd6d8d7d820ad5c0f05f949ca502ce1aa2d Mon Sep 17 00:00:00 2001 From: Scott Wilson Date: Thu, 24 Apr 2025 13:44:43 -0700 Subject: [PATCH] improvements: address feedback --- .../ldap-password/ldap-password-rotation-schemas.ts | 3 +++ backend/src/lib/regex/index.ts | 3 +++ .../app-connection/ldap/ldap-connection-schemas.ts | 8 +++++++- .../forms/schemas/ldap-password-rotation-schema.ts | 7 ++++++- frontend/src/helpers/string.ts | 3 +++ .../components/AppConnectionForm/LdapConnectionFields.tsx | 7 ++++++- 6 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 backend/src/lib/regex/index.ts diff --git a/backend/src/ee/services/secret-rotation-v2/ldap-password/ldap-password-rotation-schemas.ts b/backend/src/ee/services/secret-rotation-v2/ldap-password/ldap-password-rotation-schemas.ts index 9441a4cb9..e99569d9a 100644 --- a/backend/src/ee/services/secret-rotation-v2/ldap-password/ldap-password-rotation-schemas.ts +++ b/backend/src/ee/services/secret-rotation-v2/ldap-password/ldap-password-rotation-schemas.ts @@ -1,3 +1,4 @@ +import RE2 from "re2"; import { z } from "zod"; import { SecretRotation } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-enums"; @@ -8,6 +9,7 @@ import { } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-schemas"; import { PasswordRequirementsSchema } from "@app/ee/services/secret-rotation-v2/shared/general"; import { SecretRotations } from "@app/lib/api-docs"; +import { DistinguishedNameRegex } from "@app/lib/regex"; import { SecretNameSchema } from "@app/server/lib/schemas"; import { AppConnection } from "@app/services/app-connection/app-connection-enums"; @@ -24,6 +26,7 @@ const LdapPasswordRotationParametersSchema = z.object({ dn: z .string() .trim() + .regex(new RE2(DistinguishedNameRegex), "Invalid DN format, ie; CN=user,OU=users,DC=example,DC=com") .min(1, "Distinguished Name (DN) Required") .describe(SecretRotations.PARAMETERS.LDAP_PASSWORD.dn), passwordRequirements: PasswordRequirementsSchema.optional() diff --git a/backend/src/lib/regex/index.ts b/backend/src/lib/regex/index.ts new file mode 100644 index 000000000..68ba7671d --- /dev/null +++ b/backend/src/lib/regex/index.ts @@ -0,0 +1,3 @@ +export const DistinguishedNameRegex = + // DN format, ie; CN=user,OU=users,DC=example,DC=com + /^(?:(?:[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)(?:(?:\\+[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)*)(?:,(?:[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)(?:(?:\\+[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)*))*)?$/; diff --git a/backend/src/services/app-connection/ldap/ldap-connection-schemas.ts b/backend/src/services/app-connection/ldap/ldap-connection-schemas.ts index 9a92285b6..91884b914 100644 --- a/backend/src/services/app-connection/ldap/ldap-connection-schemas.ts +++ b/backend/src/services/app-connection/ldap/ldap-connection-schemas.ts @@ -2,6 +2,7 @@ import RE2 from "re2"; import { z } from "zod"; import { AppConnections } from "@app/lib/api-docs"; +import { DistinguishedNameRegex } from "@app/lib/regex"; import { AppConnection } from "@app/services/app-connection/app-connection-enums"; import { BaseAppConnectionSchema, @@ -19,7 +20,12 @@ export const LdapConnectionSimpleBindCredentialsSchema = z.object({ .min(1, "URL required") .regex(new RE2(/^ldaps?:\/\//)) .describe(AppConnections.CREDENTIALS.LDAP.url), - dn: z.string().trim().min(1, "Distinguished Name (DN) required").describe(AppConnections.CREDENTIALS.LDAP.dn), + dn: z + .string() + .trim() + .regex(new RE2(DistinguishedNameRegex), "Invalid DN format, ie; CN=user,OU=users,DC=example,DC=com") + .min(1, "Distinguished Name (DN) required") + .describe(AppConnections.CREDENTIALS.LDAP.dn), password: z.string().trim().min(1, "Password required").describe(AppConnections.CREDENTIALS.LDAP.password), sslRejectUnauthorized: z.boolean().optional().describe(AppConnections.CREDENTIALS.LDAP.sslRejectUnauthorized), sslCertificate: z diff --git a/frontend/src/components/secret-rotations-v2/forms/schemas/ldap-password-rotation-schema.ts b/frontend/src/components/secret-rotations-v2/forms/schemas/ldap-password-rotation-schema.ts index 8cebc199f..e18609f04 100644 --- a/frontend/src/components/secret-rotations-v2/forms/schemas/ldap-password-rotation-schema.ts +++ b/frontend/src/components/secret-rotations-v2/forms/schemas/ldap-password-rotation-schema.ts @@ -2,13 +2,18 @@ import { z } from "zod"; import { BaseSecretRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/base-secret-rotation-v2-schema"; import { PasswordRequirementsSchema } from "@app/components/secret-rotations-v2/forms/schemas/shared"; +import { DistinguishedNameRegex } from "@app/helpers/string"; import { SecretRotation } from "@app/hooks/api/secretRotationsV2"; export const LdapPasswordRotationSchema = z .object({ type: z.literal(SecretRotation.LdapPassword), parameters: z.object({ - dn: z.string().trim().min(1, "Distinguished Name (DN) required"), + dn: z + .string() + .trim() + .regex(DistinguishedNameRegex, "Invalid Distinguished Name format") + .min(1, "Distinguished Name (DN) required"), passwordRequirements: PasswordRequirementsSchema.optional() }), secretsMapping: z.object({ diff --git a/frontend/src/helpers/string.ts b/frontend/src/helpers/string.ts index 109b51d49..ddd9fb7c9 100644 --- a/frontend/src/helpers/string.ts +++ b/frontend/src/helpers/string.ts @@ -12,3 +12,6 @@ export const isValidPath = (val: string): boolean => { const validPathRegex = /^[a-zA-Z0-9-_.:]+(?:\/[a-zA-Z0-9-_.:]+)*$/; return validPathRegex.test(val); }; + +export const DistinguishedNameRegex = + /^(?:(?:[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)(?:(?:\\+[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)*)(?:,(?:[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)(?:(?:\\+[a-zA-Z0-9]+=[^,+="<>#;\\\\]+)*))*)?$/; diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/LdapConnectionFields.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/LdapConnectionFields.tsx index 308ac6f33..7346f84af 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/LdapConnectionFields.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/LdapConnectionFields.tsx @@ -19,6 +19,7 @@ import { Tooltip } from "@app/components/v2"; import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections"; +import { DistinguishedNameRegex } from "@app/helpers/string"; import { LdapConnectionMethod, LdapConnectionProvider, @@ -51,7 +52,11 @@ const formSchema = z.discriminatedUnion("method", [ .url() .trim() .min(1, "LDAP URL required"), - dn: z.string().trim().min(1, "Distinguished Name (DN) required"), + dn: z + .string() + .trim() + .regex(DistinguishedNameRegex, "Invalid Distinguished Name format") + .min(1, "Distinguished Name (DN) required"), password: z.string().trim().min(1, "Password required"), sslRejectUnauthorized: z.boolean(), sslCertificate: z