mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
234 lines
8.8 KiB
JavaScript
234 lines
8.8 KiB
JavaScript
|
|
let PassportOpenIDConnect = require('../auth/modules/passport-providers/oidc');
|
||
|
|
const AppError = require('../middleware/AppError');
|
||
|
|
const authUserAssoc = require('../models/authUserAssociation');
|
||
|
|
const userModel = require('../models/users');
|
||
|
|
|
||
|
|
global.fetch = jest.fn();
|
||
|
|
|
||
|
|
// Mock the authUserAssoc methods
|
||
|
|
jest.mock('../models/authUserAssociation', () => ({
|
||
|
|
find_user_association: jest.fn(),
|
||
|
|
link: jest.fn(),
|
||
|
|
unlink: jest.fn(),
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Mock userModel methods
|
||
|
|
jest.mock('../models/users', () => ({
|
||
|
|
getById: jest.fn(),
|
||
|
|
getId: jest.fn(),
|
||
|
|
generatePassword: jest.fn(),
|
||
|
|
register: jest.fn(),
|
||
|
|
editUser: jest.fn(),
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Mock db connection methods
|
||
|
|
jest.mock('../config/db', () => ({
|
||
|
|
connect: jest.fn(),
|
||
|
|
getConnection: jest.fn(() => ({
|
||
|
|
collection: jest.fn(() => ({
|
||
|
|
findOne: jest.fn(),
|
||
|
|
insertOne: jest.fn(),
|
||
|
|
deleteOne: jest.fn(),
|
||
|
|
})),
|
||
|
|
})),
|
||
|
|
}));
|
||
|
|
|
||
|
|
const getProfileMock = (id = 'test-auth-id', email = 'test@example.com', name = 'Test User', roles = ['teacher']) => ({
|
||
|
|
id,
|
||
|
|
emails: [{ value: email }],
|
||
|
|
name: { displayName: name },
|
||
|
|
roles,
|
||
|
|
});
|
||
|
|
|
||
|
|
const setupMocks = (authAssocReturn = null, userReturn = null, fetchReturn = {}) => {
|
||
|
|
// Mock authUserAssoc and userModel
|
||
|
|
authUserAssoc.find_user_association.mockResolvedValue(authAssocReturn);
|
||
|
|
userModel.getId.mockResolvedValue(userReturn);
|
||
|
|
userModel.getById.mockResolvedValue(userReturn);
|
||
|
|
|
||
|
|
// Mock fetch to return a fake configuration
|
||
|
|
fetch.mockResolvedValue({
|
||
|
|
json: jest.fn().mockResolvedValue(fetchReturn),
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
const createOidcConfig = () => ({
|
||
|
|
OIDC_CONFIG_URL: 'https://example.com/.well-known/openid-configuration',
|
||
|
|
OIDC_CLIENT_ID: 'test-client-id',
|
||
|
|
OIDC_CLIENT_SECRET: 'test-client-secret',
|
||
|
|
OIDC_ADD_SCOPE: '',
|
||
|
|
OIDC_ROLE_TEACHER_VALUE: 'teacher',
|
||
|
|
OIDC_ROLE_STUDENT_VALUE: 'student',
|
||
|
|
tokenURL: 'https://example.com/token',
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('PassportOpenIDConnect Class', () => {
|
||
|
|
let passportMock;
|
||
|
|
let appMock;
|
||
|
|
let oidcInstance;
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
passportMock = { use: jest.fn(), register: jest.fn(), authenticate: jest.fn()};
|
||
|
|
appMock = { get: jest.fn() };
|
||
|
|
|
||
|
|
// Mock configuration object
|
||
|
|
const oidcConfig = {
|
||
|
|
issuer: 'exom', // Ensure the issuer is correctly set
|
||
|
|
authorization_endpoint: 'https://example.com/auth',
|
||
|
|
token_endpoint: 'https://example.com/token',
|
||
|
|
tokenURL: 'https://example.com/token',
|
||
|
|
userInfoURL: 'https://example.com/userinfo',
|
||
|
|
clientID: 'test-client-id',
|
||
|
|
clientSecret: 'test-client-secret',
|
||
|
|
callbackURL: 'https://example.com/callback',
|
||
|
|
passReqToCallback: true,
|
||
|
|
scope: 'openid profile email', // Set required scopes
|
||
|
|
};
|
||
|
|
// Mock passport's use method to simulate adding the strategy
|
||
|
|
passportMock.use.mockImplementation((strategy, callback) => {
|
||
|
|
passportMock._callback = callback;
|
||
|
|
});
|
||
|
|
passportMock.register = jest.fn().mockResolvedValue(getProfileMock());
|
||
|
|
|
||
|
|
// Instantiate the PassportOpenIDConnect class with the mock
|
||
|
|
oidcInstance = new PassportOpenIDConnect(passportMock, oidcConfig);
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
jest.clearAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should fetch OIDC configuration', async () => {
|
||
|
|
const fakeConfig = { issuer: 'exom', authorization_endpoint: 'https://example.com/auth' };
|
||
|
|
fetch.mockResolvedValue({ json: jest.fn().mockResolvedValue(fakeConfig) });
|
||
|
|
|
||
|
|
const result = await oidcInstance.getConfigFromConfigURL('test-provider', { OIDC_CONFIG_URL: 'https://example.com/.well-known/openid-configuration' });
|
||
|
|
|
||
|
|
expect(fetch).toHaveBeenCalledWith('https://example.com/.well-known/openid-configuration');
|
||
|
|
expect(result).toEqual(fakeConfig);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should throw AppError if fetching OIDC config fails', async () => {
|
||
|
|
fetch.mockRejectedValue(new Error('Network error'));
|
||
|
|
|
||
|
|
await expect(oidcInstance.getConfigFromConfigURL('test-provider', { OIDC_CONFIG_URL: 'https://example.com' }))
|
||
|
|
.rejects.toThrow(AppError);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should register passport strategy and process new users consent flag true', async () => {
|
||
|
|
setupMocks(null, null, {
|
||
|
|
issuer: 'https://example.com',
|
||
|
|
authorization_endpoint: 'https://example.com/auth',
|
||
|
|
token_endpoint: 'https://example.com/token'
|
||
|
|
});
|
||
|
|
const profileMock = getProfileMock();
|
||
|
|
|
||
|
|
|
||
|
|
const reqMock = { session: {} };
|
||
|
|
const doneMock = jest.fn((error, user) => {
|
||
|
|
console.log('doneMock was called:', error, user); // Log to check if doneMock is called
|
||
|
|
});
|
||
|
|
|
||
|
|
// Updated configuration with tokenURL
|
||
|
|
const config = createOidcConfig();
|
||
|
|
|
||
|
|
// Ensure `passportMock.use` is being called correctly with the expected config
|
||
|
|
await oidcInstance.register(appMock, passportMock, '/auth', 'oidc-test', config, userModel);
|
||
|
|
|
||
|
|
|
||
|
|
// Check that passport.use has been called, which registers the strategy
|
||
|
|
expect(passportMock.use).toHaveBeenCalledWith('oidc-test', expect.objectContaining({
|
||
|
|
_issuer: 'https://example.com', // Assert that tokenURL is present in the strategy config
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Ensure routes are defined
|
||
|
|
expect(appMock.get).toHaveBeenCalledWith('/auth/oidc-test', expect.any(Function));
|
||
|
|
expect(appMock.get).toHaveBeenCalledWith('/auth/oidc-test/callback', expect.any(Function), expect.any(Function));
|
||
|
|
|
||
|
|
// Access the _verify method inside the passportMock._callback (which is a Strategy instance)
|
||
|
|
const strategyCallback = passportMock._callback._verify;
|
||
|
|
|
||
|
|
// Ensure the callback is correctly registered and is a function
|
||
|
|
expect(typeof strategyCallback).toBe('function');
|
||
|
|
|
||
|
|
doneMock.mockImplementation((error, user) => {
|
||
|
|
// Check if session.requiresConsent is set
|
||
|
|
console.log("In doneMock, error:", error, "user:", user);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Simulate the strategy callback being invoked
|
||
|
|
await strategyCallback(reqMock, null, profileMock, null, null, doneMock, null, userModel);
|
||
|
|
|
||
|
|
// Ensure the doneMock was called
|
||
|
|
expect(doneMock).toHaveBeenCalled();
|
||
|
|
// Validate that consent flag is set for new users
|
||
|
|
expect(reqMock.session.requiresConsent).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
it('should correctly process new users and set consent flag', async () => {
|
||
|
|
setupMocks(null, { _id: 'mocked-user-id', email: 'test@example.com' }, {
|
||
|
|
issuer: 'https://example.com',
|
||
|
|
authorization_endpoint: 'https://example.com/auth',
|
||
|
|
token_endpoint: 'https://example.com/token'
|
||
|
|
});
|
||
|
|
|
||
|
|
const config = createOidcConfig();
|
||
|
|
const profileMock = getProfileMock();
|
||
|
|
|
||
|
|
const reqMock = { session: {} };
|
||
|
|
const doneMock = jest.fn((error, user) => {
|
||
|
|
console.log('doneMock was called:', error, user);
|
||
|
|
});
|
||
|
|
passportMock.register.mockResolvedValue({ _id: 'new-user-id' });
|
||
|
|
|
||
|
|
|
||
|
|
await oidcInstance.register(appMock, passportMock, '/auth', 'oidc-test', config, userModel);
|
||
|
|
|
||
|
|
const strategyCallback = passportMock._callback._verify;
|
||
|
|
expect(typeof strategyCallback).toBe('function');
|
||
|
|
|
||
|
|
doneMock.mockImplementation((error, user) => {
|
||
|
|
console.log("In doneMock, error:", error, "user:", user);
|
||
|
|
});
|
||
|
|
|
||
|
|
await strategyCallback(reqMock, null, profileMock, null, null, doneMock, null, userModel);
|
||
|
|
|
||
|
|
expect(doneMock).toHaveBeenCalled();
|
||
|
|
expect(reqMock.session.requiresConsent).toBe(true);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should correctly process existing users without setting consent flag', async () => {
|
||
|
|
let linkData = {
|
||
|
|
user_id: 'existing-user-id',
|
||
|
|
provider_id: 'test-auth-id',
|
||
|
|
provider: 'oidc',
|
||
|
|
email: 'test@example.com',
|
||
|
|
role: 'teacher',
|
||
|
|
};
|
||
|
|
|
||
|
|
setupMocks(linkData, { _id: 'mocked-user-id', email: 'test@example.com' }, {
|
||
|
|
issuer: 'https://example.com',
|
||
|
|
authorization_endpoint: 'https://example.com/auth',
|
||
|
|
token_endpoint: 'https://example.com/token'
|
||
|
|
});
|
||
|
|
|
||
|
|
const config = createOidcConfig();
|
||
|
|
const profileMock = getProfileMock();
|
||
|
|
const reqMock = { session: {} };
|
||
|
|
const doneMock = jest.fn((error, user) => {
|
||
|
|
console.log('doneMock was called:', error, user);
|
||
|
|
});
|
||
|
|
|
||
|
|
await oidcInstance.register(appMock, passportMock, '/auth', 'oidc-test', config, userModel);
|
||
|
|
|
||
|
|
const strategyCallback = passportMock._callback._verify;
|
||
|
|
expect(typeof strategyCallback).toBe('function');
|
||
|
|
|
||
|
|
await strategyCallback(reqMock, null, profileMock, null, null, doneMock, null, userModel);
|
||
|
|
|
||
|
|
expect(doneMock).toHaveBeenCalled();
|
||
|
|
expect(reqMock.session.requiresConsent).toBe(false);
|
||
|
|
});
|
||
|
|
});
|