mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-03-13 11:26:18 +01:00
🪪 feat: Add OPENID_EMAIL_CLAIM for Configurable OpenID User Identifier (#11699)
* Allow setting the claim field to be used when OpenID login is configured * fix(openid): harden getOpenIdEmail and expand test coverage Guard against non-string claim values in getOpenIdEmail to prevent a TypeError crash in isEmailDomainAllowed when domain restrictions are configured. Improve warning messages to name the fallback chain explicitly and distinguish missing vs. non-string claim values. Fix the domain-block error log to record the resolved identifier rather than userinfo.email, which was misleading when OPENID_EMAIL_CLAIM resolved to a different field (e.g. upn). Fix a latent test defect in openIdJwtStrategy.spec.js where the ~/server/services/Config mock exported getCustomConfig instead of getAppConfig, the symbol actually consumed by openidStrategy.js. Add refreshController tests covering the OPENID_EMAIL_CLAIM paths, which were previously untested despite being a stated fix target. Expand JWT strategy tests with null-payload, empty/whitespace OPENID_EMAIL_CLAIM, migration-via-preferred_username, and call-order assertions for the findUser lookup sequence. * test(auth): enhance AuthController and openIdJwtStrategy tests for openidId updates Added a new test in AuthController to verify that the openidId is updated correctly when a migration is triggered during the refresh process. Expanded the openIdJwtStrategy tests to include assertions for the updateUser function, ensuring that the correct parameters are passed when a user is found with a legacy email. This improves test coverage for OpenID-related functionality. --------- Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
e978a934fc
commit
13df8ed67c
8 changed files with 447 additions and 13 deletions
|
|
@ -267,6 +267,34 @@ function getFullName(userinfo) {
|
|||
return userinfo.username || userinfo.email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the user identifier from OpenID claims.
|
||||
* Configurable via OPENID_EMAIL_CLAIM; defaults to: email -> preferred_username -> upn.
|
||||
*
|
||||
* @param {Object} userinfo - The user information object from OpenID Connect
|
||||
* @returns {string|undefined} The resolved identifier string
|
||||
*/
|
||||
function getOpenIdEmail(userinfo) {
|
||||
const claimKey = process.env.OPENID_EMAIL_CLAIM?.trim();
|
||||
if (claimKey) {
|
||||
const value = userinfo[claimKey];
|
||||
if (typeof value === 'string' && value) {
|
||||
return value;
|
||||
}
|
||||
if (value !== undefined && value !== null) {
|
||||
logger.warn(
|
||||
`[openidStrategy] OPENID_EMAIL_CLAIM="${claimKey}" resolved to a non-string value (type: ${typeof value}). Falling back to: email -> preferred_username -> upn.`,
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
`[openidStrategy] OPENID_EMAIL_CLAIM="${claimKey}" not present in userinfo. Falling back to: email -> preferred_username -> upn.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const fallback = userinfo.email || userinfo.preferred_username || userinfo.upn;
|
||||
return typeof fallback === 'string' ? fallback : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an input into a string suitable for a username.
|
||||
* If the input is a string, it will be returned as is.
|
||||
|
|
@ -379,11 +407,10 @@ async function processOpenIDAuth(tokenset, existingUsersOnly = false) {
|
|||
}
|
||||
|
||||
const appConfig = await getAppConfig();
|
||||
/** Azure AD sometimes doesn't return email, use preferred_username as fallback */
|
||||
const email = userinfo.email || userinfo.preferred_username || userinfo.upn;
|
||||
const email = getOpenIdEmail(userinfo);
|
||||
if (!isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) {
|
||||
logger.error(
|
||||
`[OpenID Strategy] Authentication blocked - email domain not allowed [Email: ${userinfo.email}]`,
|
||||
`[OpenID Strategy] Authentication blocked - email domain not allowed [Identifier: ${email}]`,
|
||||
);
|
||||
throw new Error('Email domain not allowed');
|
||||
}
|
||||
|
|
@ -728,4 +755,5 @@ function getOpenIdConfig() {
|
|||
module.exports = {
|
||||
setupOpenId,
|
||||
getOpenIdConfig,
|
||||
getOpenIdEmail,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue