Encryptors 2.30__tar.gz → 2.32__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.
- {encryptors-2.30 → encryptors-2.32}/PKG-INFO +1 -1
- {encryptors-2.30 → encryptors-2.32}/setup.py +1 -1
- {encryptors-2.30 → encryptors-2.32}/src/Encryptors.egg-info/PKG-INFO +1 -1
- {encryptors-2.30 → encryptors-2.32}/src/Encryptors.egg-info/SOURCES.txt +11 -26
- encryptors-2.32/src/Osdental/Database/Connection.py +66 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Decorators/SecureResolver.py +11 -28
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Encryptor/Bcrypt.py +1 -1
- encryptors-2.32/src/Osdental/Exception/ControlledException.py +142 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Graphql/Extensions/AuditExtension.py +11 -9
- encryptors-2.32/src/Osdental/Graphql/_Exceptions/__init__.py +8 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Graphql/_Helpers/_AuditHelper.py +9 -13
- encryptors-2.32/src/Osdental/Graphql/_Helpers/_ExtractAuthToken.py +11 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Graphql/_Helpers/_TenantPolicy.py +10 -2
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Graphql/_Helpers/_TokenService.py +4 -6
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Helpers/AuditDispatcher.py +47 -19
- encryptors-2.32/src/Osdental/Http/APIClient.py +137 -0
- encryptors-2.32/src/Osdental/Http/_Exceptions.py +12 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Messaging/AzureServiceBus.py +12 -3
- encryptors-2.32/src/Osdental/Messaging/Kafka.py +11 -0
- encryptors-2.32/src/Osdental/Messaging/RabbitMQ.py +11 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Messaging/__init__.py +2 -2
- encryptors-2.32/src/Osdental/Models/Response.py +19 -0
- encryptors-2.32/src/Osdental/Models/_Audit.py +13 -0
- encryptors-2.32/src/Osdental/Rest/Context/RequestContext.py +19 -0
- encryptors-2.32/src/Osdental/Rest/Middlewares/RequestContextMiddleware.py +22 -0
- encryptors-2.32/src/Osdental/Shared/Enums/Constant.py +10 -0
- encryptors-2.30/src/Osdental/BlobStorage/Storage.py +0 -50
- encryptors-2.30/src/Osdental/Database/Connection.py +0 -218
- encryptors-2.30/src/Osdental/Database/UnitOfWork.py +0 -44
- encryptors-2.30/src/Osdental/Database/UowFactory.py +0 -8
- encryptors-2.30/src/Osdental/Decorators/AuditLog.py +0 -87
- encryptors-2.30/src/Osdental/Decorators/DecryptedData.py +0 -139
- encryptors-2.30/src/Osdental/Exception/ControlledException.py +0 -189
- encryptors-2.30/src/Osdental/ExternalHttp/Client.py +0 -117
- encryptors-2.30/src/Osdental/Grpc/Base/GrpcClientBase.py +0 -61
- encryptors-2.30/src/Osdental/Grpc/Client/PortalClient.py +0 -44
- encryptors-2.30/src/Osdental/Grpc/Generated/Common_pb2.py +0 -40
- encryptors-2.30/src/Osdental/Grpc/Generated/Common_pb2_grpc.py +0 -24
- encryptors-2.30/src/Osdental/Grpc/Generated/Portal_pb2.py +0 -37
- encryptors-2.30/src/Osdental/Grpc/Generated/Portal_pb2_grpc.py +0 -140
- encryptors-2.30/src/Osdental/InternalHttp/Request.py +0 -105
- encryptors-2.30/src/Osdental/InternalHttp/Response.py +0 -39
- encryptors-2.30/src/Osdental/Messaging/Kafka.py +0 -12
- encryptors-2.30/src/Osdental/Messaging/RabbitMQ.py +0 -12
- encryptors-2.30/src/Osdental/Models/CDataIntegration.py +0 -41
- encryptors-2.30/src/Osdental/Models/Response.py +0 -12
- encryptors-2.30/src/Osdental/ServicesBus/ServicesBus.py +0 -26
- encryptors-2.30/src/Osdental/ServicesBus/TaskQueue.py +0 -52
- encryptors-2.30/src/Osdental/Shared/Config/__init__.py +0 -15
- encryptors-2.30/src/Osdental/Shared/Enums/Constant.py +0 -16
- encryptors-2.30/src/Osdental/Shared/Enums/__init__.py +0 -0
- encryptors-2.30/src/Osdental/Shared/Utils/__init__.py +0 -0
- encryptors-2.30/src/Osdental/Shared/__init__.py +0 -0
- encryptors-2.30/src/Osdental/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/README.md +0 -0
- {encryptors-2.30 → encryptors-2.32}/setup.cfg +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Encryptors.egg-info/dependency_links.txt +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Encryptors.egg-info/entry_points.txt +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Encryptors.egg-info/requires.txt +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Encryptors.egg-info/top_level.txt +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Cli/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Database/BaseRepository.py +0 -0
- {encryptors-2.30/src/Osdental/BlobStorage → encryptors-2.32/src/Osdental/Database}/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Decorators/Grpc.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Decorators/Retry.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Decorators/SqlDataNormalizer.py +0 -0
- {encryptors-2.30/src/Osdental/Database → encryptors-2.32/src/Osdental/Decorators}/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Encryptor/Aes.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Encryptor/Argon2.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Encryptor/Jwt.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Encryptor/Rsa.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Encryptor/Sha512.py +0 -0
- {encryptors-2.30/src/Osdental/Decorators → encryptors-2.32/src/Osdental/Encryptor}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/Encryptor → encryptors-2.32/src/Osdental/Exception}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/Exception → encryptors-2.32/src/Osdental/Graphql/Extensions}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/ExternalHttp → encryptors-2.32/src/Osdental/Graphql/_Helpers}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/Graphql/Extensions → encryptors-2.32/src/Osdental/Graphql}/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Helpers/KeyVaultService.py +0 -0
- {encryptors-2.30/src/Osdental/Graphql/_Helpers → encryptors-2.32/src/Osdental/Helpers}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/Graphql → encryptors-2.32/src/Osdental/Http}/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Models/AuditConfig.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Models/Catalog.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Models/Legacy.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Models/Token.py +0 -0
- {encryptors-2.30/src/Osdental/Grpc/Base → encryptors-2.32/src/Osdental/Models}/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/RedisCache/Redis.py +0 -0
- {encryptors-2.30/src/Osdental/Grpc/Client → encryptors-2.32/src/Osdental/RedisCache}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/Grpc/Generated → encryptors-2.32/src/Osdental/Rest/Context}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/Grpc → encryptors-2.32/src/Osdental/Rest/Middlewares}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/Helpers → encryptors-2.32/src/Osdental/Rest}/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Enums/Code.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Enums/FileType.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Enums/GrahpqlOperation.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Enums/Message.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Enums/Profile.py +0 -0
- {encryptors-2.30/src/Osdental/InternalHttp → encryptors-2.32/src/Osdental/Shared/Enums}/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Logger.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/CaseConverter.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/CodeGenerator.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/DataNormalizer.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/DataUtils.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/DateUtils.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/FileMetaData.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/HashValidator.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/Mapper.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/PasswordGenerator.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/QueryGenerator.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Shared/Utils/TextProcessor.py +0 -0
- {encryptors-2.30/src/Osdental/Models → encryptors-2.32/src/Osdental/Shared/Utils}/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/RedisCache → encryptors-2.32/src/Osdental/Shared}/__init__.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Storage/AzureBlobStorage.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Storage/S3Storage.py +0 -0
- {encryptors-2.30 → encryptors-2.32}/src/Osdental/Storage/__init__.py +0 -0
- {encryptors-2.30/src/Osdental/ServicesBus → encryptors-2.32/src/Osdental}/__init__.py +0 -0
|
@@ -7,16 +7,10 @@ src/Encryptors.egg-info/entry_points.txt
|
|
|
7
7
|
src/Encryptors.egg-info/requires.txt
|
|
8
8
|
src/Encryptors.egg-info/top_level.txt
|
|
9
9
|
src/Osdental/__init__.py
|
|
10
|
-
src/Osdental/BlobStorage/Storage.py
|
|
11
|
-
src/Osdental/BlobStorage/__init__.py
|
|
12
10
|
src/Osdental/Cli/__init__.py
|
|
13
11
|
src/Osdental/Database/BaseRepository.py
|
|
14
12
|
src/Osdental/Database/Connection.py
|
|
15
|
-
src/Osdental/Database/UnitOfWork.py
|
|
16
|
-
src/Osdental/Database/UowFactory.py
|
|
17
13
|
src/Osdental/Database/__init__.py
|
|
18
|
-
src/Osdental/Decorators/AuditLog.py
|
|
19
|
-
src/Osdental/Decorators/DecryptedData.py
|
|
20
14
|
src/Osdental/Decorators/Grpc.py
|
|
21
15
|
src/Osdental/Decorators/Retry.py
|
|
22
16
|
src/Osdental/Decorators/SecureResolver.py
|
|
@@ -31,50 +25,41 @@ src/Osdental/Encryptor/Sha512.py
|
|
|
31
25
|
src/Osdental/Encryptor/__init__.py
|
|
32
26
|
src/Osdental/Exception/ControlledException.py
|
|
33
27
|
src/Osdental/Exception/__init__.py
|
|
34
|
-
src/Osdental/ExternalHttp/Client.py
|
|
35
|
-
src/Osdental/ExternalHttp/__init__.py
|
|
36
28
|
src/Osdental/Graphql/__init__.py
|
|
37
29
|
src/Osdental/Graphql/Extensions/AuditExtension.py
|
|
38
30
|
src/Osdental/Graphql/Extensions/__init__.py
|
|
31
|
+
src/Osdental/Graphql/_Exceptions/__init__.py
|
|
39
32
|
src/Osdental/Graphql/_Helpers/_AuditHelper.py
|
|
33
|
+
src/Osdental/Graphql/_Helpers/_ExtractAuthToken.py
|
|
40
34
|
src/Osdental/Graphql/_Helpers/_TenantPolicy.py
|
|
41
35
|
src/Osdental/Graphql/_Helpers/_TokenService.py
|
|
42
36
|
src/Osdental/Graphql/_Helpers/__init__.py
|
|
43
|
-
src/Osdental/Grpc/__init__.py
|
|
44
|
-
src/Osdental/Grpc/Base/GrpcClientBase.py
|
|
45
|
-
src/Osdental/Grpc/Base/__init__.py
|
|
46
|
-
src/Osdental/Grpc/Client/PortalClient.py
|
|
47
|
-
src/Osdental/Grpc/Client/__init__.py
|
|
48
|
-
src/Osdental/Grpc/Generated/Common_pb2.py
|
|
49
|
-
src/Osdental/Grpc/Generated/Common_pb2_grpc.py
|
|
50
|
-
src/Osdental/Grpc/Generated/Portal_pb2.py
|
|
51
|
-
src/Osdental/Grpc/Generated/Portal_pb2_grpc.py
|
|
52
|
-
src/Osdental/Grpc/Generated/__init__.py
|
|
53
37
|
src/Osdental/Helpers/AuditDispatcher.py
|
|
54
38
|
src/Osdental/Helpers/KeyVaultService.py
|
|
55
39
|
src/Osdental/Helpers/__init__.py
|
|
56
|
-
src/Osdental/
|
|
57
|
-
src/Osdental/
|
|
58
|
-
src/Osdental/
|
|
40
|
+
src/Osdental/Http/APIClient.py
|
|
41
|
+
src/Osdental/Http/_Exceptions.py
|
|
42
|
+
src/Osdental/Http/__init__.py
|
|
59
43
|
src/Osdental/Messaging/AzureServiceBus.py
|
|
60
44
|
src/Osdental/Messaging/Kafka.py
|
|
61
45
|
src/Osdental/Messaging/RabbitMQ.py
|
|
62
46
|
src/Osdental/Messaging/__init__.py
|
|
63
47
|
src/Osdental/Models/AuditConfig.py
|
|
64
|
-
src/Osdental/Models/CDataIntegration.py
|
|
65
48
|
src/Osdental/Models/Catalog.py
|
|
66
49
|
src/Osdental/Models/Legacy.py
|
|
67
50
|
src/Osdental/Models/Response.py
|
|
68
51
|
src/Osdental/Models/Token.py
|
|
52
|
+
src/Osdental/Models/_Audit.py
|
|
69
53
|
src/Osdental/Models/__init__.py
|
|
70
54
|
src/Osdental/RedisCache/Redis.py
|
|
71
55
|
src/Osdental/RedisCache/__init__.py
|
|
72
|
-
src/Osdental/
|
|
73
|
-
src/Osdental/
|
|
74
|
-
src/Osdental/
|
|
56
|
+
src/Osdental/Rest/__init__.py
|
|
57
|
+
src/Osdental/Rest/Context/RequestContext.py
|
|
58
|
+
src/Osdental/Rest/Context/__init__.py
|
|
59
|
+
src/Osdental/Rest/Middlewares/RequestContextMiddleware.py
|
|
60
|
+
src/Osdental/Rest/Middlewares/__init__.py
|
|
75
61
|
src/Osdental/Shared/Logger.py
|
|
76
62
|
src/Osdental/Shared/__init__.py
|
|
77
|
-
src/Osdental/Shared/Config/__init__.py
|
|
78
63
|
src/Osdental/Shared/Enums/Code.py
|
|
79
64
|
src/Osdental/Shared/Enums/Constant.py
|
|
80
65
|
src/Osdental/Shared/Enums/FileType.py
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import struct
|
|
2
|
+
import urllib
|
|
3
|
+
from typing import Dict
|
|
4
|
+
from azure.identity import DefaultAzureCredential
|
|
5
|
+
from sqlalchemy import event
|
|
6
|
+
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
|
7
|
+
from sqlalchemy.orm import sessionmaker
|
|
8
|
+
|
|
9
|
+
SQL_COPT_SS_ACCESS_TOKEN = 1256
|
|
10
|
+
class Connection:
|
|
11
|
+
|
|
12
|
+
_instances: Dict[str, 'Connection'] = {}
|
|
13
|
+
|
|
14
|
+
def __new__(cls, db_url: str):
|
|
15
|
+
if db_url not in cls._instances:
|
|
16
|
+
cls._instances[db_url] = super(Connection, cls).__new__(cls)
|
|
17
|
+
return cls._instances[db_url]
|
|
18
|
+
|
|
19
|
+
def __init__(self, db_url: str):
|
|
20
|
+
if not hasattr(self, 'initialized'):
|
|
21
|
+
self.credential = DefaultAzureCredential()
|
|
22
|
+
raw_odbc_string = db_url
|
|
23
|
+
params = urllib.parse.quote_plus(raw_odbc_string)
|
|
24
|
+
sqlalchemy_url = f"mssql+aioodbc:///?odbc_connect={params}"
|
|
25
|
+
self.engine = create_async_engine(
|
|
26
|
+
sqlalchemy_url,
|
|
27
|
+
pool_size=20,
|
|
28
|
+
max_overflow=40,
|
|
29
|
+
pool_timeout=30,
|
|
30
|
+
pool_recycle=1800,
|
|
31
|
+
pool_pre_ping=True
|
|
32
|
+
)
|
|
33
|
+
self._attach_token_listener()
|
|
34
|
+
self.session_factory = sessionmaker(
|
|
35
|
+
bind=self.engine,
|
|
36
|
+
class_=AsyncSession,
|
|
37
|
+
expire_on_commit=False
|
|
38
|
+
)
|
|
39
|
+
self.initialized = True
|
|
40
|
+
|
|
41
|
+
def _attach_token_listener(self):
|
|
42
|
+
|
|
43
|
+
@event.listens_for(self.engine.sync_engine, "do_connect")
|
|
44
|
+
def provide_token(dialect, conn_rec, cargs, cparams):
|
|
45
|
+
|
|
46
|
+
token = self.credential.get_token(
|
|
47
|
+
"https://database.windows.net/.default"
|
|
48
|
+
).token
|
|
49
|
+
|
|
50
|
+
token_bytes = token.encode("utf-16-le")
|
|
51
|
+
|
|
52
|
+
token_struct = struct.pack(
|
|
53
|
+
f"<I{len(token_bytes)}s",
|
|
54
|
+
len(token_bytes),
|
|
55
|
+
token_bytes
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
cparams["attrs_before"] = {
|
|
59
|
+
SQL_COPT_SS_ACCESS_TOKEN: token_struct
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
async def close_engine(self) -> None:
|
|
64
|
+
"""Dispose of the engine and remove instance."""
|
|
65
|
+
if self.engine:
|
|
66
|
+
await self.engine.dispose()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
import
|
|
2
|
+
import copy
|
|
3
3
|
from functools import wraps
|
|
4
4
|
from typing import Callable, Dict, Any
|
|
5
5
|
from graphql import GraphQLResolveInfo
|
|
@@ -33,38 +33,21 @@ def secure_resolver(action = None):
|
|
|
33
33
|
|
|
34
34
|
result: Response = await func(obj, info, **kwargs)
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
result.data = aes.encrypt(aes_key, result.data)
|
|
38
|
-
|
|
39
|
-
return result
|
|
40
|
-
|
|
41
|
-
# await info.context.audit_dispatcher.dispatch(
|
|
42
|
-
# security=security,
|
|
43
|
-
# result=result
|
|
44
|
-
# )
|
|
36
|
+
info.context.audit_plain_response = copy.deepcopy(result)
|
|
45
37
|
|
|
46
38
|
if result.data is not None:
|
|
47
|
-
result.data = aes.encrypt(
|
|
48
|
-
|
|
39
|
+
result.data = aes.encrypt(aes_key, result.data)
|
|
49
40
|
|
|
50
|
-
return result
|
|
41
|
+
return result.send()
|
|
51
42
|
|
|
52
43
|
except (Exception, OSDException) as e:
|
|
53
|
-
result =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
# _ = asyncio.create_task(
|
|
61
|
-
# info.context.audit_dispatcher.dispatch(
|
|
62
|
-
# security=security,
|
|
63
|
-
# result=result
|
|
64
|
-
# )
|
|
65
|
-
# )
|
|
66
|
-
|
|
67
|
-
return result
|
|
44
|
+
result = Response(
|
|
45
|
+
status=getattr(e, "status_code", "DB_ERROR_UNEXPECTED"),
|
|
46
|
+
message=getattr(e, "message", "Could not process request."),
|
|
47
|
+
error=f"{type(e).__name__}: {str(e)}"
|
|
48
|
+
)
|
|
49
|
+
info.context.audit_plain_response = result
|
|
50
|
+
return result.send()
|
|
68
51
|
|
|
69
52
|
return wrapper
|
|
70
53
|
return decorator
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from Osdental.Shared.Enums.Code import Code
|
|
3
|
+
from Osdental.Shared.Enums.Message import Message
|
|
4
|
+
|
|
5
|
+
class OSDException(Exception):
|
|
6
|
+
""" Base class for all custom exceptions. """
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
10
|
+
error: str = None,
|
|
11
|
+
status_code: Any = Code.APP_ERROR_CODE
|
|
12
|
+
):
|
|
13
|
+
super().__init__(error)
|
|
14
|
+
self.message = message
|
|
15
|
+
self.error = error
|
|
16
|
+
self.status_code = status_code
|
|
17
|
+
|
|
18
|
+
class UnauthorizedException(OSDException):
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
message: str = Message.PORTAL_ACCESS_RESTRICTED_MSG,
|
|
22
|
+
error: str = None,
|
|
23
|
+
status_code: str = Code.UNAUTHORIZATED_CODE
|
|
24
|
+
):
|
|
25
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
26
|
+
|
|
27
|
+
class RequestDataException(OSDException):
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
message: str = Message.INVALID_REQUEST_PARAMS_MSG,
|
|
31
|
+
error: str = None,
|
|
32
|
+
status_code: str = Code.INVALID_REQUEST_PARAMS_CODE
|
|
33
|
+
):
|
|
34
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
35
|
+
|
|
36
|
+
class DatabaseConnectionException(OSDException):
|
|
37
|
+
def __init__(
|
|
38
|
+
self,
|
|
39
|
+
message: str = Message.INVALID_FORMAT_MSG,
|
|
40
|
+
error: str = None,
|
|
41
|
+
status_code: str = Code.DATABASE_CONNECTION_ERROR_CODE
|
|
42
|
+
):
|
|
43
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
44
|
+
|
|
45
|
+
class DatabaseException(OSDException):
|
|
46
|
+
def __init__(
|
|
47
|
+
self,
|
|
48
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
49
|
+
error: str = None,
|
|
50
|
+
status_code: str = Code.DATABASE_ERROR_CODE
|
|
51
|
+
):
|
|
52
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
53
|
+
|
|
54
|
+
class RSAEncryptException(OSDException):
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
58
|
+
error: str = None,
|
|
59
|
+
status_code: str = Code.RSA_ERROR_CODE
|
|
60
|
+
):
|
|
61
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
62
|
+
|
|
63
|
+
class AESEncryptException(OSDException):
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
67
|
+
error: str = None,
|
|
68
|
+
status_code: str = Code.AES_ERROR_CODE
|
|
69
|
+
):
|
|
70
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
71
|
+
|
|
72
|
+
class JWTokenException(OSDException):
|
|
73
|
+
def __init__(
|
|
74
|
+
self,
|
|
75
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
76
|
+
error: str = None,
|
|
77
|
+
status_code: str = Code.JWT_ERROR_CODE
|
|
78
|
+
):
|
|
79
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
80
|
+
|
|
81
|
+
class AzureException(OSDException):
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
85
|
+
error: str = None,
|
|
86
|
+
status_code: str = Code.AZURE_ERROR_CODE
|
|
87
|
+
):
|
|
88
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
89
|
+
|
|
90
|
+
class RedisException(OSDException):
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
94
|
+
error: str = None,
|
|
95
|
+
status_code: str = Code.REDIS_ERROR_CODE
|
|
96
|
+
):
|
|
97
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
98
|
+
|
|
99
|
+
class ValidationDataException(OSDException):
|
|
100
|
+
def __init__(
|
|
101
|
+
self,
|
|
102
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
103
|
+
error: str = None,
|
|
104
|
+
status_code: str = Code.REQUEST_VALIDATION_ERROR_CODE
|
|
105
|
+
):
|
|
106
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
107
|
+
|
|
108
|
+
class UnexpectedException(OSDException):
|
|
109
|
+
def __init__(
|
|
110
|
+
self,
|
|
111
|
+
message: str = Message.UNEXPECTED_ERROR_MSG,
|
|
112
|
+
error: str = None,
|
|
113
|
+
status_code: str = Code.UNEXPECTED_ERROR_CODE
|
|
114
|
+
):
|
|
115
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
116
|
+
|
|
117
|
+
class MissingFieldException(OSDException):
|
|
118
|
+
def __init__(
|
|
119
|
+
self,
|
|
120
|
+
message: str = Message.MISSING_FIELD_ERROR_MSG,
|
|
121
|
+
error: str = None,
|
|
122
|
+
status_code: str = Code.MISSING_FIELD_ERROR_CODE
|
|
123
|
+
):
|
|
124
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
125
|
+
|
|
126
|
+
class ProfilePermissionDeniedException(OSDException):
|
|
127
|
+
def __init__(
|
|
128
|
+
self,
|
|
129
|
+
message: str = Message.PROFILE_PERMISSION_DENIED_MSG,
|
|
130
|
+
error: str = None,
|
|
131
|
+
status_code: str = Code.PROFILE_PERMISSION_DENIED_CODE
|
|
132
|
+
):
|
|
133
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
134
|
+
|
|
135
|
+
class InvalidFormatException(OSDException):
|
|
136
|
+
def __init__(
|
|
137
|
+
self,
|
|
138
|
+
message: str = Message.INVALID_FORMAT_MSG,
|
|
139
|
+
error: str = None,
|
|
140
|
+
status_code: str = Code.INVALID_FORMAT_CODE
|
|
141
|
+
):
|
|
142
|
+
super().__init__(message=message, error=error, status_code=status_code)
|
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import time
|
|
2
1
|
import json
|
|
3
2
|
from graphql.pyutils import is_awaitable
|
|
4
3
|
from ariadne.types import Extension
|
|
5
4
|
from Osdental.Encryptor.Aes import AES
|
|
6
5
|
from Osdental.Graphql._Helpers._TenantPolicy import TenantPolicy
|
|
7
|
-
from Osdental.
|
|
6
|
+
from Osdental.Graphql._Exceptions import AESKeyNotFound
|
|
8
7
|
|
|
9
8
|
class AuditExtension(Extension):
|
|
10
9
|
|
|
11
10
|
def request_started(self, context):
|
|
12
|
-
self.start_time = time.perf_counter()
|
|
13
11
|
self.errors = None
|
|
14
12
|
self.request_payload = None
|
|
15
13
|
self.result = None
|
|
@@ -31,7 +29,7 @@ class AuditExtension(Extension):
|
|
|
31
29
|
|
|
32
30
|
aes_key = request.app.state.aes_auth
|
|
33
31
|
if not aes_key:
|
|
34
|
-
raise
|
|
32
|
+
raise AESKeyNotFound("Could not find authorization key Aes.")
|
|
35
33
|
|
|
36
34
|
original_token = await token_service.authenticate(request)
|
|
37
35
|
|
|
@@ -52,7 +50,7 @@ class AuditExtension(Extension):
|
|
|
52
50
|
except Exception:
|
|
53
51
|
decrypted_payload = None
|
|
54
52
|
|
|
55
|
-
token
|
|
53
|
+
token = TenantPolicy.resolve(
|
|
56
54
|
token=original_token,
|
|
57
55
|
headers=request.headers,
|
|
58
56
|
decrypted_payload=decrypted_payload,
|
|
@@ -67,9 +65,9 @@ class AuditExtension(Extension):
|
|
|
67
65
|
"user": token.user_full_name
|
|
68
66
|
}
|
|
69
67
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
context.decrypted_payload = decrypted_payload
|
|
69
|
+
context.token = token
|
|
70
|
+
context.aes_key = aes_key
|
|
73
71
|
|
|
74
72
|
result = next_(root, info, **kwargs)
|
|
75
73
|
|
|
@@ -85,12 +83,16 @@ class AuditExtension(Extension):
|
|
|
85
83
|
self.errors = errors
|
|
86
84
|
|
|
87
85
|
def request_finished(self, context):
|
|
86
|
+
query = self.request_payload.get("query", "")
|
|
87
|
+
if "__schema" in query or "__type" in query: return
|
|
88
|
+
|
|
89
|
+
if not hasattr(context, "audit_plain_response"): return
|
|
88
90
|
|
|
89
91
|
dispatcher = context.request.app.state.audit_dispatcher
|
|
90
92
|
|
|
91
93
|
dispatcher.dispatch(
|
|
92
94
|
request=self.request,
|
|
93
95
|
request_payload=self.request_payload,
|
|
94
|
-
result=
|
|
96
|
+
result=context.audit_plain_response,
|
|
95
97
|
errors=self.errors
|
|
96
98
|
)
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from typing import Dict, Literal, Any, Optional
|
|
3
|
-
from
|
|
4
|
-
from Osdental.Models.AuditConfig import AuditConfig
|
|
3
|
+
from Osdental.Models._Audit import Audit
|
|
5
4
|
|
|
6
5
|
class AuditHelper:
|
|
7
6
|
|
|
8
7
|
@staticmethod
|
|
9
|
-
async def build_request_payload(
|
|
10
|
-
request
|
|
11
|
-
audit_config
|
|
12
|
-
payload
|
|
13
|
-
|
|
14
|
-
full_name: str = "Joe Doe"
|
|
15
|
-
) -> Dict:
|
|
16
|
-
|
|
8
|
+
async def build_request_payload(audit: Audit) -> Dict:
|
|
9
|
+
request = audit.request
|
|
10
|
+
audit_config = audit.audit_config
|
|
11
|
+
payload = audit.payload
|
|
12
|
+
|
|
17
13
|
default_value = "*"
|
|
18
14
|
|
|
19
15
|
user_ip = request.headers.get("X-Forwarded-For")
|
|
@@ -39,14 +35,14 @@ class AuditHelper:
|
|
|
39
35
|
"microServiceUrl": str(request.url),
|
|
40
36
|
"microServiceName": audit_config.microservice_name,
|
|
41
37
|
"microServiceVersion": audit_config.microservice_version,
|
|
42
|
-
"serviceName": operation_name,
|
|
38
|
+
"serviceName": audit.operation_name,
|
|
43
39
|
"machineNameUser": request.headers.get("Machinenameuser", default_value),
|
|
44
40
|
"ipUser": user_ip or default_value,
|
|
45
|
-
"userName": full_name,
|
|
41
|
+
"userName": audit.full_name,
|
|
46
42
|
"localitation": default_value,
|
|
47
43
|
"httpMethod": request.method,
|
|
48
44
|
"messageIn": json.dumps(payload) if payload else default_value,
|
|
49
|
-
"auditLog":
|
|
45
|
+
"auditLog": audit.audit_type
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
@staticmethod
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from fastapi import Request
|
|
2
|
+
|
|
3
|
+
class ExtractAuthToken:
|
|
4
|
+
|
|
5
|
+
@staticmethod
|
|
6
|
+
async def get_auth_token(request: Request) -> str:
|
|
7
|
+
authorization = request.headers.get("authorization")
|
|
8
|
+
if not authorization or not authorization.startswith("Bearer "):
|
|
9
|
+
raise ValueError("Missing Bearer token")
|
|
10
|
+
|
|
11
|
+
return authorization.split(" ")[1]
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Dict, Any
|
|
2
2
|
from uuid import UUID
|
|
3
3
|
from graphql import OperationType
|
|
4
|
+
from starlette.datastructures import Headers
|
|
5
|
+
from Osdental.Encryptor.Aes import AES
|
|
6
|
+
from Osdental.Models.Token import AuthToken
|
|
4
7
|
|
|
5
8
|
class TenantPolicy:
|
|
6
9
|
|
|
7
10
|
@staticmethod
|
|
8
|
-
def resolve(
|
|
11
|
+
def resolve(
|
|
12
|
+
token: AuthToken,
|
|
13
|
+
headers: Headers,
|
|
14
|
+
decrypted_payload: Dict[str, Any],
|
|
15
|
+
operation_type: str
|
|
16
|
+
) -> AuthToken:
|
|
9
17
|
aes = AES()
|
|
10
18
|
# Solo aplicamos cambios si es QUERY
|
|
11
19
|
if operation_type != OperationType.QUERY.value:
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
from fastapi import Request
|
|
1
2
|
from Osdental.Encryptor.Aes import AES
|
|
2
3
|
from Osdental.Encryptor.Jwt import JWT
|
|
3
4
|
from Osdental.Models.Token import AuthToken
|
|
5
|
+
from Osdental.Graphql._Helpers._ExtractAuthToken import ExtractAuthToken
|
|
4
6
|
|
|
5
7
|
class TokenService:
|
|
6
8
|
|
|
@@ -9,12 +11,8 @@ class TokenService:
|
|
|
9
11
|
self.auth_validator = auth_validator
|
|
10
12
|
self.aes = AES()
|
|
11
13
|
|
|
12
|
-
async def authenticate(self, request):
|
|
13
|
-
|
|
14
|
-
if not authorization or not authorization.startswith("Bearer "):
|
|
15
|
-
raise ValueError("Missing Bearer token")
|
|
16
|
-
|
|
17
|
-
encrypted_token = authorization.split(" ")[1]
|
|
14
|
+
async def authenticate(self, request: Request) -> AuthToken:
|
|
15
|
+
encrypted_token = ExtractAuthToken.get_auth_token(request)
|
|
18
16
|
|
|
19
17
|
aes_user = request.app.state.aes_user
|
|
20
18
|
|