mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-07-26 11:59:14 +00:00
Add LDAP and OpenID Connect authentication
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/f53b9394-0261-478c-aa14-813efc485813.jpg
This commit is contained in:
+38
-4
@@ -3,7 +3,7 @@ import { Strategy as LocalStrategy } from "passport-local";
|
||||
import { Strategy as JwtStrategy, ExtractJwt } from "passport-jwt";
|
||||
import LdapStrategy from "passport-ldapauth";
|
||||
import { Strategy as OpenIDStrategy } from "passport-openidconnect";
|
||||
import { Express } from "express";
|
||||
import { Express, Request, Response, NextFunction } from "express";
|
||||
import session from "express-session";
|
||||
import { scrypt, randomBytes, timingSafeEqual } from "crypto";
|
||||
import { promisify } from "util";
|
||||
@@ -140,7 +140,7 @@ export function setupAuth(app: Express) {
|
||||
// OpenID Connect authentication strategy
|
||||
if (process.env.OIDC_ENABLED === "true") {
|
||||
passport.use(
|
||||
new OpenIDConnectStrategy(
|
||||
new OpenIDStrategy(
|
||||
{
|
||||
issuer: process.env.OIDC_ISSUER,
|
||||
authorizationURL: process.env.OIDC_AUTHORIZATION_URL,
|
||||
@@ -151,7 +151,7 @@ export function setupAuth(app: Express) {
|
||||
callbackURL: process.env.OIDC_CALLBACK_URL || "http://localhost:3000/api/auth/oidc/callback",
|
||||
scope: ["openid", "profile", "email"],
|
||||
},
|
||||
async (issuer, profile, done) => {
|
||||
async (issuer: string, profile: any, done: any) => {
|
||||
try {
|
||||
const { id, displayName, emails } = profile;
|
||||
|
||||
@@ -236,7 +236,7 @@ export function setupAuth(app: Express) {
|
||||
}
|
||||
});
|
||||
|
||||
// Login endpoint
|
||||
// Login endpoint (local strategy)
|
||||
app.post("/api/login", (req, res, next) => {
|
||||
passport.authenticate("local", (err: any, user: any, info: any) => {
|
||||
if (err) return next(err);
|
||||
@@ -251,6 +251,40 @@ export function setupAuth(app: Express) {
|
||||
});
|
||||
})(req, res, next);
|
||||
});
|
||||
|
||||
// LDAP authentication routes
|
||||
if (process.env.LDAP_ENABLED === "true") {
|
||||
// LDAP login endpoint
|
||||
app.post("/api/auth/ldap", (req, res, next) => {
|
||||
passport.authenticate("ldapauth", (err: any, user: any, info: any) => {
|
||||
if (err) return next(err);
|
||||
if (!user) {
|
||||
return res.status(401).json({ message: info?.message || "LDAP authentication failed" });
|
||||
}
|
||||
req.login(user, (loginErr) => {
|
||||
if (loginErr) return next(loginErr);
|
||||
// Remove password from response
|
||||
const userResponse = { ...user, password: undefined };
|
||||
res.json(userResponse);
|
||||
});
|
||||
})(req, res, next);
|
||||
});
|
||||
}
|
||||
|
||||
// OpenID Connect authentication routes
|
||||
if (process.env.OIDC_ENABLED === "true") {
|
||||
// OIDC login initiation
|
||||
app.get("/api/auth/oidc", passport.authenticate("openidconnect"));
|
||||
|
||||
// OIDC callback
|
||||
app.get("/api/auth/oidc/callback",
|
||||
passport.authenticate("openidconnect", { failureRedirect: "/auth" }),
|
||||
(req: Request, res: Response) => {
|
||||
// Successful authentication, redirect to the main application
|
||||
res.redirect("/");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Logout endpoint
|
||||
app.post("/api/logout", (req, res, next) => {
|
||||
|
||||
@@ -168,6 +168,16 @@ export class DatabaseStorage implements IStorage {
|
||||
const result = await db.select().from(users).where(eq(users.username, username));
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async getUserByProviderUserId(provider: string, providerUserId: string): Promise<User | undefined> {
|
||||
const result = await db.select().from(users).where(
|
||||
and(
|
||||
eq(users.authProvider, provider),
|
||||
eq(users.providerUserId, providerUserId)
|
||||
)
|
||||
);
|
||||
return result.length > 0 ? result[0] : undefined;
|
||||
}
|
||||
|
||||
async createUser(insertUser: InsertUser): Promise<User> {
|
||||
const result = await db.insert(users).values(insertUser).returning();
|
||||
|
||||
+3
-1
@@ -106,7 +106,7 @@ export const rolePermissions = pgTable("role_permissions", {
|
||||
};
|
||||
});
|
||||
|
||||
// User schema for local authentication
|
||||
// User schema for authentication (local, LDAP, or OIDC)
|
||||
export const users = pgTable("users", {
|
||||
id: serial("id").primaryKey(),
|
||||
username: text("username").notNull().unique(),
|
||||
@@ -114,6 +114,8 @@ export const users = pgTable("users", {
|
||||
email: text("email"),
|
||||
fullName: text("full_name"),
|
||||
roleId: integer("role_id").references(() => roles.id),
|
||||
authProvider: text("auth_provider").default("local"),
|
||||
providerUserId: text("provider_user_id"),
|
||||
createdAt: timestamp("created_at").defaultNow(),
|
||||
});
|
||||
|
||||
|
||||
Vendored
+47
@@ -0,0 +1,47 @@
|
||||
declare module 'passport-ldapauth' {
|
||||
import { Strategy as PassportStrategy } from 'passport';
|
||||
|
||||
export interface LdapAuthOptions {
|
||||
server: {
|
||||
url: string;
|
||||
bindDN?: string;
|
||||
bindCredentials?: string;
|
||||
searchBase: string;
|
||||
searchFilter: string;
|
||||
searchAttributes?: string[];
|
||||
tlsOptions?: {
|
||||
rejectUnauthorized?: boolean;
|
||||
};
|
||||
};
|
||||
usernameField?: string;
|
||||
passwordField?: string;
|
||||
passReqToCallback?: boolean;
|
||||
}
|
||||
|
||||
export type VerifyCallback = (
|
||||
err?: Error | null,
|
||||
user?: object,
|
||||
info?: object
|
||||
) => void;
|
||||
|
||||
export type VerifyFunction = (
|
||||
user: any,
|
||||
verified: VerifyCallback
|
||||
) => void;
|
||||
|
||||
export type VerifyFunctionWithRequest = (
|
||||
req: object,
|
||||
user: any,
|
||||
verified: VerifyCallback
|
||||
) => void;
|
||||
|
||||
export default class Strategy extends PassportStrategy {
|
||||
constructor(
|
||||
options: LdapAuthOptions,
|
||||
verify?: VerifyFunction | VerifyFunctionWithRequest
|
||||
);
|
||||
|
||||
name: string;
|
||||
authenticate(req: object, options?: object): void;
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
declare module 'passport-openidconnect' {
|
||||
import { Strategy as PassportStrategy } from 'passport';
|
||||
|
||||
export interface Profile {
|
||||
id: string;
|
||||
displayName?: string;
|
||||
name?: {
|
||||
familyName?: string;
|
||||
givenName?: string;
|
||||
middleName?: string;
|
||||
};
|
||||
emails?: Array<{ value: string; type?: string }>;
|
||||
photos?: Array<{ value: string }>;
|
||||
username?: string;
|
||||
_json: any;
|
||||
_raw: string;
|
||||
}
|
||||
|
||||
export interface StrategyOptions {
|
||||
issuer?: string;
|
||||
authorizationURL?: string;
|
||||
tokenURL?: string;
|
||||
userInfoURL?: string;
|
||||
clientID: string;
|
||||
clientSecret: string;
|
||||
callbackURL: string;
|
||||
scope?: string | string[];
|
||||
passReqToCallback?: false;
|
||||
}
|
||||
|
||||
export interface StrategyOptionsWithRequest {
|
||||
issuer?: string;
|
||||
authorizationURL?: string;
|
||||
tokenURL?: string;
|
||||
userInfoURL?: string;
|
||||
clientID: string;
|
||||
clientSecret: string;
|
||||
callbackURL: string;
|
||||
scope?: string | string[];
|
||||
passReqToCallback: true;
|
||||
}
|
||||
|
||||
export type VerifyCallback = (
|
||||
err?: Error | null,
|
||||
user?: object,
|
||||
info?: object
|
||||
) => void;
|
||||
|
||||
export type VerifyFunction = (
|
||||
issuer: string,
|
||||
profile: Profile,
|
||||
verified: VerifyCallback
|
||||
) => void;
|
||||
|
||||
export type VerifyFunctionWithRequest = (
|
||||
req: object,
|
||||
issuer: string,
|
||||
profile: Profile,
|
||||
verified: VerifyCallback
|
||||
) => void;
|
||||
|
||||
export class Strategy extends PassportStrategy {
|
||||
constructor(
|
||||
options: StrategyOptions,
|
||||
verify: VerifyFunction
|
||||
);
|
||||
constructor(
|
||||
options: StrategyOptionsWithRequest,
|
||||
verify: VerifyFunctionWithRequest
|
||||
);
|
||||
|
||||
name: string;
|
||||
authenticate(req: object, options?: object): void;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user