193 lines
5.0 KiB
JavaScript
193 lines
5.0 KiB
JavaScript
const jwt = require('jsonwebtoken');
|
|
const bcrypt = require('bcryptjs');
|
|
|
|
class AuthenticationManager {
|
|
constructor(model, secretKey) {
|
|
this.Authentication = model;
|
|
this.SECRET_KEY = secretKey;
|
|
}
|
|
|
|
// =========================================================
|
|
// USER
|
|
// =========================================================
|
|
|
|
async findUser(sAMAccountName) {
|
|
return this.Authentication.findOne({
|
|
where: { sAMAccountName }
|
|
});
|
|
}
|
|
|
|
// =========================================================
|
|
// PASSWORD
|
|
// =========================================================
|
|
|
|
async setPassword(sAMAccountName, password) {
|
|
const user = await this.findUser(sAMAccountName);
|
|
|
|
if (!user) {
|
|
return { token: null, levelId: 2, message: 'Unbekannter User' };
|
|
}
|
|
|
|
user.password = await bcrypt.hash(password, 10);
|
|
await user.save();
|
|
|
|
return { token: null, levelId: 0, message: 'Passwort gesetzt' };
|
|
}
|
|
|
|
// =========================================================
|
|
// LOGIN
|
|
// =========================================================
|
|
|
|
async login(sAMAccountName, password) {
|
|
const user = await this.findUser(sAMAccountName);
|
|
|
|
if (!user) {
|
|
return { token: null, levelId: 2, message: 'Unbekannter Benutzer' };
|
|
}
|
|
|
|
if (!user.password) {
|
|
await this.setPassword(sAMAccountName, password);
|
|
return { token: null, levelId: 1, message: 'Benutzer nicht registriert' };
|
|
}
|
|
|
|
const ok = await bcrypt.compare(password, user.password);
|
|
|
|
if (!ok) {
|
|
return { token: null, levelId: 2, message: 'Falsches Passwort' };
|
|
}
|
|
|
|
const token = jwt.sign(
|
|
{
|
|
ObjectGUID: user.ObjectGUID,
|
|
sAMAccountName: user.sAMAccountName
|
|
},
|
|
this.SECRET_KEY,
|
|
{ expiresIn: '1y' }
|
|
);
|
|
|
|
user.refreshtoken = token;
|
|
user.online = true;
|
|
await user.save();
|
|
|
|
return { token, levelId: 0, message: 'Erfolgreich angemeldet' };
|
|
}
|
|
|
|
// =========================================================
|
|
// LOGOUT
|
|
// =========================================================
|
|
|
|
async logout(sAMAccountName) {
|
|
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' };
|
|
}
|
|
|
|
// =========================================================
|
|
// VERIFY TOKEN
|
|
// =========================================================
|
|
|
|
async verifyUserToken(sAMAccountName) {
|
|
const user = await this.findUser(sAMAccountName);
|
|
|
|
if (!user || !user.refreshtoken) {
|
|
return { valid: false, levelId: 1 };
|
|
}
|
|
|
|
try {
|
|
const payload = jwt.verify(user.refreshtoken, this.SECRET_KEY);
|
|
|
|
return {
|
|
valid: true,
|
|
user,
|
|
payload
|
|
};
|
|
} catch {
|
|
return { valid: false, levelId: 4 };
|
|
}
|
|
}
|
|
|
|
// =========================================================
|
|
// 🔥 MIDDLEWARE BLEIBT HIER
|
|
// =========================================================
|
|
authenticate() {
|
|
return async (req, res, next) => {
|
|
|
|
try {
|
|
|
|
// =====================================================
|
|
// 🔥 GLOBAL PUBLIC ROUTE BYPASS (ROBUST)
|
|
// =====================================================
|
|
|
|
const url = req.originalUrl.split('?')[0];
|
|
|
|
const publicRoutes = [
|
|
'/login',
|
|
'/public'
|
|
];
|
|
|
|
const isPublicRoute = publicRoutes.some(route =>
|
|
url === route || url.startsWith(route + '/')
|
|
);
|
|
|
|
if (isPublicRoute) {
|
|
return next();
|
|
}
|
|
|
|
// =====================================================
|
|
// 🔐 AUTH FLOW
|
|
// =====================================================
|
|
|
|
const sAMAccountName = req.cookies?.sAMAccountName;
|
|
|
|
if (!sAMAccountName) {
|
|
return res.redirect('/login');
|
|
}
|
|
|
|
const user = await this.findUser(sAMAccountName);
|
|
|
|
if (!user || !user.active) {
|
|
return res.redirect('/login');
|
|
}
|
|
|
|
let payload;
|
|
|
|
try {
|
|
payload = jwt.verify(user.refreshtoken, this.SECRET_KEY);
|
|
} catch {
|
|
return res.redirect('/login');
|
|
}
|
|
|
|
const rbac = await this.rbac.resolvePermissions(user.ObjectGUID);
|
|
|
|
const normalized = this.rbac.normalize(rbac.permissions);
|
|
const isSuperAdmin = this.rbac.isSuperAdmin(normalized);
|
|
|
|
req.user = {
|
|
...user.toJSON(),
|
|
jwt: payload,
|
|
groups: rbac.groups,
|
|
roles: rbac.roles,
|
|
permissions: normalized,
|
|
isSuperAdmin
|
|
};
|
|
|
|
next();
|
|
|
|
} catch (err) {
|
|
console.error(err);
|
|
return res.redirect('/login');
|
|
}
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
module.exports = AuthenticationManager; |