Skip to content

Commit 4783ec5

Browse files
popagruiapopagruia
andauthored
Fix tag handling for vault plugin. Additional handling for PAT features using a tag. (#1557)
* Fix tag handling from array of strings to array of dicts Signed-off-by: popagruia <adrian.popa@ro.ibm.com> * Fix flake 8 issues Signed-off-by: popagruia <adrian.popa@ro.ibm.com> * Fix flake 8 issues Signed-off-by: popagruia <adrian.popa@ro.ibm.com> * Add sample testing --------- Signed-off-by: popagruia <adrian.popa@ro.ibm.com> Co-authored-by: popagruia <adrian.popa@ro.ibm.com>
1 parent 23c1e2a commit 4783ec5

File tree

2 files changed

+274
-113
lines changed

2 files changed

+274
-113
lines changed

plugins/vault/README.md

Lines changed: 185 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,225 @@
11
# Vault Plugin
22

3-
The Vault Plugin provides secure storage and retrieval of secrets, ensuring that sensitive information is protected and managed effectively. It generates bearer tokens based on vault-saved tokens and integrates with gateway metadata and OAuth2 configurations.
4-
5-
## Quick Start
3+
The Vault plugin generates bearer tokens from vault-saved tokens based on OAuth2 configuration protecting a tool.
4+
It receives a dictionary of secrets and use them to dispatch the authorization token to the server based on rules.
65

76
## Features
87

9-
Replace the Bearer token in a tool invocation based on a header that is send to the agent. Header is matched based on the MCP server metadata
10-
- tag that start with system_tag_prefix
11-
- extract the host of the authentication server from
12-
8+
- **Tag-based metadata handling**: Supports dict format `{"id": "...", "label": "..."}`
9+
- Supported tags must be created on an MCP server to drive the secret handling:
10+
- system:<system host> where system host is the IDP provider for that MCP Server. For example system:github.com or system:mural.com
11+
- AUTH_HEADER:<header name> where header name is the authorization header to be used for this MCP header if a PAT token is send
1312

13+
- **Complex token key format**: Supports secrets send via a header containing a JSON dictionary with keys like `github.com:USER:OAUTH2:TOKEN` or simple `github.com`
14+
- **PAT (Personal Access Token) support**: Use `AUTH_HEADER` tag to specify a custom header to be dispatched to the backend server.
15+
- **OAuth2 token support**: Default bearer token handling for OAuth2 tokens. If no specific rule for PAT the default behavior is to send the secret as Bearer token in Authorization header
16+
- **Flexible configuration**: Falls back to default bearer token behavior when parts are missing
1417

15-
## Installation
18+
## Configuration
1619

17-
1. Copy .env.example .env
18-
2. Enable plugins in `.env`
19-
3. Add the plugin configuration to `plugins/config.yaml`:
20+
### Basic Configuration
2021

2122
```yaml
22-
- name: "VaultPlugin"
23-
kind: "plugins.vault.vault_plugin.Vault"
24-
description: "Vault plugin that based that will generate bearer token based on a vault saved token"
25-
version: "0.0.1"
26-
author: "Adrian Popa"
27-
hooks: ["tool_pre_invoke"]
28-
tags: ["security", "vault", "OAUTH2"]
29-
mode: "permissive" # enforce | permissive | disabled
30-
priority: 10 # Lower number = higher priority (runs first)
31-
conditions:
32-
- prompts: [] # Empty list = apply to all prompts
33-
server_ids: [] # Apply to all servers
34-
tenant_ids: [] # Apply to all tenants
35-
config:
36-
system_tag_prefix: "system"
37-
vault_header_name: "X-Vault-Tokens"
38-
vault_handling: "raw"
23+
vault:
24+
enabled: true
25+
config:
26+
system_tag_prefix: "system"
27+
vault_header_name: "X-Vault-Tokens"
28+
vault_handling: "raw"
29+
system_handling: "tag"
30+
auth_header_tag_prefix: "AUTH_HEADER"
31+
```
32+
33+
### Configuration Options
3934
35+
- **system_tag_prefix**: Prefix for system identification tags (default: `"system"`)
36+
- **vault_header_name**: HTTP header name for vault tokens (default: `"X-Vault-Tokens"`)
37+
- **vault_handling**: Token handling mode (default: `"raw"`). Future version will handle token unwrapping
38+
- **system_handling**: System identification mode (default: `"tag"`)
39+
- **auth_header_tag_prefix**: Prefix for auth header tags (default: `"AUTH_HEADER"`)
40+
41+
## Token Key Format
42+
43+
The plugin supports complex token keys in the format:
44+
45+
```
46+
system[:scope][:token_type][:token_name]
4047
```
4148

42-
## Configuration Examples
49+
Where:
50+
- **system** (required): The system identifier (e.g., `github.com`, `gitlab.com`)
51+
- **scope** (optional): USER or GROUP (ignored in processing)
52+
- **token_type** (optional): PAT or OAUTH2
53+
- **token_name** (optional): Name of the token
4354

44-
### Development Environment (Permissive)
45-
```yaml
46-
config:
47-
system_tag_prefix: "system" ### The prefix of the tag that contains the system name
48-
system_handling: "tag" # # Gets the OAUTH2 IDP host from tags. The tag must have the format "system:host" where host is the hostname of the IDP. Use oauth2_config to extract IDP hostname from the OAUTH_CONFIG metadata of the MCP Server template.
49-
vault_header_name: "X-Vault-Tokens" # Name of the header that contains the tokens.
50-
vault_handling: "raw" # Use the token that matches the system as bearer token
55+
### Examples
56+
57+
1. **Simple key**: `github.com`
58+
- Uses default OAuth2 bearer token handling
59+
60+
2. **Full PAT key**: `github.com:USER:PAT:my-token`
61+
- System: `github.com`
62+
- Scope: `USER` (ignored)
63+
- Token type: `PAT`
64+
- Token name: `my-token`
65+
- Checks for `AUTH_HEADER` tag to determine header name
66+
67+
3. **OAuth2 key**: `gitlab.com:GROUP:OAUTH2:app-token`
68+
- System: `gitlab.com`
69+
- Scope: `GROUP` (ignored)
70+
- Token type: `OAUTH2`
71+
- Token name: `TOKEN` (default name)
72+
- Uses OAuth2 bearer token handling
5173

74+
## Token Type Handling
5275

53-
### Features
54-
- Secure storage of secrets
55-
- Retrieval of secrets with access control
56-
- Integration with gateway metadata and OAuth2 configurations
76+
### PAT (Personal Access Token)
5777

58-
## Available Hooks
78+
When `token_type` is `PAT`:
79+
1. Checks if AUTH_HEADER:header tag exists
80+
2. If found, uses the configured custom header
81+
3. If not found, falls back to `Authorization: Bearer <token>`
5982

60-
The Vault Plugin implement hooks at these lifecycle points:
83+
### OAUTH2
6184

62-
| Hook | Description | Payload Type | Use Cases |
63-
|------|-------------|--------------|-----------|
64-
| `tool_pre_invoke` | Before tool invocation | `ToolPreInvokePayload` | Access control for OAUTH2 server |
85+
When `token_type` is `OAUTH2` or missing:
86+
- Uses standard `Authorization: Bearer <token>` header
6587

88+
### Unknown Types
6689

90+
For any other token type:
91+
- Logs a warning
92+
- Falls back to `Authorization: Bearer <token>`
6793

68-
### Plugin Modes
94+
## Gateway Metadata Tags
6995

96+
The plugin handles tags in dict format:
7097

71-
- **`permissive`**: Change headers if possible but allows request to continue
98+
```json
99+
{
100+
"tags": [
101+
{"id": "auto-generated-id", "label": "system:github.com"},
102+
{"id": "another-id", "label": "AUTH_HEADER:X-GitHub-Token"},
103+
{"id": "third-id", "label": "environment:production"}
104+
]
105+
}
106+
```
107+
108+
The plugin extracts the `label` field from dict tags (the actual tag value), while `id` is autogenerated.
72109

73-
### Plugin Priority
110+
### Tag Types
74111

75-
Lower priority numbers run first (higher priority). Recommended ranges:
76-
- **1-50**: Critical security plugins (access control)
77-
- **51-100**: Content filtering and validation
78-
- **101-200**: Transformations and enhancements
79-
- **201+**: Logging and monitoring
112+
1. **System Tag**: `system:<system_name>`
113+
- Identifies which system the token is for
114+
- Example: `system:github.com`
115+
- Required for the plugin to work
80116

117+
2. **Auth Header Tag**: `AUTH_HEADER:<header_name>`
118+
- Specifies custom header for PAT tokens
119+
- Example: `AUTH_HEADER:X-GitHub-Token`
120+
- Only used when token type is PAT
121+
- Optional - falls back to Bearer token if not present
81122

82-
### Logging and Monitoring
123+
## Example Usage
83124

84-
```python
85-
def __init__(self, config: PluginConfig):
86-
super().__init__(config)
87-
self.logger.info(f"Initialized {self.name} v{self.version}")
125+
### Request with Vault Tokens
88126

89-
async def vault_pre_fetch(self, payload: VaultPreFetchPayload) -> VaultPreFetchPayload:
90-
self.logger.debug(f"Processing vault: {payload.secret_name}")
91-
# ... plugin logic
92-
self.metrics.increment("requests_processed")
127+
```http
128+
POST /api/tools/invoke
129+
X-Vault-Tokens: {"github.com:USER:PAT:my-token": "ghp_xxxxxxxxxxxx", "gitlab.com": "glpat-yyyyyyyy"}
93130
```
94131

132+
### Gateway with AUTH_HEADER Tag
95133

96-
## Testing
97-
### Create an MCP gateway that is OAUTH2 authenticated:
134+
If gateway has tags including `AUTH_HEADER:X-GitHub-Token`:
135+
```json
136+
{
137+
"tags": [
138+
{"id": "1", "label": "system:github.com"},
139+
{"id": "2", "label": "AUTH_HEADER:X-GitHub-Token"}
140+
]
141+
}
142+
```
98143

99-
```bash
100-
curl -s \
101-
-X POST \
102-
-H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
103-
-H "Content-Type: application/json" \
104-
-d '{
105-
"name": "github_com",
106-
"url": "https://api.githubcopilot.com/mcp/",
107-
"description": "A new MCP server added with OAuth2 authentication",
108-
"auth_type": "oauth",
109-
"auth_value": {
110-
"client_id": "'$CLIENT_ID'",
111-
"client_secret": "'$CLIENT_SECRET'",
112-
"token_url": "https://github.com/login/oauth/access_token",
113-
"redirect_url": "http://localhost:4444/oauth/callback"
114-
},
115-
"tags": ["system:github.com"],
116-
"passthrough_headers": ["X-Vault-Tokens"]
117-
}' \
118-
http://localhost:4444/gateways
144+
The plugin will set:
145+
```http
146+
X-GitHub-Token: ghp_xxxxxxxxxxxx
119147
```
120-
The bearer token can be created by running:
121148

122-
```bash
123-
export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token \ --username admin@example.com --exp 10080 --secret my-test-key)
149+
### Without AUTH_HEADER Tag
150+
151+
If no `AUTH_HEADER` tag is defined, the plugin will use default Bearer token:
152+
```http
153+
Authorization: Bearer ghp_xxxxxxxxxxxx
124154
```
125155

126-
### Invoke a tool sending the tokens in a dictionary
156+
## System Identification
157+
158+
The plugin supports two modes for identifying the system:
159+
160+
### TAG Mode (Default)
161+
162+
Extracts system from gateway tags with the configured prefix:
163+
- Tag: `system:github.com` → System: `github.com`
164+
165+
### OAUTH2_CONFIG Mode
166+
167+
Extracts system from the OAuth2 configuration's `token_url`:
168+
- Token URL: `https://github.com/login/oauth/access_token` → System: `github.com`
169+
170+
## Hook
171+
172+
- **tool_pre_invoke**: Processes vault tokens before tool invocation
173+
174+
175+
## Testing
176+
177+
## Create a token
178+
export MCPGATEWAY_BEARER_TOKEN = python3 -m mcpgateway.utils.create_jwt_token --username admin@example.com --exp 10080 --secret my-test-key
179+
180+
export CLIENT_ID=xxx
181+
export CLIENT_SECRET=xxx
182+
183+
184+
## Register MCP server with the gateway and add OAuth2 configuration Using UI
185+
curl -s -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
186+
-H "Content-Type: application/json" \
187+
-d '{
188+
"name": "github_com",
189+
"url": "https://api.githubcopilot.com/mcp/",
190+
"description": "A new MCP server added with OAuth2 authentication",
191+
"auth_type": "oauth",
192+
"auth_value": {
193+
"client_id": "'$CLIENT_ID'",
194+
"client_secret": "'$CLIENT_SECRET'",
195+
"token_url": "https://github.com/login/oauth/access_token",
196+
"redirect_url": "http://localhost:4444/oauth/callback"
197+
},
198+
"tags": ["system:github.com"],
199+
"passthrough_headers": ["X-Vault-Tokens"]
200+
}' \
201+
http://localhost:4444/gateways
202+
203+
## Invocation
204+
When the server is configured invoke the server and send a pass through header of form
205+
206+
"X-Vault-Tokens": {
207+
"github.com": "key"
208+
},
209+
210+
## Sample of Invoking a Tool on the Added Gateway
211+
127212
```bash
128-
curl --request POST \
129-
--url http://localhost:4444/rpc \
130-
--header "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
131-
--header "Content-Type: application/json" \
132-
--header "x-vault-tokens: {\"github.com\": \"123\"}" \
133-
--data '{
134-
"jsonrpc": "2.0",
135-
"id": 1,
136-
"method": "tools/call",
137-
"params": {
138-
"name": "github-com-get-me",
139-
"arguments": {
140-
"timezone": "Asia/Kolkata"
141-
}
142-
}
143-
}'
213+
# Invoke a tool on the added gateway
214+
curl -s -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
215+
-H "Content-Type: application/json" \
216+
-H 'X-Vault-Tokens: "{\"github.com\": \"key\"}"' \
217+
-d '{
218+
"tool_name": "github-com-list-issues",
219+
"arguments": {
220+
"repo": "reponame"
221+
}
222+
}' \
223+
http://localhost:4444/tools/invoke
144224
```
225+

0 commit comments

Comments
 (0)