mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
Adds Oauths parsing
Co-authored-by: roesnerb <roesnerb@users.noreply.github.com> Co-authored-by: MathieuSevignyLavallee <MathieuSevignyLavallee@users.noreply.github.com>
This commit is contained in:
parent
f7f03ebeaa
commit
8f7c0a3ac9
6 changed files with 244 additions and 149 deletions
|
|
@ -1,21 +1,24 @@
|
||||||
var OAuth2Strategy = require('passport-oauth2')
|
var OAuth2Strategy = require('passport-oauth2')
|
||||||
|
var authProvider = require('../../../models/authProvider')
|
||||||
var authUserAssoc = require('../../../models/authUserAssociation')
|
var authUserAssoc = require('../../../models/authUserAssociation')
|
||||||
var users = require('../../../models/users')
|
var users = require('../../../models/users')
|
||||||
var {hasNestedValue} = require('../../../utils')
|
var { hasNestedValue } = require('../../../utils')
|
||||||
|
|
||||||
|
|
||||||
class PassportOAuth {
|
class PassportOAuth {
|
||||||
constructor(passportjs,auth_id){
|
constructor(passportjs,auth_name){
|
||||||
this.passportjs = passportjs
|
this.passportjs = passportjs
|
||||||
this.auth_id = auth_id
|
this.auth_name = auth_name
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUser(userinfos){
|
async getProviderInfo(auth_name){
|
||||||
|
return await authProvider.find(auth_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
register(app, passport,endpoint, name, provider) {
|
register(app, passport,endpoint, name, provider) {
|
||||||
const cb_url =`${process.env['BACKEND_URL']}${endpoint}/${name}/callback`
|
const cb_url =`${process.env['BACKEND_URL']}${endpoint}/${name}/callback`
|
||||||
|
const self = this
|
||||||
|
|
||||||
passport.use(name, new OAuth2Strategy({
|
passport.use(name, new OAuth2Strategy({
|
||||||
authorizationURL: provider.OAUTH_AUTHORIZATION_URL,
|
authorizationURL: provider.OAUTH_AUTHORIZATION_URL,
|
||||||
tokenURL: provider.OAUTH_TOKEN_URL,
|
tokenURL: provider.OAUTH_TOKEN_URL,
|
||||||
|
|
@ -32,31 +35,32 @@ class PassportOAuth {
|
||||||
const userInfo = await userInfoResponse.json();
|
const userInfo = await userInfoResponse.json();
|
||||||
|
|
||||||
let received_user = {
|
let received_user = {
|
||||||
|
auth_id: userInfo.sub,
|
||||||
email: userInfo.email,
|
email: userInfo.email,
|
||||||
name: userInfo.name,
|
name: userInfo.name,
|
||||||
roles: []
|
roles: []
|
||||||
};
|
};
|
||||||
if(hasNestedValue(userInfo,provider.OIDC_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
|
|
||||||
if(hasNestedValue(userInfo,provider.OIDC_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
|
|
||||||
|
|
||||||
const user_association = await authUserAssoc.find_user_association(userInfo.sub)
|
if(hasNestedValue(userInfo,provider.OAUTH_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
|
||||||
|
if(hasNestedValue(userInfo,provider.OAUTH_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
|
||||||
|
|
||||||
if(user_linked){
|
const user_association = await authUserAssoc.find_user_association(self.auth_name._id,userInfo.sub)
|
||||||
let user = await users.getById(user_association.user_id)
|
|
||||||
user.name = received_user.name
|
let user_account = null
|
||||||
user.email = received_user.email
|
if(user_association){
|
||||||
user.roles = received_user.roles
|
user_account = await users.getById(user_association.user_id)
|
||||||
users.editUser(user)
|
|
||||||
this.passportjs.authenticate(user)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let user_id = await users.getId(userInfo.email)
|
let user_id = await users.getId(userInfo.email)
|
||||||
if(!user_id){
|
user_account = user_id ? await users.getById(user_id) : await users.register(received_user.email,"")
|
||||||
await users.register(received_user.email,"");
|
await authUserAssoc.link(self.auth_name,received_user.auth_id,user_account._id)
|
||||||
users.editUser
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user_account.name = received_user.name
|
||||||
|
user_account.roles = received_user.roles
|
||||||
|
await users.editUser(user_account)
|
||||||
|
self.passportjs.authenticate(user_account)
|
||||||
|
|
||||||
// Store the tokens in the session
|
// Store the tokens in the session
|
||||||
req.session.oauth2Tokens = {
|
req.session.oauth2Tokens = {
|
||||||
accessToken: accessToken,
|
accessToken: accessToken,
|
||||||
|
|
@ -64,7 +68,7 @@ class PassportOAuth {
|
||||||
expiresIn: params.expires_in
|
expiresIn: params.expires_in
|
||||||
};
|
};
|
||||||
|
|
||||||
return done(null, user);
|
return done(null, user_account);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Erreur dans la strategie OAuth2 '${name}' : ${error}`);
|
console.error(`Erreur dans la strategie OAuth2 '${name}' : ${error}`);
|
||||||
return done(error);
|
return done(error);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class PassportJs{
|
||||||
const auth_id = `passportjs_${provider.type}_${name}`
|
const auth_id = `passportjs_${provider.type}_${name}`
|
||||||
|
|
||||||
if(!(provider.type in this.registeredProviders)){
|
if(!(provider.type in this.registeredProviders)){
|
||||||
this.registerProvider(provider.typename,auth_id)
|
this.registerProvider(provider.type,auth_id)
|
||||||
}
|
}
|
||||||
try{
|
try{
|
||||||
this.registeredProviders[provider.type].register(expressapp,passport,this.endpoint,name,provider)
|
this.registeredProviders[provider.type].register(expressapp,passport,this.endpoint,name,provider)
|
||||||
|
|
@ -56,7 +56,7 @@ class PassportJs{
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticate(userinfos){
|
authenticate(userinfos){
|
||||||
this.authenticate(userinfos)
|
this.authmanager.login(userinfos)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,20 @@ class AuthProvider {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getId(name){
|
||||||
|
await db.connect()
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const collection = conn.collection('authprovider');
|
||||||
|
|
||||||
|
const existingauth = await collection.findOne({ name:name });
|
||||||
|
|
||||||
|
if(existingauth){
|
||||||
|
return existingauth._id
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
async create(name) {
|
async create(name) {
|
||||||
await db.connect()
|
await db.connect()
|
||||||
const conn = db.getConnection();
|
const conn = db.getConnection();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
const authProvider = require('./authProvider.js')
|
||||||
const db = require('../config/db.js')
|
const db = require('../config/db.js')
|
||||||
const { ObjectId } = require('mongodb');
|
const { ObjectId } = require('mongodb');
|
||||||
|
|
||||||
|
|
@ -11,14 +12,48 @@ class AuthUserAssociation {
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async find_user_association(authId){
|
async find_user_association(provider_name,auth_id){
|
||||||
await db.connect()
|
await db.connect()
|
||||||
const conn = db.getConnection();
|
const conn = db.getConnection();
|
||||||
|
|
||||||
const collection = conn.collection('authUserAssociation');
|
const collection = conn.collection('authUserAssociation');
|
||||||
|
const provider_id = await authProvider.getId(provider_name)
|
||||||
|
|
||||||
const userAssociation = await collection.findOne({ authId: authId });
|
const userAssociation = await collection.findOne({ authProvider_id: provider_id,auth_id,auth_id });
|
||||||
return userAssociation
|
return userAssociation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async link(provider_name,auth_id,user_id){
|
||||||
|
await db.connect()
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const collection = conn.collection('authUserAssociation');
|
||||||
|
const provider_id = await authProvider.getId(provider_name)
|
||||||
|
|
||||||
|
const userAssociation = await collection.findOne({ authProvider_id: provider_id, user_id: user_id });
|
||||||
|
|
||||||
|
if(!userAssociation){
|
||||||
|
return await collection.insertOne({
|
||||||
|
_id:ObjectId,
|
||||||
|
authProvider_id:provider_id,
|
||||||
|
auth_id:auth_id,
|
||||||
|
user_id:user_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async unlink(provider_name,user_id){
|
||||||
|
await db.connect()
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const collection = conn.collection('authUserAssociation');
|
||||||
|
const provider_id = await authProvider.getId(provider_name)
|
||||||
|
|
||||||
|
const userAssociation = await collection.findOne({ authProvider_id: provider_id, user_id: user_id });
|
||||||
|
|
||||||
|
if(userAssociation){
|
||||||
|
return await collection.deleteOne(userAssociation)
|
||||||
|
} else return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
module.exports = new AuthUserAssociation;
|
module.exports = new AuthUserAssociation;
|
||||||
|
|
@ -1,151 +1,180 @@
|
||||||
//user
|
//user
|
||||||
const db = require('../config/db.js');
|
const db = require("../config/db.js");
|
||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require("bcrypt");
|
||||||
const AppError = require('../middleware/AppError.js');
|
const AppError = require("../middleware/AppError.js");
|
||||||
const { USER_ALREADY_EXISTS } = require('../constants/errorCodes');
|
const { USER_ALREADY_EXISTS } = require("../constants/errorCodes");
|
||||||
const Folders = require('../models/folders.js');
|
const Folders = require("../models/folders.js");
|
||||||
|
|
||||||
class Users {
|
class Users {
|
||||||
async hashPassword(password) {
|
async hashPassword(password) {
|
||||||
return await bcrypt.hash(password, 10)
|
return await bcrypt.hash(password, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
generatePassword() {
|
||||||
|
return Math.random().toString(36).slice(-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
async verify(password, hash) {
|
||||||
|
return await bcrypt.compare(password, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
async register(email, password) {
|
||||||
|
await db.connect();
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const userCollection = conn.collection("users");
|
||||||
|
|
||||||
|
const existingUser = await userCollection.findOne({ email: email });
|
||||||
|
|
||||||
|
if (existingUser) {
|
||||||
|
throw new AppError(USER_ALREADY_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
generatePassword() {
|
const newUser = {
|
||||||
return Math.random().toString(36).slice(-8);
|
email: email,
|
||||||
|
password: await this.hashPassword(password),
|
||||||
|
created_at: new Date(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let created_user = await userCollection.insertOne(newUser);
|
||||||
|
let user = await this.getById(created_user.insertedId)
|
||||||
|
|
||||||
|
const folderTitle = "Dossier par Défaut";
|
||||||
|
const userId = newUser._id.toString();
|
||||||
|
await Folders.create(folderTitle, userId);
|
||||||
|
|
||||||
|
// TODO: verif if inserted properly...
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
async login(userid) {
|
||||||
|
await db.connect();
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const userCollection = conn.collection("users");
|
||||||
|
const user = await userCollection.findOne({ _id: userid });
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async verify(password, hash) {
|
return user;
|
||||||
return await bcrypt.compare(password, hash)
|
}
|
||||||
|
|
||||||
|
async login(email, password) {
|
||||||
|
await db.connect();
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const userCollection = conn.collection("users");
|
||||||
|
|
||||||
|
const user = await userCollection.findOne({ email: email });
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async register(email, password) {
|
const passwordMatch = await this.verify(password, user.password);
|
||||||
await db.connect()
|
|
||||||
const conn = db.getConnection();
|
|
||||||
|
|
||||||
const userCollection = conn.collection('users');
|
if (!passwordMatch) {
|
||||||
|
return false;
|
||||||
const existingUser = await userCollection.findOne({ email: email });
|
|
||||||
|
|
||||||
if (existingUser) {
|
|
||||||
throw new AppError(USER_ALREADY_EXISTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newUser = {
|
|
||||||
email: email,
|
|
||||||
password: await this.hashPassword(password),
|
|
||||||
created_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
await userCollection.insertOne(newUser);
|
|
||||||
|
|
||||||
const folderTitle = 'Dossier par Défaut';
|
|
||||||
const userId = newUser._id.toString();
|
|
||||||
await Folders.create(folderTitle, userId);
|
|
||||||
|
|
||||||
// TODO: verif if inserted properly...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(email, password) {
|
return user;
|
||||||
await db.connect()
|
}
|
||||||
const conn = db.getConnection();
|
|
||||||
|
|
||||||
const userCollection = conn.collection('users');
|
async resetPassword(email) {
|
||||||
|
const newPassword = this.generatePassword();
|
||||||
|
|
||||||
const user = await userCollection.findOne({ email: email });
|
return await this.changePassword(email, newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) {
|
async changePassword(email, newPassword) {
|
||||||
return false;
|
await db.connect();
|
||||||
}
|
const conn = db.getConnection();
|
||||||
|
|
||||||
const passwordMatch = await this.verify(password, user.password);
|
const userCollection = conn.collection("users");
|
||||||
|
|
||||||
if (!passwordMatch) {
|
const hashedPassword = await this.hashPassword(newPassword);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
const result = await userCollection.updateOne(
|
||||||
|
{ email },
|
||||||
|
{ $set: { password: hashedPassword } }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.modifiedCount != 1) return null;
|
||||||
|
|
||||||
|
return newPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(email) {
|
||||||
|
await db.connect();
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const userCollection = conn.collection("users");
|
||||||
|
|
||||||
|
const result = await userCollection.deleteOne({ email });
|
||||||
|
|
||||||
|
if (result.deletedCount != 1) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getId(email) {
|
||||||
|
await db.connect();
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const userCollection = conn.collection("users");
|
||||||
|
|
||||||
|
const user = await userCollection.findOne({ email: email });
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async resetPassword(email) {
|
return user._id;
|
||||||
const newPassword = this.generatePassword();
|
}
|
||||||
|
|
||||||
return await this.changePassword(email, newPassword);
|
async getById(id) {
|
||||||
|
await db.connect();
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
const userCollection = conn.collection("users");
|
||||||
|
|
||||||
|
const user = await userCollection.findOne({ _id: id });
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async changePassword(email, newPassword) {
|
return user;
|
||||||
await db.connect()
|
}
|
||||||
const conn = db.getConnection();
|
|
||||||
|
|
||||||
const userCollection = conn.collection('users');
|
async editUser(userInfo) {
|
||||||
|
await db.connect();
|
||||||
|
const conn = db.getConnection();
|
||||||
|
|
||||||
const hashedPassword = await this.hashPassword(newPassword);
|
const userCollection = conn.collection("users");
|
||||||
|
|
||||||
const result = await userCollection.updateOne({ email }, { $set: { password: hashedPassword } });
|
const user = await userCollection.findOne({ _id: userInfo.id });
|
||||||
|
|
||||||
if (result.modifiedCount != 1) return null;
|
if (!user) {
|
||||||
|
return false;
|
||||||
return newPassword
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(email) {
|
const updatedFields = { ...userInfo };
|
||||||
await db.connect()
|
delete updatedFields.id;
|
||||||
const conn = db.getConnection();
|
|
||||||
|
|
||||||
const userCollection = conn.collection('users');
|
const result = await userCollection.updateOne(
|
||||||
|
{ _id: userInfo.id },
|
||||||
|
{ $set: updatedFields }
|
||||||
|
);
|
||||||
|
|
||||||
const result = await userCollection.deleteOne({ email });
|
if (result.modifiedCount === 1) {
|
||||||
|
return true;
|
||||||
if (result.deletedCount != 1) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getId(email) {
|
return false;
|
||||||
await db.connect()
|
}
|
||||||
const conn = db.getConnection();
|
|
||||||
|
|
||||||
const userCollection = conn.collection('users');
|
|
||||||
|
|
||||||
const user = await userCollection.findOne({ email: email });
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return user._id;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getById(id){
|
|
||||||
await db.connect()
|
|
||||||
const conn = db.getConnection();
|
|
||||||
|
|
||||||
const userCollection = conn.collection('users');
|
|
||||||
|
|
||||||
const user = await userCollection.findOne({ _id: id });
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
async editUser(userInfo){
|
|
||||||
await db.connect()
|
|
||||||
const conn = db.getConnection();
|
|
||||||
|
|
||||||
const userCollection = conn.collection('users');
|
|
||||||
|
|
||||||
const user = await userCollection.findOne({ _id: userInfo.id });
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedFields = { ...userInfo };
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new Users;
|
module.exports = new Users();
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,28 @@
|
||||||
function hasNestedValue(obj, path, delimiter="_") {
|
function hasNestedValue(obj, path, delimiter = "_") {
|
||||||
const keys = path.split(delimiter);
|
const keys = path.split(delimiter);
|
||||||
let current = obj;
|
let current = obj;
|
||||||
|
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
if (current && typeof current === 'object' && key in current) {
|
if (current && typeof current === "object") {
|
||||||
|
if (Array.isArray(current)) {
|
||||||
|
const index = current.findIndex(x => x == key)
|
||||||
|
if (index != -1) {
|
||||||
|
current = current[index];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (key in current) {
|
||||||
current = current[key];
|
current = current[key];
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { hasNestedValue};
|
||||||
Loading…
Reference in a new issue