mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
Merge pull request #140 from ets-cfuhrman-pfe/adds-configuration-to-oauth-integration
Adds configuration to oauth integration
This commit is contained in:
commit
ac8b6d34b7
12 changed files with 543 additions and 85 deletions
|
|
@ -23,6 +23,8 @@ services:
|
||||||
EMAIL_PSW: 'vvml wmfr dkzb vjzb'
|
EMAIL_PSW: 'vvml wmfr dkzb vjzb'
|
||||||
JWT_SECRET: haQdgd2jp09qb897GeBZyJetC8ECSpbFJe
|
JWT_SECRET: haQdgd2jp09qb897GeBZyJetC8ECSpbFJe
|
||||||
FRONTEND_URL: "http://localhost:5173"
|
FRONTEND_URL: "http://localhost:5173"
|
||||||
|
volumes:
|
||||||
|
- ./server/auth_config.json:/usr/src/app/serveur/config/auth_config.json
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
||||||
1
server/.gitignore
vendored
Normal file
1
server/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
auth_config.json
|
||||||
206
server/__tests__/auth.test.js
Normal file
206
server/__tests__/auth.test.js
Normal file
|
|
@ -0,0 +1,206 @@
|
||||||
|
const request = require("supertest");
|
||||||
|
const AuthConfig = require("../config/auth.js");
|
||||||
|
const AuthManager = require("../auth/auth-manager.js");
|
||||||
|
|
||||||
|
const mockConfig = {
|
||||||
|
auth: {
|
||||||
|
passportjs: [
|
||||||
|
{
|
||||||
|
provider1: {
|
||||||
|
type: "oauth",
|
||||||
|
OAUTH_AUTHORIZATION_URL: "https://www.testurl.com/oauth2/authorize",
|
||||||
|
OAUTH_TOKEN_URL: "https://www.testurl.com/oauth2/token",
|
||||||
|
OAUTH_USERINFO_URL: "https://www.testurl.com/oauth2/userinfo/",
|
||||||
|
OAUTH_CLIENT_ID: "your_oauth_client_id",
|
||||||
|
OAUTH_CLIENT_SECRET: "your_oauth_client_secret",
|
||||||
|
OAUTH_ADD_SCOPE: "scopes",
|
||||||
|
OAUTH_ROLE_TEACHER_VALUE: "teacher-claim-value",
|
||||||
|
OAUTH_ROLE_STUDENT_VALUE: "student-claim-value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provider2: {
|
||||||
|
type: "oidc",
|
||||||
|
OIDC_CLIENT_ID: "your_oidc_client_id",
|
||||||
|
OIDC_CLIENT_SECRET: "your_oidc_client_secret",
|
||||||
|
OIDC_ISSUER_URL: "https://your-issuer.com",
|
||||||
|
OIDC_ROLE_TEACHER_VALUE: "teacher-claim-value",
|
||||||
|
OIDC_ROLE_STUDENT_VALUE: "student-claim-value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"simple-login": {
|
||||||
|
enabled: true,
|
||||||
|
name: "provider3",
|
||||||
|
SESSION_SECRET: "your_session_secret",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Créez une instance de AuthConfig en utilisant la configuration mockée
|
||||||
|
describe(
|
||||||
|
"AuthConfig Class Tests",
|
||||||
|
() => {
|
||||||
|
let authConfigInstance;
|
||||||
|
|
||||||
|
// Initialisez l'instance avec la configuration mockée
|
||||||
|
beforeAll(() => {
|
||||||
|
authConfigInstance = new AuthConfig();
|
||||||
|
authConfigInstance.loadConfigTest(mockConfig); // On injecte la configuration mockée
|
||||||
|
});
|
||||||
|
|
||||||
|
it("devrait retourner la configuration PassportJS", () => {
|
||||||
|
const config = authConfigInstance.getPassportJSConfig();
|
||||||
|
expect(config).toHaveProperty("provider1");
|
||||||
|
expect(config).toHaveProperty("provider2");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("devrait retourner la configuration Simple Login", () => {
|
||||||
|
const config = authConfigInstance.getSimpleLoginConfig();
|
||||||
|
expect(config).toHaveProperty("name", "provider3");
|
||||||
|
expect(config).toHaveProperty("SESSION_SECRET", "your_session_secret");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("devrait retourner les providers OAuth", () => {
|
||||||
|
const oauthProviders = authConfigInstance.getOAuthProviders();
|
||||||
|
expect(Array.isArray(oauthProviders)).toBe(true);
|
||||||
|
expect(oauthProviders.length).toBe(1); // Il y a un seul provider OAuth
|
||||||
|
expect(oauthProviders[0]).toHaveProperty("provider1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("devrait valider la configuration des providers", () => {
|
||||||
|
expect(() => authConfigInstance.validateProvidersConfig()).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("devrait lever une erreur si une configuration manque", () => {
|
||||||
|
const invalidMockConfig = {
|
||||||
|
auth: {
|
||||||
|
passportjs: [
|
||||||
|
{
|
||||||
|
provider1: {
|
||||||
|
type: "oauth",
|
||||||
|
OAUTH_CLIENT_ID: "your_oauth_client_id", // Il manque des champs nécessaires
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const instanceWithInvalidConfig = new AuthConfig();
|
||||||
|
instanceWithInvalidConfig.loadConfigTest(invalidMockConfig);
|
||||||
|
|
||||||
|
// Vérifiez que l'erreur est lancée avec les champs manquants corrects
|
||||||
|
expect(() => instanceWithInvalidConfig.validateProvidersConfig()).toThrow(
|
||||||
|
new Error(`Configuration invalide pour les providers suivants : [
|
||||||
|
{
|
||||||
|
"provider": "provider1",
|
||||||
|
"missingFields": [
|
||||||
|
"OAUTH_AUTHORIZATION_URL",
|
||||||
|
"OAUTH_TOKEN_URL",
|
||||||
|
"OAUTH_USERINFO_URL",
|
||||||
|
"OAUTH_CLIENT_SECRET",
|
||||||
|
"OAUTH_ROLE_TEACHER_VALUE",
|
||||||
|
"OAUTH_ROLE_STUDENT_VALUE"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]`)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
describe("Auth Module Registration", () => {
|
||||||
|
let expressMock = jest.mock("express");
|
||||||
|
expressMock.use = () => {}
|
||||||
|
expressMock.get = () => {}
|
||||||
|
|
||||||
|
let authConfigInstance;
|
||||||
|
let logSpy;
|
||||||
|
|
||||||
|
// Initialisez l'instance avec la configuration mockée
|
||||||
|
beforeAll(() => {
|
||||||
|
authConfigInstance = new AuthConfig();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should load valid modules", () => {
|
||||||
|
const logSpy = jest.spyOn(global.console, "error");
|
||||||
|
const validModule = {
|
||||||
|
auth: {
|
||||||
|
passportjs: [
|
||||||
|
{
|
||||||
|
provider1: {
|
||||||
|
type: "oauth",
|
||||||
|
OAUTH_AUTHORIZATION_URL:
|
||||||
|
"https://www.testurl.com/oauth2/authorize",
|
||||||
|
OAUTH_TOKEN_URL: "https://www.testurl.com/oauth2/token",
|
||||||
|
OAUTH_USERINFO_URL: "https://www.testurl.com/oauth2/userinfo/",
|
||||||
|
OAUTH_CLIENT_ID: "your_oauth_client_id",
|
||||||
|
OAUTH_CLIENT_SECRET: "your_oauth_client_secret",
|
||||||
|
OAUTH_ADD_SCOPE: "scopes",
|
||||||
|
OAUTH_ROLE_TEACHER_VALUE: "teacher-claim-value",
|
||||||
|
OAUTH_ROLE_STUDENT_VALUE: "student-claim-value",
|
||||||
|
},
|
||||||
|
provider2: {
|
||||||
|
type: "oauth",
|
||||||
|
OAUTH_AUTHORIZATION_URL:
|
||||||
|
"https://www.testurl.com/oauth2/authorize",
|
||||||
|
OAUTH_TOKEN_URL: "https://www.testurl.com/oauth2/token",
|
||||||
|
OAUTH_USERINFO_URL: "https://www.testurl.com/oauth2/userinfo/",
|
||||||
|
OAUTH_CLIENT_ID: "your_oauth_client_id",
|
||||||
|
OAUTH_CLIENT_SECRET: "your_oauth_client_secret",
|
||||||
|
OAUTH_ADD_SCOPE: "scopes",
|
||||||
|
OAUTH_ROLE_TEACHER_VALUE: "teacher-claim-value",
|
||||||
|
OAUTH_ROLE_STUDENT_VALUE: "student-claim-value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
authConfigInstance.loadConfigTest(validModule); // On injecte la configuration mockée
|
||||||
|
authmanagerInstance = new AuthManager(expressMock,authConfigInstance.config);
|
||||||
|
expect(logSpy).toHaveBeenCalledTimes(0);
|
||||||
|
logSpy.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not load invalid modules", () => {
|
||||||
|
const logSpy = jest.spyOn(global.console, "error");
|
||||||
|
const invalidModule = {
|
||||||
|
auth: {
|
||||||
|
ModuleX:{}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
authConfigInstance.loadConfigTest(invalidModule); // On injecte la configuration mockée
|
||||||
|
authmanagerInstance = new AuthManager(expressMock,authConfigInstance.config);
|
||||||
|
expect(logSpy).toHaveBeenCalledTimes(1);
|
||||||
|
logSpy.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("should not load invalid provider from passport", () => {
|
||||||
|
const logSpy = jest.spyOn(global.console, "error");
|
||||||
|
const validModuleInvalidProvider = {
|
||||||
|
auth: {
|
||||||
|
passportjs: [
|
||||||
|
{
|
||||||
|
provider1: {
|
||||||
|
type: "x",
|
||||||
|
OAUTH_AUTHORIZATION_URL:
|
||||||
|
"https://www.testurl.com/oauth2/authorize",
|
||||||
|
OAUTH_TOKEN_URL: "https://www.testurl.com/oauth2/token",
|
||||||
|
OAUTH_USERINFO_URL: "https://www.testurl.com/oauth2/userinfo/",
|
||||||
|
OAUTH_CLIENT_ID: "your_oauth_client_id",
|
||||||
|
OAUTH_CLIENT_SECRET: "your_oauth_client_secret",
|
||||||
|
OAUTH_ADD_SCOPE: "scopes",
|
||||||
|
OAUTH_ROLE_TEACHER_VALUE: "teacher-claim-value",
|
||||||
|
OAUTH_ROLE_STUDENT_VALUE: "student-claim-value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
authConfigInstance.loadConfigTest(validModuleInvalidProvider); // On injecte la configuration mockée
|
||||||
|
authmanagerInstance = new AuthManager(expressMock,authConfigInstance.config);
|
||||||
|
expect(logSpy).toHaveBeenCalledTimes(2);
|
||||||
|
logSpy.mockClear();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
@ -13,6 +13,7 @@ const folderRouter = require('./routers/folders.js');
|
||||||
const quizRouter = require('./routers/quiz.js');
|
const quizRouter = require('./routers/quiz.js');
|
||||||
const imagesRouter = require('./routers/images.js')
|
const imagesRouter = require('./routers/images.js')
|
||||||
const AuthManager = require('./auth/auth-manager.js')
|
const AuthManager = require('./auth/auth-manager.js')
|
||||||
|
const authRouter = require('./routers/auth.js')
|
||||||
|
|
||||||
// Setup environement
|
// Setup environement
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
@ -49,6 +50,7 @@ app.use('/api/user', userRouter);
|
||||||
app.use('/api/folder', folderRouter);
|
app.use('/api/folder', folderRouter);
|
||||||
app.use('/api/quiz', quizRouter);
|
app.use('/api/quiz', quizRouter);
|
||||||
app.use('/api/image', imagesRouter);
|
app.use('/api/image', imagesRouter);
|
||||||
|
app.use('/api/auth', authRouter);
|
||||||
|
|
||||||
// Add Auths methods
|
// Add Auths methods
|
||||||
const session = require('express-session');
|
const session = require('express-session');
|
||||||
|
|
@ -60,8 +62,6 @@ app.use(session({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
authManager = new AuthManager(app)
|
authManager = new AuthManager(app)
|
||||||
authManager.addModule('passport-js')
|
|
||||||
authManager.registerAuths()
|
|
||||||
|
|
||||||
app.use(errorHandler)
|
app.use(errorHandler)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,20 @@
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const AuthConfig = require('../config/auth.js');
|
||||||
const settings = {
|
|
||||||
"passport-js":{
|
|
||||||
"gmatte" : {
|
|
||||||
type: "oauth",
|
|
||||||
authorization_url: process.env['OAUTH_AuthorizeUrl'],
|
|
||||||
client_id : process.env['OAUTH_ClientID'],
|
|
||||||
client_secret: process.env['OAUTH_ClientSecret'],
|
|
||||||
config_url: process.env['OAUTH_ConfigUrl'],
|
|
||||||
userinfo_url: process.env['OAUTH_UserinfoUrl'],
|
|
||||||
token_url: process.env['OAUTH_TokenUrl'],
|
|
||||||
logout_url: process.env['OAUTH_LogoutUrl'],
|
|
||||||
jwks : process.env['OAUTH_JWKS'],
|
|
||||||
scopes: ['openid','email','profile','groups','offline_access']
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AuthManager{
|
class AuthManager{
|
||||||
constructor(expressapp){
|
constructor(expressapp,configs=null){
|
||||||
this.modules = []
|
this.modules = []
|
||||||
this.app = expressapp
|
this.app = expressapp
|
||||||
|
|
||||||
|
this.configs = configs ?? (new AuthConfig()).loadConfig()
|
||||||
|
this.addModules()
|
||||||
|
this.registerAuths()
|
||||||
|
}
|
||||||
|
|
||||||
|
async addModules(){
|
||||||
|
for(const module in this.configs.auth){
|
||||||
|
this.addModule(module)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async addModule(name){
|
async addModule(name){
|
||||||
|
|
@ -28,25 +22,23 @@ class AuthManager{
|
||||||
|
|
||||||
if(fs.existsSync(modulePath)){
|
if(fs.existsSync(modulePath)){
|
||||||
const Module = require(modulePath);
|
const Module = require(modulePath);
|
||||||
this.modules.push(new Module(this,settings[name]));
|
this.modules.push(new Module(this,this.configs.auth[name]));
|
||||||
console.debug(`Auth module ${name} added`)
|
console.info(`Module d'authentification '${name}' ajouté`)
|
||||||
|
} else{
|
||||||
|
console.error(`Le module d'authentification ${name} n'as pas été chargé car il est introuvable`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerAuths(){
|
async registerAuths(){
|
||||||
for(const module of this.modules){
|
for(const module of this.modules){
|
||||||
module.registerAuth(this.app)
|
try{
|
||||||
|
module.registerAuth(this.app)
|
||||||
|
} catch(error){
|
||||||
|
console.error(`L'enregistrement du module ${module} a échoué.`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async showAuths(){
|
|
||||||
let authsData = []
|
|
||||||
for(const module in this.modules){
|
|
||||||
authsData.push(module.showAuth())
|
|
||||||
}
|
|
||||||
return authsData;
|
|
||||||
}
|
|
||||||
|
|
||||||
async login(userInfos){
|
async login(userInfos){
|
||||||
// TODO global user login method
|
// TODO global user login method
|
||||||
console.log(userInfos)
|
console.log(userInfos)
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
const fs = require('fs');
|
|
||||||
var passport = require('passport')
|
|
||||||
|
|
||||||
class PassportJs{
|
|
||||||
constructor(authmanager,settings){
|
|
||||||
this.authmanager = authmanager
|
|
||||||
this.registeredProviders = {}
|
|
||||||
this.providers = Object.entries(settings)
|
|
||||||
}
|
|
||||||
|
|
||||||
registerAuth(expressapp){
|
|
||||||
expressapp.use(passport.initialize());
|
|
||||||
expressapp.use(passport.session());
|
|
||||||
|
|
||||||
for(const [name,provider] of this.providers){
|
|
||||||
if(!(provider.type in this.registeredProviders)){
|
|
||||||
this.registerProvider(provider.type)
|
|
||||||
}
|
|
||||||
this.registeredProviders[provider.type].register(expressapp,passport,name,provider)
|
|
||||||
}
|
|
||||||
|
|
||||||
passport.serializeUser(function(user, done) {
|
|
||||||
done(null, user);
|
|
||||||
});
|
|
||||||
|
|
||||||
passport.deserializeUser(function(user, done) {
|
|
||||||
done(null, user);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
registerProvider(providerType){
|
|
||||||
const providerPath = `${process.cwd()}/auth/modules/passport-providers/${providerType}.js`
|
|
||||||
|
|
||||||
if(fs.existsSync(providerPath)){
|
|
||||||
const Provider = require(providerPath);
|
|
||||||
this.registeredProviders[providerType]= new Provider()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = PassportJs;
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
var OAuth2Strategy = require('passport-oauth2')
|
var OAuth2Strategy = require('passport-oauth2')
|
||||||
|
|
||||||
class PassportOAuth {
|
class PassportOAuth {
|
||||||
register(app, passport, name, provider) {
|
register(app, passport,endpoint, name, provider) {
|
||||||
passport.use(name, new OAuth2Strategy({
|
passport.use(name, new OAuth2Strategy({
|
||||||
authorizationURL: provider.authorization_url,
|
authorizationURL: provider.OAUTH_AUTHORIZATION_URL,
|
||||||
tokenURL: provider.token_url,
|
tokenURL: provider.OAUTH_TOKEN_URL,
|
||||||
clientID: provider.client_id,
|
clientID: provider.OAUTH_CLIENT_ID,
|
||||||
clientSecret: provider.client_secret,
|
clientSecret: provider.OAUTH_CLIENT_SECRET,
|
||||||
callbackURL: `http://localhost:4400/api/auth/gmatte/callback`,
|
callbackURL: `${endpoint}/${name}/callback`,
|
||||||
passReqToCallback: true
|
passReqToCallback: true
|
||||||
},
|
},
|
||||||
async function(req, accessToken, refreshToken, params, profile, done) {
|
async function(req, accessToken, refreshToken, params, profile, done) {
|
||||||
try {
|
try {
|
||||||
const userInfoResponse = await fetch(provider.userinfo_url, {
|
const userInfoResponse = await fetch(provider.OAUTH_USERINFO_URL, {
|
||||||
headers: { 'Authorization': `Bearer ${accessToken}` }
|
headers: { 'Authorization': `Bearer ${accessToken}` }
|
||||||
});
|
});
|
||||||
const userInfo = await userInfoResponse.json();
|
const userInfo = await userInfoResponse.json();
|
||||||
|
|
@ -35,27 +35,28 @@ class PassportOAuth {
|
||||||
|
|
||||||
return done(null, user);
|
return done(null, user);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error in OAuth2 Strategy ${name} :`, error);
|
console.error(`Erreur dans la strategie OAuth2 '${name}' : ${error}`);
|
||||||
return done(error);
|
return done(error);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
app.get(`/api/auth/${name}`, (req, res, next) => {
|
app.get(`${endpoint}/${name}`, (req, res, next) => {
|
||||||
passport.authenticate(name, {
|
passport.authenticate(name, {
|
||||||
scope: provider.scopes.join(' ') ?? 'openid profile email offline_access',
|
scope: 'openid profile email offline_access'+ ` ${provider.OAUTH_ADD_SCOPE}`,
|
||||||
prompt: 'consent'
|
prompt: 'consent'
|
||||||
})(req, res, next);
|
})(req, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get(`/api/auth/${name}/callback`,
|
app.get(`${endpoint}/${name}/callback`,
|
||||||
(req, res, next) => {
|
(req, res, next) => {
|
||||||
passport.authenticate(name, { failureRedirect: '/login' })(req, res, next);
|
passport.authenticate(name, { failureRedirect: '/login' })(req, res, next);
|
||||||
},
|
},
|
||||||
(req, res) => {
|
(req, res) => {
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
res.json(req.user)
|
res.json(req.user)
|
||||||
|
console.info(`L'utilisateur '${req.user.name}' vient de se connecter`)
|
||||||
} else {
|
} else {
|
||||||
res.status(401).json({ error: 'Authentication failed' });
|
res.status(401).json({ error: "L'authentification a échoué" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
51
server/auth/modules/passportjs.js
Normal file
51
server/auth/modules/passportjs.js
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
var passport = require('passport')
|
||||||
|
|
||||||
|
class PassportJs{
|
||||||
|
constructor(authmanager,settings){
|
||||||
|
this.authmanager = authmanager
|
||||||
|
this.registeredProviders = {}
|
||||||
|
this.providers = settings
|
||||||
|
this.endpoint = "/api/auth"
|
||||||
|
}
|
||||||
|
|
||||||
|
registerAuth(expressapp){
|
||||||
|
expressapp.use(passport.initialize());
|
||||||
|
expressapp.use(passport.session());
|
||||||
|
|
||||||
|
for(const p of this.providers){
|
||||||
|
for(const [name,provider] of Object.entries(p)){
|
||||||
|
if(!(provider.type in this.registeredProviders)){
|
||||||
|
this.registerProvider(provider.type)
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
this.registeredProviders[provider.type].register(expressapp,passport,this.endpoint,name,provider)
|
||||||
|
} catch(error){
|
||||||
|
console.error(`La connexion ${name} de type ${provider.type} n'as pu être chargé.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
passport.serializeUser(function(user, done) {
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
|
||||||
|
passport.deserializeUser(function(user, done) {
|
||||||
|
done(null, user);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
registerProvider(providerType){
|
||||||
|
try{
|
||||||
|
const providerPath = `${process.cwd()}/auth/modules/passport-providers/${providerType}.js`
|
||||||
|
const Provider = require(providerPath);
|
||||||
|
this.registeredProviders[providerType]= new Provider()
|
||||||
|
console.info(`Le type de connexion '${providerType}' a été ajouté dans passportjs.`)
|
||||||
|
} catch(error){
|
||||||
|
console.error(`Le type de connexion '${providerType}' n'as pas pu être chargé dans passportjs.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PassportJs;
|
||||||
28
server/auth_config.json.example
Normal file
28
server/auth_config.json.example
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"auth": {
|
||||||
|
"passportjs":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"gmatte": {
|
||||||
|
"type": "oauth",
|
||||||
|
"OAUTH_AUTHORIZATION_URL": "https://auth.gmatte.xyz/application/o/authorize/",
|
||||||
|
"OAUTH_TOKEN_URL": "https://auth.gmatte.xyz/application/o/token/",
|
||||||
|
"OAUTH_USERINFO_URL": "https://auth.gmatte.xyz/application/o/userinfo/",
|
||||||
|
"OAUTH_CLIENT_ID": "clientID",
|
||||||
|
"OAUTH_CLIENT_SECRET": "clientSecret",
|
||||||
|
"OAUTH_ADD_SCOPE": "groups",
|
||||||
|
"OAUTH_ROLE_TEACHER_VALUE": "groups_evaluetonsavoir-prof",
|
||||||
|
"OAUTH_ROLE_STUDENT_VALUE": "groups_evaluetonsavoir"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"oidc":{
|
||||||
|
"type":"oidc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Module X":{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
185
server/config/auth.js
Normal file
185
server/config/auth.js
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const pathAuthConfig = './auth_config.json';
|
||||||
|
|
||||||
|
const configPath = path.join(process.cwd(), pathAuthConfig);
|
||||||
|
|
||||||
|
class AuthConfig {
|
||||||
|
|
||||||
|
config = null;
|
||||||
|
|
||||||
|
|
||||||
|
// Méthode pour lire le fichier de configuration JSON
|
||||||
|
loadConfig() {
|
||||||
|
try {
|
||||||
|
const configData = fs.readFileSync(configPath, 'utf-8');
|
||||||
|
this.config = JSON.parse(configData);
|
||||||
|
return this.config
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la lecture du fichier de configuration :", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode pour load le fichier de test
|
||||||
|
loadConfigTest(mockConfig) {
|
||||||
|
this.config = mockConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode pour retourner la configuration des fournisseurs PassportJS
|
||||||
|
getPassportJSConfig() {
|
||||||
|
if (this.config && this.config.auth && this.config.auth.passportjs) {
|
||||||
|
const passportConfig = {};
|
||||||
|
|
||||||
|
this.config.auth.passportjs.forEach(provider => {
|
||||||
|
const providerName = Object.keys(provider)[0];
|
||||||
|
passportConfig[providerName] = provider[providerName];
|
||||||
|
});
|
||||||
|
|
||||||
|
return passportConfig;
|
||||||
|
} else {
|
||||||
|
return { error: "Aucune configuration PassportJS disponible." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode pour retourner la configuration de Simple Login
|
||||||
|
getSimpleLoginConfig() {
|
||||||
|
if (this.config && this.config.auth && this.config.auth["simple-login"]) {
|
||||||
|
return this.config.auth["simple-login"];
|
||||||
|
} else {
|
||||||
|
return { error: "Aucune configuration Simple Login disponible." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode pour retourner tous les providers de type OAuth
|
||||||
|
getOAuthProviders() {
|
||||||
|
if (this.config && this.config.auth && this.config.auth.passportjs) {
|
||||||
|
const oauthProviders = this.config.auth.passportjs.filter(provider => {
|
||||||
|
const providerName = Object.keys(provider)[0];
|
||||||
|
return provider[providerName].type === 'oauth';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (oauthProviders.length > 0) {
|
||||||
|
return oauthProviders;
|
||||||
|
} else {
|
||||||
|
return { error: "Aucun fournisseur OAuth disponible." };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { error: "Aucune configuration PassportJS disponible." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode pour retourner tous les providers de type OIDC
|
||||||
|
getOIDCProviders() {
|
||||||
|
if (this.config && this.config.auth && this.config.auth.passportjs) {
|
||||||
|
const oidcProviders = this.config.auth.passportjs.filter(provider => {
|
||||||
|
const providerName = Object.keys(provider)[0];
|
||||||
|
return provider[providerName].type === 'oidc';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (oidcProviders.length > 0) {
|
||||||
|
return oidcProviders;
|
||||||
|
} else {
|
||||||
|
return { error: "Aucun fournisseur OIDC disponible." };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { error: "Aucune configuration PassportJS disponible." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode pour vérifier si tous les providers ont les variables nécessaires
|
||||||
|
validateProvidersConfig() {
|
||||||
|
const requiredOAuthFields = [
|
||||||
|
'OAUTH_AUTHORIZATION_URL', 'OAUTH_TOKEN_URL','OAUTH_USERINFO_URL', 'OAUTH_CLIENT_ID', 'OAUTH_CLIENT_SECRET', 'OAUTH_ROLE_TEACHER_VALUE', 'OAUTH_ROLE_STUDENT_VALUE'
|
||||||
|
];
|
||||||
|
|
||||||
|
const requiredOIDCFields = [
|
||||||
|
'OIDC_CLIENT_ID', 'OIDC_CLIENT_SECRET', 'OIDC_ISSUER_URL', 'OIDC_ROLE_TEACHER_VALUE', 'OIDC_ROLE_STUDENT_VALUE'
|
||||||
|
];
|
||||||
|
|
||||||
|
const missingFieldsReport = [];
|
||||||
|
|
||||||
|
if (this.config && this.config.auth && this.config.auth.passportjs) {
|
||||||
|
this.config.auth.passportjs.forEach(provider => {
|
||||||
|
const providerName = Object.keys(provider)[0];
|
||||||
|
const providerConfig = provider[providerName];
|
||||||
|
|
||||||
|
let missingFields = [];
|
||||||
|
|
||||||
|
// Vérification des providers de type OAuth
|
||||||
|
if (providerConfig.type === 'oauth') {
|
||||||
|
missingFields = requiredOAuthFields.filter(field => !(field in providerConfig));
|
||||||
|
}
|
||||||
|
// Vérification des providers de type OIDC
|
||||||
|
else if (providerConfig.type === 'oidc') {
|
||||||
|
missingFields = requiredOIDCFields.filter(field => !(field in providerConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si des champs manquent, on les ajoute au rapport
|
||||||
|
if (missingFields.length > 0) {
|
||||||
|
missingFieldsReport.push({
|
||||||
|
provider: providerName,
|
||||||
|
missingFields: missingFields
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Si des champs manquent, lever une exception
|
||||||
|
if (missingFieldsReport.length > 0) {
|
||||||
|
throw new Error(`Configuration invalide pour les providers suivants : ${JSON.stringify(missingFieldsReport, null, 2)}`);
|
||||||
|
} else {
|
||||||
|
console.log("Configuration auth_config.json: Tous les providers ont les variables nécessaires.")
|
||||||
|
return { success: "Tous les providers ont les variables nécessaires." };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Aucune configuration PassportJS disponible.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Méthode pour retourner la configuration des fournisseurs PassportJS pour le frontend
|
||||||
|
getActiveAuth() {
|
||||||
|
if (this.config && this.config.auth) {
|
||||||
|
const passportConfig = {};
|
||||||
|
|
||||||
|
// Gestion des providers PassportJS
|
||||||
|
if (this.config.auth.passportjs) {
|
||||||
|
this.config.auth.passportjs.forEach(provider => {
|
||||||
|
const providerName = Object.keys(provider)[0];
|
||||||
|
const providerConfig = provider[providerName];
|
||||||
|
|
||||||
|
passportConfig[providerName] = {};
|
||||||
|
|
||||||
|
if (providerConfig.type === 'oauth') {
|
||||||
|
passportConfig[providerName] = {
|
||||||
|
type: providerConfig.type,
|
||||||
|
authorizationUrl: providerConfig.OAUTH_AUTHORIZATION_URL,
|
||||||
|
callbackUrl: providerConfig.OAUTH_CALLBACK_URL,
|
||||||
|
};
|
||||||
|
} else if (providerConfig.type === 'oidc') {
|
||||||
|
passportConfig[providerName] = {
|
||||||
|
type: providerConfig.type,
|
||||||
|
issuerUrl: providerConfig.OIDC_ISSUER_URL,
|
||||||
|
callbackUrl: providerConfig.OIDC_CALLBACK_URL
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gestion du Simple Login
|
||||||
|
if (this.config.auth["simple-login"] && this.config.auth["simple-login"].enabled) {
|
||||||
|
passportConfig['simple-login'] = {
|
||||||
|
type: "simple-login",
|
||||||
|
name: this.config.auth["simple-login"].name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return passportConfig;
|
||||||
|
} else {
|
||||||
|
return { error: "Aucune configuration d'authentification disponible." };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AuthConfig;
|
||||||
25
server/controllers/auth.js
Normal file
25
server/controllers/auth.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
const AuthConfig = require('../config/auth.js');
|
||||||
|
|
||||||
|
class authController {
|
||||||
|
|
||||||
|
async getActive(req, res, next) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
const authC = new AuthConfig();
|
||||||
|
authC.loadConfig();
|
||||||
|
|
||||||
|
const authActive = authC.getActiveAuth();
|
||||||
|
|
||||||
|
const response = {
|
||||||
|
authActive
|
||||||
|
};
|
||||||
|
return res.json(response);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
return next(error); // Gérer l'erreur
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new authController;
|
||||||
9
server/routers/auth.js
Normal file
9
server/routers/auth.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const jwt = require('../middleware/jwtToken.js');
|
||||||
|
|
||||||
|
const authController = require('../controllers/auth.js')
|
||||||
|
|
||||||
|
router.get("/getActiveAuth",jwt.authenticate, authController.getActive);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
Loading…
Reference in a new issue