embed-client 1.0.1.1__py3-none-any.whl → 3.1.0.0__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.
@@ -0,0 +1,248 @@
1
+ """
2
+ Authentication examples for embed-client.
3
+
4
+ This module provides examples of how to use the authentication system
5
+ with different authentication methods and configurations.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ from typing import Dict, Any
12
+ from embed_client.auth import ClientAuthManager, create_auth_manager, create_auth_headers
13
+
14
+
15
+ def get_api_key_auth_example() -> Dict[str, Any]:
16
+ """
17
+ Get example configuration for API key authentication.
18
+
19
+ Returns:
20
+ Configuration dictionary for API key authentication
21
+ """
22
+ return {
23
+ "auth": {
24
+ "method": "api_key",
25
+ "api_keys": {
26
+ "admin": "admin_key_123",
27
+ "user": "user_key_456",
28
+ "readonly": "readonly_key_789"
29
+ }
30
+ }
31
+ }
32
+
33
+
34
+ def get_jwt_auth_example() -> Dict[str, Any]:
35
+ """
36
+ Get example configuration for JWT authentication.
37
+
38
+ Returns:
39
+ Configuration dictionary for JWT authentication
40
+ """
41
+ return {
42
+ "auth": {
43
+ "method": "jwt",
44
+ "jwt": {
45
+ "username": "testuser",
46
+ "password": "testpass",
47
+ "secret": "jwt_secret_key_123",
48
+ "expiry_hours": 24
49
+ }
50
+ }
51
+ }
52
+
53
+
54
+ def get_basic_auth_example() -> Dict[str, Any]:
55
+ """
56
+ Get example configuration for basic authentication.
57
+
58
+ Returns:
59
+ Configuration dictionary for basic authentication
60
+ """
61
+ return {
62
+ "auth": {
63
+ "method": "basic",
64
+ "basic": {
65
+ "username": "testuser",
66
+ "password": "testpass"
67
+ }
68
+ }
69
+ }
70
+
71
+
72
+ def get_certificate_auth_example() -> Dict[str, Any]:
73
+ """
74
+ Get example configuration for certificate authentication.
75
+
76
+ Returns:
77
+ Configuration dictionary for certificate authentication
78
+ """
79
+ return {
80
+ "auth": {
81
+ "method": "certificate",
82
+ "certificate": {
83
+ "enabled": True,
84
+ "cert_file": "certs/client.crt",
85
+ "key_file": "keys/client.key",
86
+ "ca_cert_file": "certs/ca.crt"
87
+ }
88
+ }
89
+ }
90
+
91
+
92
+ def demo_api_key_authentication():
93
+ """Demonstrate API key authentication."""
94
+ print("=== API Key Authentication Demo ===")
95
+
96
+ config = get_api_key_auth_example()
97
+ auth_manager = create_auth_manager(config)
98
+
99
+ # Test authentication
100
+ result = auth_manager.authenticate_api_key("admin_key_123")
101
+ print(f"Authentication result: {result.success}")
102
+ print(f"User ID: {result.user_id}")
103
+
104
+ # Get headers for request
105
+ headers = auth_manager.get_auth_headers("api_key", api_key="admin_key_123")
106
+ print(f"Request headers: {headers}")
107
+
108
+ # Validate configuration
109
+ errors = auth_manager.validate_auth_config()
110
+ print(f"Configuration errors: {errors}")
111
+
112
+
113
+ def demo_jwt_authentication():
114
+ """Demonstrate JWT authentication."""
115
+ print("\n=== JWT Authentication Demo ===")
116
+
117
+ config = get_jwt_auth_example()
118
+ auth_manager = create_auth_manager(config)
119
+
120
+ try:
121
+ # Create JWT token
122
+ token = auth_manager.create_jwt_token("testuser", ["admin", "user"])
123
+ print(f"Created JWT token: {token[:50]}...")
124
+
125
+ # Validate token
126
+ result = auth_manager.authenticate_jwt(token)
127
+ print(f"Token validation: {result.success}")
128
+ print(f"User ID: {result.user_id}")
129
+ print(f"Roles: {result.roles}")
130
+
131
+ # Get headers for request
132
+ headers = auth_manager.get_auth_headers("jwt", token=token)
133
+ print(f"Request headers: {headers}")
134
+
135
+ except Exception as e:
136
+ print(f"JWT authentication failed: {e}")
137
+
138
+
139
+ def demo_basic_authentication():
140
+ """Demonstrate basic authentication."""
141
+ print("\n=== Basic Authentication Demo ===")
142
+
143
+ config = get_basic_auth_example()
144
+ auth_manager = create_auth_manager(config)
145
+
146
+ # Test authentication
147
+ result = auth_manager.authenticate_basic("testuser", "testpass")
148
+ print(f"Authentication result: {result.success}")
149
+ print(f"User ID: {result.user_id}")
150
+
151
+ # Get headers for request
152
+ headers = auth_manager.get_auth_headers("basic", username="testuser", password="testpass")
153
+ print(f"Request headers: {headers}")
154
+
155
+
156
+ def demo_certificate_authentication():
157
+ """Demonstrate certificate authentication."""
158
+ print("\n=== Certificate Authentication Demo ===")
159
+
160
+ config = get_certificate_auth_example()
161
+ auth_manager = create_auth_manager(config)
162
+
163
+ # Test authentication (will fail without real certificates)
164
+ result = auth_manager.authenticate_certificate("certs/client.crt", "keys/client.key")
165
+ print(f"Authentication result: {result.success}")
166
+ print(f"User ID: {result.user_id}")
167
+ print(f"Error: {result.error}")
168
+
169
+ # Get headers for request (should be empty for certificate auth)
170
+ headers = auth_manager.get_auth_headers("certificate")
171
+ print(f"Request headers: {headers}")
172
+
173
+
174
+ def demo_auth_headers_creation():
175
+ """Demonstrate creating authentication headers."""
176
+ print("\n=== Authentication Headers Demo ===")
177
+
178
+ # API Key headers
179
+ headers = create_auth_headers("api_key", api_key="test_key")
180
+ print(f"API Key headers: {headers}")
181
+
182
+ # JWT headers
183
+ headers = create_auth_headers("jwt", token="test_token")
184
+ print(f"JWT headers: {headers}")
185
+
186
+ # Basic auth headers
187
+ headers = create_auth_headers("basic", username="user", password="pass")
188
+ print(f"Basic auth headers: {headers}")
189
+
190
+ # Certificate headers (should be empty)
191
+ headers = create_auth_headers("certificate")
192
+ print(f"Certificate headers: {headers}")
193
+
194
+
195
+ def demo_configuration_validation():
196
+ """Demonstrate configuration validation."""
197
+ print("\n=== Configuration Validation Demo ===")
198
+
199
+ # Valid configuration
200
+ valid_config = get_api_key_auth_example()
201
+ auth_manager = create_auth_manager(valid_config)
202
+ errors = auth_manager.validate_auth_config()
203
+ print(f"Valid config errors: {errors}")
204
+
205
+ # Invalid configuration
206
+ invalid_config = {
207
+ "auth": {
208
+ "method": "api_key",
209
+ "api_keys": {} # Empty API keys
210
+ }
211
+ }
212
+ auth_manager = create_auth_manager(invalid_config)
213
+ errors = auth_manager.validate_auth_config()
214
+ print(f"Invalid config errors: {errors}")
215
+
216
+
217
+ def demo_supported_methods():
218
+ """Demonstrate getting supported authentication methods."""
219
+ print("\n=== Supported Methods Demo ===")
220
+
221
+ config = {"auth": {"method": "api_key"}}
222
+ auth_manager = create_auth_manager(config)
223
+
224
+ methods = auth_manager.get_supported_methods()
225
+ print(f"Supported authentication methods: {methods}")
226
+
227
+ print(f"Authentication enabled: {auth_manager.is_auth_enabled()}")
228
+ print(f"Current auth method: {auth_manager.get_auth_method()}")
229
+
230
+
231
+ def run_all_demos():
232
+ """Run all authentication demos."""
233
+ print("🚀 Authentication System Examples")
234
+ print("=" * 50)
235
+
236
+ demo_api_key_authentication()
237
+ demo_jwt_authentication()
238
+ demo_basic_authentication()
239
+ demo_certificate_authentication()
240
+ demo_auth_headers_creation()
241
+ demo_configuration_validation()
242
+ demo_supported_methods()
243
+
244
+ print("\n✅ All authentication demos completed!")
245
+
246
+
247
+ if __name__ == "__main__":
248
+ run_all_demos()
@@ -0,0 +1,396 @@
1
+ """
2
+ Client Factory for Embedding Service
3
+
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+
7
+ This module provides a factory for creating EmbeddingServiceAsyncClient instances
8
+ with automatic security mode detection and configuration.
9
+ """
10
+
11
+ import os
12
+ import ssl
13
+ from typing import Optional, Dict, Any, Union, Tuple
14
+ from urllib.parse import urlparse
15
+
16
+ from .async_client import EmbeddingServiceAsyncClient
17
+ from .config import ClientConfig
18
+ from .auth import create_auth_manager
19
+ from .ssl_manager import create_ssl_manager
20
+
21
+
22
+ class SecurityMode:
23
+ """Security mode constants."""
24
+ HTTP = "http"
25
+ HTTP_TOKEN = "http_token"
26
+ HTTPS = "https"
27
+ HTTPS_TOKEN = "https_token"
28
+ MTLS = "mtls"
29
+ MTLS_ROLES = "mtls_roles"
30
+
31
+
32
+ class ClientFactory:
33
+ """
34
+ Factory for creating EmbeddingServiceAsyncClient instances with automatic
35
+ security mode detection and configuration.
36
+
37
+ Supports all 6 security modes:
38
+ 1. HTTP - plain HTTP without authentication
39
+ 2. HTTP + Token - HTTP with API Key, JWT, or Basic authentication
40
+ 3. HTTPS - HTTPS with server certificate verification
41
+ 4. HTTPS + Token - HTTPS with server certificates + authentication
42
+ 5. mTLS - mutual TLS with client and server certificates
43
+ 6. mTLS + Roles - mTLS with role-based access control
44
+ """
45
+
46
+ @staticmethod
47
+ def detect_security_mode(
48
+ base_url: str,
49
+ auth_method: Optional[str] = None,
50
+ ssl_enabled: Optional[bool] = None,
51
+ cert_file: Optional[str] = None,
52
+ key_file: Optional[str] = None,
53
+ **kwargs
54
+ ) -> str:
55
+ """
56
+ Automatically detect security mode based on provided parameters.
57
+
58
+ Args:
59
+ base_url: Server base URL
60
+ auth_method: Authentication method (none, api_key, jwt, basic, certificate)
61
+ ssl_enabled: Whether SSL is enabled
62
+ cert_file: Client certificate file path
63
+ key_file: Client private key file path
64
+ **kwargs: Additional parameters
65
+
66
+ Returns:
67
+ Detected security mode string
68
+ """
69
+ # Parse URL to determine protocol
70
+ parsed_url = urlparse(base_url)
71
+ is_https = parsed_url.scheme.lower() == 'https'
72
+
73
+ # Determine SSL status
74
+ if ssl_enabled is None:
75
+ ssl_enabled = is_https
76
+ else:
77
+ ssl_enabled = bool(ssl_enabled)
78
+
79
+ # Check for mTLS (client certificates)
80
+ has_client_cert = bool(cert_file and key_file)
81
+
82
+ # Check for authentication
83
+ has_auth = auth_method and auth_method != 'none'
84
+
85
+ # Determine security mode
86
+ if ssl_enabled and has_client_cert:
87
+ # Check for role-based access (additional certificate attributes)
88
+ if kwargs.get('roles') or kwargs.get('role_attributes'):
89
+ return SecurityMode.MTLS_ROLES
90
+ else:
91
+ return SecurityMode.MTLS
92
+ elif ssl_enabled and has_auth:
93
+ return SecurityMode.HTTPS_TOKEN
94
+ elif ssl_enabled:
95
+ return SecurityMode.HTTPS
96
+ elif has_auth:
97
+ return SecurityMode.HTTP_TOKEN
98
+ else:
99
+ return SecurityMode.HTTP
100
+
101
+ @staticmethod
102
+ def create_client(
103
+ base_url: str,
104
+ port: int = 8001,
105
+ auth_method: Optional[str] = None,
106
+ ssl_enabled: Optional[bool] = None,
107
+ **kwargs
108
+ ) -> EmbeddingServiceAsyncClient:
109
+ """
110
+ Create a client with automatic security mode detection.
111
+
112
+ Args:
113
+ base_url: Server base URL
114
+ port: Server port
115
+ auth_method: Authentication method
116
+ ssl_enabled: Whether SSL is enabled
117
+ **kwargs: Additional configuration parameters
118
+
119
+ Returns:
120
+ Configured EmbeddingServiceAsyncClient instance
121
+ """
122
+ # Detect security mode
123
+ security_mode = ClientFactory.detect_security_mode(
124
+ base_url, auth_method, ssl_enabled, **kwargs
125
+ )
126
+
127
+ # Create configuration based on detected mode
128
+ config_dict = ClientFactory._create_config_for_mode(
129
+ security_mode, base_url, port, auth_method, ssl_enabled, **kwargs
130
+ )
131
+
132
+ # Create and return client
133
+ return EmbeddingServiceAsyncClient(config_dict=config_dict)
134
+
135
+ @staticmethod
136
+ def _create_config_for_mode(
137
+ security_mode: str,
138
+ base_url: str,
139
+ port: int,
140
+ auth_method: Optional[str],
141
+ ssl_enabled: Optional[bool],
142
+ **kwargs
143
+ ) -> Dict[str, Any]:
144
+ """
145
+ Create configuration dictionary for specific security mode.
146
+
147
+ Args:
148
+ security_mode: Detected security mode
149
+ base_url: Server base URL
150
+ port: Server port
151
+ auth_method: Authentication method
152
+ ssl_enabled: Whether SSL is enabled
153
+ **kwargs: Additional parameters
154
+
155
+ Returns:
156
+ Configuration dictionary
157
+ """
158
+ config_dict = {
159
+ "server": {
160
+ "host": base_url,
161
+ "port": port
162
+ },
163
+ "client": {
164
+ "timeout": kwargs.get("timeout", 30.0)
165
+ }
166
+ }
167
+
168
+ # Configure authentication
169
+ if security_mode in [SecurityMode.HTTP_TOKEN, SecurityMode.HTTPS_TOKEN]:
170
+ config_dict["auth"] = ClientFactory._create_auth_config(auth_method, **kwargs)
171
+ elif security_mode in [SecurityMode.MTLS, SecurityMode.MTLS_ROLES] and auth_method and auth_method != "none":
172
+ config_dict["auth"] = ClientFactory._create_auth_config(auth_method, **kwargs)
173
+
174
+ # Configure SSL/TLS
175
+ if security_mode in [SecurityMode.HTTPS, SecurityMode.HTTPS_TOKEN, SecurityMode.MTLS, SecurityMode.MTLS_ROLES]:
176
+ config_dict["ssl"] = ClientFactory._create_ssl_config(security_mode, ssl_enabled, **kwargs)
177
+
178
+ return config_dict
179
+
180
+ @staticmethod
181
+ def _create_auth_config(auth_method: str, **kwargs) -> Dict[str, Any]:
182
+ """Create authentication configuration."""
183
+ auth_config = {"method": auth_method}
184
+
185
+ if auth_method == "api_key":
186
+ api_key = kwargs.get("api_key") or os.environ.get("EMBED_CLIENT_API_KEY")
187
+ if api_key:
188
+ auth_config["api_keys"] = {"user": api_key}
189
+ if kwargs.get("api_key_header"):
190
+ auth_config["api_key_header"] = kwargs["api_key_header"]
191
+
192
+ elif auth_method == "jwt":
193
+ jwt_secret = kwargs.get("jwt_secret") or os.environ.get("EMBED_CLIENT_JWT_SECRET")
194
+ jwt_username = kwargs.get("jwt_username") or os.environ.get("EMBED_CLIENT_JWT_USERNAME")
195
+ jwt_password = kwargs.get("jwt_password") or os.environ.get("EMBED_CLIENT_JWT_PASSWORD")
196
+
197
+ if jwt_secret and jwt_username and jwt_password:
198
+ auth_config["jwt"] = {
199
+ "secret": jwt_secret,
200
+ "username": jwt_username,
201
+ "password": jwt_password
202
+ }
203
+ if kwargs.get("jwt_expiry"):
204
+ auth_config["jwt"]["expiry"] = kwargs["jwt_expiry"]
205
+
206
+ elif auth_method == "basic":
207
+ username = kwargs.get("username") or os.environ.get("EMBED_CLIENT_USERNAME")
208
+ password = kwargs.get("password") or os.environ.get("EMBED_CLIENT_PASSWORD")
209
+
210
+ if username and password:
211
+ auth_config["basic"] = {
212
+ "username": username,
213
+ "password": password
214
+ }
215
+
216
+ elif auth_method == "certificate":
217
+ cert_file = kwargs.get("cert_file") or os.environ.get("EMBED_CLIENT_CERT_FILE")
218
+ key_file = kwargs.get("key_file") or os.environ.get("EMBED_CLIENT_KEY_FILE")
219
+
220
+ if cert_file and key_file:
221
+ auth_config["certificate"] = {
222
+ "cert_file": cert_file,
223
+ "key_file": key_file
224
+ }
225
+
226
+ return auth_config
227
+
228
+ @staticmethod
229
+ def _create_ssl_config(security_mode: str, ssl_enabled: bool, **kwargs) -> Dict[str, Any]:
230
+ """Create SSL/TLS configuration."""
231
+ ssl_config = {
232
+ "enabled": ssl_enabled,
233
+ "verify_mode": kwargs.get("verify_mode", "CERT_REQUIRED"),
234
+ "check_hostname": kwargs.get("check_hostname", True),
235
+ "check_expiry": kwargs.get("check_expiry", True)
236
+ }
237
+
238
+ # Add CA certificate if provided
239
+ ca_cert_file = kwargs.get("ca_cert_file") or os.environ.get("EMBED_CLIENT_CA_CERT_FILE")
240
+ if ca_cert_file:
241
+ ssl_config["ca_cert_file"] = ca_cert_file
242
+
243
+ # Add client certificates for mTLS
244
+ if security_mode in [SecurityMode.MTLS, SecurityMode.MTLS_ROLES]:
245
+ cert_file = kwargs.get("cert_file") or os.environ.get("EMBED_CLIENT_CERT_FILE")
246
+ key_file = kwargs.get("key_file") or os.environ.get("EMBED_CLIENT_KEY_FILE")
247
+
248
+ if cert_file:
249
+ ssl_config["cert_file"] = cert_file
250
+ if key_file:
251
+ ssl_config["key_file"] = key_file
252
+
253
+ return ssl_config
254
+
255
+ @staticmethod
256
+ def create_http_client(base_url: str, port: int = 8001, **kwargs) -> EmbeddingServiceAsyncClient:
257
+ """Create HTTP client (no authentication, no SSL)."""
258
+ return ClientFactory.create_client(
259
+ base_url, port, auth_method="none", ssl_enabled=False, **kwargs
260
+ )
261
+
262
+ @staticmethod
263
+ def create_http_token_client(
264
+ base_url: str,
265
+ port: int = 8001,
266
+ auth_method: str = "api_key",
267
+ **kwargs
268
+ ) -> EmbeddingServiceAsyncClient:
269
+ """Create HTTP client with authentication."""
270
+ return ClientFactory.create_client(
271
+ base_url, port, auth_method=auth_method, ssl_enabled=False, **kwargs
272
+ )
273
+
274
+ @staticmethod
275
+ def create_https_client(
276
+ base_url: str,
277
+ port: int = 8001,
278
+ **kwargs
279
+ ) -> EmbeddingServiceAsyncClient:
280
+ """Create HTTPS client (no authentication, with SSL)."""
281
+ return ClientFactory.create_client(
282
+ base_url, port, auth_method="none", ssl_enabled=True, **kwargs
283
+ )
284
+
285
+ @staticmethod
286
+ def create_https_token_client(
287
+ base_url: str,
288
+ port: int = 8001,
289
+ auth_method: str = "api_key",
290
+ **kwargs
291
+ ) -> EmbeddingServiceAsyncClient:
292
+ """Create HTTPS client with authentication."""
293
+ return ClientFactory.create_client(
294
+ base_url, port, auth_method=auth_method, ssl_enabled=True, **kwargs
295
+ )
296
+
297
+ @staticmethod
298
+ def create_mtls_client(
299
+ base_url: str,
300
+ cert_file: str,
301
+ key_file: str,
302
+ port: int = 8001,
303
+ auth_method: Optional[str] = None,
304
+ **kwargs
305
+ ) -> EmbeddingServiceAsyncClient:
306
+ """Create mTLS client with client certificates."""
307
+ return ClientFactory.create_client(
308
+ base_url, port, auth_method=auth_method, ssl_enabled=True,
309
+ cert_file=cert_file, key_file=key_file, **kwargs
310
+ )
311
+
312
+ @staticmethod
313
+ def create_mtls_roles_client(
314
+ base_url: str,
315
+ cert_file: str,
316
+ key_file: str,
317
+ port: int = 8001,
318
+ roles: Optional[list] = None,
319
+ role_attributes: Optional[dict] = None,
320
+ auth_method: Optional[str] = None,
321
+ **kwargs
322
+ ) -> EmbeddingServiceAsyncClient:
323
+ """Create mTLS client with role-based access control."""
324
+ return ClientFactory.create_client(
325
+ base_url, port, auth_method=auth_method, ssl_enabled=True,
326
+ cert_file=cert_file, key_file=key_file,
327
+ roles=roles, role_attributes=role_attributes, **kwargs
328
+ )
329
+
330
+ @staticmethod
331
+ def from_config_file(config_path: str) -> EmbeddingServiceAsyncClient:
332
+ """Create client from configuration file."""
333
+ config = ClientConfig()
334
+ config.load_config_file(config_path)
335
+ return EmbeddingServiceAsyncClient.from_config(config)
336
+
337
+ @staticmethod
338
+ def from_environment() -> EmbeddingServiceAsyncClient:
339
+ """Create client from environment variables."""
340
+ base_url = os.environ.get("EMBED_CLIENT_BASE_URL", "http://localhost")
341
+ port = int(os.environ.get("EMBED_CLIENT_PORT", "8001"))
342
+ auth_method = os.environ.get("EMBED_CLIENT_AUTH_METHOD", "none")
343
+
344
+ # Check if SSL should be enabled
345
+ ssl_enabled = os.environ.get("EMBED_CLIENT_SSL_ENABLED", "").lower() in ["true", "1", "yes"]
346
+ if not ssl_enabled and base_url.startswith("https://"):
347
+ ssl_enabled = True
348
+
349
+ return ClientFactory.create_client(
350
+ base_url, port, auth_method=auth_method, ssl_enabled=ssl_enabled
351
+ )
352
+
353
+
354
+ # Convenience functions for common use cases
355
+ def create_client(
356
+ base_url: str,
357
+ port: int = 8001,
358
+ auth_method: Optional[str] = None,
359
+ ssl_enabled: Optional[bool] = None,
360
+ **kwargs
361
+ ) -> EmbeddingServiceAsyncClient:
362
+ """
363
+ Create a client with automatic security mode detection.
364
+
365
+ This is a convenience function that delegates to ClientFactory.create_client().
366
+ """
367
+ return ClientFactory.create_client(base_url, port, auth_method, ssl_enabled, **kwargs)
368
+
369
+
370
+ def create_client_from_config(config_path: str) -> EmbeddingServiceAsyncClient:
371
+ """Create client from configuration file."""
372
+ return ClientFactory.from_config_file(config_path)
373
+
374
+
375
+ def create_client_from_env() -> EmbeddingServiceAsyncClient:
376
+ """Create client from environment variables."""
377
+ return ClientFactory.from_environment()
378
+
379
+
380
+ # Security mode detection function
381
+ def detect_security_mode(
382
+ base_url: str,
383
+ auth_method: Optional[str] = None,
384
+ ssl_enabled: Optional[bool] = None,
385
+ cert_file: Optional[str] = None,
386
+ key_file: Optional[str] = None,
387
+ **kwargs
388
+ ) -> str:
389
+ """
390
+ Detect security mode based on provided parameters.
391
+
392
+ This is a convenience function that delegates to ClientFactory.detect_security_mode().
393
+ """
394
+ return ClientFactory.detect_security_mode(
395
+ base_url, auth_method, ssl_enabled, cert_file, key_file, **kwargs
396
+ )