Separate ldap boot/parent wrapper logic, move ldap services into docker compose profile, update ldap form logic to use zod

This commit is contained in:
Tuan Dang
2024-03-10 12:28:50 -07:00
parent 440a58a49b
commit 7594929042
8 changed files with 71 additions and 70 deletions

View File

@@ -7,6 +7,9 @@ push:
up-dev: up-dev:
docker compose -f docker-compose.dev.yml up --build docker compose -f docker-compose.dev.yml up --build
up-dev-ldap:
docker compose -f docker-compose.dev.yml --profile ldap up --build
up-prod: up-prod:
docker-compose -f docker-compose.prod.yml up --build docker-compose -f docker-compose.prod.yml up --build

View File

@@ -8,7 +8,7 @@ export async function up(knex: Knex): Promise<void> {
await knex.schema.createTable(TableName.LdapConfig, (t) => { await knex.schema.createTable(TableName.LdapConfig, (t) => {
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
t.uuid("orgId").notNullable().unique(); t.uuid("orgId").notNullable().unique();
t.foreign("orgId").references("id").inTable(TableName.Organization); t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
t.boolean("isActive").notNullable(); t.boolean("isActive").notNullable();
t.string("url").notNullable(); t.string("url").notNullable();
t.string("encryptedBindDN"); t.string("encryptedBindDN");

View File

@@ -21,7 +21,7 @@ export let userPublicKey: string | undefined;
export const seedData1 = { export const seedData1 = {
id: "3dafd81d-4388-432b-a4c5-f735616868c1", id: "3dafd81d-4388-432b-a4c5-f735616868c1",
username: process.env.TEST_USER_USERNAME || "test@localhost.local", username: process.env.TEST_USER_USERNAME || "test",
email: process.env.TEST_USER_EMAIL || "test@localhost.local", email: process.env.TEST_USER_EMAIL || "test@localhost.local",
password: process.env.TEST_USER_PASSWORD || "testInfisical@1", password: process.env.TEST_USER_PASSWORD || "testInfisical@1",
organization: { organization: {

View File

@@ -27,9 +27,25 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
await server.register(passport.initialize()); await server.register(passport.initialize());
await server.register(passport.secureSession()); await server.register(passport.secureSession());
const getLdapPassportOpts = (req: FastifyRequest, done: any) => {
const { organizationSlug } = req.body as {
organizationSlug: string;
};
process.nextTick(async () => {
try {
const { opts, ldapConfig } = await server.services.ldap.bootLdap(organizationSlug);
req.ldapConfig = ldapConfig;
done(null, opts);
} catch (err) {
done(err);
}
});
};
passport.use( passport.use(
new LdapStrategy( new LdapStrategy(
server.services.ldap.getLdapPassportOpts as any, getLdapPassportOpts as any,
// eslint-disable-next-line // eslint-disable-next-line
async (req: IncomingMessage, user, cb) => { async (req: IncomingMessage, user, cb) => {
try { try {

View File

@@ -1,5 +1,4 @@
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { FastifyRequest } from "fastify";
import jwt from "jsonwebtoken"; import jwt from "jsonwebtoken";
import { OrgMembershipRole, OrgMembershipStatus, SecretKeyEncoding, TLdapConfigsUpdate } from "@app/db/schemas"; import { OrgMembershipRole, OrgMembershipStatus, SecretKeyEncoding, TLdapConfigsUpdate } from "@app/db/schemas";
@@ -13,7 +12,6 @@ import {
infisicalSymmetricEncypt infisicalSymmetricEncypt
} from "@app/lib/crypto/encryption"; } from "@app/lib/crypto/encryption";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { TOrgPermission } from "@app/lib/types"; 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 { TOrgBotDALFactory } from "@app/services/org/org-bot-dal"; import { TOrgBotDALFactory } from "@app/services/org/org-bot-dal";
@@ -284,14 +282,7 @@ export const ldapConfigServiceFactory = ({
}); });
}; };
// eslint-disable-next-line const bootLdap = async (organizationSlug: string) => {
const getLdapPassportOpts = (req: FastifyRequest, done: any) => {
const { organizationSlug } = req.body as {
organizationSlug: string;
};
const boot = async () => {
try {
const organization = await orgDAL.findOne({ slug: organizationSlug }); const organization = await orgDAL.findOne({ slug: organizationSlug });
if (!organization) throw new BadRequestError({ message: "Org not found" }); if (!organization) throw new BadRequestError({ message: "Org not found" });
@@ -299,7 +290,6 @@ export const ldapConfigServiceFactory = ({
orgId: organization.id, orgId: organization.id,
isActive: true isActive: true
}); });
req.ldapConfig = ldapConfig;
const opts = { const opts = {
server: { server: {
@@ -320,18 +310,7 @@ export const ldapConfigServiceFactory = ({
passReqToCallback: true passReqToCallback: true
}; };
// eslint-disable-next-line return { opts, ldapConfig };
done(null, opts);
} catch (err) {
logger.error(err);
// eslint-disable-next-line
done(err);
}
};
process.nextTick(async () => {
await boot();
});
}; };
const ldapLogin = async ({ externalId, username, firstName, lastName, emails, orgId, relayState }: TLdapLoginDTO) => { const ldapLogin = async ({ externalId, username, firstName, lastName, emails, orgId, relayState }: TLdapLoginDTO) => {
@@ -443,7 +422,8 @@ export const ldapConfigServiceFactory = ({
updateLdapCfg, updateLdapCfg,
getLdapCfgWithPermissionCheck, getLdapCfgWithPermissionCheck,
getLdapCfg, getLdapCfg,
getLdapPassportOpts, // getLdapPassportOpts,
ldapLogin ldapLogin,
bootLdap
}; };
}; };

View File

@@ -140,6 +140,7 @@ services:
volumes: volumes:
- ldap_data:/var/lib/ldap - ldap_data:/var/lib/ldap
- ldap_config:/etc/ldap/slapd.d - ldap_config:/etc/ldap/slapd.d
profiles: [ldap]
phpldapadmin: # username: cn=admin,dc=acme,dc=com, pass is admin phpldapadmin: # username: cn=admin,dc=acme,dc=com, pass is admin
image: osixia/phpldapadmin:latest image: osixia/phpldapadmin:latest
@@ -151,6 +152,7 @@ services:
- 6433:80 - 6433:80
depends_on: depends_on:
- openldap - openldap
profiles: [ldap]
volumes: volumes:
postgres-data: postgres-data:

View File

@@ -121,7 +121,7 @@ export const AdminLayout = ({ children }: LayoutProps) => {
</div> </div>
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="start" className="p-1"> <DropdownMenuContent align="start" className="p-1">
<div className="px-2 py-1 text-xs text-mineshaft-400">{user.username}</div> <div className="px-2 py-1 text-xs text-mineshaft-400">{user?.username}</div>
<Link href="/personal-settings"> <Link href="/personal-settings">
<DropdownMenuItem>Personal Settings</DropdownMenuItem> <DropdownMenuItem>Personal Settings</DropdownMenuItem>
</Link> </Link>

View File

@@ -1,7 +1,7 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup"; import { zodResolver } from "@hookform/resolvers/zod";
import * as yup from "yup"; import { z } from "zod";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { import {
@@ -20,15 +20,15 @@ import {
} from "@app/hooks/api"; } from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
const schema = yup.object({ const LDAPFormSchema = z.object({
url: yup.string().required("URL is required"), url: z.string().min(1, "URL is requiredx"),
bindDN: yup.string().required("Bind DN is required"), bindDN: z.string().min(1, "Bind DN is requiredx"),
bindPass: yup.string().required("Bind Pass is required"), bindPass: z.string().min(1, "Bind Pass is required"),
searchBase: yup.string().required("Search Base is required"), searchBase: z.string().min(1, "Search Base is required"),
caCert: yup.string() caCert: z.string().optional()
}).required(); });
export type AddLDAPFormData = yup.InferType<typeof schema>; export type TLDAPFormData = z.infer<typeof LDAPFormSchema>;
type Props = { type Props = {
popUp: UsePopUpState<["addLDAP"]>; popUp: UsePopUpState<["addLDAP"]>;
@@ -51,9 +51,9 @@ export const LDAPModal = ({
control, control,
handleSubmit, handleSubmit,
reset, reset,
} = useForm<AddLDAPFormData>({ } = useForm<TLDAPFormData>({
resolver: yupResolver(schema) resolver: zodResolver(LDAPFormSchema)
}); })
useEffect(() => { useEffect(() => {
if (data) { if (data) {
@@ -73,7 +73,7 @@ export const LDAPModal = ({
bindPass, bindPass,
searchBase, searchBase,
caCert caCert
}: AddLDAPFormData) => { }: TLDAPFormData) => {
try { try {
if (!currentOrg) return; if (!currentOrg) return;