dataflow-core 2.1.8__tar.gz → 2.1.18rc3__tar.gz

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.

Potentially problematic release.


This version of dataflow-core might be problematic. Click here for more details.

Files changed (89) hide show
  1. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/PKG-INFO +4 -1
  2. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/authenticator/dataflowairflowauthenticator.py +10 -2
  3. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/authenticator/dataflowhubauthenticator.py +153 -47
  4. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/authenticator/dataflowsupersetauthenticator.py +11 -6
  5. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/configuration.py +7 -0
  6. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/database_manager.py +23 -0
  7. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/dataflow.py +162 -62
  8. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/db.py +4 -3
  9. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/environment.py +82 -51
  10. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/models/__init__.py +7 -3
  11. dataflow_core-2.1.18rc3/dataflow/models/app_types.py +31 -0
  12. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/models/blacklist_library.py +3 -3
  13. dataflow_core-2.1.18rc3/dataflow/models/connection.py +43 -0
  14. dataflow_core-2.1.18rc3/dataflow/models/dataflow_zone.py +33 -0
  15. dataflow_core-2.1.18rc3/dataflow/models/environment.py +246 -0
  16. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/models/environment_status.py +6 -0
  17. dataflow_core-2.1.18rc3/dataflow/models/git_ssh.py +35 -0
  18. dataflow_core-2.1.18rc3/dataflow/models/org_associations.py +71 -0
  19. dataflow_core-2.1.18rc3/dataflow/models/organization.py +123 -0
  20. dataflow_core-2.1.18rc3/dataflow/models/pinned_projects.py +28 -0
  21. dataflow_core-2.1.18rc3/dataflow/models/pod_activity.py +30 -0
  22. dataflow_core-2.1.18rc3/dataflow/models/pod_session_history.py +29 -0
  23. dataflow_core-2.1.18rc3/dataflow/models/project_details.py +52 -0
  24. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/models/recent_project_studio.py +17 -1
  25. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/models/recent_projects.py +7 -0
  26. dataflow_core-2.1.18rc3/dataflow/models/role.py +54 -0
  27. dataflow_core-2.1.18rc3/dataflow/models/role_server.py +18 -0
  28. dataflow_core-2.1.18rc3/dataflow/models/role_zone.py +37 -0
  29. dataflow_core-2.1.18rc3/dataflow/models/server_config.py +77 -0
  30. dataflow_core-2.1.18rc3/dataflow/models/session.py +22 -0
  31. dataflow_core-2.1.18rc3/dataflow/models/team.py +32 -0
  32. dataflow_core-2.1.18rc3/dataflow/models/user.py +101 -0
  33. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/models/user_team.py +12 -4
  34. dataflow_core-2.1.18rc3/dataflow/models/variables.py +60 -0
  35. dataflow_core-2.1.18rc3/dataflow/schemas/connection.py +129 -0
  36. dataflow_core-2.1.18rc3/dataflow/schemas/git_ssh.py +84 -0
  37. dataflow_core-2.1.18rc3/dataflow/schemas/secret.py +75 -0
  38. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/scripts/clone_environment.sh +2 -1
  39. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/scripts/create_environment.sh +4 -0
  40. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/factory.py +20 -10
  41. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/interface.py +3 -0
  42. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/providers/aws_manager.py +55 -0
  43. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/providers/azure_manager.py +55 -0
  44. dataflow_core-2.1.18rc3/dataflow/secrets_manager/providers/gcp_manager.py +332 -0
  45. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/service.py +17 -9
  46. dataflow_core-2.1.18rc3/dataflow/secrets_manager/utils.py +58 -0
  47. dataflow_core-2.1.18rc3/dataflow/utils/get_current_user.py +74 -0
  48. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/PKG-INFO +4 -1
  49. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/SOURCES.txt +11 -2
  50. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/requires.txt +3 -0
  51. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/top_level.txt +1 -0
  52. dataflow_core-2.1.18rc3/dfmigration/__init__.py +0 -0
  53. dataflow_core-2.1.18rc3/dfmigration/env.py +55 -0
  54. dataflow_core-2.1.18rc3/dfmigration/versions/001_initial_baseline_migration.py +20 -0
  55. dataflow_core-2.1.18rc3/dfmigration/versions/__init__.py +0 -0
  56. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/setup.py +6 -3
  57. dataflow_core-2.1.8/dataflow/models/app_types.py +0 -10
  58. dataflow_core-2.1.8/dataflow/models/connection.py +0 -25
  59. dataflow_core-2.1.8/dataflow/models/dataflow_zone.py +0 -19
  60. dataflow_core-2.1.8/dataflow/models/environment.py +0 -75
  61. dataflow_core-2.1.8/dataflow/models/git_ssh.py +0 -18
  62. dataflow_core-2.1.8/dataflow/models/pinned_projects.py +0 -15
  63. dataflow_core-2.1.8/dataflow/models/project_details.py +0 -23
  64. dataflow_core-2.1.8/dataflow/models/role.py +0 -29
  65. dataflow_core-2.1.8/dataflow/models/role_server.py +0 -14
  66. dataflow_core-2.1.8/dataflow/models/role_zone.py +0 -17
  67. dataflow_core-2.1.8/dataflow/models/server_config.py +0 -33
  68. dataflow_core-2.1.8/dataflow/models/session.py +0 -17
  69. dataflow_core-2.1.8/dataflow/models/team.py +0 -17
  70. dataflow_core-2.1.8/dataflow/models/user.py +0 -30
  71. dataflow_core-2.1.8/dataflow/models/user_environment.py +0 -16
  72. dataflow_core-2.1.8/dataflow/models/variables.py +0 -27
  73. dataflow_core-2.1.8/dataflow/schemas/connection.py +0 -84
  74. dataflow_core-2.1.8/dataflow/schemas/git_ssh.py +0 -50
  75. dataflow_core-2.1.8/dataflow/schemas/secret.py +0 -44
  76. dataflow_core-2.1.8/dataflow/utils/get_current_user.py +0 -37
  77. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/README.md +0 -0
  78. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/authenticator/__init__.py +0 -0
  79. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/__init__.py +0 -0
  80. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/schemas/__init__.py +0 -0
  81. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/scripts/update_environment.sh +0 -0
  82. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/__init__.py +0 -0
  83. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/providers/__init__.py +0 -0
  84. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/utils/__init__.py +0 -0
  85. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/utils/exceptions.py +0 -0
  86. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow/utils/logger.py +0 -0
  87. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/dependency_links.txt +0 -0
  88. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/entry_points.txt +0 -0
  89. {dataflow_core-2.1.8 → dataflow_core-2.1.18rc3}/setup.cfg +0 -0
@@ -1,16 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataflow-core
3
- Version: 2.1.8
3
+ Version: 2.1.18rc3
4
4
  Summary: Dataflow core package
5
5
  Author: Dataflow
6
6
  Author-email:
7
7
  Requires-Dist: sqlalchemy
8
+ Requires-Dist: alembic
8
9
  Requires-Dist: boto3
9
10
  Requires-Dist: psycopg2-binary
10
11
  Requires-Dist: pymysql
11
12
  Requires-Dist: requests
12
13
  Requires-Dist: azure-identity
13
14
  Requires-Dist: azure-keyvault-secrets
15
+ Requires-Dist: google-auth
16
+ Requires-Dist: google-cloud-secret-manager
14
17
  Dynamic: author
15
18
  Dynamic: requires-dist
16
19
  Dynamic: summary
@@ -18,9 +18,14 @@ dataflow = Dataflow()
18
18
  class DataflowAuthDBView(AuthDBView):
19
19
  @expose('/login/', methods=['GET', 'POST'])
20
20
  def login(self):
21
+
22
+ """This method checks for a 'dataflow_session' cookie, retrieves user details from Dataflow,
23
+ and logs in or creates the user in Airflow accordingly.
24
+ If the cookie is not present, it falls back to the standard login process.
25
+
26
+ Overrides the default login method to integrate with Dataflow authentication.
21
27
  """
22
- Override the default login method to handle custom authentication
23
- """
28
+
24
29
  try:
25
30
  session_id = request.cookies.get('dataflow_session')
26
31
  if not session_id:
@@ -52,6 +57,9 @@ class DataflowAuthDBView(AuthDBView):
52
57
  return super().login()
53
58
 
54
59
  class DataflowAirflowAuthenticator(FabAirflowSecurityManagerOverride):
60
+
61
+ """Custom Security Manager to integrate Airflow authentication with Dataflow."""
62
+
55
63
  authdbview = DataflowAuthDBView
56
64
 
57
65
  def __init__(self, appbuilder):
@@ -1,6 +1,4 @@
1
- import os
2
- import uuid
3
- import re
1
+ import os, uuid, re, hashlib, secrets
4
2
  from datetime import datetime, timedelta
5
3
  from zoneinfo import ZoneInfo
6
4
  from traitlets import Bool, Unicode
@@ -8,9 +6,17 @@ from jupyterhub.auth import Authenticator
8
6
  from oauthenticator.google import GoogleOAuthenticator
9
7
  from oauthenticator.azuread import AzureAdOAuthenticator
10
8
  from dataflow.db import get_db
11
- from dataflow.models import user as m_user, session as m_session, role as m_role
9
+ from dataflow.models import user as m_user, session as m_session
10
+ from sqlalchemy import or_
12
11
 
13
12
  class DataflowBaseAuthenticator(Authenticator):
13
+
14
+ """Base Authenticator to handle Dataflow authentication and session management.
15
+ Provides methods to authenticate users via Dataflow credentials, manage sessions.
16
+
17
+ Overrides JupyterHub's Authenticator class.
18
+ """
19
+
14
20
  enable_dataflow_auth = Bool(True, config=True, help="Enable username/password authentication")
15
21
 
16
22
  def __init__(self, **kwargs):
@@ -25,10 +31,20 @@ class DataflowBaseAuthenticator(Authenticator):
25
31
  raise
26
32
 
27
33
  def generate_session_id(self):
34
+
35
+ """Generate and return a unique session ID using UUID4."""
36
+
28
37
  return str(uuid.uuid4())
29
38
 
30
39
  def set_session_cookie(self, handler, session_id):
31
- expires = datetime.now(ZoneInfo("UTC")) + timedelta(days=365)
40
+
41
+ """Set the dataflow_session cookie in the user's browser.
42
+
43
+ Args:
44
+ handler: The request handler to set the cookie on.
45
+ session_id: The session ID to set in the cookie."""
46
+
47
+ expires = datetime.now(ZoneInfo("UTC")) + timedelta(days=60)
32
48
  host = handler.request.host
33
49
  domain = '.'.join(host.split('.')[-2:]) if len(host.split('.')) >= 2 else host
34
50
  handler.set_cookie(
@@ -44,19 +60,22 @@ class DataflowBaseAuthenticator(Authenticator):
44
60
  self.log.info(f"Set session cookie: dataflow_session={session_id} for host={host}")
45
61
 
46
62
  def get_or_create_session(self, user_id):
47
- existing_session = (
48
- self.db.query(m_session.Session)
49
- .filter(m_session.Session.user_id == str(user_id))
50
- .first()
51
- )
52
- if existing_session:
53
- self.log.info(f"Reusing existing session: {existing_session.session_id}")
54
- return existing_session.session_id
63
+
64
+ """Retrieve existing session ID for user or create a new one.
65
+
66
+ Args:
67
+ user_id: The ID of the user to get or create a session for.
68
+
69
+ Returns:
70
+ session_id (str): The existing or newly created session ID.
71
+ """
72
+
55
73
  session_id = self.generate_session_id()
56
74
  while self.db.query(m_session.Session).filter(
57
75
  m_session.Session.session_id == session_id
58
76
  ).first():
59
77
  session_id = self.generate_session_id()
78
+
60
79
  db_item = m_session.Session(user_id=user_id, session_id=session_id)
61
80
  self.db.add(db_item)
62
81
  self.db.commit()
@@ -65,6 +84,16 @@ class DataflowBaseAuthenticator(Authenticator):
65
84
  return session_id
66
85
 
67
86
  def check_blocked_users(self, username, authenticated):
87
+
88
+ """Check if the authenticated user is blocked based on allowed_users list.
89
+
90
+ Args:
91
+ username (str): The username of the authenticated user.
92
+ authenticated (dict|None): The authentication data returned from authenticate method.
93
+
94
+ Returns:
95
+ username (str|None): The username if not blocked, else None."""
96
+
68
97
  self.log.info(f"Checking blocked users for {username}: authenticated={authenticated}, allowed_users={self.allowed_users}")
69
98
 
70
99
  if not authenticated:
@@ -77,42 +106,54 @@ class DataflowBaseAuthenticator(Authenticator):
77
106
 
78
107
  return super().check_blocked_users(username, authenticated)
79
108
 
80
- def get_applicant_role_id(self):
81
- """Get the role ID for 'Applicant' role"""
82
- try:
83
- applicant_role = (
84
- self.db.query(m_role.Role)
85
- .filter(m_role.Role.name == "Applicant")
86
- .first()
87
- )
88
- if applicant_role:
89
- return applicant_role.id
90
- else:
91
- self.log.warning("Applicant role not found in database")
92
- return None
93
- except Exception as e:
94
- self.log.error(f"Error getting Applicant role: {str(e)}")
95
- return None
96
-
97
109
  def extract_username_from_email(self, email):
98
- """Extract username from email by removing domain"""
110
+
111
+ """Extract username from email by removing domain
112
+
113
+ Args:
114
+ email (str): User's email address
115
+
116
+ Returns:
117
+ username (str): Extracted username after removing domain
118
+ """
119
+
99
120
  if '@' in email:
100
121
  return email.split('@')[0]
101
122
  return email
102
123
 
124
+ def generate_secure_password(self):
125
+
126
+ """Generate secure random password hash
127
+
128
+ Returns:
129
+ password_hash (str): Securely hashed password
130
+ """
131
+
132
+ salt = secrets.token_hex(16)
133
+ random_uuid = str(uuid.uuid4())
134
+ hash_obj = hashlib.sha256((random_uuid + salt).encode())
135
+ return hash_obj.hexdigest()
136
+
103
137
  def create_new_user(self, email, first_name=None, last_name=None):
104
- """Create a new user with Applicant role"""
138
+
139
+ """Create a new user with Applicant role
140
+
141
+ Args:
142
+ email (str): User's email address
143
+ first_name (str): User's first name
144
+ last_name (str): User's last name
145
+
146
+ Returns:
147
+ new_user (m_user.User|None): Created user object or None if creation failed
148
+ """
149
+
105
150
  try:
106
- role_id = self.get_applicant_role_id()
107
- if not role_id:
108
- self.log.error("Cannot create user: Applicant role not found")
109
- return None
110
-
111
151
  username = self.extract_username_from_email(email)
112
152
  username = re.sub(r'[^a-z0-9]', '', username.lower())
113
153
  if not username:
114
154
  self.log.error("Cannot create user: Username is empty")
115
155
  return None
156
+
116
157
  existing_user = (
117
158
  self.db.query(m_user.User)
118
159
  .filter(m_user.User.user_name == username)
@@ -122,7 +163,7 @@ class DataflowBaseAuthenticator(Authenticator):
122
163
  counter = 1
123
164
  original_username = username
124
165
  while existing_user:
125
- username = f"{original_username}_{counter}"
166
+ username = f"{original_username}{counter}"
126
167
  existing_user = (
127
168
  self.db.query(m_user.User)
128
169
  .filter(m_user.User.user_name == username)
@@ -130,13 +171,13 @@ class DataflowBaseAuthenticator(Authenticator):
130
171
  )
131
172
  counter += 1
132
173
 
174
+ secure_password = self.generate_secure_password()
133
175
  new_user = m_user.User(
134
176
  user_name=username,
135
177
  first_name=first_name or username,
136
178
  last_name=last_name or "",
137
179
  email=email,
138
- role_id=role_id,
139
- password='user@123',
180
+ password=secure_password,
140
181
  )
141
182
 
142
183
  self.db.add(new_user)
@@ -152,24 +193,42 @@ class DataflowBaseAuthenticator(Authenticator):
152
193
  return None
153
194
 
154
195
  async def authenticate_dataflow(self, handler, data):
196
+
197
+ """Authenticate user using Dataflow username/password.
198
+
199
+ Args:
200
+ handler: The request handler.
201
+ data: The authentication data containing username and password.
202
+
203
+ Returns:
204
+ dict|None: Authentication result with username and session_id if successful, else None.
205
+ """
206
+
155
207
  if not (self.enable_dataflow_auth and isinstance(data, dict) and data.get("username") and data.get("password")):
156
208
  return None
157
- username = data["username"]
209
+ user_name_or_email = data["username"]
158
210
  password = data["password"]
159
- self.log.info(f"Attempting Dataflow authentication for user: {username}")
211
+ self.log.info(f"Attempting Dataflow authentication for user: {user_name_or_email}")
160
212
  try:
161
213
  user = (
162
214
  self.db.query(m_user.User)
163
- .filter(m_user.User.user_name == username)
215
+ .filter(
216
+ or_(
217
+ m_user.User.email == user_name_or_email,
218
+ m_user.User.user_name == user_name_or_email
219
+ )
220
+ )
164
221
  .first()
165
222
  )
223
+
166
224
  if not user or user.password != password:
167
- self.log.warning(f"Dataflow authentication failed for user: {username}")
225
+ self.log.warning(f"Dataflow authentication failed for user: {user_name_or_email}")
168
226
  return None
227
+
169
228
  session_id = self.get_or_create_session(user.user_id)
170
229
  self.set_session_cookie(handler, session_id)
171
- self.log.info(f"Dataflow authentication successful for user: {username}")
172
- return {"name": username, "session_id": session_id, "auth_state": {}}
230
+ self.log.info(f"Dataflow authentication successful for user: {user.user_name}")
231
+ return {"name": user.user_name, "session_id": session_id, "auth_state": {}}
173
232
  except Exception as e:
174
233
  self.log.error(f"Dataflow authentication error: {str(e)}")
175
234
  return None
@@ -177,6 +236,18 @@ class DataflowBaseAuthenticator(Authenticator):
177
236
  self.db.close()
178
237
 
179
238
  class DataflowGoogleAuthenticator(DataflowBaseAuthenticator, GoogleOAuthenticator):
239
+
240
+ """Authenticator to handle Google OAuth authentication with Dataflow integration.
241
+
242
+ Overrides
243
+ - DataflowBaseAuthenticator
244
+ - GoogleOAuthenticator
245
+
246
+ Requires Google OAuth credentials.
247
+ - google_client_id
248
+ - google_client_secret
249
+ """
250
+
180
251
  dataflow_oauth_type = Unicode(
181
252
  default_value="google",
182
253
  config=True,
@@ -195,6 +266,17 @@ class DataflowGoogleAuthenticator(DataflowBaseAuthenticator, GoogleOAuthenticato
195
266
  f"enable_dataflow_auth={self.enable_dataflow_auth}")
196
267
 
197
268
  async def authenticate(self, handler, data):
269
+
270
+ """Authenticate user using Google OAuth with Dataflow integration.
271
+
272
+ Args:
273
+ handler: The request handler.
274
+ data: The authentication data.
275
+
276
+ Returns:
277
+ dict|None: Authentication result with username and session_id if successful, else None.
278
+ """
279
+
198
280
  self.log.info(f"Authenticate called with data: {data}, request_uri: {handler.request.uri}")
199
281
  result = await self.authenticate_dataflow(handler, data)
200
282
  if result:
@@ -243,6 +325,19 @@ class DataflowGoogleAuthenticator(DataflowBaseAuthenticator, GoogleOAuthenticato
243
325
  self.db.close()
244
326
 
245
327
  class DataflowAzureAuthenticator(DataflowBaseAuthenticator, AzureAdOAuthenticator):
328
+
329
+ """Authenticator to handle Azure AD OAuth authentication with Dataflow integration.
330
+
331
+ Overrides
332
+ - DataflowBaseAuthenticator
333
+ - AzureAdOAuthenticator
334
+
335
+ Requires Azure AD OAuth credentials.
336
+ - azure_client_id
337
+ - azure_client_secret
338
+ - azure_tenant_id
339
+ """
340
+
246
341
  azure_client_id = Unicode(config=True, help="Azure AD OAuth client ID")
247
342
  azure_client_secret = Unicode(config=True, help="Azure AD OAuth client secret")
248
343
  azure_tenant_id = Unicode(config=True, help="Azure AD tenant ID")
@@ -264,6 +359,17 @@ class DataflowAzureAuthenticator(DataflowBaseAuthenticator, AzureAdOAuthenticato
264
359
  f"enable_dataflow_auth={self.enable_dataflow_auth}")
265
360
 
266
361
  async def authenticate(self, handler, data):
362
+
363
+ """Authenticate user using Azure AD OAuth with Dataflow integration.
364
+
365
+ Args:
366
+ handler: The request handler.
367
+ data: The authentication data.
368
+
369
+ Returns:
370
+ dict|None: Authentication result with username and session_id if successful, else None.
371
+ """
372
+
267
373
  result = await self.authenticate_dataflow(handler, data)
268
374
  if result:
269
375
  return result
@@ -302,7 +408,7 @@ class DataflowAzureAuthenticator(DataflowBaseAuthenticator, AzureAdOAuthenticato
302
408
  self.set_session_cookie(handler, session_id)
303
409
  self.log.info(f"Azure AD OAuth completed for user: {username}, session_id={session_id}")
304
410
  return {
305
- "name": db_user.first_name,
411
+ "name": username,
306
412
  "session_id": session_id,
307
413
  "auth_state": user.get("auth_state", {})
308
414
  }
@@ -12,6 +12,7 @@ from superset.security import SupersetSecurityManager
12
12
  from dataflow.dataflow import Dataflow
13
13
 
14
14
  class DataflowAuthDBView(AuthDBView):
15
+
15
16
  def __init__(self):
16
17
  self.dataflow = Dataflow()
17
18
 
@@ -33,14 +34,15 @@ class DataflowAuthDBView(AuthDBView):
33
34
  @expose('/login/', methods=['GET', "POST"])
34
35
  def login(self):
35
36
  """
36
- Handles both GET and POST login requests.
37
+ This method handles authentication for superset in Dataflow.
37
38
 
38
- - GET: Used for browser-based login. Authenticates using session cookie and redirects to home.
39
- - POST: Used for API-based login. Returns JWT access token for programmatic access.
39
+ Methods:
40
+ - GET:
41
+ Used for browser-based login. Authenticates using session cookie and redirects to home.
40
42
 
41
- Returns:
42
- - Redirect to home page (GET)
43
- - JSON response with access token (POST)
43
+ - POST:
44
+ Used for API-based login. Returns JWT access token for programmatic access.
45
+ Returns JSON response with access token
44
46
  """
45
47
  if request.method == "GET":
46
48
  session_id = request.cookies.get('dataflow_session')
@@ -71,6 +73,9 @@ class DataflowAuthDBView(AuthDBView):
71
73
  return jsonify(resp)
72
74
 
73
75
  class DataflowSecurityManager(SupersetSecurityManager):
76
+
77
+ """Custom Security Manager integrating Dataflow authentication with superset."""
78
+
74
79
  authdbview = DataflowAuthDBView
75
80
  def __init__(self, appbuilder):
76
81
  super(DataflowSecurityManager, self).__init__(appbuilder)
@@ -20,6 +20,13 @@ class ConfigurationManager:
20
20
  def get_config_value(self, section, option):
21
21
  """
22
22
  Get configuration value
23
+
24
+ Args:
25
+ section (str): The section in the config file.
26
+ option (str): The option within the section.
27
+
28
+ Returns:
29
+ str | None: The configuration value or None if not found.
23
30
  """
24
31
  try:
25
32
  return self.config.get(section, option)
@@ -5,11 +5,22 @@ from sqlalchemy import create_engine
5
5
  from sqlalchemy.orm import sessionmaker
6
6
 
7
7
  class DatabaseManager:
8
+
9
+ """Manages database connections and sessions."""
10
+
8
11
  def __init__(self, db_url):
9
12
  self.db_url = db_url
10
13
  self.engine = self.get_engine()
11
14
 
12
15
  def get_engine(self):
16
+
17
+ """
18
+ Create a new SQLAlchemy engine instance.
19
+
20
+ Returns:
21
+ Engine: The SQLAlchemy engine instance.
22
+ """
23
+
13
24
  try:
14
25
  engine = create_engine(self.db_url)
15
26
  return engine
@@ -17,6 +28,12 @@ class DatabaseManager:
17
28
  raise e
18
29
 
19
30
  def get_session(self):
31
+ """
32
+ Create a new SQLAlchemy session.
33
+
34
+ Returns:
35
+ Session: The SQLAlchemy session instance.
36
+ """
20
37
  try:
21
38
  engine = self.engine
22
39
  session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
@@ -30,4 +47,10 @@ class DatabaseManager:
30
47
  raise e
31
48
 
32
49
  def get_base(self):
50
+ """
51
+ Get the declarative base class for the ORM models.
52
+
53
+ Returns:
54
+ Base: The declarative base class.
55
+ """
33
56
  return declarative_base()