From 12d7de50658ece4857fda8b567a7938d3bae1088 Mon Sep 17 00:00:00 2001 From: "manuel.sowada" Date: Thu, 23 Apr 2026 11:58:02 +0200 Subject: [PATCH] handle case sensitive --- server.js | 2 +- src/services/authenticationManager.js | 318 +++++++++++++++++++------- utils.js | 2 +- 3 files changed, 242 insertions(+), 80 deletions(-) diff --git a/server.js b/server.js index b8d46b7..e507254 100644 --- a/server.js +++ b/server.js @@ -118,7 +118,7 @@ const server = https.createServer(httpsOptions, app); databaseModel.set('authentication', require(`@models/authenticationModel`)(service.get('sqlManager').getInstance('main'))); service.set('fileSystemManager', new FileSystemManager()); - service.set('authenticationManager', new AuthenticationManager(databaseModel.get('authentication'), app.locals.configuration.integration.token.secret, service.get('eventManager'))); + service.set('authenticationManager', new AuthenticationManager(databaseModel.get('authentication'), app.locals.configuration.integration.token.secret)); service.set('activeDirectoryManager', new ActiveDirectory(app.locals.configuration.integration.activedirectory)) // everytime last created service! diff --git a/src/services/authenticationManager.js b/src/services/authenticationManager.js index eb9263b..62d2e32 100644 --- a/src/services/authenticationManager.js +++ b/src/services/authenticationManager.js @@ -1,80 +1,66 @@ const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); - -let { levelId, message } = ''; +const { fn, col, where } = require('sequelize'); /** * Authentication class for login method, token validation and password setting */ class AuthenticationManager { - /** - * - * @param {object} model - Use the authentication database model for interact with the database - * @param {string} secretKey - Defines the server secret for token validation - */ - constructor(model, secretKey, eventManager) { - this.eventManager = eventManager; - - // if (!model) throw new Error('Sequelize Model wird benötigt'); - // if (!secretKey) throw new Error('Secret Key wird benötigt'); - + constructor(model, secretKey) { this.Authentication = model; this.SECRET_KEY = secretKey; } + /** + * Helper: Case-insensitive User Lookup + */ + async findUser(sAMAccountName) { + return await this.Authentication.findOne({ + where: where( + fn('LOWER', col('sAMAccountName')), + sAMAccountName.toLowerCase() + ) + }); + } + /** * Set or reset password of user - * @param {string} sAMAccountName - Windows account name - * @param {string} password - Set the new password */ async setPassword(sAMAccountName, password) { - const user = await this.Authentication.findOne({ where: { sAMAccountName } }); + const user = await this.findUser(sAMAccountName); + if (!user) { - // this.eventManager.write(null, 2, 0, { aboveLevel: 1 }, `User nicht gefunden`); - levelId = 2; - message = `Unbekannter User` - return {token: null, levelId: levelId }; - // throw new Error(`User ${sAMAccountName} nicht gefunden`); + return { token: null, levelId: 2, message: 'Unbekannter User' }; } - // if (user.password) throw new Error('Passwort bereits gesetzt'); const hashedPassword = await bcrypt.hash(password, 10); user.password = hashedPassword; await user.save(); + + return { token: null, levelId: 0, message: 'Passwort gesetzt' }; } /** - * Login mit Speicherung des Tokens in der Datenbank + * Login */ async login(sAMAccountName, password) { - const user = await this.Authentication.findOne({ where: { sAMAccountName } }); + const user = await this.findUser(sAMAccountName); if (!user) { - //this.eventManager.write(null, 2, null, null, `User ${sAMAccountName} nicht geufunden`) - levelId = 2; - message = `Unbekannter Benutzer`; - return { token: null, levelId: levelId, message: message }; - // throw new Error('Unkown user'); + return { token: null, levelId: 2, message: 'Unbekannter Benutzer' }; } + if (!user.password) { - this.setPassword(sAMAccountName, password); - // this.eventManager.write(user.ObjectGUID, 2, null, null, 'User registration initialized') - levelId = 1; - message = `Benutzer nicht registiert`; - return { token: null, levelId: levelId, message: message }; - // throw new Error('User not registered'); + await this.setPassword(sAMAccountName, password); + return { token: null, levelId: 1, message: 'Benutzer nicht registriert' }; } const passwordMatch = await bcrypt.compare(password, user.password); + if (!passwordMatch) { - // this.eventManager.write(user.ObjectGUID, 2, null, null, 'Password doesn\'t match'); - levelId = 2; - message = `Falsches Passwort`; - return { token: null, levelId: levelId, message: message }; - // throw new Error('Wrong password'); + return { token: null, levelId: 2, message: 'Falsches Passwort' }; } - // Token erzeugen const payload = { sAMAccountName: user.sAMAccountName, mail: user.mail, @@ -83,90 +69,266 @@ class AuthenticationManager { }; const token = jwt.sign(payload, this.SECRET_KEY, { expiresIn: '100y' }); - // Token in DB speichern + user.refreshtoken = token; user.online = true; await user.save(); - // this.eventManager.write(user.ObjectGUID, 1, null, null, 'Erfolgreich angemeldet'); - levelId = 0; - message = `Erfolgreich angemeldet`; - return { token: token, levelId: levelId, message: message }; + return { + token, + levelId: 0, + message: 'Erfolgreich angemeldet' + }; } /** - * Logout löscht Token aus der DB + * Logout */ async logout(sAMAccountName) { - const user = await this.Authentication.findOne({ where: { sAMAccountName } }); - if (user) { - user.refreshtoken = null; - user.online = false; - await user.save(); - levelId = 0; - message = `Erfolgreich abgemeldet`; - return { token: null, levelId: levelId, message: message }; + const user = await this.findUser(sAMAccountName); + + if (!user) { + return { token: null, levelId: 2, message: 'User nicht gefunden' }; } + + user.refreshtoken = null; + user.online = false; + await user.save(); + + return { token: null, levelId: 0, message: 'Erfolgreich abgemeldet' }; } /** - * Token-Prüfung (über DB) + * Token prüfen */ async verifyUserToken(sAMAccountName) { - const user = await this.Authentication.findOne({ where: { sAMAccountName } }); + const user = await this.findUser(sAMAccountName); + if (!user || !user.refreshtoken) { - levelId = 1, - message = `Kein gültiger Token`; - // throw new Error('Kein gespeicherter Token gefunden'); + return { valid: false, levelId: 1, message: 'Kein gültiger Token' }; } try { const payload = jwt.verify(user.refreshtoken, this.SECRET_KEY); - levelId = 0; - message = `User verifiziert`; - return { valid: true, payload, user, levelId: levelId, message: message } + + return { + valid: true, + payload, + user, + levelId: 0, + message: 'User verifiziert' + }; } catch { - levelId = 4; - message = `Ungültiger Token`; - return { valid: false, payload, user, levelId: levelId, message: message } + return { + valid: false, + levelId: 4, + message: 'Ungültiger Token' + }; } } /** - * Express Middleware – prüft Token direkt aus DB anhand sAMAccountNamec + * Middleware */ authenticate() { return async (req, res, next) => { try { const sAMAccountName = req.cookies?.sAMAccountName; const objectGUID = req.cookies?.ObjectGUID; + if (!sAMAccountName || !objectGUID) { return res.redirect('/login'); - // return res.status(401).json({ message: 'Kein Benutzer-Cookie gefunden' }); } - const user = await this.Authentication.findOne({ where: { sAMAccountName } }); - if (!user || !user.refreshtoken) { + const user = await this.findUser(sAMAccountName); + + if (!user || !user.refreshtoken || user.active === false) { return res.redirect('/login'); - // return res.status(401).json({ message: 'Benutzer oder Token nicht gefunden' }); } - if (user.active === false) { - return res.redirect('/login'); - // return res.status(401).json({ message: 'Benutzer ist nicht aktiv' }); - } + jwt.verify(user.refreshtoken, this.SECRET_KEY); - // Token aus DB prüfen - const payload = jwt.verify(user.refreshtoken, this.SECRET_KEY); req.user = user; next(); } catch (err) { console.error(err); return res.redirect('/login'); - // res.status(401).json({ message: 'Authentifizierung fehlgeschlagen' }); } }; } } module.exports = AuthenticationManager; + +// const jwt = require('jsonwebtoken'); +// const bcrypt = require('bcryptjs'); + +// let { levelId, message } = ''; + +// /** +// * Authentication class for login method, token validation and password setting +// */ +// class AuthenticationManager { +// /** +// * +// * @param {object} model - Use the authentication database model for interact with the database +// * @param {string} secretKey - Defines the server secret for token validation +// */ +// constructor(model, secretKey, eventManager) { +// this.eventManager = eventManager; + +// // if (!model) throw new Error('Sequelize Model wird benötigt'); +// // if (!secretKey) throw new Error('Secret Key wird benötigt'); + +// this.Authentication = model; +// this.SECRET_KEY = secretKey; +// } + +// /** +// * Set or reset password of user +// * @param {string} sAMAccountName - Windows account name +// * @param {string} password - Set the new password +// */ +// async setPassword(sAMAccountName, password) { +// const user = await this.Authentication.findOne({ where: { sAMAccountName } }); +// if (!user) { +// // this.eventManager.write(null, 2, 0, { aboveLevel: 1 }, `User nicht gefunden`); +// levelId = 2; +// message = `Unbekannter User` +// return {token: null, levelId: levelId }; +// // throw new Error(`User ${sAMAccountName} nicht gefunden`); +// } +// // if (user.password) throw new Error('Passwort bereits gesetzt'); + +// const hashedPassword = await bcrypt.hash(password, 10); +// user.password = hashedPassword; +// await user.save(); +// } + +// /** +// * Login mit Speicherung des Tokens in der Datenbank +// */ +// async login(sAMAccountName, password) { +// const user = await this.Authentication.findOne({ where: { sAMAccountName } }); + +// if (!user) { +// //this.eventManager.write(null, 2, null, null, `User ${sAMAccountName} nicht geufunden`) +// levelId = 2; +// message = `Unbekannter Benutzer`; +// return { token: null, levelId: levelId, message: message }; +// // throw new Error('Unkown user'); +// } +// if (!user.password) { +// this.setPassword(sAMAccountName, password); +// // this.eventManager.write(user.ObjectGUID, 2, null, null, 'User registration initialized') +// levelId = 1; +// message = `Benutzer nicht registiert`; +// return { token: null, levelId: levelId, message: message }; +// // throw new Error('User not registered'); +// } + +// const passwordMatch = await bcrypt.compare(password, user.password); +// if (!passwordMatch) { +// // this.eventManager.write(user.ObjectGUID, 2, null, null, 'Password doesn\'t match'); +// levelId = 2; +// message = `Falsches Passwort`; +// return { token: null, levelId: levelId, message: message }; +// // throw new Error('Wrong password'); +// } + +// // Token erzeugen +// const payload = { +// sAMAccountName: user.sAMAccountName, +// mail: user.mail, +// givenName: user.givenName, +// sn: user.sn +// }; + +// const token = jwt.sign(payload, this.SECRET_KEY, { expiresIn: '100y' }); +// // Token in DB speichern +// user.refreshtoken = token; +// user.online = true; +// await user.save(); + +// // this.eventManager.write(user.ObjectGUID, 1, null, null, 'Erfolgreich angemeldet'); +// levelId = 0; +// message = `Erfolgreich angemeldet`; +// return { token: token, levelId: levelId, message: message }; +// } + +// /** +// * Logout löscht Token aus der DB +// */ +// async logout(sAMAccountName) { +// const user = await this.Authentication.findOne({ where: { sAMAccountName } }); +// if (user) { +// user.refreshtoken = null; +// user.online = false; +// await user.save(); +// levelId = 0; +// message = `Erfolgreich abgemeldet`; +// return { token: null, levelId: levelId, message: message }; +// } +// } + +// /** +// * Token-Prüfung (über DB) +// */ +// async verifyUserToken(sAMAccountName) { +// const user = await this.Authentication.findOne({ where: { sAMAccountName } }); +// if (!user || !user.refreshtoken) { +// levelId = 1, +// message = `Kein gültiger Token`; +// // throw new Error('Kein gespeicherter Token gefunden'); +// } + +// try { +// const payload = jwt.verify(user.refreshtoken, this.SECRET_KEY); +// levelId = 0; +// message = `User verifiziert`; +// return { valid: true, payload, user, levelId: levelId, message: message } +// } catch { +// levelId = 4; +// message = `Ungültiger Token`; +// return { valid: false, payload, user, levelId: levelId, message: message } +// } +// } + +// /** +// * Express Middleware – prüft Token direkt aus DB anhand sAMAccountNamec +// */ +// authenticate() { +// return async (req, res, next) => { +// try { +// const sAMAccountName = req.cookies?.sAMAccountName; +// const objectGUID = req.cookies?.ObjectGUID; +// if (!sAMAccountName || !objectGUID) { +// return res.redirect('/login'); +// // return res.status(401).json({ message: 'Kein Benutzer-Cookie gefunden' }); +// } + +// const user = await this.Authentication.findOne({ where: { sAMAccountName } }); +// if (!user || !user.refreshtoken) { +// return res.redirect('/login'); +// // return res.status(401).json({ message: 'Benutzer oder Token nicht gefunden' }); +// } + +// if (user.active === false) { +// return res.redirect('/login'); +// // return res.status(401).json({ message: 'Benutzer ist nicht aktiv' }); +// } + +// // Token aus DB prüfen +// const payload = jwt.verify(user.refreshtoken, this.SECRET_KEY); +// req.user = user; +// next(); +// } catch (err) { +// console.error(err); +// return res.redirect('/login'); +// // res.status(401).json({ message: 'Authentifizierung fehlgeschlagen' }); +// } +// }; +// } +// } + +// module.exports = AuthenticationManager; diff --git a/utils.js b/utils.js index e57a3a0..d5fb9d9 100644 --- a/utils.js +++ b/utils.js @@ -50,7 +50,7 @@ function safeClone(obj) { const authorized = item.label === 'hr' || item.permissions.includes('Administration') - ? global.json.configuration.live.administration.includes(sAMAccountName) + ? global.json.configuration.live.administration.some(name => name.toLowerCase() === sAMAccountName.toLowerCase()) : item.permissions.includes('*') || ( await Promise.all(