Files
cmdb-insight/backend/src/middleware/authorization.ts
Bert Hausmans 1fa424efb9 Add authentication, user management, and database migration features
- Implement OAuth 2.0 and PAT authentication methods
- Add user management, roles, and profile functionality
- Add database migrations and admin user scripts
- Update services for authentication and user settings
- Add protected routes and permission hooks
- Update documentation for authentication and database access
2026-01-15 03:20:50 +01:00

116 lines
3.3 KiB
TypeScript

/**
* Authorization Middleware
*
* Middleware functions for route protection based on authentication and permissions.
*/
import { Request, Response, NextFunction } from 'express';
import { authService, type SessionUser } from '../services/authService.js';
import { roleService } from '../services/roleService.js';
import { logger } from '../services/logger.js';
// Extend Express Request to include user info
declare global {
namespace Express {
interface Request {
sessionId?: string;
user?: SessionUser;
accessToken?: string;
}
}
}
/**
* Middleware to require authentication
*/
export function requireAuth(req: Request, res: Response, next: NextFunction) {
const sessionId = req.headers['x-session-id'] as string || req.cookies?.sessionId;
if (!sessionId) {
return res.status(401).json({ error: 'Authentication required' });
}
// Get session user
authService.getSession(sessionId)
.then(session => {
if (!session) {
return res.status(401).json({ error: 'Invalid or expired session' });
}
// Check if it's a local user session
if ('id' in session.user) {
req.sessionId = sessionId;
req.user = session.user as SessionUser;
req.accessToken = session.accessToken;
next();
} else {
// OAuth-only session (Jira user without local account)
// For now, allow through but user won't have permissions
req.sessionId = sessionId;
req.accessToken = session.accessToken;
next();
}
})
.catch(error => {
logger.error('Auth middleware error:', error);
res.status(500).json({ error: 'Authentication check failed' });
});
}
/**
* Middleware to require a specific role
*/
export function requireRole(roleName: string) {
return async (req: Request, res: Response, next: NextFunction) => {
if (!req.user || !('id' in req.user)) {
return res.status(403).json({ error: 'Permission denied' });
}
const hasRole = await roleService.userHasRole(req.user.id, roleName);
if (!hasRole) {
return res.status(403).json({ error: `Role '${roleName}' required` });
}
next();
};
}
/**
* Middleware to require a specific permission
*/
export function requirePermission(permissionName: string) {
return async (req: Request, res: Response, next: NextFunction) => {
if (!req.user || !('id' in req.user)) {
return res.status(403).json({ error: 'Permission denied' });
}
const hasPermission = await roleService.userHasPermission(req.user.id, permissionName);
if (!hasPermission) {
return res.status(403).json({ error: `Permission '${permissionName}' required` });
}
next();
};
}
/**
* Middleware to check permission (optional, doesn't fail if missing)
* Sets req.hasPermission flag
*/
export function checkPermission(permissionName: string) {
return async (req: Request, res: Response, next: NextFunction) => {
if (req.user && 'id' in req.user) {
const hasPermission = await roleService.userHasPermission(req.user.id, permissionName);
(req as any).hasPermission = hasPermission;
} else {
(req as any).hasPermission = false;
}
next();
};
}
/**
* Middleware to require admin role
*/
export const requireAdmin = requireRole('administrator');