diff --git a/api/server/middleware/checkDomainAllowed.js b/api/server/middleware/checkDomainAllowed.js index be3f737ad..914ac44da 100644 --- a/api/server/middleware/checkDomainAllowed.js +++ b/api/server/middleware/checkDomainAllowed.js @@ -11,18 +11,25 @@ const { getAppConfig } = require('~/server/services/Config'); * @param {Object} res - Express response object. * @param {Function} next - Next middleware function. * - * @returns {Promise} - Returns a Promise which when resolved calls next middleware if the domain's email is allowed + * @returns {Promise} - Calls next middleware if the domain's email is allowed, otherwise redirects to login */ -const checkDomainAllowed = async (req, res, next = () => {}) => { - const email = req?.user?.email; - const appConfig = await getAppConfig({ - role: req?.user?.role, - }); - if (email && !isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) { - logger.error(`[Social Login] [Social Login not allowed] [Email: ${email}]`); - return res.redirect('/login'); - } else { - return next(); +const checkDomainAllowed = async (req, res, next) => { + try { + const email = req?.user?.email; + const appConfig = await getAppConfig({ + role: req?.user?.role, + }); + + if (email && !isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) { + logger.error(`[Social Login] [Social Login not allowed] [Email: ${email}]`); + res.redirect('/login'); + return; + } + + next(); + } catch (error) { + logger.error('[checkDomainAllowed] Error checking domain:', error); + res.redirect('/login'); } }; diff --git a/api/server/routes/oauth.js b/api/server/routes/oauth.js index 74faa90ce..0b1252f63 100644 --- a/api/server/routes/oauth.js +++ b/api/server/routes/oauth.js @@ -26,9 +26,12 @@ const domains = { router.use(logHeaders); router.use(loginLimiter); -const oauthHandler = async (req, res) => { +const oauthHandler = async (req, res, next) => { try { - await checkDomainAllowed(req, res); + if (res.headersSent) { + return; + } + await checkBan(req, res); if (req.banned) { return; @@ -46,6 +49,7 @@ const oauthHandler = async (req, res) => { res.redirect(domains.client); } catch (err) { logger.error('Error in setting authentication tokens:', err); + next(err); } }; @@ -79,6 +83,7 @@ router.get( scope: ['openid', 'profile', 'email'], }), setBalanceConfig, + checkDomainAllowed, oauthHandler, ); @@ -104,6 +109,7 @@ router.get( profileFields: ['id', 'email', 'name'], }), setBalanceConfig, + checkDomainAllowed, oauthHandler, ); @@ -125,6 +131,7 @@ router.get( session: false, }), setBalanceConfig, + checkDomainAllowed, oauthHandler, ); @@ -148,6 +155,7 @@ router.get( scope: ['user:email', 'read:user'], }), setBalanceConfig, + checkDomainAllowed, oauthHandler, ); @@ -171,6 +179,7 @@ router.get( scope: ['identify', 'email'], }), setBalanceConfig, + checkDomainAllowed, oauthHandler, ); @@ -192,6 +201,7 @@ router.post( session: false, }), setBalanceConfig, + checkDomainAllowed, oauthHandler, ); diff --git a/api/strategies/ldapStrategy.js b/api/strategies/ldapStrategy.js index c5796f62e..6f3adf694 100644 --- a/api/strategies/ldapStrategy.js +++ b/api/strategies/ldapStrategy.js @@ -4,6 +4,7 @@ const { logger } = require('@librechat/data-schemas'); const { isEnabled, getBalanceConfig } = require('@librechat/api'); const { SystemRoles, ErrorTypes } = require('librechat-data-provider'); const { createUser, findUser, updateUser, countUsers } = require('~/models'); +const { isEmailDomainAllowed } = require('~/server/services/domains'); const { getAppConfig } = require('~/server/services/Config'); const { @@ -124,6 +125,15 @@ const ldapLogin = new LdapStrategy(ldapOptions, async (userinfo, done) => { if (!user) { const isFirstRegisteredUser = (await countUsers()) === 0; const role = isFirstRegisteredUser ? SystemRoles.ADMIN : SystemRoles.USER; + const appConfig = await getAppConfig({ role }); + + if (!isEmailDomainAllowed(mail, appConfig?.registration?.allowedDomains)) { + logger.error( + `[LDAP Strategy] Registration blocked - email domain not allowed [Email: ${mail}]`, + ); + return done(null, false, { message: 'Email domain not allowed for registration' }); + } + user = { provider: 'ldap', ldapId, @@ -133,7 +143,6 @@ const ldapLogin = new LdapStrategy(ldapOptions, async (userinfo, done) => { name: fullName, role, }; - const appConfig = await getAppConfig({ role: user?.role }); const balanceConfig = getBalanceConfig(appConfig); const userId = await createUser(user, balanceConfig); user._id = userId; diff --git a/api/strategies/openidStrategy.js b/api/strategies/openidStrategy.js index 370d502ab..6f35e2af8 100644 --- a/api/strategies/openidStrategy.js +++ b/api/strategies/openidStrategy.js @@ -15,6 +15,7 @@ const { getBalanceConfig, } = require('@librechat/api'); const { getStrategyFunctions } = require('~/server/services/Files/strategies'); +const { isEmailDomainAllowed } = require('~/server/services/domains'); const { findUser, createUser, updateUser } = require('~/models'); const { getAppConfig } = require('~/server/services/Config'); const getLogStores = require('~/cache/getLogStores'); @@ -400,6 +401,13 @@ async function setupOpenId() { const appConfig = await getAppConfig(); if (!user) { + if (!isEmailDomainAllowed(userinfo.email, appConfig?.registration?.allowedDomains)) { + logger.error( + `[OpenID Strategy] Registration blocked - email domain not allowed [Email: ${userinfo.email}]`, + ); + return done(null, false, { message: 'Email domain not allowed for registration' }); + } + user = { provider: 'openid', openidId: userinfo.sub, diff --git a/api/strategies/samlStrategy.js b/api/strategies/samlStrategy.js index 93118f674..ffc61ad19 100644 --- a/api/strategies/samlStrategy.js +++ b/api/strategies/samlStrategy.js @@ -7,6 +7,7 @@ const { ErrorTypes } = require('librechat-data-provider'); const { hashToken, logger } = require('@librechat/data-schemas'); const { Strategy: SamlStrategy } = require('@node-saml/passport-saml'); const { getStrategyFunctions } = require('~/server/services/Files/strategies'); +const { isEmailDomainAllowed } = require('~/server/services/domains'); const { findUser, createUser, updateUser } = require('~/models'); const { getAppConfig } = require('~/server/services/Config'); const paths = require('~/config/paths'); @@ -222,11 +223,19 @@ async function setupSaml() { const appConfig = await getAppConfig(); if (!user) { + const userEmail = getEmail(profile) || ''; + if (!isEmailDomainAllowed(userEmail, appConfig?.registration?.allowedDomains)) { + logger.error( + `[SAML Strategy] Registration blocked - email domain not allowed [Email: ${userEmail}]`, + ); + return done(null, false, { message: 'Email domain not allowed for registration' }); + } + user = { provider: 'saml', samlId: profile.nameID, username, - email: getEmail(profile) || '', + email: userEmail, emailVerified: true, name: fullName, }; diff --git a/api/strategies/socialLogin.js b/api/strategies/socialLogin.js index 5808cbc9b..902c9e873 100644 --- a/api/strategies/socialLogin.js +++ b/api/strategies/socialLogin.js @@ -2,6 +2,7 @@ const { isEnabled } = require('@librechat/api'); const { logger } = require('@librechat/data-schemas'); const { ErrorTypes } = require('librechat-data-provider'); const { createSocialUser, handleExistingUser } = require('./process'); +const { isEmailDomainAllowed } = require('~/server/services/domains'); const { getAppConfig } = require('~/server/services/Config'); const { findUser } = require('~/models'); @@ -17,6 +18,16 @@ const socialLogin = const existingUser = await findUser({ email: email.trim() }); const ALLOW_SOCIAL_REGISTRATION = isEnabled(process.env.ALLOW_SOCIAL_REGISTRATION); + if (!existingUser && !isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) { + logger.error( + `[${provider}Login] Registration blocked - email domain not allowed [Email: ${email}]`, + ); + const error = new Error(ErrorTypes.AUTH_FAILED); + error.code = ErrorTypes.AUTH_FAILED; + error.message = 'Email domain not allowed for registration'; + return cb(error); + } + if (existingUser?.provider === provider) { await handleExistingUser(existingUser, avatarUrl, appConfig); return cb(null, existingUser);