mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
Incorporate auth config
This commit is contained in:
parent
ec9adc1440
commit
d97f3f55e2
10 changed files with 284 additions and 183 deletions
|
|
@ -20,29 +20,10 @@
|
||||||
"OIDC_CLIENT_ID": "your_oidc_client_id",
|
"OIDC_CLIENT_ID": "your_oidc_client_id",
|
||||||
"OIDC_CLIENT_SECRET": "your_oidc_client_secret",
|
"OIDC_CLIENT_SECRET": "your_oidc_client_secret",
|
||||||
"OIDC_ISSUER_URL": "https://your-issuer.com",
|
"OIDC_ISSUER_URL": "https://your-issuer.com",
|
||||||
"OIDC_CALLBACK_URL": "http://localhost:3000/auth/oidc/callback"
|
"OIDC_CALLBACK_URL": "http://localhost:3000/auth/oidc/callback",
|
||||||
}
|
"OIDC_ADD_SCOPE": "scopes",
|
||||||
},
|
"OIDC_ROLE_TEACHER_VALUE": "teacher-claim-value",
|
||||||
{
|
"OIDC_ROLE_STUDENT_VALUE": "student-claim-value"
|
||||||
"provider3": {
|
|
||||||
"type": "oauth",
|
|
||||||
"OAUTH_AUTHORIZATION_URL": "https://www.testurl.com/oauth2/authorize",
|
|
||||||
"OAUTH_TOKEN_URL": "https://www.testurl.com/oauth2/token",
|
|
||||||
"OAUTH_CLIENT_ID": "your_oauth_client_id",
|
|
||||||
"OAUTH_CLIENT_SECRET": "your_oauth_client_secret",
|
|
||||||
"OAUTH_CALLBACK_URL": "https://localhost:3000/auth/provider/callback",
|
|
||||||
"OAUTH_ADD_SCOPE": "scopes",
|
|
||||||
"OAUTH_ROLE_TEACHER_VALUE": "teacher-claim-value",
|
|
||||||
"OAUTH_ROLE_STUDENT_VALUE": "student-claim-value"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"provider4": {
|
|
||||||
"type": "oidc",
|
|
||||||
"OIDC_CLIENT_ID": "your_oidc_client_id",
|
|
||||||
"OIDC_CLIENT_SECRET": "your_oidc_client_secret",
|
|
||||||
"OIDC_ISSUER_URL": "https://your-issuer.com",
|
|
||||||
"OIDC_CALLBACK_URL": "http://localhost:3000/auth/oidc/callback"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
1
server/.gitignore
vendored
Normal file
1
server/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
auth_config.json
|
||||||
|
|
@ -1,103 +1,193 @@
|
||||||
const request = require('supertest');
|
const request = require("supertest");
|
||||||
const AuthConfig = require('../config/auth.js');
|
const AuthConfig = require("../config/auth.js");
|
||||||
|
const AuthManager = require("../auth/auth-manager.js");
|
||||||
|
|
||||||
const mockConfig = {
|
const mockConfig = {
|
||||||
"auth": {
|
auth: {
|
||||||
"passportjs": [
|
passportjs: [
|
||||||
{
|
{
|
||||||
"provider1": {
|
provider1: {
|
||||||
"type": "oauth",
|
type: "oauth",
|
||||||
"OAUTH_AUTHORIZATION_URL": "https://www.testurl.com/oauth2/authorize",
|
OAUTH_AUTHORIZATION_URL: "https://www.testurl.com/oauth2/authorize",
|
||||||
"OAUTH_TOKEN_URL": "https://www.testurl.com/oauth2/token",
|
OAUTH_TOKEN_URL: "https://www.testurl.com/oauth2/token",
|
||||||
"OAUTH_CLIENT_ID": "your_oauth_client_id",
|
OAUTH_USERINFO_URL: "https://www.testurl.com/oauth2/userinfo/",
|
||||||
"OAUTH_CLIENT_SECRET": "your_oauth_client_secret",
|
OAUTH_CLIENT_ID: "your_oauth_client_id",
|
||||||
"OAUTH_CALLBACK_URL": "https://localhost:3000/auth/provider/callback",
|
OAUTH_CLIENT_SECRET: "your_oauth_client_secret",
|
||||||
"OAUTH_ADD_SCOPE": "scopes",
|
OAUTH_ADD_SCOPE: "scopes",
|
||||||
"OAUTH_ROLE_TEACHER_VALUE": "teacher-claim-value",
|
OAUTH_ROLE_TEACHER_VALUE: "teacher-claim-value",
|
||||||
"OAUTH_ROLE_STUDENT_VALUE": "student-claim-value"
|
OAUTH_ROLE_STUDENT_VALUE: "student-claim-value",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"provider2": {
|
provider2: {
|
||||||
"type": "oidc",
|
type: "oidc",
|
||||||
"OIDC_CLIENT_ID": "your_oidc_client_id",
|
OIDC_CLIENT_ID: "your_oidc_client_id",
|
||||||
"OIDC_CLIENT_SECRET": "your_oidc_client_secret",
|
OIDC_CLIENT_SECRET: "your_oidc_client_secret",
|
||||||
"OIDC_ISSUER_URL": "https://your-issuer.com",
|
OIDC_ISSUER_URL: "https://your-issuer.com",
|
||||||
"OIDC_CALLBACK_URL": "http://localhost:3000/auth/oidc/callback"
|
OIDC_ROLE_TEACHER_VALUE: "teacher-claim-value",
|
||||||
}
|
OIDC_ROLE_STUDENT_VALUE: "student-claim-value",
|
||||||
}
|
},
|
||||||
],
|
},
|
||||||
"simple-login": {
|
],
|
||||||
"enabled": true,
|
"simple-login": {
|
||||||
"name": "provider3",
|
enabled: true,
|
||||||
"SESSION_SECRET": "your_session_secret"
|
name: "provider3",
|
||||||
}
|
SESSION_SECRET: "your_session_secret",
|
||||||
}
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Créez une instance de AuthConfig en utilisant la configuration mockée
|
// Créez une instance de AuthConfig en utilisant la configuration mockée
|
||||||
describe('AuthConfig Class Tests', () => {
|
describe(
|
||||||
|
"AuthConfig Class Tests",
|
||||||
|
() => {
|
||||||
let authConfigInstance;
|
let authConfigInstance;
|
||||||
|
|
||||||
// Initialisez l'instance avec la configuration mockée
|
// Initialisez l'instance avec la configuration mockée
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
authConfigInstance = new AuthConfig();
|
authConfigInstance = new AuthConfig();
|
||||||
authConfigInstance.loadConfigTest(mockConfig); // On injecte la configuration mockée
|
authConfigInstance.loadConfigTest(mockConfig); // On injecte la configuration mockée
|
||||||
});
|
});
|
||||||
|
|
||||||
it('devrait retourner la configuration PassportJS', () => {
|
it("devrait retourner la configuration PassportJS", () => {
|
||||||
const config = authConfigInstance.getPassportJSConfig();
|
const config = authConfigInstance.getPassportJSConfig();
|
||||||
expect(config).toHaveProperty('provider1');
|
expect(config).toHaveProperty("provider1");
|
||||||
expect(config).toHaveProperty('provider2');
|
expect(config).toHaveProperty("provider2");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('devrait retourner la configuration Simple Login', () => {
|
it("devrait retourner la configuration Simple Login", () => {
|
||||||
const config = authConfigInstance.getSimpleLoginConfig();
|
const config = authConfigInstance.getSimpleLoginConfig();
|
||||||
expect(config).toHaveProperty('name', 'provider3');
|
expect(config).toHaveProperty("name", "provider3");
|
||||||
expect(config).toHaveProperty('SESSION_SECRET', 'your_session_secret');
|
expect(config).toHaveProperty("SESSION_SECRET", "your_session_secret");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('devrait retourner les providers OAuth', () => {
|
it("devrait retourner les providers OAuth", () => {
|
||||||
const oauthProviders = authConfigInstance.getOAuthProviders();
|
const oauthProviders = authConfigInstance.getOAuthProviders();
|
||||||
expect(Array.isArray(oauthProviders)).toBe(true);
|
expect(Array.isArray(oauthProviders)).toBe(true);
|
||||||
expect(oauthProviders.length).toBe(1); // Il y a un seul provider OAuth
|
expect(oauthProviders.length).toBe(1); // Il y a un seul provider OAuth
|
||||||
expect(oauthProviders[0]).toHaveProperty('provider1');
|
expect(oauthProviders[0]).toHaveProperty("provider1");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('devrait valider la configuration des providers', () => {
|
it("devrait valider la configuration des providers", () => {
|
||||||
expect(() => authConfigInstance.validateProvidersConfig()).not.toThrow();
|
expect(() => authConfigInstance.validateProvidersConfig()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('devrait lever une erreur si une configuration manque', () => {
|
it("devrait lever une erreur si une configuration manque", () => {
|
||||||
const invalidMockConfig = {
|
const invalidMockConfig = {
|
||||||
"auth": {
|
auth: {
|
||||||
"passportjs": [
|
passportjs: [
|
||||||
{
|
{
|
||||||
"provider1": {
|
provider1: {
|
||||||
"type": "oauth",
|
type: "oauth",
|
||||||
"OAUTH_CLIENT_ID": "your_oauth_client_id" // Il manque des champs nécessaires
|
OAUTH_CLIENT_ID: "your_oauth_client_id", // Il manque des champs nécessaires
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const instanceWithInvalidConfig = new AuthConfig();
|
const instanceWithInvalidConfig = new AuthConfig();
|
||||||
instanceWithInvalidConfig.loadConfigTest(invalidMockConfig);
|
instanceWithInvalidConfig.loadConfigTest(invalidMockConfig);
|
||||||
|
|
||||||
// Vérifiez que l'erreur est lancée avec les champs manquants corrects
|
// Vérifiez que l'erreur est lancée avec les champs manquants corrects
|
||||||
expect(() => instanceWithInvalidConfig.validateProvidersConfig()).toThrow(
|
expect(() => instanceWithInvalidConfig.validateProvidersConfig()).toThrow(
|
||||||
new Error(`Configuration invalide pour les providers suivants : [
|
new Error(`Configuration invalide pour les providers suivants : [
|
||||||
{
|
{
|
||||||
"provider": "provider1",
|
"provider": "provider1",
|
||||||
"missingFields": [
|
"missingFields": [
|
||||||
"OAUTH_AUTHORIZATION_URL",
|
"OAUTH_AUTHORIZATION_URL",
|
||||||
"OAUTH_TOKEN_URL",
|
"OAUTH_TOKEN_URL",
|
||||||
|
"OAUTH_USERINFO_URL",
|
||||||
"OAUTH_CLIENT_SECRET",
|
"OAUTH_CLIENT_SECRET",
|
||||||
"OAUTH_CALLBACK_URL"
|
"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",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
authConfigInstance.loadConfigTest(validModule); // On injecte la configuration mockée
|
||||||
|
authmanagerInstance = new AuthManager(expressMock,authConfigInstance.config);
|
||||||
|
expect(logSpy).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
|
||||||
|
|
@ -62,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":{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const pathAuthConfig = './auth_config.json';
|
const pathAuthConfig = './auth_config.json';
|
||||||
|
|
||||||
const configPath = path.join(__dirname, pathAuthConfig);
|
const configPath = path.join(process.cwd(), pathAuthConfig);
|
||||||
|
|
||||||
class AuthConfig {
|
class AuthConfig {
|
||||||
|
|
||||||
|
|
@ -14,6 +14,7 @@ class AuthConfig {
|
||||||
try {
|
try {
|
||||||
const configData = fs.readFileSync(configPath, 'utf-8');
|
const configData = fs.readFileSync(configPath, 'utf-8');
|
||||||
this.config = JSON.parse(configData);
|
this.config = JSON.parse(configData);
|
||||||
|
return this.config
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Erreur lors de la lecture du fichier de configuration :", error);
|
console.error("Erreur lors de la lecture du fichier de configuration :", error);
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -89,11 +90,11 @@ class AuthConfig {
|
||||||
// Méthode pour vérifier si tous les providers ont les variables nécessaires
|
// Méthode pour vérifier si tous les providers ont les variables nécessaires
|
||||||
validateProvidersConfig() {
|
validateProvidersConfig() {
|
||||||
const requiredOAuthFields = [
|
const requiredOAuthFields = [
|
||||||
'OAUTH_AUTHORIZATION_URL', 'OAUTH_TOKEN_URL', 'OAUTH_CLIENT_ID', 'OAUTH_CLIENT_SECRET', 'OAUTH_CALLBACK_URL'
|
'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 = [
|
const requiredOIDCFields = [
|
||||||
'OIDC_CLIENT_ID', 'OIDC_CLIENT_SECRET', 'OIDC_ISSUER_URL', 'OIDC_CALLBACK_URL'
|
'OIDC_CLIENT_ID', 'OIDC_CLIENT_SECRET', 'OIDC_ISSUER_URL', 'OIDC_ROLE_TEACHER_VALUE', 'OIDC_ROLE_STUDENT_VALUE'
|
||||||
];
|
];
|
||||||
|
|
||||||
const missingFieldsReport = [];
|
const missingFieldsReport = [];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue