mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
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:
3
Makefile
3
Makefile
@@ -7,6 +7,9 @@ push:
|
||||
up-dev:
|
||||
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:
|
||||
docker-compose -f docker-compose.prod.yml up --build
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
await knex.schema.createTable(TableName.LdapConfig, (t) => {
|
||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||
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.string("url").notNullable();
|
||||
t.string("encryptedBindDN");
|
||||
|
||||
@@ -21,7 +21,7 @@ export let userPublicKey: string | undefined;
|
||||
|
||||
export const seedData1 = {
|
||||
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",
|
||||
password: process.env.TEST_USER_PASSWORD || "testInfisical@1",
|
||||
organization: {
|
||||
|
||||
@@ -27,11 +27,27 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
||||
await server.register(passport.initialize());
|
||||
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(
|
||||
new LdapStrategy(
|
||||
server.services.ldap.getLdapPassportOpts as any,
|
||||
getLdapPassportOpts as any,
|
||||
// eslint-disable-next-line
|
||||
async (req: IncomingMessage, user, cb) => {
|
||||
async (req: IncomingMessage, user, cb) => {
|
||||
try {
|
||||
const { isUserCompleted, providerAuthToken } = await server.services.ldap.ldapLogin({
|
||||
externalId: user.uidNumber,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
import { FastifyRequest } from "fastify";
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
import { OrgMembershipRole, OrgMembershipStatus, SecretKeyEncoding, TLdapConfigsUpdate } from "@app/db/schemas";
|
||||
@@ -13,7 +12,6 @@ import {
|
||||
infisicalSymmetricEncypt
|
||||
} from "@app/lib/crypto/encryption";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { TOrgPermission } from "@app/lib/types";
|
||||
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
|
||||
import { TOrgBotDALFactory } from "@app/services/org/org-bot-dal";
|
||||
@@ -284,54 +282,35 @@ export const ldapConfigServiceFactory = ({
|
||||
});
|
||||
};
|
||||
|
||||
// eslint-disable-next-line
|
||||
const getLdapPassportOpts = (req: FastifyRequest, done: any) => {
|
||||
const { organizationSlug } = req.body as {
|
||||
organizationSlug: string;
|
||||
};
|
||||
const bootLdap = async (organizationSlug: string) => {
|
||||
const organization = await orgDAL.findOne({ slug: organizationSlug });
|
||||
if (!organization) throw new BadRequestError({ message: "Org not found" });
|
||||
|
||||
const boot = async () => {
|
||||
try {
|
||||
const organization = await orgDAL.findOne({ slug: organizationSlug });
|
||||
if (!organization) throw new BadRequestError({ message: "Org not found" });
|
||||
|
||||
const ldapConfig = await getLdapCfg({
|
||||
orgId: organization.id,
|
||||
isActive: true
|
||||
});
|
||||
req.ldapConfig = ldapConfig;
|
||||
|
||||
const opts = {
|
||||
server: {
|
||||
url: ldapConfig.url,
|
||||
bindDN: ldapConfig.bindDN,
|
||||
bindCredentials: ldapConfig.bindPass,
|
||||
searchBase: ldapConfig.searchBase,
|
||||
searchFilter: "(uid={{username}})",
|
||||
searchAttributes: ["uid", "uidNumber", "givenName", "sn", "mail"],
|
||||
...(ldapConfig.caCert !== ""
|
||||
? {
|
||||
tlsOptions: {
|
||||
ca: [ldapConfig.caCert]
|
||||
}
|
||||
}
|
||||
: {})
|
||||
},
|
||||
passReqToCallback: true
|
||||
};
|
||||
|
||||
// eslint-disable-next-line
|
||||
done(null, opts);
|
||||
} catch (err) {
|
||||
logger.error(err);
|
||||
// eslint-disable-next-line
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
|
||||
process.nextTick(async () => {
|
||||
await boot();
|
||||
const ldapConfig = await getLdapCfg({
|
||||
orgId: organization.id,
|
||||
isActive: true
|
||||
});
|
||||
|
||||
const opts = {
|
||||
server: {
|
||||
url: ldapConfig.url,
|
||||
bindDN: ldapConfig.bindDN,
|
||||
bindCredentials: ldapConfig.bindPass,
|
||||
searchBase: ldapConfig.searchBase,
|
||||
searchFilter: "(uid={{username}})",
|
||||
searchAttributes: ["uid", "uidNumber", "givenName", "sn", "mail"],
|
||||
...(ldapConfig.caCert !== ""
|
||||
? {
|
||||
tlsOptions: {
|
||||
ca: [ldapConfig.caCert]
|
||||
}
|
||||
}
|
||||
: {})
|
||||
},
|
||||
passReqToCallback: true
|
||||
};
|
||||
|
||||
return { opts, ldapConfig };
|
||||
};
|
||||
|
||||
const ldapLogin = async ({ externalId, username, firstName, lastName, emails, orgId, relayState }: TLdapLoginDTO) => {
|
||||
@@ -443,7 +422,8 @@ export const ldapConfigServiceFactory = ({
|
||||
updateLdapCfg,
|
||||
getLdapCfgWithPermissionCheck,
|
||||
getLdapCfg,
|
||||
getLdapPassportOpts,
|
||||
ldapLogin
|
||||
// getLdapPassportOpts,
|
||||
ldapLogin,
|
||||
bootLdap
|
||||
};
|
||||
};
|
||||
|
||||
@@ -140,6 +140,7 @@ services:
|
||||
volumes:
|
||||
- ldap_data:/var/lib/ldap
|
||||
- ldap_config:/etc/ldap/slapd.d
|
||||
profiles: [ldap]
|
||||
|
||||
phpldapadmin: # username: cn=admin,dc=acme,dc=com, pass is admin
|
||||
image: osixia/phpldapadmin:latest
|
||||
@@ -151,6 +152,7 @@ services:
|
||||
- 6433:80
|
||||
depends_on:
|
||||
- openldap
|
||||
profiles: [ldap]
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
|
||||
@@ -91,7 +91,7 @@ export const AdminLayout = ({ children }: LayoutProps) => {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="dark hidden h-screen w-full flex-col overflow-x-hidden md:flex">
|
||||
@@ -121,7 +121,7 @@ export const AdminLayout = ({ children }: LayoutProps) => {
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<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">
|
||||
<DropdownMenuItem>Personal Settings</DropdownMenuItem>
|
||||
</Link>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect } from "react";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as yup from "yup";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
|
||||
import {
|
||||
@@ -20,15 +20,15 @@ import {
|
||||
} from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
const schema = yup.object({
|
||||
url: yup.string().required("URL is required"),
|
||||
bindDN: yup.string().required("Bind DN is required"),
|
||||
bindPass: yup.string().required("Bind Pass is required"),
|
||||
searchBase: yup.string().required("Search Base is required"),
|
||||
caCert: yup.string()
|
||||
}).required();
|
||||
const LDAPFormSchema = z.object({
|
||||
url: z.string().min(1, "URL is requiredx"),
|
||||
bindDN: z.string().min(1, "Bind DN is requiredx"),
|
||||
bindPass: z.string().min(1, "Bind Pass is required"),
|
||||
searchBase: z.string().min(1, "Search Base is required"),
|
||||
caCert: z.string().optional()
|
||||
});
|
||||
|
||||
export type AddLDAPFormData = yup.InferType<typeof schema>;
|
||||
export type TLDAPFormData = z.infer<typeof LDAPFormSchema>;
|
||||
|
||||
type Props = {
|
||||
popUp: UsePopUpState<["addLDAP"]>;
|
||||
@@ -51,9 +51,9 @@ export const LDAPModal = ({
|
||||
control,
|
||||
handleSubmit,
|
||||
reset,
|
||||
} = useForm<AddLDAPFormData>({
|
||||
resolver: yupResolver(schema)
|
||||
});
|
||||
} = useForm<TLDAPFormData>({
|
||||
resolver: zodResolver(LDAPFormSchema)
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
@@ -73,7 +73,7 @@ export const LDAPModal = ({
|
||||
bindPass,
|
||||
searchBase,
|
||||
caCert
|
||||
}: AddLDAPFormData) => {
|
||||
}: TLDAPFormData) => {
|
||||
try {
|
||||
if (!currentOrg) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user