auth-gateway-serverkit 0.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.
File without changes
@@ -0,0 +1,54 @@
1
+ """ Email sending module for user notifications in KalSense."""
2
+ import smtplib
3
+ from email.mime.text import MIMEText
4
+ from email.mime.multipart import MIMEMultipart
5
+ from .logger import init_logger
6
+
7
+
8
+ logger = init_logger('user.email')
9
+
10
+
11
+ def send_password_email(
12
+ app_password,
13
+ app_email,
14
+ first_name,
15
+ user_email,
16
+ user_name,
17
+ generated_password
18
+ ):
19
+ try:
20
+ message = MIMEMultipart("alternative")
21
+ message["From"] = app_email
22
+ message["To"] = user_email
23
+ message["Subject"] = "Welcome to KalSense"
24
+
25
+ html = f"""
26
+ <html>
27
+ <body>
28
+ <p>Hi {first_name},<br>
29
+ Welcome! Your new user was created with the following details: <br>
30
+ Your user name is: <b>{user_name}</b><br>
31
+ Your password is: <b>{generated_password}</b><br>
32
+ Please change it upon your first login.<br>
33
+ </p>
34
+ <p>Best Regards,<br>
35
+ <i>IT Services Team</i>
36
+ </p>
37
+ </body>
38
+ </html>
39
+ """
40
+
41
+ part = MIMEText(html, "html")
42
+ message.attach(part)
43
+
44
+ server = smtplib.SMTP("smtp.gmail.com", 587)
45
+ server.starttls()
46
+ server.login(app_email, app_password)
47
+ text = message.as_string()
48
+ server.sendmail(app_email, user_email, text)
49
+ server.quit()
50
+ logger.info(f"Email sent to {user_email}")
51
+ except smtplib.SMTPException as e:
52
+ logger.error(f"Failed to send email to {user_email}, error: {str(e)}")
53
+ except Exception as e:
54
+ logger.error(f"Failed to send email to {user_email}, error: {str(e)}")
@@ -0,0 +1,104 @@
1
+ """ http client utilities for making asynchronous HTTP requests using httpx. """
2
+ import httpx
3
+ from typing import Optional, Dict
4
+ from .logger import init_logger
5
+
6
+ logger = init_logger("utils.requests")
7
+
8
+
9
+ async def post(
10
+ url: str,
11
+ json: Optional[dict] = None,
12
+ data: Optional[dict] = None,
13
+ files: Optional[dict] = None,
14
+ headers: Optional[Dict[str, str]] = None,
15
+ timeout=20,
16
+ connect=5
17
+ ) -> dict:
18
+ try:
19
+ timeout = httpx.Timeout(timeout, connect=connect)
20
+ async with httpx.AsyncClient(timeout=timeout, headers=headers) as client:
21
+ if json is not None:
22
+ response = await client.post(url, json=json)
23
+ elif files is not None or data is not None:
24
+ response = await client.post(url, data=data, files=files)
25
+ else:
26
+ response = await client.post(url, data=data)
27
+ response.raise_for_status()
28
+ return response.json()
29
+ except httpx.HTTPStatusError as e:
30
+ logger.error(f"HTTP error: {e.response.status_code} - {e.response.text} - URL: {url}")
31
+ raise
32
+ except Exception as e:
33
+ logger.error(f"Request error: {e} - URL: {url}")
34
+ raise
35
+
36
+
37
+ async def get(
38
+ url: str,
39
+ params: dict = None,
40
+ headers: Optional[Dict[str, str]] = None,
41
+ timeout=20,
42
+ connect=5
43
+ ) -> dict:
44
+ try:
45
+ timeout = httpx.Timeout(timeout, connect=connect)
46
+ async with httpx.AsyncClient(headers=headers) as client:
47
+ response = await client.get(url, params=params, timeout=timeout)
48
+ response.raise_for_status()
49
+ return response.json()
50
+ except httpx.HTTPStatusError as e:
51
+ logger.error(f"HTTP error: {e.response.status_code} - {e.response.text}")
52
+ raise
53
+ except Exception as e:
54
+ logger.error(f"Request error: {e}")
55
+ raise
56
+
57
+
58
+ async def delete(
59
+ url: str,
60
+ params: Optional[dict] = None,
61
+ headers: Optional[Dict[str, str]] = None,
62
+ timeout=20,
63
+ connect=5
64
+ ) -> dict:
65
+ try:
66
+ timeout = httpx.Timeout(timeout, connect=connect)
67
+ async with httpx.AsyncClient(timeout=timeout, headers=headers) as client:
68
+ response = await client.delete(url, params=params)
69
+ response.raise_for_status()
70
+ return response.json()
71
+ except httpx.HTTPStatusError as e:
72
+ logger.error(f"HTTP error: {e.response.status_code} - {e.response.text} - URL: {url}")
73
+ raise
74
+ except Exception as e:
75
+ logger.error(f"Request error: {e} - URL: {url}")
76
+ raise
77
+
78
+
79
+ async def put(
80
+ url: str,
81
+ json: Optional[dict] = None,
82
+ data: Optional[dict] = None,
83
+ files: Optional[dict] = None,
84
+ headers: Optional[Dict[str, str]] = None,
85
+ timeout=20,
86
+ connect=5
87
+ ) -> dict:
88
+ try:
89
+ timeout = httpx.Timeout(timeout, connect=connect)
90
+ async with httpx.AsyncClient(timeout=timeout, headers=headers) as client:
91
+ if json is not None:
92
+ response = await client.put(url, json=json)
93
+ elif files is not None or data is not None:
94
+ response = await client.put(url, data=data, files=files)
95
+ else:
96
+ response = await client.put(url, data=data)
97
+ response.raise_for_status()
98
+ return response.json()
99
+ except httpx.HTTPStatusError as e:
100
+ logger.error(f"HTTP error: {e.response.status_code} - {e.response.text} - URL: {url}")
101
+ raise
102
+ except Exception as e:
103
+ logger.error(f"Request error: {e} - URL: {url}")
104
+ raise
@@ -0,0 +1,3 @@
1
+ """
2
+
3
+ """
@@ -0,0 +1,88 @@
1
+ import aiohttp
2
+ from typing import Dict, Optional
3
+ from .config import settings
4
+ from .client_api import get_admin_token, get_client_uuid
5
+ from ..logger import init_logger
6
+ from .json_transformer import KeycloakConfigTransformer
7
+
8
+
9
+ logger = init_logger("serverkit.keycloak.authorization")
10
+
11
+
12
+ class KeycloakAuthorizationAPI:
13
+
14
+ def __init__(self):
15
+ self.base_url = f"{settings.SERVER_URL}/admin/realms/{settings.REALM}"
16
+
17
+ async def update_authorization_config(self, authorization_config: Dict) -> bool:
18
+ """Update complete authorization configuration via API"""
19
+
20
+ try:
21
+ # Get admin token and client UUID
22
+ admin_token = await get_admin_token()
23
+ if not admin_token:
24
+ logger.error("Failed to get admin token")
25
+ return False
26
+
27
+ client_uuid = await get_client_uuid(admin_token)
28
+ if not client_uuid:
29
+ logger.error("Failed to get client UUID")
30
+ return False
31
+
32
+ # Update authorization settings
33
+ url = f"{self.base_url}/clients/{client_uuid}/authz/resource-server"
34
+ headers = {
35
+ 'Authorization': f'Bearer {admin_token}',
36
+ 'Content-Type': 'application/json'
37
+ }
38
+
39
+ async with aiohttp.ClientSession() as session:
40
+ async with session.put(url, json=authorization_config, headers=headers) as response:
41
+ if response.status == 200:
42
+ logger.info("Authorization configuration updated successfully")
43
+ return True
44
+ else:
45
+ error_text = await response.text()
46
+ logger.error(f"Failed to update authorization config: {error_text}")
47
+ return False
48
+
49
+ except Exception as e:
50
+ logger.error(f"Error updating authorization configuration: {e}")
51
+ return False
52
+
53
+ async def sync_configuration(self, config_file_path: str) -> bool:
54
+ """Load, transform, and sync configuration"""
55
+
56
+ try:
57
+ # Transform configuration
58
+ transformer = KeycloakConfigTransformer()
59
+ keycloak_config = transformer.load_and_transform(config_file_path)
60
+
61
+ # Update via API
62
+ return await self.update_authorization_config(keycloak_config)
63
+
64
+ except Exception as e:
65
+ logger.error(f"Error syncing configuration: {e}")
66
+ return False
67
+
68
+ async def get_current_authorization_config(self) -> Optional[Dict]:
69
+ """Get current authorization configuration"""
70
+
71
+ try:
72
+ admin_token = await get_admin_token()
73
+ client_uuid = await get_client_uuid(admin_token)
74
+
75
+ url = f"{self.base_url}/clients/{client_uuid}/authz/resource-server"
76
+ headers = {'Authorization': f'Bearer {admin_token}'}
77
+
78
+ async with aiohttp.ClientSession() as session:
79
+ async with session.get(url, headers=headers) as response:
80
+ if response.status == 200:
81
+ return await response.json()
82
+ else:
83
+ logger.error(f"Failed to get current config: {response.status}")
84
+ return None
85
+
86
+ except Exception as e:
87
+ logger.error(f"Error getting current configuration: {e}")
88
+ return None