Add permissions with providers

This commit is contained in:
fserres 2024-10-01 00:52:25 -04:00
parent 19f545b24f
commit 04577d5ce2
10 changed files with 122 additions and 17 deletions

View file

@ -357,8 +357,9 @@ const Dashboard: React.FC = () => {
} }
} }
if (!ApiService.isTeacher()) {
return (<div className="dashboard"></div>);
}
return ( return (

View file

@ -171,6 +171,10 @@ const QuizForm: React.FC = () => {
navigator.clipboard.writeText(link); navigator.clipboard.writeText(link);
} }
if (!ApiService.isTeacher()) {
return (<div className="dashboard"></div>);
}
return ( return (
<div className='quizEditor'> <div className='quizEditor'>

View file

@ -76,6 +76,22 @@ class ApiService {
return true; return true;
} }
public isTeacher(): boolean {
const token = this.getToken()
if (token == null) {
return false;
}
let user = JSON.parse(atob(token.split('.')[1]))
if (user.role == "teacher") {
return true;
} else {
return false;
}
}
public logout(): void { public logout(): void {
return localStorage.removeItem("jwt"); return localStorage.removeItem("jwt");
} }

View file

@ -1,4 +1,5 @@
var OAuth2Strategy = require('passport-oauth2') var OAuth2Strategy = require('passport-oauth2')
const model = require("../../../models/users");
class PassportOAuth { class PassportOAuth {
register(app, passport,endpoint, name, provider) { register(app, passport,endpoint, name, provider) {
@ -17,6 +18,15 @@ class PassportOAuth {
headers: { 'Authorization': `Bearer ${accessToken}` } headers: { 'Authorization': `Bearer ${accessToken}` }
}); });
const userInfo = await userInfoResponse.json(); const userInfo = await userInfoResponse.json();
let role;
if (userInfo.groups.includes(provider.OAUTH_ROLE_TEACHER_VALUE)) {
role = "teacher";
} else if (userInfo.groups.includes(provider.OAUTH_ROLE_STUDENT_VALUE)) {
role = "student";
} else {
role = "anonymous";
}
const user = { const user = {
id: userInfo.sub, id: userInfo.sub,
@ -25,7 +35,8 @@ class PassportOAuth {
groups: userInfo.groups ?? [], groups: userInfo.groups ?? [],
accessToken: accessToken, accessToken: accessToken,
refreshToken: refreshToken, refreshToken: refreshToken,
expiresIn: params.expires_in expiresIn: params.expires_in,
role: role
}; };
// Store the tokens in the session // Store the tokens in the session

View file

@ -1,4 +1,5 @@
var OpenIDConnectStrategy = require('passport-openidconnect') var OpenIDConnectStrategy = require('passport-openidconnect')
const model = require("../../../models/users");
class PassportOpenIDConnect { class PassportOpenIDConnect {
@ -54,6 +55,13 @@ class PassportOpenIDConnect {
}, },
(req, res) => { (req, res) => {
if (req.user) { if (req.user) {
if (req.user.groups.includes(provider.OAUTH_ROLE_TEACHER_VALUE)) {
model.register(req.user.email, "teacher");
} else if (req.user.groups.includes(provider.OAUTH_ROLE_STUDENT_VALUE)) {
model.register(req.user.email, "student");
} else {
model.register(req.user.email, "anonymous");
}
res.json(req.user) res.json(req.user)
console.info(`L'utilisateur '${req.user.name}' vient de se connecter`) console.info(`L'utilisateur '${req.user.name}' vient de se connecter`)
} else { } else {

View file

@ -151,15 +151,11 @@ class AuthConfig {
if (providerConfig.type === 'oauth') { if (providerConfig.type === 'oauth') {
passportConfig[providerName] = { passportConfig[providerName] = {
type: providerConfig.type, type: providerConfig.type
authorizationUrl: providerConfig.OAUTH_AUTHORIZATION_URL,
callbackUrl: providerConfig.OAUTH_CALLBACK_URL,
}; };
} else if (providerConfig.type === 'oidc') { } else if (providerConfig.type === 'oidc') {
passportConfig[providerName] = { passportConfig[providerName] = {
type: providerConfig.type, type: providerConfig.type
issuerUrl: providerConfig.OIDC_ISSUER_URL,
callbackUrl: providerConfig.OIDC_CALLBACK_URL
}; };
} }
}); });

View file

@ -14,7 +14,8 @@
"permissions": [ "permissions": [
"crud_quiz", "crud_quiz",
"crud_folders", "crud_folders",
"crud_images" "crud_images",
"participate_quiz"
] ]
}, },
{ {

View file

@ -1,12 +1,18 @@
const Permissions = require('../models/permissions'); const Permissions = require('../models/permissions');
const AppError = require("./AppError"); const AppError = require("./AppError");
const { UNAUTHORIZED_PERMISSION_MISSING} = require("../constants/errorCodes"); const { UNAUTHORIZED_PERMISSION_MISSING} = require("../constants/errorCodes");
const jwt = require("jsonwebtoken");
class Rbac { class Rbac {
checkPermission = (...permissions) => { checkPermission = (...permissions) => {
return (req, res, next) => { return (req, res, next) => {
const userRole = req.user ? req.user.role : 'anonymous'; let userRole;
if (req.user) {
userRole = req.user.role;
} else if (req.session.passport.user) {
userRole = req.session.passport.user.role;
} else {
userRole = 'anonymous';
}
const userPermissions = Permissions.getPermissionsByRoleName(userRole); const userPermissions = Permissions.getPermissionsByRoleName(userRole);
for (let permission of permissions) { for (let permission of permissions) {

View file

@ -47,6 +47,37 @@ class Users {
// TODO: verif if inserted properly... // TODO: verif if inserted properly...
} }
async register(email, role) {
await db.connect();
const conn = db.getConnection();
const userCollection = conn.collection('users');
const existingUser = await userCollection.findOne({ email: email });
if (existingUser) {
await userCollection.updateOne(
{ email: existingUser.email },
{
$set: { 'role': role },
$currentDate: { lastModified: true }
}
);
} else {
const newUser = {
email: email,
role: role,
created_at: new Date()
};
await userCollection.insertOne(newUser);
const folderTitle = 'Dossier par Défaut';
const userId = newUser._id.toString();
await Folders.create(folderTitle, userId);
}
}
async login(email, password) { async login(email, password) {
await db.connect() await db.connect()
const conn = db.getConnection(); const conn = db.getConnection();

View file

@ -1,11 +1,38 @@
const MAX_USERS_PER_ROOM = 60; const MAX_USERS_PER_ROOM = 60;
const MAX_TOTAL_CONNECTIONS = 2000; const MAX_TOTAL_CONNECTIONS = 2000;
var passport = require('passport')
const Permissions = require("../models/permissions");
const AppError = require("../middleware/AppError");
const {UNAUTHORIZED_PERMISSION_MISSING} = require("../constants/errorCodes");
const setupWebsocket = (io) => { const setupWebsocket = (io) => {
let totalConnections = 0; let totalConnections = 0;
function onlyForHandshake(middleware) {
return (req, res, next) => {
const isHandshake = req._query.sid === undefined;
if (isHandshake) {
middleware(req, res, next);
} else {
next();
}
};
}
io.engine.use(onlyForHandshake(passport.session()));
io.engine.use(
onlyForHandshake((req, res, next) => {
if (req.user) {
next();
} else {
res.writeHead(401);
res.end();
}
}),
);
io.on("connection", (socket) => { io.on("connection", (socket) => {
// Get jwt and roles const userRole = socket.request.user.role;
if (totalConnections >= MAX_TOTAL_CONNECTIONS) { if (totalConnections >= MAX_TOTAL_CONNECTIONS) {
console.log("Connection limit reached. Disconnecting client."); console.log("Connection limit reached. Disconnecting client.");
socket.emit( socket.emit(
@ -25,10 +52,10 @@ const setupWebsocket = (io) => {
); );
socket.on("create-room", (sentRoomName) => { socket.on("create-room", (sentRoomName) => {
// If roles authorize else send error message const userPermissions = Permissions.getPermissionsByRoleName(userRole);
// else { if (!userPermissions.includes("create_quiz")) {
// socket.emit('access_denied', 'You do not have permission to perform this action'); socket.emit(UNAUTHORIZED_PERMISSION_MISSING.code, UNAUTHORIZED_PERMISSION_MISSING.message);
// } }
if (sentRoomName) { if (sentRoomName) {
const roomName = sentRoomName.toUpperCase(); const roomName = sentRoomName.toUpperCase();
if (!io.sockets.adapter.rooms.get(roomName)) { if (!io.sockets.adapter.rooms.get(roomName)) {
@ -49,6 +76,10 @@ const setupWebsocket = (io) => {
}); });
socket.on("join-room", ({ enteredRoomName, username }) => { socket.on("join-room", ({ enteredRoomName, username }) => {
const userPermissions = Permissions.getPermissionsByRoleName(userRole);
if (!userPermissions.includes("participate_quiz")) {
socket.emit(UNAUTHORIZED_PERMISSION_MISSING.code, UNAUTHORIZED_PERMISSION_MISSING.message);
}
if (io.sockets.adapter.rooms.has(enteredRoomName)) { if (io.sockets.adapter.rooms.has(enteredRoomName)) {
const clientsInRoom = const clientsInRoom =
io.sockets.adapter.rooms.get(enteredRoomName).size; io.sockets.adapter.rooms.get(enteredRoomName).size;