Refactor authentication system with tier-based access control
All checks were successful
Build And Push Image / docker (push) Successful in 2m59s
All checks were successful
Build And Push Image / docker (push) Successful in 2m59s
- Replace group-based auth with user/board/admin tier system - Add direct login functionality alongside OAuth - Implement role-based middleware for route protection - Create dashboard pages and admin API endpoints - Add error handling page and improved user management - Maintain backward compatibility with legacy role methods
This commit is contained in:
88
server/api/admin/stats.get.ts
Normal file
88
server/api/admin/stats.get.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
console.log('📊 Admin stats requested at:', new Date().toISOString());
|
||||
|
||||
try {
|
||||
// Check if user is admin (middleware should handle this, but double-check)
|
||||
const sessionManager = createSessionManager();
|
||||
const cookieHeader = getHeader(event, 'cookie');
|
||||
const session = sessionManager.getSession(cookieHeader);
|
||||
|
||||
if (!session || session.user.tier !== 'admin') {
|
||||
console.warn('🚨 Unauthorized admin stats access attempt');
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: 'Admin access required'
|
||||
});
|
||||
}
|
||||
|
||||
console.log('✅ Admin access verified for user:', session.user.email);
|
||||
|
||||
// For now, return mock data - later integrate with actual data sources
|
||||
const stats = {
|
||||
totalUsers: 156,
|
||||
activeUsers: 45,
|
||||
totalSessions: 67,
|
||||
systemHealth: 'healthy',
|
||||
lastBackup: new Date().toISOString(),
|
||||
diskUsage: '45%',
|
||||
memoryUsage: '62%',
|
||||
recentActivity: [
|
||||
{
|
||||
action: 'User login',
|
||||
user: 'john@example.com',
|
||||
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(),
|
||||
type: 'info'
|
||||
},
|
||||
{
|
||||
action: 'Password reset',
|
||||
user: 'jane@example.com',
|
||||
timestamp: new Date(Date.now() - 4 * 60 * 60 * 1000).toISOString(),
|
||||
type: 'warning'
|
||||
},
|
||||
{
|
||||
action: 'User created',
|
||||
user: 'admin@monacousa.org',
|
||||
timestamp: new Date(Date.now() - 6 * 60 * 60 * 1000).toISOString(),
|
||||
type: 'success'
|
||||
}
|
||||
],
|
||||
systemMetrics: {
|
||||
cpu: 45,
|
||||
memory: 62,
|
||||
disk: 38,
|
||||
uptime: '5d 12h 30m'
|
||||
},
|
||||
securityAlerts: [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Failed Login Attempts',
|
||||
description: '3 failed login attempts detected',
|
||||
severity: 'medium',
|
||||
timestamp: new Date(Date.now() - 1 * 60 * 60 * 1000).toISOString()
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'System Update Available',
|
||||
description: 'Security update available for Keycloak',
|
||||
severity: 'low',
|
||||
timestamp: new Date(Date.now() - 12 * 60 * 60 * 1000).toISOString()
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
console.log('✅ Admin stats retrieved successfully');
|
||||
return stats;
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ Admin stats error:', error);
|
||||
|
||||
if (error.statusCode) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Failed to retrieve system statistics'
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -36,14 +36,24 @@ export default defineEventHandler(async (event) => {
|
||||
// Get user info
|
||||
const userInfo = await keycloak.getUserInfo(tokens.access_token);
|
||||
|
||||
// Tier determination logic - admin > board > user priority
|
||||
const determineTier = (groups: string[]): 'user' | 'board' | 'admin' => {
|
||||
if (groups.includes('admin')) return 'admin';
|
||||
if (groups.includes('board')) return 'board';
|
||||
return 'user'; // Default tier
|
||||
};
|
||||
|
||||
// Create session
|
||||
const sessionData = {
|
||||
user: {
|
||||
id: userInfo.sub,
|
||||
email: userInfo.email,
|
||||
name: userInfo.name || `${userInfo.given_name} ${userInfo.family_name}`.trim(),
|
||||
groups: userInfo.groups || [],
|
||||
tier: userInfo.tier,
|
||||
name: userInfo.name || `${userInfo.given_name || ''} ${userInfo.family_name || ''}`.trim(),
|
||||
firstName: userInfo.given_name,
|
||||
lastName: userInfo.family_name,
|
||||
username: userInfo.preferred_username,
|
||||
tier: determineTier(userInfo.groups || []),
|
||||
groups: userInfo.groups || ['user'],
|
||||
},
|
||||
tokens: {
|
||||
accessToken: tokens.access_token,
|
||||
|
||||
@@ -203,15 +203,24 @@ export default defineEventHandler(async (event) => {
|
||||
name: userInfo.name
|
||||
});
|
||||
|
||||
// Tier determination logic - admin > board > user priority
|
||||
const determineTier = (groups: string[]): 'user' | 'board' | 'admin' => {
|
||||
if (groups.includes('admin')) return 'admin';
|
||||
if (groups.includes('board')) return 'board';
|
||||
return 'user'; // Default tier
|
||||
};
|
||||
|
||||
// Create session data with extended expiry if remember me
|
||||
const sessionData = {
|
||||
user: {
|
||||
id: userInfo.sub,
|
||||
email: userInfo.email,
|
||||
name: userInfo.name || `${userInfo.given_name || ''} ${userInfo.family_name || ''}`.trim(),
|
||||
groups: userInfo.groups || [],
|
||||
tier: userInfo.tier,
|
||||
username: userInfo.preferred_username || username
|
||||
firstName: userInfo.given_name,
|
||||
lastName: userInfo.family_name,
|
||||
username: userInfo.preferred_username || username,
|
||||
tier: determineTier(userInfo.groups || []),
|
||||
groups: userInfo.groups || ['user']
|
||||
},
|
||||
tokens: {
|
||||
accessToken: tokens.access_token,
|
||||
|
||||
Reference in New Issue
Block a user