mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
🔐 feat: Support Multiple Roles in OPENID_REQUIRED_ROLE (#9171)
* feat: support multiple roles in OPENID_REQUIRED_ROLE - Allow comma-separated roles in OPENID_REQUIRED_ROLE environment variable - User needs ANY of the specified roles to login (OR logic) - Maintain backward compatibility with single role configuration - Add comprehensive test coverage for multiple role scenarios * Add tests * Fix linter * Add missing closing brace * Add new line * Simplify tests * Refresh OpenID verify callback in tests * Fix OpenID spec and resolve linting errors * test: Add backward compatibility test for single required role in OpenID strategy --------- Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
2153db2f5f
commit
d83826b604
2 changed files with 81 additions and 3 deletions
|
|
@ -338,7 +338,25 @@ describe('setupOpenId', () => {
|
|||
|
||||
// Assert – verify that the strategy rejects login
|
||||
expect(user).toBe(false);
|
||||
expect(details.message).toBe('You must have the "requiredRole" role to log in.');
|
||||
expect(details.message).toBe('You must have "requiredRole" role to log in.');
|
||||
});
|
||||
|
||||
it('should allow login when single required role is present (backward compatibility)', async () => {
|
||||
// Arrange – ensure single role configuration (as set in beforeEach)
|
||||
// OPENID_REQUIRED_ROLE = 'requiredRole'
|
||||
// Default jwtDecode mock in beforeEach already returns this role
|
||||
jwtDecode.mockReturnValue({
|
||||
roles: ['requiredRole', 'anotherRole'],
|
||||
});
|
||||
|
||||
// Act
|
||||
const { user } = await validate(tokenset);
|
||||
|
||||
// Assert – verify that login succeeds with single role configuration
|
||||
expect(user).toBeTruthy();
|
||||
expect(user.email).toBe(tokenset.claims().email);
|
||||
expect(user.username).toBe(tokenset.claims().preferred_username);
|
||||
expect(createUser).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should attempt to download and save the avatar if picture is provided', async () => {
|
||||
|
|
@ -364,6 +382,58 @@ describe('setupOpenId', () => {
|
|||
// Depending on your implementation, user.avatar may be undefined or an empty string.
|
||||
});
|
||||
|
||||
it('should support comma-separated multiple roles', async () => {
|
||||
// Arrange
|
||||
process.env.OPENID_REQUIRED_ROLE = 'someRole,anotherRole,admin';
|
||||
await setupOpenId(); // Re-initialize the strategy
|
||||
verifyCallback = require('openid-client/passport').__getVerifyCallback();
|
||||
jwtDecode.mockReturnValue({
|
||||
roles: ['anotherRole', 'aThirdRole'],
|
||||
});
|
||||
|
||||
// Act
|
||||
const { user } = await validate(tokenset);
|
||||
|
||||
// Assert
|
||||
expect(user).toBeTruthy();
|
||||
expect(user.email).toBe(tokenset.claims().email);
|
||||
});
|
||||
|
||||
it('should reject login when user has none of the required multiple roles', async () => {
|
||||
// Arrange
|
||||
process.env.OPENID_REQUIRED_ROLE = 'someRole,anotherRole,admin';
|
||||
await setupOpenId(); // Re-initialize the strategy
|
||||
verifyCallback = require('openid-client/passport').__getVerifyCallback();
|
||||
jwtDecode.mockReturnValue({
|
||||
roles: ['aThirdRole', 'aFourthRole'],
|
||||
});
|
||||
|
||||
// Act
|
||||
const { user, details } = await validate(tokenset);
|
||||
|
||||
// Assert
|
||||
expect(user).toBe(false);
|
||||
expect(details.message).toBe(
|
||||
'You must have one of: "someRole", "anotherRole", "admin" role to log in.',
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle spaces in comma-separated roles', async () => {
|
||||
// Arrange
|
||||
process.env.OPENID_REQUIRED_ROLE = ' someRole , anotherRole , admin ';
|
||||
await setupOpenId(); // Re-initialize the strategy
|
||||
verifyCallback = require('openid-client/passport').__getVerifyCallback();
|
||||
jwtDecode.mockReturnValue({
|
||||
roles: ['someRole'],
|
||||
});
|
||||
|
||||
// Act
|
||||
const { user } = await validate(tokenset);
|
||||
|
||||
// Assert
|
||||
expect(user).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should default to usePKCE false when OPENID_USE_PKCE is not defined', async () => {
|
||||
const OpenIDStrategy = require('openid-client/passport').Strategy;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue