mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-08-22 16:17:17 +00:00
Add LDAP and OpenID Connect login options.
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/86ee1cbb-c19b-4b38-bd5b-4db88983e811.jpg
This commit is contained in:
Generated
+773
-1
File diff suppressed because it is too large
Load Diff
@@ -81,7 +81,10 @@
|
|||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-jwt": "^4.0.1",
|
"passport-jwt": "^4.0.1",
|
||||||
|
"passport-ldapauth": "^3.0.1",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
|
"passport-openid-connect": "^0.1.0",
|
||||||
|
"passport-openidconnect": "^0.1.2",
|
||||||
"pg": "^8.14.1",
|
"pg": "^8.14.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import passport from "passport";
|
import passport from "passport";
|
||||||
import { Strategy as LocalStrategy } from "passport-local";
|
import { Strategy as LocalStrategy } from "passport-local";
|
||||||
import { Strategy as JwtStrategy, ExtractJwt } from "passport-jwt";
|
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 } from "express";
|
||||||
import session from "express-session";
|
import session from "express-session";
|
||||||
import { scrypt, randomBytes, timingSafeEqual } from "crypto";
|
import { scrypt, randomBytes, timingSafeEqual } from "crypto";
|
||||||
import { promisify } from "util";
|
import { promisify } from "util";
|
||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
import { storage } from "./storage";
|
import { storage } from "./storage";
|
||||||
|
import { ldapClient } from "./ldap";
|
||||||
import { User as SelectUser, loginSchema } from "@shared/schema";
|
import { User as SelectUser, loginSchema } from "@shared/schema";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -85,6 +88,102 @@ export function setupAuth(app: Express) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// LDAP authentication strategy
|
||||||
|
if (process.env.LDAP_ENABLED === "true") {
|
||||||
|
passport.use(
|
||||||
|
new LdapStrategy(
|
||||||
|
{
|
||||||
|
server: {
|
||||||
|
url: process.env.LDAP_URL || "ldap://localhost:389",
|
||||||
|
bindDN: process.env.LDAP_BIND_DN || "",
|
||||||
|
bindCredentials: process.env.LDAP_BIND_PASSWORD || "",
|
||||||
|
searchBase: process.env.LDAP_SEARCH_BASE || "",
|
||||||
|
searchFilter: process.env.LDAP_SEARCH_FILTER || "(uid={{username}})",
|
||||||
|
searchAttributes: ["dn", "cn", "uid", "mail", "memberOf"],
|
||||||
|
tlsOptions: {
|
||||||
|
rejectUnauthorized: process.env.LDAP_TLS_REJECT_UNAUTHORIZED === "true",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
usernameField: "username",
|
||||||
|
passwordField: "password",
|
||||||
|
},
|
||||||
|
async (user, done) => {
|
||||||
|
try {
|
||||||
|
// Find user in our database or create one if it doesn't exist
|
||||||
|
let existingUser = await storage.getUserByUsername(user.uid);
|
||||||
|
|
||||||
|
if (!existingUser) {
|
||||||
|
// Create a new user in our local database
|
||||||
|
const defaultRole = await storage.getDefaultRole();
|
||||||
|
|
||||||
|
existingUser = await storage.createUser({
|
||||||
|
username: user.uid,
|
||||||
|
// Create a random password that won't be used (LDAP auth will be used instead)
|
||||||
|
password: await hashPassword(randomBytes(32).toString("hex")),
|
||||||
|
email: user.mail || null,
|
||||||
|
fullName: user.cn || null,
|
||||||
|
roleId: defaultRole?.id || null,
|
||||||
|
authProvider: "ldap",
|
||||||
|
providerUserId: user.dn,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return done(null, existingUser);
|
||||||
|
} catch (error) {
|
||||||
|
return done(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenID Connect authentication strategy
|
||||||
|
if (process.env.OIDC_ENABLED === "true") {
|
||||||
|
passport.use(
|
||||||
|
new OpenIDConnectStrategy(
|
||||||
|
{
|
||||||
|
issuer: process.env.OIDC_ISSUER,
|
||||||
|
authorizationURL: process.env.OIDC_AUTHORIZATION_URL,
|
||||||
|
tokenURL: process.env.OIDC_TOKEN_URL,
|
||||||
|
userInfoURL: process.env.OIDC_USERINFO_URL,
|
||||||
|
clientID: process.env.OIDC_CLIENT_ID || "",
|
||||||
|
clientSecret: process.env.OIDC_CLIENT_SECRET || "",
|
||||||
|
callbackURL: process.env.OIDC_CALLBACK_URL || "http://localhost:3000/api/auth/oidc/callback",
|
||||||
|
scope: ["openid", "profile", "email"],
|
||||||
|
},
|
||||||
|
async (issuer, profile, done) => {
|
||||||
|
try {
|
||||||
|
const { id, displayName, emails } = profile;
|
||||||
|
|
||||||
|
// Find user in our database or create one if it doesn't exist
|
||||||
|
let existingUser = await storage.getUserByProviderUserId("oidc", id);
|
||||||
|
|
||||||
|
if (!existingUser) {
|
||||||
|
// Create a new user in our local database
|
||||||
|
const defaultRole = await storage.getDefaultRole();
|
||||||
|
const email = emails && emails.length > 0 ? emails[0].value : null;
|
||||||
|
|
||||||
|
existingUser = await storage.createUser({
|
||||||
|
username: profile.username || `user_${id.substring(0, 8)}`,
|
||||||
|
// Create a random password that won't be used (OIDC auth will be used instead)
|
||||||
|
password: await hashPassword(randomBytes(32).toString("hex")),
|
||||||
|
email,
|
||||||
|
fullName: displayName || null,
|
||||||
|
roleId: defaultRole?.id || null,
|
||||||
|
authProvider: "oidc",
|
||||||
|
providerUserId: id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return done(null, existingUser);
|
||||||
|
} catch (error) {
|
||||||
|
return done(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
passport.serializeUser((user, done) => done(null, user.id));
|
passport.serializeUser((user, done) => done(null, user.id));
|
||||||
passport.deserializeUser(async (id: number, done) => {
|
passport.deserializeUser(async (id: number, done) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user