Skip to main content
Glama

MCP Firebird

authorization.ts7.67 kB
/** * Authorization functionality for the MCP Firebird server */ import { securityConfig } from './config.js'; import { createLogger } from '../utils/logger.js'; const logger = createLogger('security:authorization'); // Define FirebirdError class if it doesn't exist class FirebirdError extends Error { type: string; originalError?: any; constructor(message: string, type: string = 'UNKNOWN_ERROR', cause?: any) { super(message); this.name = 'FirebirdError'; this.type = type; if (cause) { this.originalError = cause; } } } /** * Interface for user information */ export interface UserInfo { id: string; username: string; role: string; } /** * Check if a user is authorized to access a table * @param {string} tableName - Name of the table * @param {UserInfo} user - User information * @returns {boolean} Whether the user is authorized * @throws {FirebirdError} If the user is not authorized */ export function checkTableAccess(tableName: string, user?: UserInfo): boolean { // If no authorization is configured, allow access if (!securityConfig.authorization || securityConfig.authorization.type === 'none') { return true; } // If no user is provided, deny access if (!user) { throw new FirebirdError('User information required for authorization', 'AUTHORIZATION_ERROR'); } // Check if the user has a role if (!user.role) { throw new FirebirdError('User role required for authorization', 'AUTHORIZATION_ERROR'); } // Check if the role has permissions const rolePermissions = securityConfig.authorization.rolePermissions?.[user.role]; if (!rolePermissions) { throw new FirebirdError(`No permissions defined for role: ${user.role}`, 'AUTHORIZATION_ERROR'); } // Check if the role has access to all tables if (rolePermissions.allTablesAllowed) { return true; } // Check if the role has access to the specific table if (rolePermissions.tables && rolePermissions.tables.includes(tableName)) { return true; } // Deny access throw new FirebirdError(`Access to table ${tableName} denied for role ${user.role}`, 'AUTHORIZATION_ERROR'); } /** * Check if a user is authorized to perform an operation * @param {string} operation - Operation to perform (SELECT, INSERT, UPDATE, DELETE, etc.) * @param {UserInfo} user - User information * @returns {boolean} Whether the user is authorized * @throws {FirebirdError} If the user is not authorized */ export function checkOperationAccess(operation: string, user?: UserInfo): boolean { // If no authorization is configured, check the allowed operations if (!securityConfig.authorization || securityConfig.authorization.type === 'none') { return checkAllowedOperation(operation); } // If no user is provided, deny access if (!user) { throw new FirebirdError('User information required for authorization', 'AUTHORIZATION_ERROR'); } // Check if the user has a role if (!user.role) { throw new FirebirdError('User role required for authorization', 'AUTHORIZATION_ERROR'); } // Check if the role has permissions const rolePermissions = securityConfig.authorization.rolePermissions?.[user.role]; if (!rolePermissions) { throw new FirebirdError(`No permissions defined for role: ${user.role}`, 'AUTHORIZATION_ERROR'); } // Check if the role has access to the operation if (rolePermissions.operations && rolePermissions.operations.includes(operation as any)) { return true; } // Deny access throw new FirebirdError(`Operation ${operation} denied for role ${user.role}`, 'AUTHORIZATION_ERROR'); } /** * Check if an operation is allowed based on the security configuration * @param {string} operation - Operation to check * @returns {boolean} Whether the operation is allowed * @throws {FirebirdError} If the operation is not allowed */ export function checkAllowedOperation(operation: string): boolean { // Check if the operation is explicitly forbidden if (securityConfig.forbiddenOperations && securityConfig.forbiddenOperations.includes(operation)) { throw new FirebirdError(`Operation ${operation} is forbidden`, 'AUTHORIZATION_ERROR'); } // Check if allowed operations are defined and the operation is not in the list if (securityConfig.allowedOperations && !securityConfig.allowedOperations.includes(operation)) { throw new FirebirdError(`Operation ${operation} is not allowed`, 'AUTHORIZATION_ERROR'); } return true; } /** * Check if a table is allowed based on the security configuration * @param {string} tableName - Name of the table * @returns {boolean} Whether the table is allowed * @throws {FirebirdError} If the table is not allowed */ export function checkAllowedTable(tableName: string): boolean { // Check if the table is explicitly forbidden if (securityConfig.forbiddenTables && securityConfig.forbiddenTables.includes(tableName)) { throw new FirebirdError(`Access to table ${tableName} is forbidden`, 'AUTHORIZATION_ERROR'); } // Check if allowed tables are defined and the table is not in the list if (securityConfig.allowedTables && !securityConfig.allowedTables.includes(tableName)) { throw new FirebirdError(`Access to table ${tableName} is not allowed`, 'AUTHORIZATION_ERROR'); } // Check if the table matches the table name pattern if (securityConfig.tableNamePattern) { const pattern = new RegExp(securityConfig.tableNamePattern); if (!pattern.test(tableName)) { throw new FirebirdError(`Table ${tableName} does not match the allowed pattern`, 'AUTHORIZATION_ERROR'); } } return true; } /** * Verify an OAuth2 token * @param {string} token - OAuth2 token * @returns {Promise<UserInfo>} User information * @throws {FirebirdError} If the token is invalid */ export async function verifyOAuth2Token(token: string): Promise<UserInfo> { if (!securityConfig.authorization || securityConfig.authorization.type !== 'oauth2') { throw new FirebirdError('OAuth2 authorization not configured', 'AUTHORIZATION_ERROR'); } if (!securityConfig.authorization.oauth2) { throw new FirebirdError('OAuth2 configuration missing', 'AUTHORIZATION_ERROR'); } const { tokenVerifyUrl, clientId, clientSecret } = securityConfig.authorization.oauth2; try { // Call the token verification endpoint const response = await fetch(tokenVerifyUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}` }, body: JSON.stringify({ token }) }); if (!response.ok) { throw new FirebirdError(`Token verification failed: ${response.statusText}`, 'AUTHORIZATION_ERROR'); } // Extract user information from the response const data = await response.json() as any; const userInfo: UserInfo = { id: data.sub || data.user_id || '', username: data.username || data.preferred_username || data.email || '', role: data.role || (data.roles && data.roles[0]) || 'user' }; return userInfo; } catch (error: any) { logger.error(`Error verifying OAuth2 token: ${error.message}`); throw new FirebirdError(`Token verification failed: ${error.message}`, 'AUTHORIZATION_ERROR'); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/PuroDelphi/mcpFirebird'

If you have feedback or need assistance with the MCP directory API, please join our Discord server