Group based roles
This commit is contained in:
parent
431700a888
commit
c05c0d8f75
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[serialNumber]` on the table `Printer` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "Printer" ADD COLUMN "serialNumber" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PrinterStatus" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"tonerBlackLevel" INTEGER NOT NULL,
|
||||
"tonerCyanLevel" INTEGER,
|
||||
"tonerMagentaLevel" INTEGER,
|
||||
"tonerYellowLevel" INTEGER,
|
||||
"counter" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"printerId" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "PrinterStatus_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Printer_serialNumber_key" ON "Printer"("serialNumber");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PrinterStatus" ADD CONSTRAINT "PrinterStatus_printerId_fkey" FOREIGN KEY ("printerId") REFERENCES "Printer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -21,15 +21,40 @@ CREATE TABLE "User" (
|
|||
-- CreateTable
|
||||
CREATE TABLE "Printer" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"hostname" TEXT,
|
||||
"friendlyName" TEXT,
|
||||
"serialNumber" TEXT,
|
||||
"hostname" TEXT,
|
||||
"ip" TEXT NOT NULL,
|
||||
"model" "PrinterModel" NOT NULL,
|
||||
"blackTonerModel" TEXT,
|
||||
"cyanTonerModel" TEXT,
|
||||
"magentaTonerModel" TEXT,
|
||||
"yellowTonerModel" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Printer_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PrinterStatus" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"tonerBlackLevel" INTEGER NOT NULL,
|
||||
"tonerCyanLevel" INTEGER,
|
||||
"tonerMagentaLevel" INTEGER,
|
||||
"tonerYellowLevel" INTEGER,
|
||||
"counter" INTEGER NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"printerId" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "PrinterStatus_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Printer_serialNumber_key" ON "Printer"("serialNumber");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PrinterStatus" ADD CONSTRAINT "PrinterStatus_printerId_fkey" FOREIGN KEY ("printerId") REFERENCES "Printer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -15,6 +15,7 @@ type LdapUser = {
|
|||
mail: string | null
|
||||
displayName: string
|
||||
thumbnailPhoto: string | null
|
||||
groups?: string[]
|
||||
}
|
||||
|
||||
export class LdapController extends Client implements LdapClientInterface {
|
||||
|
@ -45,19 +46,25 @@ export class LdapController extends Client implements LdapClientInterface {
|
|||
}
|
||||
}
|
||||
|
||||
async getUser(username: string) {
|
||||
async getUser(username: string): Promise<LdapUser> {
|
||||
return await this.adminBondOperation(async () => {
|
||||
const { searchEntries } = await this.search(DN, {
|
||||
scope: 'sub',
|
||||
filter: `(sAMAccountName=${username})`,
|
||||
attributes: ['mail', 'sAMAccountName', 'displayName', 'thumbnailPhoto'],
|
||||
attributes: [
|
||||
'mail',
|
||||
'sAMAccountName',
|
||||
'displayName',
|
||||
'thumbnailPhoto',
|
||||
'dn'
|
||||
],
|
||||
explicitBufferAttributes: ['thumbnailPhoto']
|
||||
})
|
||||
|
||||
if (!searchEntries.length)
|
||||
throw new Error('User not found on LDAP server.')
|
||||
|
||||
const { sAMAccountName, displayName, mail, thumbnailPhoto } =
|
||||
const { sAMAccountName, displayName, mail, thumbnailPhoto, dn } =
|
||||
searchEntries[0]
|
||||
|
||||
const ldapUser: LdapUser = {
|
||||
|
@ -66,13 +73,26 @@ export class LdapController extends Client implements LdapClientInterface {
|
|||
mail: mail.toString(),
|
||||
thumbnailPhoto: `data:image/png;base64,${Buffer.from(
|
||||
thumbnailPhoto as Buffer
|
||||
).toString('base64')}`
|
||||
).toString('base64')}`,
|
||||
groups: await this.getGroupsForUser(dn.toString())
|
||||
}
|
||||
|
||||
return ldapUser
|
||||
})
|
||||
}
|
||||
|
||||
async getGroupsForUser(dn: string) {
|
||||
const { searchEntries } = await this.search(DN, {
|
||||
scope: 'sub',
|
||||
filter: `(member:1.2.840.113556.1.4.1941:=${dn})`,
|
||||
attributes: ['cn']
|
||||
})
|
||||
|
||||
if (!searchEntries.length) throw new Error('User not found on LDAP server.')
|
||||
|
||||
return searchEntries.map(entry => entry.cn.toString())
|
||||
}
|
||||
|
||||
async authenticate(username: string, password: string) {
|
||||
await this.bind(`${DOMAIN}\\${username}`, password)
|
||||
|
||||
|
|
|
@ -1,16 +1,35 @@
|
|||
import { User } from '@prisma/client'
|
||||
import { LdapController } from '../controllers/LdapController.js'
|
||||
import { prisma } from '../prisma.js'
|
||||
|
||||
const ADMIN_GROUP = process.env.ADMIN_GROUP || 'PP-SERTI'
|
||||
const INSPECTOR_GROUP = process.env.INSPECTOR_GROUP || 'inspector'
|
||||
const USER_GROUP = process.env.USER_GROUP || 'G_SERVIDORES'
|
||||
|
||||
export class UserController {
|
||||
static async importUser(username: string) {
|
||||
const ldap = new LdapController()
|
||||
|
||||
const user = await ldap.getUser(username)
|
||||
const ldapUser = await ldap.getUser(username)
|
||||
|
||||
if (!user) throw new Error('User not found!')
|
||||
if (!ldapUser) throw new Error('User not found!')
|
||||
|
||||
const user = {
|
||||
username: ldapUser.username,
|
||||
displayName: ldapUser.displayName,
|
||||
mail: ldapUser.mail,
|
||||
thumbnailPhoto: ldapUser.thumbnailPhoto,
|
||||
roles: [] as User['roles']
|
||||
}
|
||||
|
||||
ldapUser.groups?.forEach(group => {
|
||||
if (group === USER_GROUP) user.roles?.push('USER')
|
||||
if (group === ADMIN_GROUP) user.roles?.push('ADMIN')
|
||||
if (group === INSPECTOR_GROUP) user.roles?.push('INSPECTOR')
|
||||
})
|
||||
|
||||
return await prisma.user.upsert({
|
||||
where: { username: user.username },
|
||||
where: { username: ldapUser.username },
|
||||
update: user,
|
||||
create: user
|
||||
})
|
||||
|
|
18
src/controllers/routes/LoginRouteController.ts
Normal file
18
src/controllers/routes/LoginRouteController.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { Request, Response } from 'express'
|
||||
import { AuthenticationController } from '../AuthenticationController.js'
|
||||
|
||||
export class LoginRouteController {
|
||||
static async login(req: Request, res: Response) {
|
||||
const { username, password } = req.body
|
||||
|
||||
if (!username || !password)
|
||||
return res.status(400).json({ error: 'Missing username or password' })
|
||||
|
||||
try {
|
||||
const token = await AuthenticationController.login(username, password)
|
||||
res.json({ token })
|
||||
} catch (error: any) {
|
||||
res.status(401).json({ error: error.message })
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ export class UserRouteController {
|
|||
where: { username }
|
||||
})
|
||||
|
||||
if (!user) return await UserController.importUser(username)
|
||||
if (!user) return res.json(await UserController.importUser(username))
|
||||
else UserController.importUser(username)
|
||||
|
||||
res.json(user)
|
||||
|
|
|
@ -7,6 +7,7 @@ import { hasRolesMiddleware } from './middleware/hasRolesMiddleware.js'
|
|||
|
||||
import { UserRouteController } from './controllers/routes/UserRouteController.js'
|
||||
import { AuthenticationController } from './controllers/AuthenticationController.js'
|
||||
import { LoginRouteController } from './controllers/routes/LoginRouteController.js'
|
||||
|
||||
export const app = express()
|
||||
|
||||
|
@ -22,19 +23,7 @@ app.get('/api/', async (req: Request, res: Response) => {
|
|||
})
|
||||
|
||||
// Login route
|
||||
app.post('/api/login', async (req: Request, res: Response) => {
|
||||
const { username, password } = req.body
|
||||
|
||||
if (!username || !password)
|
||||
return res.status(400).json({ error: 'Missing username or password' })
|
||||
|
||||
try {
|
||||
const token = await AuthenticationController.login(username, password)
|
||||
res.json({ token })
|
||||
} catch (error: any) {
|
||||
res.status(401).json({ error: error.message })
|
||||
}
|
||||
})
|
||||
app.post('/api/login', LoginRouteController.login)
|
||||
|
||||
app.get('/api/me', authMiddleware, async (req: Request, res: Response) =>
|
||||
res.json(res.locals.user)
|
||||
|
|
Loading…
Reference in New Issue
Block a user