-
Notifications
You must be signed in to change notification settings - Fork 595
Description
[TESTING][SECURITY]: Upstream gateway authentication manual test plan (OAuth, bearer, discovery)
Goal
Produce a comprehensive manual test plan for validating upstream gateway authentication including OAuth flows, bearer token auth, tool/resource discovery, and visibility RBAC on federated content.
Why Now?
Security testing is critical for GA release:
- Production Readiness: Gateway authentication must be validated before release
- Compliance: Required by security standards and audits
- Defense in Depth: Validates multiple protection layers
- Attack Mitigation: Prevents unauthorized upstream access
- User Trust: Security issues erode confidence
Architecture Overview
Important: Gateways are registered upstream MCP servers, NOT peer gateways with mutual authentication. The platform authenticates TO upstream gateways using standard client auth methods.
┌─────────────────────────────────────────────────────────────────────┐
│ Upstream Gateway Architecture │
│ │
│ User ──JWT──> MCP Gateway ──OAuth/Bearer/Basic──> Upstream Gateway │
│ │ │
│ │ Discovery: tools, resources, prompts │
│ │ with federation_source set │
│ │ │
│ Authentication TO Upstream: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ OAuth client_credentials: App-level tokens │ │
│ │ OAuth authorization_code: Per-user tokens via app_user_email│ │
│ │ Bearer token: Static token in auth_token field │ │
│ │ Basic auth: Username/password in auth_value │ │
│ │ Custom headers: Via auth_headers field │ │
│ │ Query params: API key in URL (auth_query_param_*) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Federated Content: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Tools, resources, prompts imported with: │ │
│ │ federation_source = gateway.name │ │
│ │ visibility = gateway's visibility setting │ │
│ │ team_id = gateway's team_id │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Test Environment Setup
# Build and start
make docker-prod && make compose-down && make testing-up
# Key settings in .env:
AUTH_REQUIRED=true
JWT_SECRET_KEY=your-secret-key-min-32-chars!!
# Create admin token
export JWT_SECRET_KEY="${JWT_SECRET_KEY:-my-test-key}"
export ADMIN_TOKEN=$(python -m mcpgateway.utils.create_jwt_token \
--username admin@example.com --exp 10080 --secret "$JWT_SECRET_KEY" --admin)
# Regular user token
export USER_TOKEN=$(python -m mcpgateway.utils.create_jwt_token \
--username user@example.com --exp 10080 --secret "$JWT_SECRET_KEY")
# For testing, you can use httpbin or a local MCP server
# Start a local MCP server for testing:
# python -m mcpgateway.translate --stdio "uvx mcp-server-git" --port 9000User Stories
Story 1: Gateway Authentication
As a security administrator
I want gateways to authenticate to upstream servers
So that only authorized connections are made
Acceptance Criteria
Feature: Upstream Gateway Authentication
Scenario: OAuth client_credentials authentication
When a gateway is registered with OAuth client_credentials
Then the gateway obtains tokens automatically
And tools are discovered using the OAuth token
Scenario: OAuth authorization_code authentication
When a gateway is registered with OAuth authorization_code
Then per-user tokens are required
And app_user_email is used to retrieve user-specific tokens
Scenario: Bearer token authentication
When a gateway is registered with a bearer token
Then the token is used for all requestsStory 2: Federated Content Access
As a security administrator
I want federated tools protected by visibility
So that access is properly restricted
Acceptance Criteria
Feature: Federated Content RBAC
Scenario: Public gateway content
When a public gateway imports tools
Then all users can see and invoke the tools
Scenario: Team gateway content
When a team-scoped gateway imports tools
Then only team members can access the toolsTest Cases
TC-GW-001: Gateway Registration with Bearer Auth
Objective: Verify gateway registration with bearer token authentication
Steps:
# Step 1: Register gateway with bearer auth
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "bearer-test-gateway",
"url": "http://localhost:9000/sse",
"transport": "SSE",
"auth_type": "bearer",
"auth_token": "test-upstream-token",
"visibility": "public"
}' \
http://localhost:4444/gateways | jq .
# Step 2: Check gateway is created
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/gateways | jq '.[] | select(.name == "bearer-test-gateway")'
# Step 3: Verify health check uses auth
# Gateway should show healthy if upstream accepts the token
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/gateways | jq '.[] | select(.name == "bearer-test-gateway") | {name, healthy}'Expected Results:
- Gateway created successfully
- Auth token stored (encrypted)
- Health check uses configured auth
TC-GW-002: Gateway Registration with OAuth Client Credentials
Objective: Verify OAuth client_credentials flow for gateways
Steps:
# Step 1: Register gateway with OAuth
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "oauth-cc-gateway",
"url": "https://upstream-mcp.example.com/sse",
"transport": "SSE",
"auth_type": "oauth",
"oauth_config": {
"grant_type": "client_credentials",
"token_url": "https://auth.example.com/oauth/token",
"client_id": "my-client-id",
"client_secret": "my-client-secret",
"scope": "mcp:read mcp:write"
},
"visibility": "public"
}' \
http://localhost:4444/gateways | jq .
# Step 2: Verify OAuth config stored
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/gateways | jq '.[] | select(.name == "oauth-cc-gateway") | .oauth_config'Expected Results:
- Gateway created with OAuth config
- Client secret encrypted at rest
- OAuth token obtained automatically when needed
TC-GW-003: Gateway with OAuth Authorization Code (Per-User Tokens)
Objective: Verify authorization_code flow uses per-user tokens
Steps:
# Step 1: Register gateway with authorization_code
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "oauth-ac-gateway",
"url": "https://upstream-mcp.example.com/sse",
"transport": "SSE",
"auth_type": "oauth",
"oauth_config": {
"grant_type": "authorization_code",
"authorization_url": "https://auth.example.com/authorize",
"token_url": "https://auth.example.com/oauth/token",
"client_id": "my-client-id",
"client_secret": "my-client-secret",
"redirect_uri": "http://localhost:4444/oauth/callback",
"scope": "openid profile"
},
"visibility": "public"
}' \
http://localhost:4444/gateways | jq .
GATEWAY_ID=$(curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/gateways | jq -r '.[] | select(.name == "oauth-ac-gateway") | .id')
# Step 2: Initiate OAuth flow for user
# User must complete OAuth authorization:
echo "OAuth authorization URL: http://localhost:4444/oauth/authorize/$GATEWAY_ID"
# Step 3: After OAuth completion, tokens are stored per-user
# The gateway will use app_user_email to retrieve user-specific tokensExpected Results:
- Gateway requires user to complete OAuth flow
- Per-user tokens stored in TokenStorageService
- Requests to upstream use user-specific tokens
TC-GW-004: Gateway with Invalid Credentials
Objective: Verify gateway shows unhealthy with wrong credentials
Steps:
# Step 1: Register gateway with wrong token
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "bad-auth-gateway",
"url": "http://localhost:9000/sse",
"transport": "SSE",
"auth_type": "bearer",
"auth_token": "wrong-token-value"
}' \
http://localhost:4444/gateways | jq .
# Step 2: Check health status
# Wait for health check to run
sleep 5
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/gateways | jq '.[] | select(.name == "bad-auth-gateway") | {name, healthy, last_error}'Expected Results:
- Gateway created but marked unhealthy
- Health check fails due to auth error
- Error message indicates auth failure
TC-GW-005: Federated Tools Discovery
Objective: Verify tools are imported from upstream with federation_source
Steps:
# Step 1: Register gateway (assuming upstream has tools)
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "discovery-gateway",
"url": "http://localhost:9000/sse",
"transport": "SSE",
"auth_type": "bearer",
"auth_token": "valid-token"
}' \
http://localhost:4444/gateways | jq .
# Step 2: Trigger tool refresh
GATEWAY_ID=$(curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/gateways | jq -r '.[] | select(.name == "discovery-gateway") | .id')
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/gateways/$GATEWAY_ID/tools/refresh | jq .
# Step 3: Check federated tools
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/tools | jq '.[] | select(.federation_source == "discovery-gateway")'Expected Results:
- Tools imported from upstream
- federation_source set to gateway name
- Tools inherit gateway's visibility
TC-GW-006: Federated Content Visibility
Objective: Verify federated tools follow gateway visibility
Steps:
# Step 1: Create team-scoped gateway
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "team-gateway",
"url": "http://localhost:9000/sse",
"transport": "SSE",
"visibility": "team",
"team_id": "team-alpha"
}' \
http://localhost:4444/gateways | jq .
# Step 2: Check tools with team token
curl -s -H "Authorization: Bearer $TEAM_TOKEN" \
http://localhost:4444/tools | jq '.[] | select(.federation_source == "team-gateway")'
# Expected: Tools visible
# Step 3: Check tools with non-team token
curl -s -H "Authorization: Bearer $USER_TOKEN" \
http://localhost:4444/tools | jq '.[] | select(.federation_source == "team-gateway")'
# Expected: Tools NOT visible (empty result)Expected Results:
- Federated tools inherit gateway visibility
- Team members see team-gateway tools
- Non-members don't see team-gateway tools
TC-GW-007: Gateway CRUD Permission Enforcement
Objective: Verify gateways.* permissions are enforced
Steps:
# Step 1: Create token with only gateways.read
READ_ONLY_TOKEN=$(python -m mcpgateway.utils.create_jwt_token \
--username reader@example.com --exp 10080 --secret "$JWT_SECRET_KEY" \
--scopes gateways.read)
# Step 2: List gateways - should work
curl -s -w "\nStatus: %{http_code}\n" \
-H "Authorization: Bearer $READ_ONLY_TOKEN" \
http://localhost:4444/gateways
# Expected: 200 OK
# Step 3: Try to create gateway - should fail
curl -s -w "\nStatus: %{http_code}\n" \
-X POST -H "Authorization: Bearer $READ_ONLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"test","url":"http://example.com"}' \
http://localhost:4444/gateways
# Expected: 403 ForbiddenExpected Results:
- gateways.read: Can list and view gateways
- gateways.create: Required to create gateways
- gateways.update: Required to update gateways
- gateways.delete: Required to delete gateways
TC-GW-008: Gateway with Query Parameter Auth
Objective: Verify query parameter authentication (for APIs requiring key in URL)
Steps:
# Step 1: Register gateway with query param auth
# Note: This is insecure (CWE-598) but needed for some APIs
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "query-param-gateway",
"url": "https://api.example.com/mcp/sse",
"transport": "SSE",
"auth_type": "query_param",
"auth_query_param_key": "api_key",
"auth_query_param_value": "secret-api-key-value"
}' \
http://localhost:4444/gateways | jq .
# Step 2: Verify auth is stored (encrypted)
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
http://localhost:4444/gateways | jq '.[] | select(.name == "query-param-gateway") | .auth_type'Expected Results:
- API key stored encrypted
- Query param added to URL when calling upstream
- Key not logged in plain text
TC-GW-009: Audit Logging
Objective: Verify gateway operations are logged
Steps:
# Step 1: Perform gateway operations
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"audit-test-gw","url":"http://example.com"}' \
http://localhost:4444/gateways
# Step 2: Check logs for gateway activities
docker logs mcpgateway 2>&1 | grep -i "gateway" | tail -10
# Expected log fields:
# - user_email
# - resource_type: "gateway"
# - resource_id
# - action: "create", "update", "delete"Expected Results:
- Gateway CRUD operations logged
- User identity captured
- Resource IDs included
Test Matrix
| Test Case | Auth Type | OAuth | Discovery | Visibility | Permissions |
|---|---|---|---|---|---|
| TC-GW-001 | ✓ Bearer | ||||
| TC-GW-002 | ✓ CC | ||||
| TC-GW-003 | ✓ AC | ||||
| TC-GW-004 | ✓ Invalid | ||||
| TC-GW-005 | ✓ | ||||
| TC-GW-006 | ✓ | ||||
| TC-GW-007 | ✓ | ||||
| TC-GW-008 | ✓ Query | ||||
| TC-GW-009 |
Success Criteria
- All 9 test cases pass
- Bearer token authentication works
- OAuth client_credentials flow obtains tokens
- OAuth authorization_code uses per-user tokens
- Invalid credentials result in unhealthy status
- Tools imported with federation_source
- Federated content follows gateway visibility
- Permission checks enforced
- Query parameter auth supported (encrypted)
Features NOT Implemented
The following features from the original issue do NOT exist:
- ❌ Peer-to-peer gateway authentication (gateways are upstream servers, not peers)
- ❌
/api/federation/*endpoints (no dedicated federation API) - ❌ Mutual TLS for federation (TLS exists but not mTLS verification)
- ❌ Bell-LaPadula clearance levels (only visibility RBAC)
- ❌ Gateway credential rotation endpoint (manual update required)
- ❌ Rate limiting on gateway routes (no @rate_limit decorator)
- ❌ User identity propagation to upstream (except via authorization_code per-user tokens)
Related Files
mcpgateway/services/gateway_service.py- Gateway service implementationmcpgateway/services/oauth_manager.py- OAuth token managementmcpgateway/main.py:1678- Gateway router (/gatewaysprefix)mcpgateway/main.py:4639-4905- Gateway endpoint handlersmcpgateway/schemas.py:2464-2550- GatewayCreate schema
Related Issues
- None identified