dataflow-core 1.0.0__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.
- dataflow-core-1.0.0/PKG-INFO +10 -0
- dataflow-core-1.0.0/README.md +1 -0
- dataflow-core-1.0.0/authenticator/__init__.py +0 -0
- dataflow-core-1.0.0/authenticator/dataflowairflowauthenticator.py +121 -0
- dataflow-core-1.0.0/authenticator/dataflowhubauthenticator.py +66 -0
- dataflow-core-1.0.0/authenticator/package/__init__.py +0 -0
- dataflow-core-1.0.0/authenticator/package/configuration.py +27 -0
- dataflow-core-1.0.0/authenticator/package/models/__init__.py +0 -0
- dataflow-core-1.0.0/authenticator/package/models/database.py +32 -0
- dataflow-core-1.0.0/authenticator/package/models/session.py +20 -0
- dataflow-core-1.0.0/authenticator/package/models/user.py +23 -0
- dataflow-core-1.0.0/dataflow/__init__.py +0 -0
- dataflow-core-1.0.0/dataflow/configuration.py +27 -0
- dataflow-core-1.0.0/dataflow/dataflow.py +92 -0
- dataflow-core-1.0.0/dataflow/models/__init__.py +0 -0
- dataflow-core-1.0.0/dataflow/models/database.py +32 -0
- dataflow-core-1.0.0/dataflow/models/session.py +17 -0
- dataflow-core-1.0.0/dataflow/models/user.py +23 -0
- dataflow-core-1.0.0/dataflow/utils/__init__.py +0 -0
- dataflow-core-1.0.0/dataflow/utils/aws_secrets_manager.py +64 -0
- dataflow-core-1.0.0/dataflow_core.egg-info/PKG-INFO +10 -0
- dataflow-core-1.0.0/dataflow_core.egg-info/SOURCES.txt +26 -0
- dataflow-core-1.0.0/dataflow_core.egg-info/dependency_links.txt +1 -0
- dataflow-core-1.0.0/dataflow_core.egg-info/entry_points.txt +3 -0
- dataflow-core-1.0.0/dataflow_core.egg-info/requires.txt +2 -0
- dataflow-core-1.0.0/dataflow_core.egg-info/top_level.txt +2 -0
- dataflow-core-1.0.0/setup.cfg +4 -0
- dataflow-core-1.0.0/setup.py +21 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Dataflow-Core
|
|
File without changes
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from .package.configuration import ConfigurationManager
|
|
2
|
+
from .package.models.database import DatabaseManager
|
|
3
|
+
from .package.models import (
|
|
4
|
+
user as m_user,
|
|
5
|
+
session as m_session
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
from typing import Any, Callable
|
|
9
|
+
from airflow.www.security import FabAirflowSecurityManagerOverride
|
|
10
|
+
|
|
11
|
+
class DataflowAirflowAuthenticator(FabAirflowSecurityManagerOverride):
|
|
12
|
+
def __init__(self, wsgi_app: Callable) -> None:
|
|
13
|
+
self.wsgi_app = wsgi_app
|
|
14
|
+
|
|
15
|
+
# Dataflow database configuration
|
|
16
|
+
self.dataflow_config = ConfigurationManager('/dataflow/app/config/dataflow.cfg')
|
|
17
|
+
self.dataflow_database_url = self.dataflow_config.get_config_value('database', 'database_url')
|
|
18
|
+
|
|
19
|
+
self.dataflow_db_instance = DatabaseManager(self.dataflow_database_url)
|
|
20
|
+
self.dataflow_db = next(self.dataflow_db_instance.get_session())
|
|
21
|
+
|
|
22
|
+
# Airflow database configuration
|
|
23
|
+
self.airflow_config = ConfigurationManager('airflow.cfg')
|
|
24
|
+
self.airflow_database_url = self.airflow_config.get_config_value('database', 'sql_alchemy_conn')
|
|
25
|
+
|
|
26
|
+
self.airflow_db_instance = DatabaseManager(self.airflow_database_url)
|
|
27
|
+
self.airflow_db = next(self.airflow_db_instance.get_session())
|
|
28
|
+
|
|
29
|
+
m_user.Base.metadata.create_all(bind=self.dataflow_db_instance.get_engine())
|
|
30
|
+
m_session.Base.metadata.create_all(bind=self.dataflow_db_instance.get_engine())
|
|
31
|
+
|
|
32
|
+
def __call__(self, environ: dict, start_response: Callable) -> Any:
|
|
33
|
+
|
|
34
|
+
path = environ.get('PATH_INFO', '')
|
|
35
|
+
if not path == '/login/':
|
|
36
|
+
return self.wsgi_app(environ, start_response)
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
# Extracting browser cookies
|
|
40
|
+
cookies = environ.get('HTTP_COOKIE', '')
|
|
41
|
+
user_session_id = None
|
|
42
|
+
parts = cookies.split('; ')
|
|
43
|
+
for part in parts:
|
|
44
|
+
if part.startswith('dataflow_session='):
|
|
45
|
+
user_session_id = part
|
|
46
|
+
break
|
|
47
|
+
|
|
48
|
+
if user_session_id is None:
|
|
49
|
+
raise Exception("No session id found")
|
|
50
|
+
|
|
51
|
+
user_session_id = user_session_id.split('=')[1]
|
|
52
|
+
|
|
53
|
+
# Retrieving user details
|
|
54
|
+
user_data = self.find_dataflow_user(user_session_id)
|
|
55
|
+
|
|
56
|
+
if user_data is None:
|
|
57
|
+
raise Exception("No user found for the dataflow_session id")
|
|
58
|
+
|
|
59
|
+
user = self.find_user(user_data.user_name)
|
|
60
|
+
|
|
61
|
+
if not user:
|
|
62
|
+
user_role = self.find_role(user_data.role.title())
|
|
63
|
+
user = self.add_user(username=user_data.user_name, first_name=self.not_none(user_data.first_name), last_name=self.not_none(user_data.last_name), email=self.not_none(user_data.email), role=user_role)
|
|
64
|
+
|
|
65
|
+
environ['REMOTE_USER'] = user.username
|
|
66
|
+
self.write_user_id(user_data.user_id)
|
|
67
|
+
return self.wsgi_app(environ, start_response)
|
|
68
|
+
|
|
69
|
+
except Exception as e:
|
|
70
|
+
return self.wsgi_app(environ, start_response)
|
|
71
|
+
|
|
72
|
+
def not_none(self, value):
|
|
73
|
+
return value if value is not None else ""
|
|
74
|
+
|
|
75
|
+
def find_dataflow_user(self, user_session_id):
|
|
76
|
+
"""Find user by session_id in dataflow database."""
|
|
77
|
+
query = self.dataflow_db.query(m_session.Session_table)
|
|
78
|
+
session = query.filter(m_session.Session_table.session_id == user_session_id).first()
|
|
79
|
+
if session is None:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
user_data = self.dataflow_db.query(m_user.User).filter(m_user.User.user_id == session.user_id).first()
|
|
83
|
+
if user_data is None:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
return user_data
|
|
87
|
+
|
|
88
|
+
def find_user(self, username=None):
|
|
89
|
+
"""Find user by username or email."""
|
|
90
|
+
return self.airflow_db.query(self.user_model).filter_by(username=username).one_or_none()
|
|
91
|
+
|
|
92
|
+
def find_role(self, role):
|
|
93
|
+
"""Find a role in the database."""
|
|
94
|
+
return self.airflow_db.query(self.role_model).filter_by(name=role).one_or_none()
|
|
95
|
+
|
|
96
|
+
def add_user(self, username, first_name, last_name, email, role, password=""):
|
|
97
|
+
"""Create a user."""
|
|
98
|
+
user = self.user_model()
|
|
99
|
+
user.first_name = first_name
|
|
100
|
+
user.last_name = last_name
|
|
101
|
+
user.username = username
|
|
102
|
+
user.email = email
|
|
103
|
+
user.active = True
|
|
104
|
+
user.roles = role if isinstance(role, list) else [role]
|
|
105
|
+
user.password = password
|
|
106
|
+
self.airflow_db.add(user)
|
|
107
|
+
self.airflow_db.commit()
|
|
108
|
+
return user
|
|
109
|
+
|
|
110
|
+
def write_user_id(self, user_id):
|
|
111
|
+
"""
|
|
112
|
+
Write the given user_id to a file named dataflow_user_id.txt.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
user_id (str): The user ID to be written to the file.
|
|
116
|
+
"""
|
|
117
|
+
file_name = 'dataflow_user_id.txt'
|
|
118
|
+
with open(file_name, 'w') as file:
|
|
119
|
+
file.write(str(user_id))
|
|
120
|
+
|
|
121
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from .package.configuration import ConfigurationManager
|
|
2
|
+
from .package.models.database import DatabaseManager
|
|
3
|
+
from .package.models import (
|
|
4
|
+
user as m_user,
|
|
5
|
+
session as m_session
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
import uuid
|
|
9
|
+
from jupyterhub.auth import Authenticator
|
|
10
|
+
|
|
11
|
+
class DataflowHubAuthenticator(Authenticator):
|
|
12
|
+
def __init__(self, **kwargs):
|
|
13
|
+
super().__init__(**kwargs)
|
|
14
|
+
|
|
15
|
+
self.dataflow_config = ConfigurationManager('/dataflow/app/config/dataflow.cfg')
|
|
16
|
+
self.database_url = self.dataflow_config.get_config_value('database', 'database_url')
|
|
17
|
+
|
|
18
|
+
self.db_instance = DatabaseManager(self.database_url)
|
|
19
|
+
self.db = next(self.db_instance.get_session())
|
|
20
|
+
|
|
21
|
+
m_user.Base.metadata.create_all(bind=self.db_instance.get_engine())
|
|
22
|
+
m_session.Base.metadata.create_all(bind=self.db_instance.get_engine())
|
|
23
|
+
|
|
24
|
+
def generate_session_id(self):
|
|
25
|
+
return str(uuid.uuid4())
|
|
26
|
+
|
|
27
|
+
async def authenticate(self, handler, data):
|
|
28
|
+
# get username and password
|
|
29
|
+
username = data["username"]
|
|
30
|
+
password = data["password"]
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
# check if user exists
|
|
34
|
+
query = self.db.query(m_user.User)
|
|
35
|
+
user = query.filter(m_user.User.user_name == username).first()
|
|
36
|
+
|
|
37
|
+
if user is not None:
|
|
38
|
+
# check if password is correct
|
|
39
|
+
if user.password != password:
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
# generate session_id
|
|
43
|
+
session_id = self.generate_session_id()
|
|
44
|
+
query = self.db.query(m_session.Session_table)
|
|
45
|
+
isSession = query.filter(m_session.Session_table.session_id == session_id).first()
|
|
46
|
+
|
|
47
|
+
# if session_id is already exists in the database, generate a new one
|
|
48
|
+
while isSession is not None:
|
|
49
|
+
session_id = self.generate_session_id()
|
|
50
|
+
isSession = query.filter(m_session.Session_table.session_id == session_id).first()
|
|
51
|
+
|
|
52
|
+
# add session_id to the database
|
|
53
|
+
db_item = m_session.Session_table(user_id=user.user_id, session_id=session_id)
|
|
54
|
+
self.db.add(db_item)
|
|
55
|
+
self.db.commit()
|
|
56
|
+
self.db.refresh(db_item)
|
|
57
|
+
|
|
58
|
+
# return user dictionary and set cookie
|
|
59
|
+
handler.set_cookie("dataflow_session", session_id)
|
|
60
|
+
user_dict = {"name": username, "session_id": session_id}
|
|
61
|
+
return user_dict
|
|
62
|
+
else:
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
except Exception as e:
|
|
66
|
+
return None
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""configuration.py"""
|
|
2
|
+
import configparser
|
|
3
|
+
from configparser import NoOptionError, NoSectionError
|
|
4
|
+
|
|
5
|
+
class ConfigurationManager:
|
|
6
|
+
"""
|
|
7
|
+
Configuration Manager
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, config_file):
|
|
11
|
+
|
|
12
|
+
self.config_file = config_file
|
|
13
|
+
self.config = configparser.ConfigParser()
|
|
14
|
+
try:
|
|
15
|
+
self.config.read(self.config_file)
|
|
16
|
+
|
|
17
|
+
except Exception as e:
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
def get_config_value(self, section, option):
|
|
21
|
+
"""
|
|
22
|
+
Get configuration value
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
return self.config.get(section, option)
|
|
26
|
+
except (NoOptionError, NoSectionError):
|
|
27
|
+
return None
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""models/database.py"""
|
|
2
|
+
from sqlalchemy.exc import SQLAlchemyError
|
|
3
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
4
|
+
from sqlalchemy import create_engine
|
|
5
|
+
from sqlalchemy.orm import sessionmaker
|
|
6
|
+
|
|
7
|
+
class DatabaseManager:
|
|
8
|
+
def __init__(self, db_url):
|
|
9
|
+
self.db_url = db_url
|
|
10
|
+
|
|
11
|
+
def get_engine(self):
|
|
12
|
+
try:
|
|
13
|
+
engine = create_engine(self.db_url)
|
|
14
|
+
return engine
|
|
15
|
+
except SQLAlchemyError as e:
|
|
16
|
+
raise e
|
|
17
|
+
|
|
18
|
+
def get_session(self):
|
|
19
|
+
try:
|
|
20
|
+
engine = self.get_engine()
|
|
21
|
+
session = sessionmaker(autocommit=False, autoflush=False, bind=engine or create_engine(self.db_url))
|
|
22
|
+
db = session()
|
|
23
|
+
try:
|
|
24
|
+
yield db
|
|
25
|
+
finally:
|
|
26
|
+
db.close()
|
|
27
|
+
|
|
28
|
+
except SQLAlchemyError as e:
|
|
29
|
+
raise e
|
|
30
|
+
|
|
31
|
+
def get_base(self):
|
|
32
|
+
return declarative_base()
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""models.py"""
|
|
2
|
+
from sqlalchemy import Column, Integer, String
|
|
3
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
4
|
+
|
|
5
|
+
#instance for create declarative base
|
|
6
|
+
Base=declarative_base()
|
|
7
|
+
|
|
8
|
+
class Session_table(Base):
|
|
9
|
+
"""
|
|
10
|
+
Table SESSIONS
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__tablename__='SESSION'
|
|
14
|
+
|
|
15
|
+
id = Column(Integer, primary_key=True, index=True, unique=True, nullable=False, autoincrement=True)
|
|
16
|
+
session_id = Column(String, unique=True, nullable=False)
|
|
17
|
+
user_id = Column(String, nullable=False)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""models.py"""
|
|
2
|
+
from sqlalchemy import Column, Integer, String, LargeBinary, Enum
|
|
3
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
4
|
+
|
|
5
|
+
#instance for create declarative base
|
|
6
|
+
Base=declarative_base()
|
|
7
|
+
|
|
8
|
+
class User(Base):
|
|
9
|
+
"""
|
|
10
|
+
Table USER
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__tablename__='USER'
|
|
14
|
+
|
|
15
|
+
user_id = Column(Integer, primary_key=True, index=True, autoincrement=True, nullable=False)
|
|
16
|
+
user_name = Column(String, unique=True, nullable=False)
|
|
17
|
+
first_name = Column(String)
|
|
18
|
+
last_name = Column(String)
|
|
19
|
+
email = Column(String, unique=True)
|
|
20
|
+
role = Column(Enum('admin', 'user', name='role_field'), nullable=False)
|
|
21
|
+
image = Column(LargeBinary)
|
|
22
|
+
active = Column(Enum('N', 'Y', name='active_field'), nullable=False, server_default=str("N"))
|
|
23
|
+
password = Column(String, nullable=False)
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""configuration.py"""
|
|
2
|
+
import configparser
|
|
3
|
+
from configparser import NoOptionError, NoSectionError
|
|
4
|
+
|
|
5
|
+
class ConfigurationManager:
|
|
6
|
+
"""
|
|
7
|
+
Configuration Manager
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, config_file):
|
|
11
|
+
|
|
12
|
+
self.config_file = config_file
|
|
13
|
+
self.config = configparser.ConfigParser()
|
|
14
|
+
try:
|
|
15
|
+
self.config.read(self.config_file)
|
|
16
|
+
|
|
17
|
+
except Exception as e:
|
|
18
|
+
return None
|
|
19
|
+
|
|
20
|
+
def get_config_value(self, section, option):
|
|
21
|
+
"""
|
|
22
|
+
Get configuration value
|
|
23
|
+
"""
|
|
24
|
+
try:
|
|
25
|
+
return self.config.get(section, option)
|
|
26
|
+
except (NoOptionError, NoSectionError):
|
|
27
|
+
return None
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from .configuration import ConfigurationManager
|
|
3
|
+
from .models import (
|
|
4
|
+
session as m_session,
|
|
5
|
+
user as m_user,
|
|
6
|
+
)
|
|
7
|
+
from .models.database import DatabaseManager
|
|
8
|
+
from sqlalchemy.inspection import inspect
|
|
9
|
+
from .utils.aws_secrets_manager import SecretsManagerClient
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Dataflow:
|
|
14
|
+
def __init__(self):
|
|
15
|
+
self.dataflow_config = ConfigurationManager('/dataflow/app/config/dataflow.cfg')
|
|
16
|
+
self.dataflow_database_url = self.dataflow_config.get_config_value('database', 'database_url')
|
|
17
|
+
|
|
18
|
+
self.dataflow_db_instance = DatabaseManager(self.dataflow_database_url)
|
|
19
|
+
self.dataflow_db = next(self.dataflow_db_instance.get_session())
|
|
20
|
+
|
|
21
|
+
self.secrets_manager = SecretsManagerClient('us-east-1')
|
|
22
|
+
|
|
23
|
+
m_user.Base.metadata.create_all(bind=self.dataflow_db_instance.get_engine())
|
|
24
|
+
m_session.Base.metadata.create_all(bind=self.dataflow_db_instance.get_engine())
|
|
25
|
+
|
|
26
|
+
def auth(self, session_id: str):
|
|
27
|
+
"""Find user by session_id in dataflow database."""
|
|
28
|
+
try:
|
|
29
|
+
query = self.dataflow_db.query(m_session.Session_table)
|
|
30
|
+
session = query.filter(m_session.Session_table.session_id == session_id).first()
|
|
31
|
+
if session is None:
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
user_data = self.dataflow_db.query(m_user.User).filter(m_user.User.user_id == session.user_id).first()
|
|
35
|
+
if user_data is None:
|
|
36
|
+
return False
|
|
37
|
+
|
|
38
|
+
user_dict = {"user_name": user_data.user_name, "name": f"{user_data.first_name} {user_data.last_name}", "email": user_data.email, "role": user_data.role}
|
|
39
|
+
return user_dict
|
|
40
|
+
|
|
41
|
+
except Exception as e:
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
def variable(self, variable_name: str):
|
|
45
|
+
"""Get variable value from secrets manager."""
|
|
46
|
+
try:
|
|
47
|
+
host_name = os.environ["HOSTNAME"]
|
|
48
|
+
user_name = host_name.replace("jupyter-","")
|
|
49
|
+
|
|
50
|
+
vault_path = "variable"
|
|
51
|
+
return self.secrets_manager.get_secret_by_key(vault_path, user_name, variable_name)
|
|
52
|
+
|
|
53
|
+
except Exception as e:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
def connection(self, conn_id: str):
|
|
57
|
+
"""Get connection details from secrets manager."""
|
|
58
|
+
try:
|
|
59
|
+
host_name = os.environ["HOSTNAME"]
|
|
60
|
+
user_name=host_name.replace("jupyter-","")
|
|
61
|
+
|
|
62
|
+
vault_path = "connections"
|
|
63
|
+
secret = self.secrets_manager.get_secret_by_key(vault_path, user_name, conn_id)
|
|
64
|
+
|
|
65
|
+
conn_type = secret['conn_type'].lower()
|
|
66
|
+
username = secret['login']
|
|
67
|
+
password = secret.get('password', '')
|
|
68
|
+
host = secret['host']
|
|
69
|
+
port = secret['port']
|
|
70
|
+
database = secret.get('schemas', '')
|
|
71
|
+
|
|
72
|
+
user_info = f"{username}:{password}@" if password else f"{username}@"
|
|
73
|
+
db_info = f"/{database}" if database else ""
|
|
74
|
+
|
|
75
|
+
connection_string = f"{conn_type}://{user_info}{host}:{port}{db_info}"
|
|
76
|
+
|
|
77
|
+
extra = secret.get('extra', '')
|
|
78
|
+
if extra:
|
|
79
|
+
try:
|
|
80
|
+
extra_params = json.loads(extra)
|
|
81
|
+
if extra_params:
|
|
82
|
+
extra_query = "&".join(f"{key}={value}" for key, value in extra_params.items())
|
|
83
|
+
connection_string += f"?{extra_query}"
|
|
84
|
+
except json.JSONDecodeError:
|
|
85
|
+
# If 'extra' is not valid JSON, skip adding extra parameters
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
connection_instance = DatabaseManager(connection_string)
|
|
89
|
+
return next(connection_instance.get_session())
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
return None
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""models/database.py"""
|
|
2
|
+
from sqlalchemy.exc import SQLAlchemyError
|
|
3
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
4
|
+
from sqlalchemy import create_engine
|
|
5
|
+
from sqlalchemy.orm import sessionmaker
|
|
6
|
+
|
|
7
|
+
class DatabaseManager:
|
|
8
|
+
def __init__(self, db_url):
|
|
9
|
+
self.db_url = db_url
|
|
10
|
+
|
|
11
|
+
def get_engine(self):
|
|
12
|
+
try:
|
|
13
|
+
engine = create_engine(self.db_url)
|
|
14
|
+
return engine
|
|
15
|
+
except SQLAlchemyError as e:
|
|
16
|
+
raise e
|
|
17
|
+
|
|
18
|
+
def get_session(self):
|
|
19
|
+
try:
|
|
20
|
+
engine = self.get_engine()
|
|
21
|
+
session = sessionmaker(autocommit=False, autoflush=False, bind=engine or create_engine(self.db_url))
|
|
22
|
+
db = session()
|
|
23
|
+
try:
|
|
24
|
+
yield db
|
|
25
|
+
finally:
|
|
26
|
+
db.close()
|
|
27
|
+
|
|
28
|
+
except SQLAlchemyError as e:
|
|
29
|
+
raise e
|
|
30
|
+
|
|
31
|
+
def get_base(self):
|
|
32
|
+
return declarative_base()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""models.py"""
|
|
2
|
+
from sqlalchemy import Column, Integer, String
|
|
3
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
4
|
+
|
|
5
|
+
#instance for create declarative base
|
|
6
|
+
Base=declarative_base()
|
|
7
|
+
|
|
8
|
+
class Session_table(Base):
|
|
9
|
+
"""
|
|
10
|
+
Table SESSIONS
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__tablename__='SESSION'
|
|
14
|
+
|
|
15
|
+
id = Column(Integer, primary_key=True, index=True, unique=True, nullable=False, autoincrement=True)
|
|
16
|
+
session_id = Column(String, unique=True, nullable=False)
|
|
17
|
+
user_id = Column(String, nullable=False)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""models.py"""
|
|
2
|
+
from sqlalchemy import Column, Integer, String, LargeBinary, Enum
|
|
3
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
4
|
+
|
|
5
|
+
#instance for create declarative base
|
|
6
|
+
Base=declarative_base()
|
|
7
|
+
|
|
8
|
+
class User(Base):
|
|
9
|
+
"""
|
|
10
|
+
Table USER
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__tablename__='USER'
|
|
14
|
+
|
|
15
|
+
user_id = Column(Integer, primary_key=True, index=True, autoincrement=True, nullable=False)
|
|
16
|
+
user_name = Column(String, unique=True, nullable=False)
|
|
17
|
+
first_name = Column(String)
|
|
18
|
+
last_name = Column(String)
|
|
19
|
+
email = Column(String, unique=True)
|
|
20
|
+
role = Column(Enum('admin', 'user', name='role_field'), nullable=False)
|
|
21
|
+
image = Column(LargeBinary)
|
|
22
|
+
active = Column(Enum('N', 'Y', name='active_field'), nullable=False, server_default=str("N"))
|
|
23
|
+
password = Column(String, nullable=False)
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import boto3
|
|
2
|
+
from botocore.exceptions import ClientError, EndpointConnectionError, NoCredentialsError
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
class SecretsManagerClient:
|
|
6
|
+
"""
|
|
7
|
+
A class to interact with AWS Secrets Manager for managing secrets.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
region_name (str): The AWS region name.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
client: The Boto3 client for Secrets Manager.
|
|
14
|
+
json_handler: An instance of JsonHandler for handling JSON operations.
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self, region_name: str):
|
|
17
|
+
try:
|
|
18
|
+
self.client = boto3.client('secretsmanager', region_name=region_name)
|
|
19
|
+
except EndpointConnectionError as e:
|
|
20
|
+
self.logger.error(f"Failed to initialize SecretsManagerClient: {e}")
|
|
21
|
+
raise Exception(f"Failed to initialize SecretsManagerClient: Unable to connect to the endpoint. {e}")
|
|
22
|
+
except NoCredentialsError as e:
|
|
23
|
+
self.logger.error(f"Failed to initialize SecretsManagerClient: {e}")
|
|
24
|
+
raise Exception(f"Failed to initialize SecretsManagerClient: No AWS credentials found. {e}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_secret_by_key(self, vault_path, user_name, secret_key: str):
|
|
28
|
+
"""
|
|
29
|
+
Get information about a specific secret.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
vault_path (str): The vault path.
|
|
33
|
+
user_name (str): The user name.
|
|
34
|
+
secret_key (str): The key of the secret to retrieve.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
str: Information about the secret in JSON format.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
Exception: If the operation fails.
|
|
41
|
+
"""
|
|
42
|
+
try:
|
|
43
|
+
if not user_name:
|
|
44
|
+
raise Exception("user_name is required when secret_key is provided")
|
|
45
|
+
|
|
46
|
+
secret_name = f"{user_name}/{vault_path}/{secret_key}"
|
|
47
|
+
response = self.client.get_secret_value(SecretId=secret_name)
|
|
48
|
+
secret_metadata = self.client.describe_secret(SecretId=secret_name)
|
|
49
|
+
secret_data = json.loads(response.get('SecretString'))
|
|
50
|
+
|
|
51
|
+
if secret_data.get('is_active') == 'Y':
|
|
52
|
+
secret_info={
|
|
53
|
+
"Name": secret_key,
|
|
54
|
+
"Description": secret_metadata.get('Description')
|
|
55
|
+
}
|
|
56
|
+
secret_info.update(secret_data)
|
|
57
|
+
return secret_info
|
|
58
|
+
else:
|
|
59
|
+
raise Exception(f"Secret named '{secret_key}' is not active")
|
|
60
|
+
except ClientError as e:
|
|
61
|
+
if e.response['Error']['Code'] == 'ResourceNotFoundException':
|
|
62
|
+
raise Exception(f"Secret named '{secret_key}' not found")
|
|
63
|
+
else:
|
|
64
|
+
raise Exception(f"Failed to get secret '{secret_key}': {e}")
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
authenticator/__init__.py
|
|
4
|
+
authenticator/dataflowairflowauthenticator.py
|
|
5
|
+
authenticator/dataflowhubauthenticator.py
|
|
6
|
+
authenticator/package/__init__.py
|
|
7
|
+
authenticator/package/configuration.py
|
|
8
|
+
authenticator/package/models/__init__.py
|
|
9
|
+
authenticator/package/models/database.py
|
|
10
|
+
authenticator/package/models/session.py
|
|
11
|
+
authenticator/package/models/user.py
|
|
12
|
+
dataflow/__init__.py
|
|
13
|
+
dataflow/configuration.py
|
|
14
|
+
dataflow/dataflow.py
|
|
15
|
+
dataflow/models/__init__.py
|
|
16
|
+
dataflow/models/database.py
|
|
17
|
+
dataflow/models/session.py
|
|
18
|
+
dataflow/models/user.py
|
|
19
|
+
dataflow/utils/__init__.py
|
|
20
|
+
dataflow/utils/aws_secrets_manager.py
|
|
21
|
+
dataflow_core.egg-info/PKG-INFO
|
|
22
|
+
dataflow_core.egg-info/SOURCES.txt
|
|
23
|
+
dataflow_core.egg-info/dependency_links.txt
|
|
24
|
+
dataflow_core.egg-info/entry_points.txt
|
|
25
|
+
dataflow_core.egg-info/requires.txt
|
|
26
|
+
dataflow_core.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="dataflow-core",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
packages=find_packages(exclude=["tests", "tests.*"]),
|
|
7
|
+
include_package_data=True,
|
|
8
|
+
package_data={},
|
|
9
|
+
install_requires=[
|
|
10
|
+
'sqlalchemy',
|
|
11
|
+
'boto3',
|
|
12
|
+
],
|
|
13
|
+
author="Dataflow",
|
|
14
|
+
author_email="",
|
|
15
|
+
description="Dataflow core package",
|
|
16
|
+
entry_points={
|
|
17
|
+
'jupyterhub.authenticators': [
|
|
18
|
+
'dataflow_authenticator = authenticator.dataflowhubauthenticator:DataflowHubAuthenticator',
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
)
|