mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_proxy_adapter/__init__.py +9 -5
- mcp_proxy_adapter/__main__.py +1 -1
- mcp_proxy_adapter/api/app.py +227 -176
- mcp_proxy_adapter/api/handlers.py +68 -60
- mcp_proxy_adapter/api/middleware/__init__.py +7 -5
- mcp_proxy_adapter/api/middleware/base.py +19 -16
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
- mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
- mcp_proxy_adapter/api/middleware/factory.py +50 -52
- mcp_proxy_adapter/api/middleware/logging.py +46 -30
- mcp_proxy_adapter/api/middleware/performance.py +19 -16
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
- mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
- mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
- mcp_proxy_adapter/api/schemas.py +69 -43
- mcp_proxy_adapter/api/tool_integration.py +83 -63
- mcp_proxy_adapter/api/tools.py +60 -50
- mcp_proxy_adapter/commands/__init__.py +15 -6
- mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
- mcp_proxy_adapter/commands/base.py +108 -112
- mcp_proxy_adapter/commands/builtin_commands.py +28 -18
- mcp_proxy_adapter/commands/catalog_manager.py +394 -265
- mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
- mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
- mcp_proxy_adapter/commands/command_registry.py +275 -226
- mcp_proxy_adapter/commands/config_command.py +48 -33
- mcp_proxy_adapter/commands/dependency_container.py +22 -23
- mcp_proxy_adapter/commands/dependency_manager.py +65 -56
- mcp_proxy_adapter/commands/echo_command.py +15 -15
- mcp_proxy_adapter/commands/health_command.py +31 -29
- mcp_proxy_adapter/commands/help_command.py +97 -61
- mcp_proxy_adapter/commands/hooks.py +65 -49
- mcp_proxy_adapter/commands/key_management_command.py +148 -147
- mcp_proxy_adapter/commands/load_command.py +58 -40
- mcp_proxy_adapter/commands/plugins_command.py +80 -54
- mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
- mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
- mcp_proxy_adapter/commands/reload_command.py +43 -37
- mcp_proxy_adapter/commands/result.py +26 -33
- mcp_proxy_adapter/commands/role_test_command.py +26 -26
- mcp_proxy_adapter/commands/roles_management_command.py +176 -173
- mcp_proxy_adapter/commands/security_command.py +134 -122
- mcp_proxy_adapter/commands/settings_command.py +47 -56
- mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
- mcp_proxy_adapter/commands/token_management_command.py +129 -158
- mcp_proxy_adapter/commands/transport_management_command.py +41 -36
- mcp_proxy_adapter/commands/unload_command.py +42 -37
- mcp_proxy_adapter/config.py +36 -35
- mcp_proxy_adapter/core/__init__.py +19 -21
- mcp_proxy_adapter/core/app_factory.py +30 -9
- mcp_proxy_adapter/core/app_runner.py +81 -64
- mcp_proxy_adapter/core/auth_validator.py +176 -182
- mcp_proxy_adapter/core/certificate_utils.py +469 -426
- mcp_proxy_adapter/core/client.py +155 -126
- mcp_proxy_adapter/core/client_manager.py +60 -54
- mcp_proxy_adapter/core/client_security.py +108 -88
- mcp_proxy_adapter/core/config_converter.py +176 -143
- mcp_proxy_adapter/core/config_validator.py +12 -4
- mcp_proxy_adapter/core/crl_utils.py +21 -7
- mcp_proxy_adapter/core/errors.py +64 -20
- mcp_proxy_adapter/core/logging.py +34 -29
- mcp_proxy_adapter/core/mtls_asgi.py +29 -25
- mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
- mcp_proxy_adapter/core/protocol_manager.py +154 -104
- mcp_proxy_adapter/core/proxy_client.py +202 -144
- mcp_proxy_adapter/core/proxy_registration.py +7 -3
- mcp_proxy_adapter/core/role_utils.py +139 -125
- mcp_proxy_adapter/core/security_adapter.py +88 -77
- mcp_proxy_adapter/core/security_factory.py +50 -44
- mcp_proxy_adapter/core/security_integration.py +72 -24
- mcp_proxy_adapter/core/server_adapter.py +68 -64
- mcp_proxy_adapter/core/server_engine.py +71 -53
- mcp_proxy_adapter/core/settings.py +68 -58
- mcp_proxy_adapter/core/ssl_utils.py +69 -56
- mcp_proxy_adapter/core/transport_manager.py +72 -60
- mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
- mcp_proxy_adapter/core/utils.py +4 -2
- mcp_proxy_adapter/custom_openapi.py +107 -99
- mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
- mcp_proxy_adapter/examples/debug_request_state.py +38 -19
- mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
- mcp_proxy_adapter/examples/demo_client.py +48 -36
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
- mcp_proxy_adapter/examples/generate_certificates.py +31 -16
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
- mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
- mcp_proxy_adapter/examples/run_example.py +23 -5
- mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
- mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
- mcp_proxy_adapter/examples/run_security_tests.py +103 -41
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
- mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/security_test_client.py +196 -127
- mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
- mcp_proxy_adapter/examples/test_config.py +19 -4
- mcp_proxy_adapter/examples/test_config_generator.py +23 -7
- mcp_proxy_adapter/examples/test_examples.py +84 -56
- mcp_proxy_adapter/examples/universal_client.py +119 -62
- mcp_proxy_adapter/openapi.py +108 -115
- mcp_proxy_adapter/utils/config_generator.py +429 -274
- mcp_proxy_adapter/version.py +1 -2
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.3.5.dist-info/RECORD +143 -0
- mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/top_level.txt +0 -0
@@ -28,29 +28,30 @@ from ..core.auth_validator import AuthValidator
|
|
28
28
|
class TokenManagementCommand(Command):
|
29
29
|
"""
|
30
30
|
Token management commands.
|
31
|
-
|
31
|
+
|
32
32
|
Provides commands for creating, validating, revoking, listing, and refreshing tokens.
|
33
33
|
Supports both JWT and API tokens.
|
34
34
|
"""
|
35
|
-
|
35
|
+
|
36
36
|
def __init__(self):
|
37
37
|
"""Initialize token management command."""
|
38
38
|
super().__init__()
|
39
39
|
self.auth_validator = AuthValidator()
|
40
40
|
self.logger = logging.getLogger(__name__)
|
41
|
-
|
41
|
+
|
42
42
|
# Load configuration
|
43
43
|
from ...config import config
|
44
|
+
|
44
45
|
self.token_config = config.get("ssl", {}).get("token_auth", {})
|
45
46
|
self.tokens_file = self.token_config.get("tokens_file", "tokens.json")
|
46
47
|
self.token_expiry = self.token_config.get("token_expiry", 3600)
|
47
48
|
self.jwt_secret = self.token_config.get("jwt_secret", "")
|
48
49
|
self.jwt_algorithm = self.token_config.get("jwt_algorithm", "HS256")
|
49
|
-
|
50
|
+
|
50
51
|
async def execute(self, **kwargs) -> CommandResult:
|
51
52
|
"""
|
52
53
|
Execute token management command.
|
53
|
-
|
54
|
+
|
54
55
|
Args:
|
55
56
|
**kwargs: Command parameters containing:
|
56
57
|
- method: Command method (token_create, token_validate, token_revoke, token_list, token_refresh)
|
@@ -58,13 +59,13 @@ class TokenManagementCommand(Command):
|
|
58
59
|
- token_data: Token data for creation
|
59
60
|
- token: Token string for validation/revocation/refresh
|
60
61
|
- active_only: Boolean for token listing
|
61
|
-
|
62
|
+
|
62
63
|
Returns:
|
63
64
|
CommandResult with operation result
|
64
65
|
"""
|
65
66
|
try:
|
66
67
|
method = kwargs.get("method")
|
67
|
-
|
68
|
+
|
68
69
|
if method == "token_create":
|
69
70
|
token_type = kwargs.get("token_type", "api")
|
70
71
|
token_data = kwargs.get("token_data", {})
|
@@ -83,22 +84,20 @@ class TokenManagementCommand(Command):
|
|
83
84
|
token = kwargs.get("token")
|
84
85
|
return await self.token_refresh(token)
|
85
86
|
else:
|
86
|
-
return ErrorResult(
|
87
|
-
|
88
|
-
code=-32601
|
89
|
-
)
|
90
|
-
|
87
|
+
return ErrorResult(message=f"Unknown method: {method}", code=-32601)
|
88
|
+
|
91
89
|
except Exception as e:
|
92
90
|
self.logger.error(f"Token management command execution error: {e}")
|
93
91
|
return ErrorResult(
|
94
|
-
message=f"Token management command failed: {str(e)}",
|
95
|
-
code=-32603
|
92
|
+
message=f"Token management command failed: {str(e)}", code=-32603
|
96
93
|
)
|
97
|
-
|
98
|
-
async def token_create(
|
94
|
+
|
95
|
+
async def token_create(
|
96
|
+
self, token_type: str, token_data: Dict[str, Any]
|
97
|
+
) -> Union[SuccessResult, ErrorResult]:
|
99
98
|
"""
|
100
99
|
Create a new token.
|
101
|
-
|
100
|
+
|
102
101
|
Args:
|
103
102
|
token_type: Type of token (jwt/api)
|
104
103
|
token_data: Token data dictionary containing:
|
@@ -106,145 +105,133 @@ class TokenManagementCommand(Command):
|
|
106
105
|
- expires_in: Token expiration time in seconds (optional)
|
107
106
|
- description: Token description (optional)
|
108
107
|
- user_id: User ID associated with token (optional)
|
109
|
-
|
108
|
+
|
110
109
|
Returns:
|
111
110
|
CommandResult with created token information
|
112
111
|
"""
|
113
112
|
try:
|
114
113
|
if token_type not in ["jwt", "api"]:
|
115
114
|
return ErrorResult(
|
116
|
-
message=f"Unsupported token type: {token_type}",
|
117
|
-
code=-32602
|
115
|
+
message=f"Unsupported token type: {token_type}", code=-32602
|
118
116
|
)
|
119
|
-
|
117
|
+
|
120
118
|
if token_type == "jwt":
|
121
119
|
return await self._create_jwt_token(token_data)
|
122
120
|
else:
|
123
121
|
return await self._create_api_token(token_data)
|
124
|
-
|
122
|
+
|
125
123
|
except Exception as e:
|
126
124
|
self.logger.error(f"Token creation error: {e}")
|
127
|
-
return ErrorResult(
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
async def token_validate(self, token: str, token_type: str = "auto") -> Union[SuccessResult, ErrorResult]:
|
125
|
+
return ErrorResult(message=f"Token creation failed: {str(e)}", code=-32603)
|
126
|
+
|
127
|
+
async def token_validate(
|
128
|
+
self, token: str, token_type: str = "auto"
|
129
|
+
) -> Union[SuccessResult, ErrorResult]:
|
133
130
|
"""
|
134
131
|
Validate a token.
|
135
|
-
|
132
|
+
|
136
133
|
Args:
|
137
134
|
token: Token string to validate
|
138
135
|
token_type: Type of token (auto/jwt/api)
|
139
|
-
|
136
|
+
|
140
137
|
Returns:
|
141
138
|
CommandResult with validation status and token information
|
142
139
|
"""
|
143
140
|
try:
|
144
141
|
if not token:
|
145
|
-
return ErrorResult(
|
146
|
-
|
147
|
-
code=-32602
|
148
|
-
)
|
149
|
-
|
142
|
+
return ErrorResult(message="Token not provided", code=-32602)
|
143
|
+
|
150
144
|
# Auto-detect token type if not specified
|
151
145
|
if token_type == "auto":
|
152
146
|
token_type = "jwt" if self._is_jwt_token(token) else "api"
|
153
|
-
|
147
|
+
|
154
148
|
# Use AuthValidator for validation
|
155
149
|
result = self.auth_validator.validate_token(token, token_type)
|
156
|
-
|
150
|
+
|
157
151
|
if result.is_valid:
|
158
152
|
return SuccessResult(
|
159
153
|
data={
|
160
154
|
"valid": True,
|
161
155
|
"token_type": token_type,
|
162
156
|
"roles": result.roles,
|
163
|
-
"expires_at": self._get_token_expiry(token, token_type)
|
157
|
+
"expires_at": self._get_token_expiry(token, token_type),
|
164
158
|
}
|
165
159
|
)
|
166
160
|
else:
|
167
161
|
error_data = result.to_json_rpc_error()
|
168
162
|
return ErrorResult(
|
169
|
-
message=error_data["message"],
|
170
|
-
code=error_data["code"]
|
163
|
+
message=error_data["message"], code=error_data["code"]
|
171
164
|
)
|
172
|
-
|
165
|
+
|
173
166
|
except Exception as e:
|
174
167
|
self.logger.error(f"Token validation error: {e}")
|
175
168
|
return ErrorResult(
|
176
|
-
message=f"Token validation failed: {str(e)}",
|
177
|
-
code=-32603
|
169
|
+
message=f"Token validation failed: {str(e)}", code=-32603
|
178
170
|
)
|
179
|
-
|
171
|
+
|
180
172
|
async def token_revoke(self, token: str) -> Union[SuccessResult, ErrorResult]:
|
181
173
|
"""
|
182
174
|
Revoke a token.
|
183
|
-
|
175
|
+
|
184
176
|
Args:
|
185
177
|
token: Token string to revoke
|
186
|
-
|
178
|
+
|
187
179
|
Returns:
|
188
180
|
CommandResult with revocation status
|
189
181
|
"""
|
190
182
|
try:
|
191
183
|
if not token:
|
192
|
-
return ErrorResult(
|
193
|
-
|
194
|
-
code=-32602
|
195
|
-
)
|
196
|
-
|
184
|
+
return ErrorResult(message="Token not provided", code=-32602)
|
185
|
+
|
197
186
|
# Load current tokens
|
198
187
|
tokens = self._load_tokens()
|
199
|
-
|
188
|
+
|
200
189
|
# Check if token exists
|
201
190
|
if token not in tokens:
|
202
|
-
return ErrorResult(
|
203
|
-
|
204
|
-
code=-32011
|
205
|
-
)
|
206
|
-
|
191
|
+
return ErrorResult(message="Token not found", code=-32011)
|
192
|
+
|
207
193
|
# Mark token as revoked
|
208
194
|
tokens[token]["active"] = False
|
209
195
|
tokens[token]["revoked_at"] = time.time()
|
210
196
|
tokens[token]["revoked_by"] = "system"
|
211
|
-
|
197
|
+
|
212
198
|
# Save updated tokens
|
213
199
|
self._save_tokens(tokens)
|
214
|
-
|
200
|
+
|
215
201
|
return SuccessResult(
|
216
202
|
data={
|
217
203
|
"revoked": True,
|
218
204
|
"token": token,
|
219
|
-
"revoked_at": datetime.now().isoformat()
|
205
|
+
"revoked_at": datetime.now().isoformat(),
|
220
206
|
}
|
221
207
|
)
|
222
|
-
|
208
|
+
|
223
209
|
except Exception as e:
|
224
210
|
self.logger.error(f"Token revocation error: {e}")
|
225
211
|
return ErrorResult(
|
226
|
-
message=f"Token revocation failed: {str(e)}",
|
227
|
-
code=-32603
|
212
|
+
message=f"Token revocation failed: {str(e)}", code=-32603
|
228
213
|
)
|
229
|
-
|
230
|
-
async def token_list(
|
214
|
+
|
215
|
+
async def token_list(
|
216
|
+
self, active_only: bool = True
|
217
|
+
) -> Union[SuccessResult, ErrorResult]:
|
231
218
|
"""
|
232
219
|
List all tokens.
|
233
|
-
|
220
|
+
|
234
221
|
Args:
|
235
222
|
active_only: If True, return only active tokens
|
236
|
-
|
223
|
+
|
237
224
|
Returns:
|
238
225
|
CommandResult with list of tokens
|
239
226
|
"""
|
240
227
|
try:
|
241
228
|
# Load tokens
|
242
229
|
tokens = self._load_tokens()
|
243
|
-
|
230
|
+
|
244
231
|
# Filter tokens if requested
|
245
232
|
if active_only:
|
246
233
|
tokens = {k: v for k, v in tokens.items() if v.get("active", True)}
|
247
|
-
|
234
|
+
|
248
235
|
# Prepare token list (without sensitive data)
|
249
236
|
token_list = []
|
250
237
|
for token_id, token_data in tokens.items():
|
@@ -256,70 +243,55 @@ class TokenManagementCommand(Command):
|
|
256
243
|
"created_at": token_data.get("created_at"),
|
257
244
|
"expires_at": token_data.get("expires_at"),
|
258
245
|
"description": token_data.get("description", ""),
|
259
|
-
"user_id": token_data.get("user_id")
|
246
|
+
"user_id": token_data.get("user_id"),
|
260
247
|
}
|
261
|
-
|
248
|
+
|
262
249
|
if "revoked_at" in token_data:
|
263
250
|
token_info["revoked_at"] = token_data["revoked_at"]
|
264
|
-
|
251
|
+
|
265
252
|
token_list.append(token_info)
|
266
|
-
|
253
|
+
|
267
254
|
return SuccessResult(
|
268
255
|
data={
|
269
256
|
"tokens": token_list,
|
270
257
|
"count": len(token_list),
|
271
|
-
"active_only": active_only
|
258
|
+
"active_only": active_only,
|
272
259
|
}
|
273
260
|
)
|
274
|
-
|
261
|
+
|
275
262
|
except Exception as e:
|
276
263
|
self.logger.error(f"Token listing error: {e}")
|
277
|
-
return ErrorResult(
|
278
|
-
|
279
|
-
code=-32603
|
280
|
-
)
|
281
|
-
|
264
|
+
return ErrorResult(message=f"Token listing failed: {str(e)}", code=-32603)
|
265
|
+
|
282
266
|
async def token_refresh(self, token: str) -> Union[SuccessResult, ErrorResult]:
|
283
267
|
"""
|
284
268
|
Refresh a token.
|
285
|
-
|
269
|
+
|
286
270
|
Args:
|
287
271
|
token: Token string to refresh
|
288
|
-
|
272
|
+
|
289
273
|
Returns:
|
290
274
|
CommandResult with refreshed token information
|
291
275
|
"""
|
292
276
|
try:
|
293
277
|
if not token:
|
294
|
-
return ErrorResult(
|
295
|
-
|
296
|
-
code=-32602
|
297
|
-
)
|
298
|
-
|
278
|
+
return ErrorResult(message="Token not provided", code=-32602)
|
279
|
+
|
299
280
|
# Load current tokens
|
300
281
|
tokens = self._load_tokens()
|
301
|
-
|
282
|
+
|
302
283
|
# Check if token exists and is active
|
303
284
|
if token not in tokens:
|
304
|
-
return ErrorResult(
|
305
|
-
|
306
|
-
code=-32011
|
307
|
-
)
|
308
|
-
|
285
|
+
return ErrorResult(message="Token not found", code=-32011)
|
286
|
+
|
309
287
|
token_data = tokens[token]
|
310
288
|
if not token_data.get("active", True):
|
311
|
-
return ErrorResult(
|
312
|
-
|
313
|
-
code=-32011
|
314
|
-
)
|
315
|
-
|
289
|
+
return ErrorResult(message="Token is revoked", code=-32011)
|
290
|
+
|
316
291
|
# Check if token has expired
|
317
292
|
if "expires_at" in token_data and time.time() > token_data["expires_at"]:
|
318
|
-
return ErrorResult(
|
319
|
-
|
320
|
-
code=-32010
|
321
|
-
)
|
322
|
-
|
293
|
+
return ErrorResult(message="Token has expired", code=-32010)
|
294
|
+
|
323
295
|
# Create new token with same data
|
324
296
|
new_token_data = {
|
325
297
|
"type": token_data.get("type", "api"),
|
@@ -329,64 +301,63 @@ class TokenManagementCommand(Command):
|
|
329
301
|
"expires_at": time.time() + self.token_expiry,
|
330
302
|
"description": token_data.get("description", ""),
|
331
303
|
"user_id": token_data.get("user_id"),
|
332
|
-
"refreshed_from": token
|
304
|
+
"refreshed_from": token,
|
333
305
|
}
|
334
|
-
|
306
|
+
|
335
307
|
# Generate new token ID
|
336
308
|
new_token_id = str(uuid.uuid4())
|
337
309
|
tokens[new_token_id] = new_token_data
|
338
|
-
|
310
|
+
|
339
311
|
# Revoke old token
|
340
312
|
tokens[token]["active"] = False
|
341
313
|
tokens[token]["refreshed_to"] = new_token_id
|
342
314
|
tokens[token]["refreshed_at"] = time.time()
|
343
|
-
|
315
|
+
|
344
316
|
# Save updated tokens
|
345
317
|
self._save_tokens(tokens)
|
346
|
-
|
318
|
+
|
347
319
|
return SuccessResult(
|
348
320
|
data={
|
349
321
|
"refreshed": True,
|
350
322
|
"old_token": token,
|
351
323
|
"new_token": new_token_id,
|
352
|
-
"expires_at": new_token_data["expires_at"]
|
324
|
+
"expires_at": new_token_data["expires_at"],
|
353
325
|
}
|
354
326
|
)
|
355
|
-
|
327
|
+
|
356
328
|
except Exception as e:
|
357
329
|
self.logger.error(f"Token refresh error: {e}")
|
358
|
-
return ErrorResult(
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
async def _create_jwt_token(self, token_data: Dict[str, Any]) -> Union[SuccessResult, ErrorResult]:
|
330
|
+
return ErrorResult(message=f"Token refresh failed: {str(e)}", code=-32603)
|
331
|
+
|
332
|
+
async def _create_jwt_token(
|
333
|
+
self, token_data: Dict[str, Any]
|
334
|
+
) -> Union[SuccessResult, ErrorResult]:
|
364
335
|
"""
|
365
336
|
Create JWT token.
|
366
|
-
|
337
|
+
|
367
338
|
Args:
|
368
339
|
token_data: Token data dictionary
|
369
|
-
|
340
|
+
|
370
341
|
Returns:
|
371
342
|
CommandResult with JWT token
|
372
343
|
"""
|
373
344
|
try:
|
374
345
|
# This is a placeholder for JWT creation
|
375
346
|
# In a real implementation, you would use a JWT library like PyJWT
|
376
|
-
|
347
|
+
|
377
348
|
# For now, create a simple token structure
|
378
349
|
token_id = str(uuid.uuid4())
|
379
350
|
expires_in = token_data.get("expires_in", self.token_expiry)
|
380
|
-
|
351
|
+
|
381
352
|
jwt_token_data = {
|
382
353
|
"jti": token_id,
|
383
354
|
"sub": token_data.get("user_id", "system"),
|
384
355
|
"roles": token_data.get("roles", []),
|
385
356
|
"exp": time.time() + expires_in,
|
386
357
|
"iat": time.time(),
|
387
|
-
"iss": "mcp_proxy_adapter"
|
358
|
+
"iss": "mcp_proxy_adapter",
|
388
359
|
}
|
389
|
-
|
360
|
+
|
390
361
|
# In a real implementation, you would encode this as JWT
|
391
362
|
# For now, return the token data
|
392
363
|
return SuccessResult(
|
@@ -395,24 +366,25 @@ class TokenManagementCommand(Command):
|
|
395
366
|
"token_type": "jwt",
|
396
367
|
"expires_at": jwt_token_data["exp"],
|
397
368
|
"roles": jwt_token_data["roles"],
|
398
|
-
"user_id": jwt_token_data["sub"]
|
369
|
+
"user_id": jwt_token_data["sub"],
|
399
370
|
}
|
400
371
|
)
|
401
|
-
|
372
|
+
|
402
373
|
except Exception as e:
|
403
374
|
self.logger.error(f"JWT token creation error: {e}")
|
404
375
|
return ErrorResult(
|
405
|
-
message=f"JWT token creation failed: {str(e)}",
|
406
|
-
code=-32603
|
376
|
+
message=f"JWT token creation failed: {str(e)}", code=-32603
|
407
377
|
)
|
408
|
-
|
409
|
-
async def _create_api_token(
|
378
|
+
|
379
|
+
async def _create_api_token(
|
380
|
+
self, token_data: Dict[str, Any]
|
381
|
+
) -> Union[SuccessResult, ErrorResult]:
|
410
382
|
"""
|
411
383
|
Create API token.
|
412
|
-
|
384
|
+
|
413
385
|
Args:
|
414
386
|
token_data: Token data dictionary
|
415
|
-
|
387
|
+
|
416
388
|
Returns:
|
417
389
|
CommandResult with API token
|
418
390
|
"""
|
@@ -420,7 +392,7 @@ class TokenManagementCommand(Command):
|
|
420
392
|
# Generate token ID
|
421
393
|
token_id = str(uuid.uuid4())
|
422
394
|
expires_in = token_data.get("expires_in", self.token_expiry)
|
423
|
-
|
395
|
+
|
424
396
|
# Create token data
|
425
397
|
api_token_data = {
|
426
398
|
"type": "api",
|
@@ -429,52 +401,51 @@ class TokenManagementCommand(Command):
|
|
429
401
|
"created_at": time.time(),
|
430
402
|
"expires_at": time.time() + expires_in,
|
431
403
|
"description": token_data.get("description", ""),
|
432
|
-
"user_id": token_data.get("user_id")
|
404
|
+
"user_id": token_data.get("user_id"),
|
433
405
|
}
|
434
|
-
|
406
|
+
|
435
407
|
# Load current tokens and add new token
|
436
408
|
tokens = self._load_tokens()
|
437
409
|
tokens[token_id] = api_token_data
|
438
410
|
self._save_tokens(tokens)
|
439
|
-
|
411
|
+
|
440
412
|
return SuccessResult(
|
441
413
|
data={
|
442
414
|
"token": token_id,
|
443
415
|
"token_type": "api",
|
444
416
|
"expires_at": api_token_data["expires_at"],
|
445
417
|
"roles": api_token_data["roles"],
|
446
|
-
"user_id": api_token_data["user_id"]
|
418
|
+
"user_id": api_token_data["user_id"],
|
447
419
|
}
|
448
420
|
)
|
449
|
-
|
421
|
+
|
450
422
|
except Exception as e:
|
451
423
|
self.logger.error(f"API token creation error: {e}")
|
452
424
|
return ErrorResult(
|
453
|
-
message=f"API token creation failed: {str(e)}",
|
454
|
-
code=-32603
|
425
|
+
message=f"API token creation failed: {str(e)}", code=-32603
|
455
426
|
)
|
456
|
-
|
427
|
+
|
457
428
|
def _is_jwt_token(self, token: str) -> bool:
|
458
429
|
"""
|
459
430
|
Check if token is JWT format.
|
460
|
-
|
431
|
+
|
461
432
|
Args:
|
462
433
|
token: Token string
|
463
|
-
|
434
|
+
|
464
435
|
Returns:
|
465
436
|
True if token appears to be JWT, False otherwise
|
466
437
|
"""
|
467
|
-
parts = token.split(
|
438
|
+
parts = token.split(".")
|
468
439
|
return len(parts) == 3
|
469
|
-
|
440
|
+
|
470
441
|
def _get_token_expiry(self, token: str, token_type: str) -> Optional[float]:
|
471
442
|
"""
|
472
443
|
Get token expiry time.
|
473
|
-
|
444
|
+
|
474
445
|
Args:
|
475
446
|
token: Token string
|
476
447
|
token_type: Type of token
|
477
|
-
|
448
|
+
|
478
449
|
Returns:
|
479
450
|
Expiry timestamp or None
|
480
451
|
"""
|
@@ -483,47 +454,47 @@ class TokenManagementCommand(Command):
|
|
483
454
|
tokens = self._load_tokens()
|
484
455
|
if token in tokens:
|
485
456
|
return tokens[token].get("expires_at")
|
486
|
-
|
457
|
+
|
487
458
|
# For JWT tokens, this would require decoding
|
488
459
|
# For now, return None
|
489
460
|
return None
|
490
|
-
|
461
|
+
|
491
462
|
except Exception as e:
|
492
463
|
self.logger.error(f"Failed to get token expiry: {e}")
|
493
464
|
return None
|
494
|
-
|
465
|
+
|
495
466
|
def _load_tokens(self) -> Dict[str, Any]:
|
496
467
|
"""
|
497
468
|
Load tokens from file.
|
498
|
-
|
469
|
+
|
499
470
|
Returns:
|
500
471
|
Dictionary of tokens
|
501
472
|
"""
|
502
473
|
try:
|
503
474
|
if not self.tokens_file or not Path(self.tokens_file).exists():
|
504
475
|
return {}
|
505
|
-
|
506
|
-
with open(self.tokens_file,
|
476
|
+
|
477
|
+
with open(self.tokens_file, "r", encoding="utf-8") as f:
|
507
478
|
return json.load(f)
|
508
|
-
|
479
|
+
|
509
480
|
except Exception as e:
|
510
481
|
self.logger.error(f"Failed to load tokens: {e}")
|
511
482
|
return {}
|
512
|
-
|
483
|
+
|
513
484
|
def _save_tokens(self, tokens: Dict[str, Any]) -> None:
|
514
485
|
"""
|
515
486
|
Save tokens to file.
|
516
|
-
|
487
|
+
|
517
488
|
Args:
|
518
489
|
tokens: Dictionary of tokens to save
|
519
490
|
"""
|
520
491
|
try:
|
521
492
|
# Ensure directory exists
|
522
493
|
Path(self.tokens_file).parent.mkdir(parents=True, exist_ok=True)
|
523
|
-
|
524
|
-
with open(self.tokens_file,
|
494
|
+
|
495
|
+
with open(self.tokens_file, "w", encoding="utf-8") as f:
|
525
496
|
json.dump(tokens, f, indent=2, ensure_ascii=False)
|
526
|
-
|
497
|
+
|
527
498
|
except Exception as e:
|
528
499
|
self.logger.error(f"Failed to save tokens: {e}")
|
529
|
-
raise
|
500
|
+
raise
|