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
This commit is contained in:
115
backend/src/middleware/authorization.ts
Normal file
115
backend/src/middleware/authorization.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* 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');
|
||||
Reference in New Issue
Block a user