embed-client 3.1.0.0__py3-none-any.whl → 3.1.0.2__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.
- embed_client/__init__.py +21 -1
- embed_client/auth.py +17 -13
- embed_client/example_async_usage.py +6 -6
- embed_client/example_async_usage_ru.py +195 -103
- embed_client/ssl_manager.py +27 -18
- {embed_client-3.1.0.0.dist-info → embed_client-3.1.0.2.dist-info}/METADATA +29 -2
- embed_client-3.1.0.2.dist-info/RECORD +17 -0
- embed_client-3.1.0.2.dist-info/licenses/LICENSE +21 -0
- embed_client-3.1.0.0.dist-info/RECORD +0 -16
- {embed_client-3.1.0.0.dist-info → embed_client-3.1.0.2.dist-info}/WHEEL +0 -0
- {embed_client-3.1.0.0.dist-info → embed_client-3.1.0.2.dist-info}/top_level.txt +0 -0
embed_client/__init__.py
CHANGED
@@ -1 +1,21 @@
|
|
1
|
-
|
1
|
+
"""
|
2
|
+
embed-client: Async client for Embedding Service API with comprehensive authentication, SSL/TLS, and mTLS support
|
3
|
+
|
4
|
+
Author: Vasiliy Zdanovskiy
|
5
|
+
email: vasilyvz@gmail.com
|
6
|
+
"""
|
7
|
+
|
8
|
+
from .async_client import EmbeddingServiceAsyncClient
|
9
|
+
from .config import ClientConfig
|
10
|
+
from .auth import AuthManager
|
11
|
+
from .ssl_manager import ClientSSLManager
|
12
|
+
from .client_factory import ClientFactory
|
13
|
+
|
14
|
+
__version__ = "3.1.0.2"
|
15
|
+
__all__ = [
|
16
|
+
"EmbeddingServiceAsyncClient",
|
17
|
+
"ClientConfig",
|
18
|
+
"AuthManager",
|
19
|
+
"ClientSSLManager",
|
20
|
+
"ClientFactory"
|
21
|
+
]
|
embed_client/auth.py
CHANGED
@@ -17,16 +17,12 @@ from urllib.parse import urlparse
|
|
17
17
|
|
18
18
|
# Try to import mcp_security_framework components
|
19
19
|
try:
|
20
|
-
from mcp_security_framework
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
verify_jwt_token,
|
27
|
-
generate_secure_token,
|
28
|
-
hash_password,
|
29
|
-
verify_password
|
20
|
+
from mcp_security_framework import (
|
21
|
+
AuthManager,
|
22
|
+
AuthConfig,
|
23
|
+
PermissionConfig,
|
24
|
+
PermissionManager,
|
25
|
+
SecurityManager
|
30
26
|
)
|
31
27
|
SECURITY_FRAMEWORK_AVAILABLE = True
|
32
28
|
except ImportError:
|
@@ -106,12 +102,20 @@ class ClientAuthManager:
|
|
106
102
|
# Create permission config
|
107
103
|
permission_config = PermissionConfig(
|
108
104
|
enabled=self.config.get("security", {}).get("roles_enabled", False),
|
109
|
-
roles_file=self.config.get("security", {}).get("roles_file")
|
105
|
+
roles_file=self.config.get("security", {}).get("roles_file") or "configs/roles.json"
|
106
|
+
)
|
107
|
+
|
108
|
+
# Create security config
|
109
|
+
from mcp_security_framework import SecurityConfig
|
110
|
+
security_config = SecurityConfig(
|
111
|
+
auth=auth_config,
|
112
|
+
permissions=permission_config
|
110
113
|
)
|
111
114
|
|
112
115
|
# Initialize managers
|
113
|
-
self.
|
114
|
-
self.auth_manager =
|
116
|
+
self.security_manager = SecurityManager(security_config)
|
117
|
+
self.auth_manager = self.security_manager.auth_manager
|
118
|
+
self.permission_manager = self.security_manager.permission_manager
|
115
119
|
|
116
120
|
self.logger.info("Security framework initialized successfully")
|
117
121
|
|
@@ -49,10 +49,10 @@ SECURITY MODES EXAMPLES:
|
|
49
49
|
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --auth-method jwt --jwt-secret secret --jwt-username admin
|
50
50
|
|
51
51
|
# 5. mTLS - mutual TLS with client and server certificates
|
52
|
-
python embed_client/example_async_usage.py --base-url https://localhost --port
|
52
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key
|
53
53
|
|
54
54
|
# 6. mTLS + Roles - mTLS with role-based access control
|
55
|
-
python embed_client/example_async_usage.py --base-url https://localhost --port
|
55
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key --roles admin,user
|
56
56
|
|
57
57
|
CLIENT FACTORY EXAMPLES:
|
58
58
|
# Automatic security mode detection
|
@@ -62,14 +62,14 @@ CLIENT FACTORY EXAMPLES:
|
|
62
62
|
python embed_client/example_async_usage.py --factory-mode https_token --base-url https://localhost --port 9443 --auth-method basic --username user --password pass
|
63
63
|
|
64
64
|
# mTLS with factory
|
65
|
-
python embed_client/example_async_usage.py --factory-mode mtls --base-url https://localhost --port
|
65
|
+
python embed_client/example_async_usage.py --factory-mode mtls --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key
|
66
66
|
|
67
67
|
SSL/TLS EXAMPLES:
|
68
68
|
# HTTPS with SSL verification disabled
|
69
69
|
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --ssl-verify-mode CERT_NONE
|
70
70
|
|
71
71
|
# mTLS with custom CA certificate
|
72
|
-
python embed_client/example_async_usage.py --base-url https://localhost --port
|
72
|
+
python embed_client/example_async_usage.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key --ca-cert-file mtls_certificates/ca/ca.crt
|
73
73
|
|
74
74
|
# HTTPS with custom SSL settings
|
75
75
|
python embed_client/example_async_usage.py --base-url https://localhost --port 9443 --ssl-verify-mode CERT_REQUIRED --ssl-check-hostname --ssl-check-expiry
|
@@ -458,7 +458,7 @@ async def demonstrate_security_modes():
|
|
458
458
|
print(" Use case: High security, client certificate authentication")
|
459
459
|
try:
|
460
460
|
client = ClientFactory.create_mtls_client(
|
461
|
-
"https://localhost", "
|
461
|
+
"https://localhost", "mtls_certificates/client/embedding-service.crt", "mtls_certificates/client/embedding-service.key", 8443
|
462
462
|
)
|
463
463
|
print(f" ✓ Created mTLS client: {client.base_url}:{client.port}")
|
464
464
|
print(f" ✓ SSL enabled: {client.is_ssl_enabled()}")
|
@@ -476,7 +476,7 @@ async def demonstrate_security_modes():
|
|
476
476
|
print(" Use case: Enterprise security, role-based permissions")
|
477
477
|
try:
|
478
478
|
client = ClientFactory.create_mtls_roles_client(
|
479
|
-
"https://localhost", "
|
479
|
+
"https://localhost", "mtls_certificates/client/embedding-service.crt", "mtls_certificates/client/embedding-service.key", 8443,
|
480
480
|
roles=["admin", "user"], role_attributes={"department": "IT"}
|
481
481
|
)
|
482
482
|
print(f" ✓ Created mTLS + Roles client: {client.base_url}:{client.port}")
|
@@ -1,17 +1,9 @@
|
|
1
1
|
"""
|
2
|
-
Пример использования EmbeddingServiceAsyncClient со всеми режимами
|
2
|
+
Пример использования EmbeddingServiceAsyncClient со всеми режимами безопасности и ClientFactory.
|
3
3
|
|
4
4
|
Author: Vasiliy Zdanovskiy
|
5
5
|
email: vasilyvz@gmail.com
|
6
6
|
|
7
|
-
Этот пример демонстрирует все 6 режимов безопасности, поддерживаемых embed-client:
|
8
|
-
1. HTTP (обычный HTTP без аутентификации)
|
9
|
-
2. HTTP + Token (HTTP с аутентификацией по API ключу)
|
10
|
-
3. HTTPS (HTTPS с проверкой сертификатов сервера)
|
11
|
-
4. HTTPS + Token (HTTPS с сертификатами сервера + аутентификация)
|
12
|
-
5. mTLS (взаимный TLS с клиентскими и серверными сертификатами)
|
13
|
-
6. mTLS + Роли (mTLS с контролем доступа на основе ролей)
|
14
|
-
|
15
7
|
ИСПОЛЬЗОВАНИЕ:
|
16
8
|
# Базовое использование без аутентификации
|
17
9
|
python embed_client/example_async_usage_ru.py --base-url http://localhost --port 8001
|
@@ -48,18 +40,28 @@ email: vasilyvz@gmail.com
|
|
48
40
|
# 4. HTTPS + Token - HTTPS с сертификатами сервера + аутентификация
|
49
41
|
python embed_client/example_async_usage_ru.py --base-url https://localhost --port 9443 --auth-method jwt --jwt-secret secret --jwt-username admin
|
50
42
|
|
51
|
-
# 5. mTLS -
|
52
|
-
python embed_client/example_async_usage_ru.py --base-url https://localhost --port
|
43
|
+
# 5. mTLS - взаимная TLS с сертификатами клиента и сервера
|
44
|
+
python embed_client/example_async_usage_ru.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key
|
45
|
+
|
46
|
+
# 6. mTLS + Roles - mTLS с контролем доступа на основе ролей
|
47
|
+
python embed_client/example_async_usage_ru.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key --roles admin,user
|
48
|
+
|
49
|
+
ПРИМЕРЫ ФАБРИКИ КЛИЕНТОВ:
|
50
|
+
# Автоматическое определение режима безопасности
|
51
|
+
python embed_client/example_async_usage_ru.py --factory-mode auto --base-url https://localhost --port 9443 --auth-method api_key --api-key key
|
52
|
+
|
53
|
+
# Создание конкретного режима безопасности
|
54
|
+
python embed_client/example_async_usage_ru.py --factory-mode https_token --base-url https://localhost --port 9443 --auth-method basic --username user --password pass
|
53
55
|
|
54
|
-
#
|
55
|
-
python embed_client/example_async_usage_ru.py --base-url https://localhost --port
|
56
|
+
# mTLS с фабрикой
|
57
|
+
python embed_client/example_async_usage_ru.py --factory-mode mtls --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key
|
56
58
|
|
57
59
|
ПРИМЕРЫ SSL/TLS:
|
58
60
|
# HTTPS с отключенной проверкой SSL
|
59
61
|
python embed_client/example_async_usage_ru.py --base-url https://localhost --port 9443 --ssl-verify-mode CERT_NONE
|
60
62
|
|
61
63
|
# mTLS с пользовательским CA сертификатом
|
62
|
-
python embed_client/example_async_usage_ru.py --base-url https://localhost --port
|
64
|
+
python embed_client/example_async_usage_ru.py --base-url https://localhost --port 8443 --cert-file mtls_certificates/client/embedding-service.crt --key-file mtls_certificates/client/embedding-service.key --ca-cert-file mtls_certificates/ca/ca.crt
|
63
65
|
|
64
66
|
# HTTPS с пользовательскими настройками SSL
|
65
67
|
python embed_client/example_async_usage_ru.py --base-url https://localhost --port 9443 --ssl-verify-mode CERT_REQUIRED --ssl-check-hostname --ssl-check-expiry
|
@@ -75,7 +77,7 @@ email: vasilyvz@gmail.com
|
|
75
77
|
export EMBED_CLIENT_API_KEY=production_key
|
76
78
|
python embed_client/example_async_usage_ru.py
|
77
79
|
|
78
|
-
|
80
|
+
Пример явного закрытия сессии:
|
79
81
|
import asyncio
|
80
82
|
from embed_client.async_client import EmbeddingServiceAsyncClient
|
81
83
|
from embed_client.config import ClientConfig
|
@@ -101,29 +103,25 @@ email: vasilyvz@gmail.com
|
|
101
103
|
'https://localhost', 9443, 'api_key', api_key='key'
|
102
104
|
)
|
103
105
|
await client.close()
|
104
|
-
|
105
|
-
# Метод 5: Использование метода with_auth для динамической аутентификации
|
106
|
-
client = EmbeddingServiceAsyncClient('http://localhost', 8001)
|
107
|
-
client = client.with_auth('api_key', api_key='dynamic_key')
|
108
|
-
await client.close()
|
109
106
|
|
110
107
|
asyncio.run(main())
|
111
108
|
"""
|
112
109
|
|
113
|
-
import asyncio
|
114
|
-
import sys
|
115
|
-
import os
|
116
110
|
import argparse
|
111
|
+
import asyncio
|
117
112
|
import json
|
113
|
+
import os
|
114
|
+
import sys
|
118
115
|
from typing import Dict, Any, Optional, Union
|
119
116
|
|
120
|
-
from embed_client.async_client import EmbeddingServiceAsyncClient, EmbeddingServiceError,
|
117
|
+
from embed_client.async_client import EmbeddingServiceAsyncClient, EmbeddingServiceError, EmbeddingServiceConfigError
|
121
118
|
from embed_client.config import ClientConfig
|
122
119
|
from embed_client.client_factory import (
|
123
120
|
ClientFactory, SecurityMode, create_client, create_client_from_config,
|
124
121
|
create_client_from_env, detect_security_mode
|
125
122
|
)
|
126
123
|
|
124
|
+
|
127
125
|
def get_params():
|
128
126
|
"""Парсинг аргументов командной строки и переменных окружения для конфигурации клиента."""
|
129
127
|
parser = argparse.ArgumentParser(description="Пример Embedding Service Async Client - Все режимы безопасности")
|
@@ -149,33 +147,26 @@ def get_params():
|
|
149
147
|
parser.add_argument("--cert-file", help="Файл сертификата для аутентификации certificate")
|
150
148
|
parser.add_argument("--key-file", help="Файл ключа для аутентификации certificate")
|
151
149
|
|
152
|
-
# SSL/TLS
|
150
|
+
# Параметры SSL/TLS
|
153
151
|
parser.add_argument("--ssl-verify-mode", choices=["CERT_NONE", "CERT_OPTIONAL", "CERT_REQUIRED"],
|
154
|
-
default="CERT_REQUIRED", help="Режим проверки SSL
|
152
|
+
default="CERT_REQUIRED", help="Режим проверки SSL сертификатов")
|
155
153
|
parser.add_argument("--ssl-check-hostname", action="store_true", default=True,
|
156
154
|
help="Включить проверку имени хоста SSL")
|
157
155
|
parser.add_argument("--ssl-check-expiry", action="store_true", default=True,
|
158
|
-
help="Включить проверку срока действия SSL
|
156
|
+
help="Включить проверку срока действия SSL сертификатов")
|
159
157
|
parser.add_argument("--ca-cert-file", help="Файл CA сертификата для проверки SSL")
|
160
158
|
|
161
|
-
# Контроль доступа на основе ролей (для mTLS +
|
162
|
-
parser.add_argument("--roles", help="Список ролей через запятую для режима mTLS +
|
163
|
-
parser.add_argument("--role-attributes", help="JSON строка атрибутов ролей для режима mTLS +
|
159
|
+
# Контроль доступа на основе ролей (для mTLS + Roles)
|
160
|
+
parser.add_argument("--roles", help="Список ролей через запятую для режима mTLS + Roles")
|
161
|
+
parser.add_argument("--role-attributes", help="JSON строка атрибутов ролей для режима mTLS + Roles")
|
164
162
|
|
165
163
|
# Дополнительные параметры
|
166
164
|
parser.add_argument("--timeout", type=float, default=30.0, help="Таймаут запроса в секундах")
|
167
|
-
parser.add_argument("--demo-mode", action="store_true", help="
|
165
|
+
parser.add_argument("--demo-mode", action="store_true", help="Запуск в демо режиме (показать все режимы безопасности)")
|
168
166
|
|
169
167
|
args = parser.parse_args()
|
170
168
|
|
171
|
-
#
|
172
|
-
args.demo_mode = args.demo_mode
|
173
|
-
|
174
|
-
# Если запрошен демо режим, возвращаем args напрямую
|
175
|
-
if args.demo_mode:
|
176
|
-
return args
|
177
|
-
|
178
|
-
# Если указан файл конфигурации, загружаем его
|
169
|
+
# Если предоставлен файл конфигурации, загружаем его
|
179
170
|
if args.config:
|
180
171
|
try:
|
181
172
|
config = ClientConfig()
|
@@ -190,7 +181,7 @@ def get_params():
|
|
190
181
|
port = args.port or int(os.environ.get("EMBED_CLIENT_PORT", "8001"))
|
191
182
|
|
192
183
|
if not base_url or not port:
|
193
|
-
print("Ошибка: base_url и port должны быть
|
184
|
+
print("Ошибка: base_url и port должны быть предоставлены через аргументы --base-url/--port или переменные окружения EMBED_CLIENT_BASE_URL/EMBED_CLIENT_PORT.")
|
194
185
|
sys.exit(1)
|
195
186
|
|
196
187
|
# Строим словарь конфигурации
|
@@ -213,7 +204,7 @@ def get_params():
|
|
213
204
|
if api_key:
|
214
205
|
config_dict["auth"]["api_keys"] = {"user": api_key}
|
215
206
|
else:
|
216
|
-
print("Предупреждение: API ключ не
|
207
|
+
print("Предупреждение: API ключ не предоставлен для аутентификации api_key")
|
217
208
|
|
218
209
|
elif args.auth_method == "jwt":
|
219
210
|
jwt_secret = args.jwt_secret or os.environ.get("EMBED_CLIENT_JWT_SECRET")
|
@@ -227,7 +218,7 @@ def get_params():
|
|
227
218
|
"password": jwt_password
|
228
219
|
}
|
229
220
|
else:
|
230
|
-
print("Предупреждение: JWT
|
221
|
+
print("Предупреждение: JWT учетные данные не полностью предоставлены")
|
231
222
|
|
232
223
|
elif args.auth_method == "basic":
|
233
224
|
username = args.username or os.environ.get("EMBED_CLIENT_USERNAME")
|
@@ -239,7 +230,7 @@ def get_params():
|
|
239
230
|
"password": password
|
240
231
|
}
|
241
232
|
else:
|
242
|
-
print("Предупреждение:
|
233
|
+
print("Предупреждение: Учетные данные базовой аутентификации не полностью предоставлены")
|
243
234
|
|
244
235
|
elif args.auth_method == "certificate":
|
245
236
|
cert_file = args.cert_file or os.environ.get("EMBED_CLIENT_CERT_FILE")
|
@@ -251,9 +242,9 @@ def get_params():
|
|
251
242
|
"key_file": key_file
|
252
243
|
}
|
253
244
|
else:
|
254
|
-
print("Предупреждение:
|
245
|
+
print("Предупреждение: Файлы сертификатов не полностью предоставлены")
|
255
246
|
|
256
|
-
# Добавляем SSL
|
247
|
+
# Добавляем конфигурацию SSL если используется HTTPS или предоставлены SSL параметры
|
257
248
|
if base_url.startswith("https://") or args.ssl_verify_mode != "CERT_REQUIRED" or args.ca_cert_file:
|
258
249
|
config_dict["ssl"] = {
|
259
250
|
"enabled": True,
|
@@ -271,7 +262,7 @@ def get_params():
|
|
271
262
|
if args.key_file:
|
272
263
|
config_dict["ssl"]["key_file"] = args.key_file
|
273
264
|
|
274
|
-
# Добавляем контроль доступа на основе ролей для mTLS +
|
265
|
+
# Добавляем контроль доступа на основе ролей для mTLS + Roles
|
275
266
|
if args.roles:
|
276
267
|
roles = [role.strip() for role in args.roles.split(",")]
|
277
268
|
config_dict["roles"] = roles
|
@@ -285,8 +276,9 @@ def get_params():
|
|
285
276
|
|
286
277
|
return config_dict
|
287
278
|
|
288
|
-
|
289
|
-
|
279
|
+
|
280
|
+
def extract_embeddings(result):
|
281
|
+
"""Извлечение эмбеддингов из ответа API, поддерживая старый и новый форматы."""
|
290
282
|
# Обработка прямого поля embeddings (совместимость со старым форматом)
|
291
283
|
if "embeddings" in result:
|
292
284
|
return result["embeddings"]
|
@@ -320,52 +312,159 @@ def extract_vectors(result):
|
|
320
312
|
|
321
313
|
raise ValueError(f"Не удается извлечь эмбеддинги из ответа: {result}")
|
322
314
|
|
315
|
+
|
323
316
|
async def run_client_examples(client):
|
324
317
|
"""Запуск примеров операций с клиентом."""
|
325
318
|
# Проверка здоровья
|
326
319
|
try:
|
327
320
|
health = await client.health()
|
328
321
|
print("Состояние сервиса:", health)
|
329
|
-
except EmbeddingServiceConnectionError as e:
|
330
|
-
print(f"[Ошибка подключения] {e}")
|
331
|
-
return
|
332
|
-
except EmbeddingServiceHTTPError as e:
|
333
|
-
print(f"[HTTP ошибка] {e.status}: {e.message}")
|
334
|
-
return
|
335
322
|
except EmbeddingServiceError as e:
|
336
|
-
print("
|
323
|
+
print(f"Ошибка при проверке здоровья: {e}")
|
337
324
|
return
|
338
|
-
|
339
|
-
#
|
340
|
-
texts = ["привет мир", "тестовый эмбеддинг"]
|
325
|
+
|
326
|
+
# Получение схемы OpenAPI
|
341
327
|
try:
|
342
|
-
|
343
|
-
print("
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
tokens = client.extract_tokens(result)
|
359
|
-
print("Токены:", tokens)
|
360
|
-
|
361
|
-
# Извлечение BM25 токенов
|
362
|
-
bm25_tokens = client.extract_bm25_tokens(result)
|
363
|
-
print("BM25 токены:", bm25_tokens)
|
328
|
+
schema = await client.get_openapi_schema()
|
329
|
+
print(f"Версия схемы OpenAPI: {schema.get('info', {}).get('version', 'неизвестно')}")
|
330
|
+
except EmbeddingServiceError as e:
|
331
|
+
print(f"Ошибка получения схемы OpenAPI: {e}")
|
332
|
+
|
333
|
+
# Получение доступных команд
|
334
|
+
try:
|
335
|
+
commands = await client.get_commands()
|
336
|
+
print(f"Доступные команды: {commands}")
|
337
|
+
except EmbeddingServiceError as e:
|
338
|
+
print(f"Ошибка получения команд: {e}")
|
339
|
+
|
340
|
+
# Тест генерации эмбеддингов
|
341
|
+
try:
|
342
|
+
texts = ["Привет, мир!", "Это тестовое предложение.", "Сервис эмбеддингов работает!"]
|
343
|
+
result = await client.cmd("embed", {"texts": texts})
|
364
344
|
|
345
|
+
if result.get("success"):
|
346
|
+
embeddings = extract_embeddings(result)
|
347
|
+
print(f"Сгенерировано {len(embeddings)} эмбеддингов")
|
348
|
+
print(f"Размерность первого эмбеддинга: {len(embeddings[0]) if embeddings else 0}")
|
349
|
+
else:
|
350
|
+
print(f"Генерация эмбеддингов не удалась: {result.get('error', 'Неизвестная ошибка')}")
|
365
351
|
except EmbeddingServiceError as e:
|
366
|
-
print(f"
|
367
|
-
|
368
|
-
|
352
|
+
print(f"Ошибка при генерации эмбеддингов: {e}")
|
353
|
+
|
354
|
+
|
355
|
+
async def demonstrate_security_modes():
|
356
|
+
"""Демонстрация всех режимов безопасности с использованием ClientFactory."""
|
357
|
+
print("=== Демонстрация режимов безопасности ===")
|
358
|
+
|
359
|
+
# 1. HTTP режим
|
360
|
+
print("\n1. HTTP режим (без аутентификации, без SSL):")
|
361
|
+
try:
|
362
|
+
client = ClientFactory.create_http_client("http://localhost", 8001)
|
363
|
+
print(f" Создан HTTP клиент: {client.base_url}:{client.port}")
|
364
|
+
print(f" SSL включен: {client.is_ssl_enabled()}")
|
365
|
+
print(f" Аутентифицирован: {client.is_authenticated()}")
|
366
|
+
await client.close()
|
367
|
+
except Exception as e:
|
368
|
+
print(f" Ошибка: {e}")
|
369
|
+
|
370
|
+
# 2. HTTP + Token режим
|
371
|
+
print("\n2. HTTP + Token режим (HTTP с API ключом):")
|
372
|
+
try:
|
373
|
+
client = ClientFactory.create_http_token_client(
|
374
|
+
"http://localhost", 8001, "api_key", api_key="demo_key"
|
375
|
+
)
|
376
|
+
print(f" Создан HTTP + Token клиент: {client.base_url}:{client.port}")
|
377
|
+
print(f" SSL включен: {client.is_ssl_enabled()}")
|
378
|
+
print(f" Аутентифицирован: {client.is_authenticated()}")
|
379
|
+
print(f" Метод аутентификации: {client.get_auth_method()}")
|
380
|
+
await client.close()
|
381
|
+
except Exception as e:
|
382
|
+
print(f" Ошибка: {e}")
|
383
|
+
|
384
|
+
# 3. HTTPS режим
|
385
|
+
print("\n3. HTTPS режим (HTTPS с сертификатами сервера):")
|
386
|
+
try:
|
387
|
+
client = ClientFactory.create_https_client("https://localhost", 9443)
|
388
|
+
print(f" Создан HTTPS клиент: {client.base_url}:{client.port}")
|
389
|
+
print(f" SSL включен: {client.is_ssl_enabled()}")
|
390
|
+
print(f" Аутентифицирован: {client.is_authenticated()}")
|
391
|
+
if client.is_ssl_enabled():
|
392
|
+
ssl_config = client.get_ssl_config()
|
393
|
+
print(f" SSL конфигурация: {ssl_config}")
|
394
|
+
await client.close()
|
395
|
+
except Exception as e:
|
396
|
+
print(f" Ошибка: {e}")
|
397
|
+
|
398
|
+
# 4. HTTPS + Token режим
|
399
|
+
print("\n4. HTTPS + Token режим (HTTPS с сертификатами сервера + аутентификация):")
|
400
|
+
try:
|
401
|
+
client = ClientFactory.create_https_token_client(
|
402
|
+
"https://localhost", 9443, "basic", username="admin", password="secret"
|
403
|
+
)
|
404
|
+
print(f" Создан HTTPS + Token клиент: {client.base_url}:{client.port}")
|
405
|
+
print(f" SSL включен: {client.is_ssl_enabled()}")
|
406
|
+
print(f" Аутентифицирован: {client.is_authenticated()}")
|
407
|
+
print(f" Метод аутентификации: {client.get_auth_method()}")
|
408
|
+
await client.close()
|
409
|
+
except Exception as e:
|
410
|
+
print(f" Ошибка: {e}")
|
411
|
+
|
412
|
+
# 5. mTLS режим
|
413
|
+
print("\n5. mTLS режим (взаимная TLS с сертификатами клиента и сервера):")
|
414
|
+
try:
|
415
|
+
client = ClientFactory.create_mtls_client(
|
416
|
+
"https://localhost", "mtls_certificates/client/embedding-service.crt", "mtls_certificates/client/embedding-service.key", 8443
|
417
|
+
)
|
418
|
+
print(f" Создан mTLS клиент: {client.base_url}:{client.port}")
|
419
|
+
print(f" SSL включен: {client.is_ssl_enabled()}")
|
420
|
+
print(f" mTLS включен: {client.is_mtls_enabled()}")
|
421
|
+
print(f" Аутентифицирован: {client.is_authenticated()}")
|
422
|
+
await client.close()
|
423
|
+
except Exception as e:
|
424
|
+
print(f" Ошибка: {e}")
|
425
|
+
|
426
|
+
# 6. mTLS + Roles режим
|
427
|
+
print("\n6. mTLS + Roles режим (mTLS с контролем доступа на основе ролей):")
|
428
|
+
try:
|
429
|
+
client = ClientFactory.create_mtls_roles_client(
|
430
|
+
"https://localhost", "client_cert.pem", "client_key.pem", 9443,
|
431
|
+
roles=["admin", "user"], role_attributes={"department": "IT"}
|
432
|
+
)
|
433
|
+
print(f" Создан mTLS + Roles клиент: {client.base_url}:{client.port}")
|
434
|
+
print(f" SSL включен: {client.is_ssl_enabled()}")
|
435
|
+
print(f" mTLS включен: {client.is_mtls_enabled()}")
|
436
|
+
print(f" Аутентифицирован: {client.is_authenticated()}")
|
437
|
+
await client.close()
|
438
|
+
except Exception as e:
|
439
|
+
print(f" Ошибка: {e}")
|
440
|
+
|
441
|
+
|
442
|
+
async def demonstrate_automatic_detection():
|
443
|
+
"""Демонстрация автоматического определения режима безопасности."""
|
444
|
+
print("\n=== Автоматическое определение режима безопасности ===")
|
445
|
+
|
446
|
+
test_cases = [
|
447
|
+
("http://localhost", None, None, None, None, "HTTP"),
|
448
|
+
("http://localhost", "api_key", None, None, None, "HTTP + Token"),
|
449
|
+
("https://localhost", None, None, None, None, "HTTPS"),
|
450
|
+
("https://localhost", "api_key", None, None, None, "HTTPS + Token"),
|
451
|
+
("https://localhost", None, None, "cert.pem", "key.pem", "mTLS"),
|
452
|
+
("https://localhost", None, None, "cert.pem", "key.pem", "mTLS + Roles", {"roles": ["admin"]}),
|
453
|
+
]
|
454
|
+
|
455
|
+
for case in test_cases:
|
456
|
+
if len(case) == 6:
|
457
|
+
base_url, auth_method, ssl_enabled, cert_file, key_file, expected = case
|
458
|
+
kwargs = {}
|
459
|
+
else:
|
460
|
+
base_url, auth_method, ssl_enabled, cert_file, key_file, expected, kwargs = case
|
461
|
+
|
462
|
+
try:
|
463
|
+
mode = detect_security_mode(base_url, auth_method, ssl_enabled, cert_file, key_file, **kwargs)
|
464
|
+
print(f" {base_url} + {auth_method or 'none'} + {cert_file or 'no cert'} -> {mode} ({expected})")
|
465
|
+
except Exception as e:
|
466
|
+
print(f" Ошибка определения режима для {base_url}: {e}")
|
467
|
+
|
369
468
|
|
370
469
|
async def main():
|
371
470
|
try:
|
@@ -373,17 +472,16 @@ async def main():
|
|
373
472
|
|
374
473
|
# Проверяем, запрошен ли демо режим
|
375
474
|
if hasattr(config, 'demo_mode') and config.demo_mode:
|
376
|
-
|
377
|
-
|
378
|
-
print("Примечание: Эти примеры создают конфигурации клиентов, но не подключаются к реальным серверам.")
|
475
|
+
await demonstrate_security_modes()
|
476
|
+
await demonstrate_automatic_detection()
|
379
477
|
return
|
380
478
|
|
381
479
|
# Создаем клиент на основе режима фабрики
|
382
480
|
if isinstance(config, ClientConfig):
|
383
|
-
#
|
481
|
+
# Использование объекта конфигурации
|
384
482
|
client = EmbeddingServiceAsyncClient.from_config(config)
|
385
483
|
else:
|
386
|
-
#
|
484
|
+
# Использование словаря конфигурации
|
387
485
|
factory_mode = getattr(config, 'factory_mode', 'auto')
|
388
486
|
|
389
487
|
if factory_mode == "auto":
|
@@ -440,24 +538,18 @@ async def main():
|
|
440
538
|
print(f" Поддерживаемые SSL протоколы: {protocols}")
|
441
539
|
print()
|
442
540
|
|
443
|
-
# Пример явного открытия/закрытия
|
541
|
+
# Пример явного открытия/закрытия
|
444
542
|
print("Пример явного открытия/закрытия сессии:")
|
445
543
|
await client.close()
|
446
544
|
print("Сессия закрыта явно (пример ручного закрытия).\n")
|
447
545
|
|
448
|
-
#
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
await run_client_examples(client)
|
456
|
-
|
457
|
-
except EmbeddingServiceError as e:
|
458
|
-
print(f"[Ошибка EmbeddingService] {e}")
|
459
|
-
except Exception as e:
|
460
|
-
print(f"[Неожиданная ошибка] {e}")
|
546
|
+
# Использование контекстного менеджера
|
547
|
+
if isinstance(config, ClientConfig):
|
548
|
+
async with EmbeddingServiceAsyncClient.from_config(config) as client:
|
549
|
+
await run_client_examples(client)
|
550
|
+
else:
|
551
|
+
async with EmbeddingServiceAsyncClient(config_dict=config) as client:
|
552
|
+
await run_client_examples(client)
|
461
553
|
|
462
554
|
except EmbeddingServiceConfigError as e:
|
463
555
|
print(f"Ошибка конфигурации: {e}")
|
@@ -467,4 +559,4 @@ async def main():
|
|
467
559
|
sys.exit(1)
|
468
560
|
|
469
561
|
if __name__ == "__main__":
|
470
|
-
asyncio.run(main())
|
562
|
+
asyncio.run(main())
|
embed_client/ssl_manager.py
CHANGED
@@ -17,16 +17,10 @@ from typing import Any, Dict, List, Optional, Union
|
|
17
17
|
|
18
18
|
# Try to import mcp_security_framework components
|
19
19
|
try:
|
20
|
-
from mcp_security_framework
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
from mcp_security_framework.utils.cert_utils import (
|
25
|
-
extract_certificate_info,
|
26
|
-
get_certificate_expiry,
|
27
|
-
is_certificate_self_signed,
|
28
|
-
parse_certificate,
|
29
|
-
validate_certificate_chain
|
20
|
+
from mcp_security_framework import (
|
21
|
+
SSLConfig,
|
22
|
+
CertificateInfo,
|
23
|
+
SecurityManager
|
30
24
|
)
|
31
25
|
SECURITY_FRAMEWORK_AVAILABLE = True
|
32
26
|
except ImportError:
|
@@ -84,18 +78,33 @@ class ClientSSLManager:
|
|
84
78
|
"""Initialize mcp_security_framework components."""
|
85
79
|
try:
|
86
80
|
# Create SSL config
|
81
|
+
ssl_config_dict = self.config.get("ssl", {})
|
87
82
|
ssl_config = SSLConfig(
|
88
|
-
enabled=
|
89
|
-
cert_file=
|
90
|
-
key_file=
|
91
|
-
ca_cert_file=
|
92
|
-
verify_mode=
|
93
|
-
check_hostname=
|
94
|
-
check_expiry=
|
83
|
+
enabled=ssl_config_dict.get("enabled", False),
|
84
|
+
cert_file=ssl_config_dict.get("cert_file") if ssl_config_dict.get("cert_file") and os.path.exists(ssl_config_dict.get("cert_file")) else None,
|
85
|
+
key_file=ssl_config_dict.get("key_file") if ssl_config_dict.get("key_file") and os.path.exists(ssl_config_dict.get("key_file")) else None,
|
86
|
+
ca_cert_file=ssl_config_dict.get("ca_cert_file") if ssl_config_dict.get("ca_cert_file") and os.path.exists(ssl_config_dict.get("ca_cert_file")) else None,
|
87
|
+
verify_mode=ssl_config_dict.get("verify_mode", "CERT_REQUIRED"),
|
88
|
+
check_hostname=ssl_config_dict.get("check_hostname", True),
|
89
|
+
check_expiry=ssl_config_dict.get("check_expiry", True)
|
90
|
+
)
|
91
|
+
|
92
|
+
# Create permission config (required by SecurityManager)
|
93
|
+
from mcp_security_framework import PermissionConfig
|
94
|
+
permission_config = PermissionConfig(
|
95
|
+
enabled=False,
|
96
|
+
roles_file="configs/roles.json"
|
97
|
+
)
|
98
|
+
|
99
|
+
# Create security config
|
100
|
+
from mcp_security_framework import SecurityConfig
|
101
|
+
security_config = SecurityConfig(
|
102
|
+
ssl=ssl_config,
|
103
|
+
permissions=permission_config
|
95
104
|
)
|
96
105
|
|
97
106
|
# Initialize managers
|
98
|
-
self.ssl_manager =
|
107
|
+
self.ssl_manager = SecurityManager(security_config)
|
99
108
|
|
100
109
|
self.logger.info("Security framework SSL/TLS components initialized successfully")
|
101
110
|
|
@@ -1,17 +1,44 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: embed-client
|
3
|
-
Version: 3.1.0.
|
3
|
+
Version: 3.1.0.2
|
4
4
|
Summary: Async client for Embedding Service API with comprehensive authentication, SSL/TLS, and mTLS support
|
5
5
|
Author-email: Vasiliy Zdanovskiy <vasilyvz@gmail.com>
|
6
|
+
License-Expression: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/vasilyvz/embed-client
|
8
|
+
Project-URL: Repository, https://github.com/vasilyvz/embed-client
|
9
|
+
Project-URL: Documentation, https://github.com/vasilyvz/embed-client#readme
|
10
|
+
Project-URL: Bug Tracker, https://github.com/vasilyvz/embed-client/issues
|
11
|
+
Keywords: embedding,async,client,api,authentication,ssl,tls,mtls
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
13
|
+
Classifier: Intended Audience :: Developers
|
14
|
+
Classifier: Operating System :: OS Independent
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
22
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
23
|
+
Classifier: Topic :: Security
|
24
|
+
Classifier: Topic :: System :: Networking
|
6
25
|
Requires-Python: >=3.8
|
7
26
|
Description-Content-Type: text/markdown
|
8
|
-
|
27
|
+
License-File: LICENSE
|
28
|
+
Requires-Dist: aiohttp>=3.8.0
|
9
29
|
Requires-Dist: PyJWT>=2.0.0
|
10
30
|
Requires-Dist: cryptography>=3.0.0
|
11
31
|
Requires-Dist: pydantic>=2.0.0
|
12
32
|
Provides-Extra: test
|
13
33
|
Requires-Dist: pytest; extra == "test"
|
14
34
|
Requires-Dist: pytest-asyncio; extra == "test"
|
35
|
+
Provides-Extra: dev
|
36
|
+
Requires-Dist: pytest; extra == "dev"
|
37
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
38
|
+
Requires-Dist: black; extra == "dev"
|
39
|
+
Requires-Dist: flake8; extra == "dev"
|
40
|
+
Requires-Dist: mypy; extra == "dev"
|
41
|
+
Dynamic: license-file
|
15
42
|
|
16
43
|
# embed-client
|
17
44
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
embed_client/__init__.py,sha256=12iI-f075Gmv8IyQ9L7-SH8eNND4qpF6Fjqz1-P4d1Y,535
|
2
|
+
embed_client/async_client.py,sha256=Zf08g-i_2ylDj4tt9E1TO9swi-zcozFDr4mJdlfiGSI,40222
|
3
|
+
embed_client/auth.py,sha256=MMk5XqFIY5htf3Bx0JA_8mJaAiLslpLUIVUaiO84XBw,18310
|
4
|
+
embed_client/auth_examples.py,sha256=QX_QWaaeyBAqvSs9uOP1ZVdAe72gJ91e8AP1e7R-yzQ,7361
|
5
|
+
embed_client/client_factory.py,sha256=-W2nvzMuyyQNu3_nNmALKHT9uL0Z9nMYTxyQ4bgVOFQ,14279
|
6
|
+
embed_client/client_factory_examples.py,sha256=7A2JWkyGEJeOB7p84ijklh8rTyeRUeg2lCIPTfAtahc,11823
|
7
|
+
embed_client/config.py,sha256=CzVmduJjuN82uiaxDyMyXJLS2tNOOlDBGwcO76SWjXg,19922
|
8
|
+
embed_client/config_examples.py,sha256=9aEF8X4h9nbfSV_CORZLrlWM5KEwuwqW6AcQDPguQ7g,6175
|
9
|
+
embed_client/example_async_usage.py,sha256=dndf79MIqZaHvWzbtKrZVwU7G4a5yNL1JPMnMBEdLBg,29803
|
10
|
+
embed_client/example_async_usage_ru.py,sha256=3HeP5YoyGd49dRlxNC-2TAh_GbwSW4jJmoLXMpMIfFs,29899
|
11
|
+
embed_client/ssl_examples.py,sha256=22lTGhK2bqGJ44uUCpc7v2egY4AP3_ar8RMaTb4KBwU,9346
|
12
|
+
embed_client/ssl_manager.py,sha256=Ts6-hKxUUNHdW3yldnoykaDblxWtGbIwKdnzPw__30U,17247
|
13
|
+
embed_client-3.1.0.2.dist-info/licenses/LICENSE,sha256=6KdtUcTwmTRbJrAmYjVn7e6S-V42ubeDJ-AiVEzZ510,1075
|
14
|
+
embed_client-3.1.0.2.dist-info/METADATA,sha256=AMYMkJVnthnj8yD6k4My247r4MT_xQRH10-14dMr3C4,8633
|
15
|
+
embed_client-3.1.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
embed_client-3.1.0.2.dist-info/top_level.txt,sha256=uG00A4d9o9DFrhiN7goObpeig72Pniby0E7UpDRgyXY,13
|
17
|
+
embed_client-3.1.0.2.dist-info/RECORD,,
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Vasiliy Zdanovskiy
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -1,16 +0,0 @@
|
|
1
|
-
embed_client/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
2
|
-
embed_client/async_client.py,sha256=Zf08g-i_2ylDj4tt9E1TO9swi-zcozFDr4mJdlfiGSI,40222
|
3
|
-
embed_client/auth.py,sha256=fw5Lc40GOTuKf4eOeAP6elSRKj6tqCfklbgTCOX1zWU,18317
|
4
|
-
embed_client/auth_examples.py,sha256=QX_QWaaeyBAqvSs9uOP1ZVdAe72gJ91e8AP1e7R-yzQ,7361
|
5
|
-
embed_client/client_factory.py,sha256=-W2nvzMuyyQNu3_nNmALKHT9uL0Z9nMYTxyQ4bgVOFQ,14279
|
6
|
-
embed_client/client_factory_examples.py,sha256=7A2JWkyGEJeOB7p84ijklh8rTyeRUeg2lCIPTfAtahc,11823
|
7
|
-
embed_client/config.py,sha256=CzVmduJjuN82uiaxDyMyXJLS2tNOOlDBGwcO76SWjXg,19922
|
8
|
-
embed_client/config_examples.py,sha256=9aEF8X4h9nbfSV_CORZLrlWM5KEwuwqW6AcQDPguQ7g,6175
|
9
|
-
embed_client/example_async_usage.py,sha256=hBlFul7aZmcm9VTHC8EsbViIs5TotEJtGAW_tj1_yks,29418
|
10
|
-
embed_client/example_async_usage_ru.py,sha256=u8yGpA8EQSOzSzwKmIl-HBuxL1A-FFqoxW75h7vy4ak,25065
|
11
|
-
embed_client/ssl_examples.py,sha256=22lTGhK2bqGJ44uUCpc7v2egY4AP3_ar8RMaTb4KBwU,9346
|
12
|
-
embed_client/ssl_manager.py,sha256=_Z9nq_dquGW-u0lMp2d-ZwyqxuSMKJJx4NUqczY-wsE,16839
|
13
|
-
embed_client-3.1.0.0.dist-info/METADATA,sha256=PLg0A10U0Lhl1veBD-DKVS13ePLC58AwqBMmHLh3EGU,7347
|
14
|
-
embed_client-3.1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
15
|
-
embed_client-3.1.0.0.dist-info/top_level.txt,sha256=uG00A4d9o9DFrhiN7goObpeig72Pniby0E7UpDRgyXY,13
|
16
|
-
embed_client-3.1.0.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|