mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
Roles done
This commit is contained in:
parent
d7986447c4
commit
e30681705f
14 changed files with 227 additions and 223 deletions
|
|
@ -15,7 +15,6 @@ const AuthSelection: React.FC = () => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const data = await authService.fetchAuthData();
|
const data = await authService.fetchAuthData();
|
||||||
console.log(data);
|
|
||||||
setAuthData(data);
|
setAuthData(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useNavigate, useLocation } from 'react-router-dom';
|
import { useNavigate, useLocation } from 'react-router-dom';
|
||||||
import apiService from '../../../services/ApiService';
|
import apiService from '../../../services/ApiService';
|
||||||
import { jwtDecode } from 'jwt-decode';
|
|
||||||
|
|
||||||
const OAuthCallback: React.FC = () => {
|
const OAuthCallback: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
@ -12,15 +11,7 @@ const OAuthCallback: React.FC = () => {
|
||||||
const user = searchParams.get('user');
|
const user = searchParams.get('user');
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
// Save user data to localStorage or sessionStorage
|
|
||||||
console.log(user);
|
|
||||||
apiService.saveToken(user);
|
apiService.saveToken(user);
|
||||||
|
|
||||||
const decodedToken = jwtDecode(user);
|
|
||||||
const { email } = decodedToken as { email: string;};
|
|
||||||
console.log(email + " connected!");
|
|
||||||
|
|
||||||
// Navigate to the dashboard or another page
|
|
||||||
navigate('/');
|
navigate('/');
|
||||||
} else {
|
} else {
|
||||||
navigate('/login');
|
navigate('/login');
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ENV_VARIABLES } from '../../../../constants';
|
|
||||||
import '../css/buttonAuth.css';
|
import '../css/buttonAuth.css';
|
||||||
|
|
||||||
interface ButtonAuthContainerProps {
|
interface ButtonAuthContainerProps {
|
||||||
|
|
@ -8,7 +7,7 @@ interface ButtonAuthContainerProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleAuthLogin = (provider: string) => {
|
const handleAuthLogin = (provider: string) => {
|
||||||
window.location.href = `${ENV_VARIABLES.VITE_BACKEND_URL}/api/auth/` + provider;
|
window.location.href = `/api/auth/` + provider;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ButtonAuth: React.FC<ButtonAuthContainerProps> = ({ providerName, providerType }) => {
|
const ButtonAuth: React.FC<ButtonAuthContainerProps> = ({ providerName, providerType }) => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useNavigate, Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
// JoinRoom.tsx
|
// JoinRoom.tsx
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
@ -11,7 +11,6 @@ import LoginContainer from '../../../../components/LoginContainer/LoginContainer
|
||||||
import ApiService from '../../../../services/ApiService';
|
import ApiService from '../../../../services/ApiService';
|
||||||
|
|
||||||
const SimpleLogin: React.FC = () => {
|
const SimpleLogin: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
|
|
@ -27,15 +26,10 @@ const SimpleLogin: React.FC = () => {
|
||||||
|
|
||||||
const login = async () => {
|
const login = async () => {
|
||||||
const result = await ApiService.login(email, password);
|
const result = await ApiService.login(email, password);
|
||||||
|
if (result !== true) {
|
||||||
if (result != true) {
|
|
||||||
setConnectionError(result);
|
setConnectionError(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
navigate("/")
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
|
|
||||||
// JoinRoom.tsx
|
// JoinRoom.tsx
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
|
@ -10,7 +8,6 @@ import LoginContainer from '../../../../components/LoginContainer/LoginContainer
|
||||||
import ApiService from '../../../../services/ApiService';
|
import ApiService from '../../../../services/ApiService';
|
||||||
|
|
||||||
const Register: React.FC = () => {
|
const Register: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const [name, setName] = useState(''); // State for name
|
const [name, setName] = useState(''); // State for name
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
|
|
@ -46,8 +43,6 @@ const Register: React.FC = () => {
|
||||||
setConnectionError(result);
|
setConnectionError(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate("/login");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import axios, { AxiosError, AxiosResponse } from 'axios';
|
import axios, { AxiosError, AxiosResponse } from 'axios';
|
||||||
import {jwtDecode} from 'jwt-decode';
|
import { jwtDecode } from 'jwt-decode';
|
||||||
import { ENV_VARIABLES } from '../constants';
|
import { ENV_VARIABLES } from '../constants';
|
||||||
|
|
||||||
import { QuizType } from '../Types/QuizType';
|
import { QuizType } from '../Types/QuizType';
|
||||||
|
|
@ -79,26 +79,25 @@ class ApiService {
|
||||||
|
|
||||||
public isLoggedInTeacher(): boolean {
|
public isLoggedInTeacher(): boolean {
|
||||||
const token = this.getToken();
|
const token = this.getToken();
|
||||||
|
|
||||||
console.log("Check if loggedIn : " + token);
|
|
||||||
|
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decodedToken = jwtDecode(token) as { roles: string[] };
|
const decodedToken = jwtDecode(token) as { roles: string[] };
|
||||||
|
|
||||||
const userRoles = decodedToken.roles;
|
const userRoles = decodedToken.roles;
|
||||||
const requiredRole = 'teacher';
|
const requiredRole = 'teacher';
|
||||||
|
|
||||||
if (!userRoles || !userRoles.includes(requiredRole)) {
|
if (!userRoles || !userRoles.includes(requiredRole)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update token expiry
|
// Update token expiry
|
||||||
this.saveToken(token);
|
this.saveToken(token);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error decoding token:", error);
|
console.error("Error decoding token:", error);
|
||||||
|
|
@ -129,8 +128,12 @@ class ApiService {
|
||||||
|
|
||||||
const result: AxiosResponse = await axios.post(url, body, { headers: headers });
|
const result: AxiosResponse = await axios.post(url, body, { headers: headers });
|
||||||
|
|
||||||
if (result.status !== 200) {
|
console.log(result);
|
||||||
throw new Error(`L'enregistrement a échoué. Status: ${result.status}`);
|
if (result.status == 200) {
|
||||||
|
window.location.href = result.request.responseURL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error(`La connexion a échoué. Status: ${result.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -152,39 +155,52 @@ class ApiService {
|
||||||
* @returns true if successful
|
* @returns true if successful
|
||||||
* @returns A error string if unsuccessful,
|
* @returns A error string if unsuccessful,
|
||||||
*/
|
*/
|
||||||
public async login(email: string, password: string): Promise<any> {
|
/**
|
||||||
try {
|
* @returns true if successful
|
||||||
|
* @returns An error string if unsuccessful
|
||||||
if (!email || !password) {
|
*/
|
||||||
throw new Error(`L'email et le mot de passe sont requis.`);
|
public async login(email: string, password: string): Promise<any> {
|
||||||
}
|
try {
|
||||||
|
if (!email || !password) {
|
||||||
const url: string = this.constructRequestUrl(`/auth/simple-auth/login`);
|
throw new Error("L'email et le mot de passe sont requis.");
|
||||||
const headers = this.constructRequestHeaders();
|
|
||||||
const body = { email, password };
|
|
||||||
|
|
||||||
const result: AxiosResponse = await axios.post(url, body, { headers: headers });
|
|
||||||
|
|
||||||
if (result.status !== 200) {
|
|
||||||
throw new Error(`La connexion a échoué. Status: ${result.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.saveToken(result.data.token);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error details: ", error);
|
|
||||||
|
|
||||||
if (axios.isAxiosError(error)) {
|
|
||||||
const err = error as AxiosError;
|
|
||||||
const data = err.response?.data as { error: string } | undefined;
|
|
||||||
return data?.error || 'Erreur serveur inconnue lors de la requête.';
|
|
||||||
}
|
|
||||||
|
|
||||||
return `Une erreur inattendue s'est produite.`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const url: string = this.constructRequestUrl(`/auth/simple-auth/login`);
|
||||||
|
const headers = this.constructRequestHeaders();
|
||||||
|
const body = { email, password };
|
||||||
|
|
||||||
|
const result: AxiosResponse = await axios.post(url, body, { headers: headers });
|
||||||
|
|
||||||
|
// If login is successful, redirect the user
|
||||||
|
if (result.status === 200) {
|
||||||
|
window.location.href = result.request.responseURL;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new Error(`La connexion a échoué. Statut: ${result.status}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error details:", error);
|
||||||
|
|
||||||
|
// Handle Axios-specific errors
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
|
const err = error as AxiosError;
|
||||||
|
const responseData = err.response?.data as { message?: string } | undefined;
|
||||||
|
|
||||||
|
// If there is a message field in the response, print it
|
||||||
|
if (responseData?.message) {
|
||||||
|
console.log("Backend error message:", responseData.message);
|
||||||
|
return responseData.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no message is found, return a fallback message
|
||||||
|
return "Erreur serveur inconnue lors de la requête.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle other non-Axios errors
|
||||||
|
return "Une erreur inattendue s'est produite.";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns true if successful
|
* @returns true if successful
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ class AuthService {
|
||||||
async fetchAuthData(){
|
async fetchAuthData(){
|
||||||
try {
|
try {
|
||||||
const response = await fetch(this.constructRequestUrl('/auth/getActiveAuth'));
|
const response = await fetch(this.constructRequestUrl('/auth/getActiveAuth'));
|
||||||
console.log("base url: " + this.BASE_URL);
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return data.authActive;
|
return data.authActive;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ services:
|
||||||
context: ./client
|
context: ./client
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
container_name: frontend
|
container_name: frontend
|
||||||
environment:
|
|
||||||
VITE_BACKEND_URL: http://localhost:3000
|
|
||||||
ports:
|
ports:
|
||||||
- "5173:5173"
|
- "5173:5173"
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ class AuthManager{
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(userInfo,req,res,next){
|
async login(userInfo,req,res,next){
|
||||||
const tokenToSave = jwt.create(userInfo.email, userInfo._id);
|
const tokenToSave = jwt.create(userInfo.email, userInfo._id,userInfo.roles);
|
||||||
res.redirect(`${process.env['FRONTEND_URL']}/auth/callback?user=${tokenToSave}`);
|
res.redirect(`/auth/callback?user=${tokenToSave}`);
|
||||||
console.info(`L'utilisateur '${userInfo.name}' vient de se connecter`)
|
console.info(`L'utilisateur '${userInfo.name}' vient de se connecter`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ var { hasNestedValue } = require('../../../utils')
|
||||||
var jwt = require('../../../middleware/jwtToken')
|
var jwt = require('../../../middleware/jwtToken')
|
||||||
|
|
||||||
class PassportOAuth {
|
class PassportOAuth {
|
||||||
constructor(passportjs,auth_name){
|
constructor(passportjs, auth_name) {
|
||||||
this.passportjs = passportjs
|
this.passportjs = passportjs
|
||||||
this.auth_name = auth_name
|
this.auth_name = 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
|
const self = this
|
||||||
|
|
||||||
passport.use(name, new OAuth2Strategy({
|
passport.use(name, new OAuth2Strategy({
|
||||||
|
|
@ -22,72 +22,72 @@ class PassportOAuth {
|
||||||
callbackURL: cb_url,
|
callbackURL: cb_url,
|
||||||
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.OAUTH_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();
|
||||||
|
|
||||||
let received_user = {
|
let received_user = {
|
||||||
auth_id: userInfo.sub,
|
auth_id: userInfo.sub,
|
||||||
email: userInfo.email,
|
email: userInfo.email,
|
||||||
name: userInfo.name,
|
name: userInfo.name,
|
||||||
roles: []
|
roles: []
|
||||||
};
|
};
|
||||||
|
|
||||||
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')
|
|
||||||
|
|
||||||
const user_association = await authUserAssoc.find_user_association(self.auth_name,received_user.auth_id)
|
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')
|
||||||
|
|
||||||
let user_account
|
const user_association = await authUserAssoc.find_user_association(self.auth_name, received_user.auth_id)
|
||||||
if(user_association){
|
|
||||||
user_account = await users.getById(user_association.user_id)
|
let user_account
|
||||||
}
|
if (user_association) {
|
||||||
else {
|
user_account = await users.getById(user_association.user_id)
|
||||||
let user_id = await users.getId(received_user.email)
|
|
||||||
if(user_id){
|
|
||||||
user_account = await users.getById(user_id);
|
|
||||||
} else {
|
|
||||||
received_user.password = users.generatePassword()
|
|
||||||
user_account = await self.passportjs.register(received_user)
|
|
||||||
}
|
}
|
||||||
await authUserAssoc.link(self.auth_name,received_user.auth_id,user_account._id)
|
else {
|
||||||
|
let user_id = await users.getId(received_user.email)
|
||||||
|
if (user_id) {
|
||||||
|
user_account = await users.getById(user_id);
|
||||||
|
} else {
|
||||||
|
received_user.password = users.generatePassword()
|
||||||
|
user_account = await self.passportjs.register(received_user)
|
||||||
|
}
|
||||||
|
await authUserAssoc.link(self.auth_name, received_user.auth_id, user_account._id)
|
||||||
|
}
|
||||||
|
|
||||||
|
user_account.name = received_user.name
|
||||||
|
user_account.roles = received_user.roles
|
||||||
|
await users.editUser(user_account)
|
||||||
|
|
||||||
|
// Store the tokens in the session
|
||||||
|
req.session.oauth2Tokens = {
|
||||||
|
accessToken: accessToken,
|
||||||
|
refreshToken: refreshToken,
|
||||||
|
expiresIn: params.expires_in
|
||||||
|
};
|
||||||
|
|
||||||
|
return done(null, user_account);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Erreur dans la strategie OAuth2 '${name}' : ${error}`);
|
||||||
|
return done(error);
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
user_account.name = received_user.name
|
|
||||||
user_account.roles = received_user.roles
|
|
||||||
await users.editUser(user_account)
|
|
||||||
|
|
||||||
// Store the tokens in the session
|
|
||||||
req.session.oauth2Tokens = {
|
|
||||||
accessToken: accessToken,
|
|
||||||
refreshToken: refreshToken,
|
|
||||||
expiresIn: params.expires_in
|
|
||||||
};
|
|
||||||
|
|
||||||
return done(null, user_account);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Erreur dans la strategie OAuth2 '${name}' : ${error}`);
|
|
||||||
return done(error);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.get(`${endpoint}/${name}`, (req, res, next) => {
|
app.get(`${endpoint}/${name}`, (req, res, next) => {
|
||||||
passport.authenticate(name, {
|
passport.authenticate(name, {
|
||||||
scope: 'openid profile email offline_access'+ ` ${provider.OAUTH_ADD_SCOPE}`,
|
scope: 'openid profile email offline_access' + ` ${provider.OAUTH_ADD_SCOPE}`,
|
||||||
prompt: 'consent'
|
prompt: 'consent'
|
||||||
})(req, res, next);
|
})(req, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get(`${endpoint}/${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) {
|
||||||
self.passportjs.authenticate(req.user,req,res)
|
self.passportjs.authenticate(req.user, req, res)
|
||||||
} else {
|
} else {
|
||||||
res.status(401).json({ error: "L'authentification a échoué" });
|
res.status(401).json({ error: "L'authentification a échoué" });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ var { hasNestedValue } = require('../../../utils')
|
||||||
var jwt = require('../../../middleware/jwtToken')
|
var jwt = require('../../../middleware/jwtToken')
|
||||||
|
|
||||||
class PassportOpenIDConnect {
|
class PassportOpenIDConnect {
|
||||||
constructor(passportjs,auth_name){
|
constructor(passportjs, auth_name) {
|
||||||
this.passportjs = passportjs
|
this.passportjs = passportjs
|
||||||
this.auth_name = auth_name
|
this.auth_name = auth_name
|
||||||
}
|
}
|
||||||
|
|
||||||
async getConfigFromConfigURL(name,provider){
|
async getConfigFromConfigURL(name, provider) {
|
||||||
try{
|
try {
|
||||||
const config = await fetch(provider.OIDC_CONFIG_URL)
|
const config = await fetch(provider.OIDC_CONFIG_URL)
|
||||||
return await config.json()
|
return await config.json()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -19,10 +19,10 @@ class PassportOpenIDConnect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async register(app, passport,endpoint, name, provider) {
|
async register(app, passport, endpoint, name, provider) {
|
||||||
|
|
||||||
const config = await this.getConfigFromConfigURL(name,provider)
|
const config = await this.getConfigFromConfigURL(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
|
const self = this
|
||||||
|
|
||||||
passport.use(name, new OpenIDConnectStrategy({
|
passport.use(name, new OpenIDConnectStrategy({
|
||||||
|
|
@ -36,59 +36,60 @@ class PassportOpenIDConnect {
|
||||||
passReqToCallback: true,
|
passReqToCallback: true,
|
||||||
scope: 'openid profile email ' + `${provider.OIDC_ADD_SCOPE}`,
|
scope: 'openid profile email ' + `${provider.OIDC_ADD_SCOPE}`,
|
||||||
},
|
},
|
||||||
// patch pour la librairie permet d'obtenir les groupes, PR en cours mais "morte" : https://github.com/jaredhanson/passport-openidconnect/pull/101
|
// patch pour la librairie permet d'obtenir les groupes, PR en cours mais "morte" : https://github.com/jaredhanson/passport-openidconnect/pull/101
|
||||||
async function(req, issuer, profile, times, tok, done) {
|
async function (req, issuer, profile, times, tok, done) {
|
||||||
try {
|
try {
|
||||||
const received_user = {
|
const received_user = {
|
||||||
auth_id: profile.id,
|
auth_id: profile.id,
|
||||||
email: profile.emails[0].value,
|
email: profile.emails[0].value,
|
||||||
name: profile.name.givenName,
|
name: profile.name.givenName,
|
||||||
roles: []
|
roles: []
|
||||||
};
|
};
|
||||||
|
|
||||||
if(hasNestedValue(profile,provider.OIDC_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
|
|
||||||
if(hasNestedValue(profile,provider.OIDC_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
|
|
||||||
|
|
||||||
const user_association = await authUserAssoc.find_user_association(self.auth_name,received_user.auth_id)
|
|
||||||
|
|
||||||
let user_account
|
if (hasNestedValue(profile, provider.OIDC_ROLE_TEACHER_VALUE)) received_user.roles.push('teacher')
|
||||||
if(user_association){
|
if (hasNestedValue(profile, provider.OIDC_ROLE_STUDENT_VALUE)) received_user.roles.push('student')
|
||||||
user_account = await users.getById(user_association.user_id)
|
|
||||||
}
|
const user_association = await authUserAssoc.find_user_association(self.auth_name, received_user.auth_id)
|
||||||
else {
|
|
||||||
let user_id = await users.getId(received_user.email)
|
let user_account
|
||||||
if(user_id){
|
if (user_association) {
|
||||||
user_account = await users.getById(user_id);
|
user_account = await users.getById(user_association.user_id)
|
||||||
} else {
|
|
||||||
received_user.password = users.generatePassword()
|
|
||||||
user_account = await self.passportjs.register(received_user)
|
|
||||||
}
|
}
|
||||||
await authUserAssoc.link(self.auth_name,received_user.auth_id,user_account._id)
|
else {
|
||||||
|
let user_id = await users.getId(received_user.email)
|
||||||
|
if (user_id) {
|
||||||
|
user_account = await users.getById(user_id);
|
||||||
|
} else {
|
||||||
|
received_user.password = users.generatePassword()
|
||||||
|
user_account = await self.passportjs.register(received_user)
|
||||||
|
}
|
||||||
|
await authUserAssoc.link(self.auth_name, received_user.auth_id, user_account._id)
|
||||||
|
}
|
||||||
|
|
||||||
|
user_account.name = received_user.name
|
||||||
|
user_account.roles = received_user.roles
|
||||||
|
await users.editUser(user_account)
|
||||||
|
|
||||||
|
return done(null, user_account);
|
||||||
|
} catch (error) {
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
user_account.name = received_user.name
|
|
||||||
user_account.roles = received_user.roles
|
|
||||||
await users.editUser(user_account)
|
|
||||||
|
|
||||||
return done(null, user_account);
|
|
||||||
} catch (error) {
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
app.get(`${endpoint}/${name}`, (req, res, next) => {
|
app.get(`${endpoint}/${name}`, (req, res, next) => {
|
||||||
passport.authenticate(name, {
|
passport.authenticate(name, {
|
||||||
scope: 'openid profile email offline_access'+ ` ${provider.OAUTH_ADD_SCOPE}`,
|
scope: 'openid profile email offline_access' + ` ${provider.OAUTH_ADD_SCOPE}`,
|
||||||
prompt: 'consent'
|
prompt: 'consent'
|
||||||
})(req, res, next);
|
})(req, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get(`${endpoint}/${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) {
|
||||||
self.passportjs.authenticate(req.user,req,res)
|
self.passportjs.authenticate(req.user, req, res)
|
||||||
} else {
|
} else {
|
||||||
res.status(401).json({ error: "L'authentification a échoué" });
|
res.status(401).json({ error: "L'authentification a échoué" });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,52 +6,34 @@ const AppError = require('../../middleware/AppError.js');
|
||||||
const { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR } = require('../../constants/errorCodes');
|
const { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR } = require('../../constants/errorCodes');
|
||||||
const { name } = require('../../models/authProvider.js');
|
const { name } = require('../../models/authProvider.js');
|
||||||
|
|
||||||
class SimpleAuth{
|
class SimpleAuth {
|
||||||
constructor(authmanager,settings){
|
constructor(authmanager, settings) {
|
||||||
this.authmanager = authmanager
|
this.authmanager = authmanager
|
||||||
this.providers = settings
|
this.providers = settings
|
||||||
this.endpoint = "/api/auth/simple-auth"
|
this.endpoint = "/api/auth/simple-auth"
|
||||||
}
|
}
|
||||||
|
|
||||||
async registerAuth(expressapp){
|
async registerAuth(expressapp) {
|
||||||
try{
|
try {
|
||||||
expressapp.post(`${this.endpoint}/register`, (req,res,next)=>this.register(this,req,res));
|
expressapp.post(`${this.endpoint}/register`, (req, res, next) => this.register(this, req, res));
|
||||||
expressapp.post(`${this.endpoint}/login`, (req,res,next)=>this.authenticate(this,req,res));
|
expressapp.post(`${this.endpoint}/login`, (req, res, next) => this.authenticate(this, req, res));
|
||||||
expressapp.post(`${this.endpoint}/reset-password`, (req,res,next)=>this.resetPassword(this,req,res));
|
expressapp.post(`${this.endpoint}/reset-password`, (req, res, next) => this.resetPassword(this, req, res));
|
||||||
expressapp.post(`${this.endpoint}/change-password`, jwt.authenticate, (req,res,next)=>this.changePassword(this,req,res));
|
expressapp.post(`${this.endpoint}/change-password`, jwt.authenticate, (req, res, next) => this.changePassword(this, req, res));
|
||||||
} catch(error){
|
} catch (error) {
|
||||||
console.error(`La connexion ${name} de type ${provider.type} n'as pu être chargé.`)
|
console.error(`La connexion ${name} de type ${provider.type} n'as pu être chargé.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async register(self,req, res) {
|
async register(self, req, res) {
|
||||||
let userInfos = {
|
|
||||||
name: req.body.name,
|
|
||||||
email: req.body.email,
|
|
||||||
password: req.body.password,
|
|
||||||
roles: req.body.roles
|
|
||||||
}
|
|
||||||
let user = await self.authmanager.register(userInfos)
|
|
||||||
if(user) res.redirect("/")
|
|
||||||
else res.redirect("/login")
|
|
||||||
}
|
|
||||||
|
|
||||||
async authenticate(self,req, res, next) {
|
|
||||||
try {
|
try {
|
||||||
const { email, password } = req.body;
|
let userInfos = {
|
||||||
|
name: req.body.name,
|
||||||
if (!email || !password) {
|
email: req.body.email,
|
||||||
throw new AppError(MISSING_REQUIRED_PARAMETER);
|
password: req.body.password,
|
||||||
|
roles: req.body.roles
|
||||||
}
|
}
|
||||||
|
let user = await self.authmanager.register(userInfos)
|
||||||
const user = await model.login(email, password);
|
if (user) res.redirect("/login")
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
throw new AppError(LOGIN_CREDENTIALS_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
user.name = user.name ?? user.email
|
|
||||||
self.authmanager.login(user,req,res,next)
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
|
|
@ -60,7 +42,29 @@ class SimpleAuth{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async resetPassword(self,req, res, next) {
|
async authenticate(self, req, res, next) {
|
||||||
|
try {
|
||||||
|
const { email, password } = req.body;
|
||||||
|
|
||||||
|
if (!email || !password) {
|
||||||
|
const error = new Error("Email or password is missing");
|
||||||
|
error.statusCode = 400;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await model.login(email, password);
|
||||||
|
|
||||||
|
await self.authmanager.login(user, req, res, next);
|
||||||
|
} catch (error) {
|
||||||
|
const statusCode = error.statusCode || 500;
|
||||||
|
const message = error.message || "An internal server error occurred";
|
||||||
|
|
||||||
|
console.error(error);
|
||||||
|
return res.status(statusCode).json({ message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async resetPassword(self, req, res, next) {
|
||||||
try {
|
try {
|
||||||
const { email } = req.body;
|
const { email } = req.body;
|
||||||
|
|
||||||
|
|
@ -85,7 +89,7 @@ class SimpleAuth{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async changePassword(self,req, res, next) {
|
async changePassword(self, req, res, next) {
|
||||||
try {
|
try {
|
||||||
const { email, oldPassword, newPassword } = req.body;
|
const { email, oldPassword, newPassword } = req.body;
|
||||||
|
|
||||||
|
|
@ -114,7 +118,7 @@ class SimpleAuth{
|
||||||
return next(error);
|
return next(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = SimpleAuth;
|
module.exports = SimpleAuth;
|
||||||
|
|
@ -7,8 +7,8 @@ dotenv.config();
|
||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
|
|
||||||
create(email, userId) {
|
create(email, userId, roles) {
|
||||||
return jwt.sign({ email, userId }, process.env.JWT_SECRET);
|
return jwt.sign({ email, userId, roles }, process.env.JWT_SECRET);
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticate(req, res, next) {
|
authenticate(req, res, next) {
|
||||||
|
|
@ -25,11 +25,11 @@ class Token {
|
||||||
|
|
||||||
req.user = payload;
|
req.user = payload;
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return next(error);
|
return next(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,24 +64,32 @@ class Users {
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(email, password) {
|
async login(email, password) {
|
||||||
await db.connect();
|
try {
|
||||||
const conn = db.getConnection();
|
await db.connect();
|
||||||
|
const conn = db.getConnection();
|
||||||
|
const userCollection = conn.collection("users");
|
||||||
|
|
||||||
const userCollection = conn.collection("users");
|
const user = await userCollection.findOne({ email: email });
|
||||||
|
|
||||||
const user = await userCollection.findOne({ email: email });
|
if (!user) {
|
||||||
|
const error = new Error("User not found");
|
||||||
|
error.statusCode = 404;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
if (!user) {
|
const passwordMatch = await this.verify(password, user.password);
|
||||||
return false;
|
|
||||||
|
if (!passwordMatch) {
|
||||||
|
const error = new Error("Password does not match");
|
||||||
|
error.statusCode = 401;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const passwordMatch = await this.verify(password, user.password);
|
|
||||||
|
|
||||||
if (!passwordMatch) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async resetPassword(email) {
|
async resetPassword(email) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue