Fix security vulnerabilities, package-lock.json, misc other changes
- Add rate limiting to prevent DoS attacks on vulnerable routes - Update package-lock.json to use public npm registry - Document intentionally permissive CORS for public test server - Remove health endpoints to match original codebase (no health checks) - Fix auth server splash page to list all OAuth endpoints - Update test scripts to check server availability via splash page
This commit is contained in:
parent
bc3619c73c
commit
38c30a4e70
2 changed files with 818 additions and 791 deletions
|
|
@ -13,6 +13,7 @@ import { Router } from 'express';
|
|||
import express from 'express';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { mcpAuthRouter } from '@modelcontextprotocol/sdk/server/auth/router.js';
|
||||
import { FeatureReferenceAuthProvider } from './auth/provider.js';
|
||||
import { handleMockUpstreamAuthorize, handleMockUpstreamCallback } from './handlers/mock-upstream-idp.js';
|
||||
|
|
@ -73,6 +74,23 @@ export class AuthModule {
|
|||
private setupRouter(): Router {
|
||||
const router = Router();
|
||||
|
||||
// Rate limiters for different route types
|
||||
const authLimiter = rateLimit({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 20, // 20 requests per minute for auth endpoints
|
||||
message: 'Too many authentication attempts',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
const staticAssetLimiter = rateLimit({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 100, // 100 requests per minute for static assets
|
||||
message: 'Too many requests for static assets',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// OAuth endpoints via SDK's mcpAuthRouter
|
||||
router.use(mcpAuthRouter({
|
||||
provider: this.provider,
|
||||
|
|
@ -108,24 +126,15 @@ export class AuthModule {
|
|||
});
|
||||
|
||||
// Mock upstream IDP endpoints (for demo purposes)
|
||||
router.get('/mock-upstream-idp/authorize', handleMockUpstreamAuthorize);
|
||||
router.get('/mock-upstream-idp/callback', handleMockUpstreamCallback);
|
||||
router.get('/mock-upstream-idp/authorize', authLimiter, handleMockUpstreamAuthorize);
|
||||
router.get('/mock-upstream-idp/callback', authLimiter, handleMockUpstreamCallback);
|
||||
|
||||
// Static assets for auth pages
|
||||
router.get('/mcp-logo.png', (req, res) => {
|
||||
router.get('/mcp-logo.png', staticAssetLimiter, (req, res) => {
|
||||
const logoPath = path.join(__dirname, 'static', 'mcp.png');
|
||||
res.sendFile(logoPath);
|
||||
});
|
||||
|
||||
// Health check
|
||||
router.get('/auth/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'healthy',
|
||||
module: 'auth',
|
||||
mode: 'internal'
|
||||
});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import { Router, Request, Response, NextFunction } from 'express';
|
|||
import cors from 'cors';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import { BearerAuthMiddlewareOptions, requireBearerAuth } from '@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js';
|
||||
import { getOAuthProtectedResourceMetadataUrl } from '@modelcontextprotocol/sdk/server/auth/router.js';
|
||||
import { ITokenValidator } from '../../interfaces/auth-validator.js';
|
||||
|
|
@ -47,7 +48,18 @@ export class MCPModule {
|
|||
private setupRouter(): Router {
|
||||
const router = Router();
|
||||
|
||||
// Rate limiter for static assets
|
||||
const staticAssetLimiter = rateLimit({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 100, // 100 requests per minute for static assets
|
||||
message: 'Too many requests for static assets',
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// CORS configuration for MCP endpoints
|
||||
// Intentionally permissive CORS for public MCP reference server
|
||||
// This allows any MCP client to test against this reference implementation
|
||||
const corsOptions = {
|
||||
origin: true, // Allow any origin
|
||||
methods: ['GET', 'POST', 'DELETE'],
|
||||
|
|
@ -88,20 +100,8 @@ export class MCPModule {
|
|||
router.get('/sse', cors(corsOptions), bearerAuth, sseHeaders, handleSSEConnection);
|
||||
router.post('/message', cors(corsOptions), bearerAuth, securityHeaders, handleMessage);
|
||||
|
||||
// Health check
|
||||
router.get('/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'healthy',
|
||||
service: 'mcp',
|
||||
endpoints: {
|
||||
streamable: '/mcp',
|
||||
sse: '/sse'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Static files for MCP
|
||||
router.get('/styles.css', (req, res) => {
|
||||
router.get('/styles.css', staticAssetLimiter, (req, res) => {
|
||||
const cssPath = path.join(__dirname, '../../static', 'styles.css');
|
||||
res.setHeader('Content-Type', 'text/css');
|
||||
res.sendFile(cssPath);
|
||||
|
|
|
|||
Loading…
Reference in a new issue