skyflow-flowvault-python 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.
Files changed (202) hide show
  1. common/.coveragerc +4 -0
  2. common/__init__.py +3 -0
  3. common/client/__init__.py +0 -0
  4. common/client/base_skyflow.py +345 -0
  5. common/client/utils/__init__.py +1 -0
  6. common/client/utils/_utils.py +127 -0
  7. common/errors/__init__.py +1 -0
  8. common/errors/_skyflow_error.py +17 -0
  9. common/generated/__init__.py +0 -0
  10. common/generated/rest/__init__.py +24 -0
  11. common/generated/rest/authentication/__init__.py +4 -0
  12. common/generated/rest/authentication/client.py +181 -0
  13. common/generated/rest/authentication/raw_client.py +241 -0
  14. common/generated/rest/client.py +153 -0
  15. common/generated/rest/core/__init__.py +52 -0
  16. common/generated/rest/core/api_error.py +23 -0
  17. common/generated/rest/core/client_wrapper.py +86 -0
  18. common/generated/rest/core/datetime_utils.py +28 -0
  19. common/generated/rest/core/file.py +67 -0
  20. common/generated/rest/core/force_multipart.py +16 -0
  21. common/generated/rest/core/http_client.py +543 -0
  22. common/generated/rest/core/http_response.py +55 -0
  23. common/generated/rest/core/jsonable_encoder.py +100 -0
  24. common/generated/rest/core/pydantic_utilities.py +255 -0
  25. common/generated/rest/core/query_encoder.py +58 -0
  26. common/generated/rest/core/remove_none_from_dict.py +11 -0
  27. common/generated/rest/core/request_options.py +35 -0
  28. common/generated/rest/core/serialization.py +276 -0
  29. common/generated/rest/environment.py +8 -0
  30. common/generated/rest/errors/__init__.py +9 -0
  31. common/generated/rest/errors/bad_request_error.py +14 -0
  32. common/generated/rest/errors/not_found_error.py +14 -0
  33. common/generated/rest/errors/unauthorized_error.py +14 -0
  34. common/generated/rest/py.typed +0 -0
  35. common/generated/rest/types/__init__.py +9 -0
  36. common/generated/rest/types/googlerpc_status.py +22 -0
  37. common/generated/rest/types/protobuf_any.py +21 -0
  38. common/generated/rest/types/v_1_get_auth_token_response.py +33 -0
  39. common/generated/rest/version.py +6 -0
  40. common/service_account/__init__.py +1 -0
  41. common/service_account/_utils.py +248 -0
  42. common/service_account/client/__init__.py +0 -0
  43. common/service_account/client/auth_client.py +13 -0
  44. common/utils/__init__.py +4 -0
  45. common/utils/_helpers.py +18 -0
  46. common/utils/_skyflow_messages.py +445 -0
  47. common/utils/_utils.py +50 -0
  48. common/utils/constants.py +291 -0
  49. common/utils/enums/__init__.py +12 -0
  50. common/utils/enums/content_types.py +9 -0
  51. common/utils/enums/detect_entities.py +73 -0
  52. common/utils/enums/detect_output_transcriptions.py +8 -0
  53. common/utils/enums/env.py +13 -0
  54. common/utils/enums/log_level.py +8 -0
  55. common/utils/enums/masking_method.py +5 -0
  56. common/utils/enums/redaction_type.py +7 -0
  57. common/utils/enums/request_method.py +8 -0
  58. common/utils/enums/token_mode.py +6 -0
  59. common/utils/enums/token_type.py +6 -0
  60. common/utils/logger/__init__.py +2 -0
  61. common/utils/logger/_log_helpers.py +47 -0
  62. common/utils/logger/_logger.py +50 -0
  63. common/utils/validations/__init__.py +11 -0
  64. common/utils/validations/_validations.py +267 -0
  65. common/vault/base_vault_client.py +122 -0
  66. common/vault/base_vault_controller.py +58 -0
  67. common/vault/data/__init__.py +2 -0
  68. common/vault/data/_base_insert_request.py +7 -0
  69. common/vault/data/_base_insert_response.py +11 -0
  70. skyflow/__init__.py +2 -0
  71. skyflow/client/__init__.py +1 -0
  72. skyflow/client/_http_config_builder.py +45 -0
  73. skyflow/client/skyflow.py +15 -0
  74. skyflow/error/__init__.py +3 -0
  75. skyflow/generated/__init__.py +0 -0
  76. skyflow/generated/rest/__init__.py +164 -0
  77. skyflow/generated/rest/_default_clients.py +32 -0
  78. skyflow/generated/rest/client.py +385 -0
  79. skyflow/generated/rest/core/__init__.py +127 -0
  80. skyflow/generated/rest/core/api_error.py +23 -0
  81. skyflow/generated/rest/core/client_wrapper.py +148 -0
  82. skyflow/generated/rest/core/datetime_utils.py +70 -0
  83. skyflow/generated/rest/core/file.py +67 -0
  84. skyflow/generated/rest/core/force_multipart.py +18 -0
  85. skyflow/generated/rest/core/http_client.py +940 -0
  86. skyflow/generated/rest/core/http_response.py +63 -0
  87. skyflow/generated/rest/core/http_sse/__init__.py +42 -0
  88. skyflow/generated/rest/core/http_sse/_api.py +455 -0
  89. skyflow/generated/rest/core/http_sse/_decoders.py +74 -0
  90. skyflow/generated/rest/core/http_sse/_exceptions.py +7 -0
  91. skyflow/generated/rest/core/http_sse/_models.py +17 -0
  92. skyflow/generated/rest/core/jsonable_encoder.py +133 -0
  93. skyflow/generated/rest/core/logging.py +107 -0
  94. skyflow/generated/rest/core/parse_error.py +36 -0
  95. skyflow/generated/rest/core/pydantic_utilities.py +486 -0
  96. skyflow/generated/rest/core/query_encoder.py +58 -0
  97. skyflow/generated/rest/core/remove_none_from_dict.py +11 -0
  98. skyflow/generated/rest/core/request_options.py +40 -0
  99. skyflow/generated/rest/core/serialization.py +347 -0
  100. skyflow/generated/rest/environment.py +8 -0
  101. skyflow/generated/rest/errors/__init__.py +53 -0
  102. skyflow/generated/rest/errors/bad_request_error.py +11 -0
  103. skyflow/generated/rest/errors/forbidden_error.py +11 -0
  104. skyflow/generated/rest/errors/internal_server_error.py +11 -0
  105. skyflow/generated/rest/errors/not_found_error.py +11 -0
  106. skyflow/generated/rest/errors/too_many_requests_error.py +11 -0
  107. skyflow/generated/rest/errors/unauthorized_error.py +11 -0
  108. skyflow/generated/rest/py.typed +0 -0
  109. skyflow/generated/rest/query/__init__.py +4 -0
  110. skyflow/generated/rest/query/client.py +139 -0
  111. skyflow/generated/rest/query/raw_client.py +239 -0
  112. skyflow/generated/rest/raw_client.py +86 -0
  113. skyflow/generated/rest/records/__init__.py +34 -0
  114. skyflow/generated/rest/records/client.py +685 -0
  115. skyflow/generated/rest/records/raw_client.py +988 -0
  116. skyflow/generated/rest/records/types/__init__.py +34 -0
  117. skyflow/generated/rest/records/types/update_request_update_type.py +5 -0
  118. skyflow/generated/rest/tokens/__init__.py +4 -0
  119. skyflow/generated/rest/tokens/client.py +246 -0
  120. skyflow/generated/rest/tokens/raw_client.py +507 -0
  121. skyflow/generated/rest/types/__init__.py +116 -0
  122. skyflow/generated/rest/types/column_redactions.py +33 -0
  123. skyflow/generated/rest/types/delete_response.py +23 -0
  124. skyflow/generated/rest/types/delete_response_object.py +42 -0
  125. skyflow/generated/rest/types/detokenize_response.py +23 -0
  126. skyflow/generated/rest/types/detokenize_response_object.py +54 -0
  127. skyflow/generated/rest/types/error_response.py +20 -0
  128. skyflow/generated/rest/types/error_response_error.py +28 -0
  129. skyflow/generated/rest/types/execute_query_record_response.py +22 -0
  130. skyflow/generated/rest/types/execute_query_response.py +26 -0
  131. skyflow/generated/rest/types/execute_query_response_metadata.py +26 -0
  132. skyflow/generated/rest/types/get_request_data.py +60 -0
  133. skyflow/generated/rest/types/get_response.py +23 -0
  134. skyflow/generated/rest/types/get_tokens_from_values_request_object.py +30 -0
  135. skyflow/generated/rest/types/get_tokens_from_values_response.py +23 -0
  136. skyflow/generated/rest/types/google_protobuf_value.py +8 -0
  137. skyflow/generated/rest/types/http_code.py +6 -0
  138. skyflow/generated/rest/types/insert_record_data.py +36 -0
  139. skyflow/generated/rest/types/insert_response.py +23 -0
  140. skyflow/generated/rest/types/record_response_object.py +70 -0
  141. skyflow/generated/rest/types/token_group_redactions.py +33 -0
  142. skyflow/generated/rest/types/tokenize_response_object.py +49 -0
  143. skyflow/generated/rest/types/unique_value.py +22 -0
  144. skyflow/generated/rest/types/update_record_data.py +52 -0
  145. skyflow/generated/rest/types/update_record_data_update_type.py +5 -0
  146. skyflow/generated/rest/types/update_response.py +23 -0
  147. skyflow/generated/rest/types/upsert.py +45 -0
  148. skyflow/generated/rest/types/upsert_update_type.py +5 -0
  149. skyflow/generated/rest/version.py +6 -0
  150. skyflow/service_account/__init__.py +15 -0
  151. skyflow/utils/__init__.py +9 -0
  152. skyflow/utils/_http_config.py +36 -0
  153. skyflow/utils/_response_parsing.py +66 -0
  154. skyflow/utils/_retry.py +97 -0
  155. skyflow/utils/_skyflow_messages.py +114 -0
  156. skyflow/utils/_utils.py +54 -0
  157. skyflow/utils/_version.py +1 -0
  158. skyflow/utils/enums/__init__.py +3 -0
  159. skyflow/utils/enums/_custom_header_key.py +10 -0
  160. skyflow/utils/enums/_env_urls.py +9 -0
  161. skyflow/utils/enums/_upsert_type.py +7 -0
  162. skyflow/utils/validations/__init__.py +9 -0
  163. skyflow/utils/validations/_validations.py +195 -0
  164. skyflow/vault/__init__.py +0 -0
  165. skyflow/vault/client/__init__.py +0 -0
  166. skyflow/vault/client/client.py +102 -0
  167. skyflow/vault/controller/__init__.py +1 -0
  168. skyflow/vault/controller/_vault.py +475 -0
  169. skyflow/vault/data/__init__.py +30 -0
  170. skyflow/vault/data/_column_redactions.py +4 -0
  171. skyflow/vault/data/_delete_options.py +8 -0
  172. skyflow/vault/data/_delete_request.py +5 -0
  173. skyflow/vault/data/_delete_response.py +9 -0
  174. skyflow/vault/data/_delete_response_record.py +9 -0
  175. skyflow/vault/data/_detokenize_options.py +8 -0
  176. skyflow/vault/data/_detokenize_request.py +9 -0
  177. skyflow/vault/data/_detokenize_response.py +9 -0
  178. skyflow/vault/data/_detokenize_response_record.py +16 -0
  179. skyflow/vault/data/_detokenize_response_record_metadata.py +10 -0
  180. skyflow/vault/data/_get_options.py +8 -0
  181. skyflow/vault/data/_get_request.py +17 -0
  182. skyflow/vault/data/_get_request_record.py +13 -0
  183. skyflow/vault/data/_get_response.py +9 -0
  184. skyflow/vault/data/_get_response_record.py +17 -0
  185. skyflow/vault/data/_insert_options.py +8 -0
  186. skyflow/vault/data/_insert_request.py +11 -0
  187. skyflow/vault/data/_insert_request_record.py +9 -0
  188. skyflow/vault/data/_insert_response.py +9 -0
  189. skyflow/vault/data/_insert_response_record.py +17 -0
  190. skyflow/vault/data/_request_context.py +16 -0
  191. skyflow/vault/data/_token.py +8 -0
  192. skyflow/vault/data/_token_group_redactions.py +4 -0
  193. skyflow/vault/data/_update_options.py +8 -0
  194. skyflow/vault/data/_update_request.py +11 -0
  195. skyflow/vault/data/_update_request_record.py +6 -0
  196. skyflow/vault/data/_update_response.py +9 -0
  197. skyflow/vault/data/_update_response_record.py +17 -0
  198. skyflow/vault/data/_upsert_options.py +7 -0
  199. skyflow_flowvault_python-1.0.0.dist-info/METADATA +896 -0
  200. skyflow_flowvault_python-1.0.0.dist-info/RECORD +202 -0
  201. skyflow_flowvault_python-1.0.0.dist-info/WHEEL +5 -0
  202. skyflow_flowvault_python-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,14 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ from ..core.api_error import ApiError
6
+
7
+
8
+ class UnauthorizedError(ApiError):
9
+ def __init__(
10
+ self,
11
+ body: typing.Dict[str, typing.Optional[typing.Any]],
12
+ headers: typing.Optional[typing.Dict[str, str]] = None,
13
+ ):
14
+ super().__init__(status_code=401, headers=headers, body=body)
File without changes
@@ -0,0 +1,9 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ # isort: skip_file
4
+
5
+ from .googlerpc_status import GooglerpcStatus
6
+ from .protobuf_any import ProtobufAny
7
+ from .v_1_get_auth_token_response import V1GetAuthTokenResponse
8
+
9
+ __all__ = ["GooglerpcStatus", "ProtobufAny", "V1GetAuthTokenResponse"]
@@ -0,0 +1,22 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
7
+ from .protobuf_any import ProtobufAny
8
+
9
+
10
+ class GooglerpcStatus(UniversalBaseModel):
11
+ code: typing.Optional[int] = None
12
+ message: typing.Optional[str] = None
13
+ details: typing.Optional[typing.List[ProtobufAny]] = None
14
+
15
+ if IS_PYDANTIC_V2:
16
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
17
+ else:
18
+
19
+ class Config:
20
+ frozen = True
21
+ smart_union = True
22
+ extra = pydantic.Extra.allow
@@ -0,0 +1,21 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ import typing_extensions
7
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
8
+ from ..core.serialization import FieldMetadata
9
+
10
+
11
+ class ProtobufAny(UniversalBaseModel):
12
+ type: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="@type")] = None
13
+
14
+ if IS_PYDANTIC_V2:
15
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
16
+ else:
17
+
18
+ class Config:
19
+ frozen = True
20
+ smart_union = True
21
+ extra = pydantic.Extra.allow
@@ -0,0 +1,33 @@
1
+ # This file was auto-generated by Fern from our API Definition.
2
+
3
+ import typing
4
+
5
+ import pydantic
6
+ import typing_extensions
7
+ from ..core.pydantic_utilities import IS_PYDANTIC_V2, UniversalBaseModel
8
+ from ..core.serialization import FieldMetadata
9
+
10
+
11
+ class V1GetAuthTokenResponse(UniversalBaseModel):
12
+ access_token: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="accessToken")] = (
13
+ pydantic.Field(default=None)
14
+ )
15
+ """
16
+ AccessToken.
17
+ """
18
+
19
+ token_type: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="tokenType")] = pydantic.Field(
20
+ default=None
21
+ )
22
+ """
23
+ TokenType : Bearer.
24
+ """
25
+
26
+ if IS_PYDANTIC_V2:
27
+ model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2
28
+ else:
29
+
30
+ class Config:
31
+ frozen = True
32
+ smart_union = True
33
+ extra = pydantic.Extra.allow
@@ -0,0 +1,6 @@
1
+ # NOTE: hand-patched, not Fern-generated content. Fern originally emitted a runtime
2
+ # metadata.version("skyflow.generated.rest") lookup here, but this code is bundled into the
3
+ # skyflow (v2) and v3 wheels via a build_py hook rather than published under that distribution
4
+ # name, so the lookup always raised PackageNotFoundError on import. Hardcoded until the Fern
5
+ # generator config (skyflow-fern-config) is updated to stop emitting a runtime lookup here.
6
+ __version__ = "0.0.9"
@@ -0,0 +1 @@
1
+ from ._utils import generate_bearer_token, generate_bearer_token_from_creds, is_expired, generate_signed_data_tokens, generate_signed_data_tokens_from_creds
@@ -0,0 +1,248 @@
1
+ import json
2
+ import datetime
3
+ import re
4
+ import time
5
+ import jwt
6
+ from urllib.parse import urlparse
7
+ from common.errors import SkyflowError
8
+ from common.service_account.client.auth_client import AuthClient
9
+ from common.utils.logger import log_info, log_error_log
10
+ from common.utils import get_base_url, format_scope, SkyflowMessages
11
+ from common.utils.constants import JWT, CredentialField, JwtField, OptionField, ResponseField
12
+ from common.generated.rest.errors.unauthorized_error import UnauthorizedError
13
+ from common.utils import is_valid_url
14
+ from common.utils.constants import CTX_KEY_REGEX
15
+
16
+
17
+ invalid_input_error_code = SkyflowMessages.ErrorCodes.INVALID_INPUT.value
18
+
19
+ _CTX_KEY_PATTERN = re.compile(CTX_KEY_REGEX)
20
+
21
+ _SNAKE_TO_CAMEL_CRED_MAP = {
22
+ 'private_key': CredentialField.PRIVATE_KEY,
23
+ 'client_id': CredentialField.CLIENT_ID,
24
+ 'key_id': CredentialField.KEY_ID,
25
+ 'token_uri': CredentialField.TOKEN_URI,
26
+ 'client_name': CredentialField.CLIENT_NAME,
27
+ }
28
+
29
+
30
+ def _normalize_credentials(credentials):
31
+ return {_SNAKE_TO_CAMEL_CRED_MAP.get(k, k): v for k, v in credentials.items()}
32
+
33
+
34
+ def _validate_and_resolve_ctx(ctx, messages=None):
35
+ """Validate ctx value and return resolved value for JWT claims.
36
+ Returns None if ctx should be omitted, the value if valid, or raises SkyflowError if invalid.
37
+ """
38
+ messages = messages or SkyflowMessages
39
+ if ctx is None:
40
+ return None
41
+ if isinstance(ctx, str):
42
+ if ctx.strip() == '':
43
+ return None
44
+ return ctx
45
+ if isinstance(ctx, dict):
46
+ if len(ctx) == 0:
47
+ return None
48
+ for key in ctx:
49
+ if not isinstance(key, str) or not _CTX_KEY_PATTERN.match(key):
50
+ raise SkyflowError(
51
+ messages.Error.INVALID_CTX_MAP_KEY.value.format(key),
52
+ invalid_input_error_code
53
+ )
54
+ return ctx
55
+ if isinstance(ctx, (bool, int, float)):
56
+ return ctx
57
+ raise SkyflowError(
58
+ messages.Error.INVALID_CTX_TYPE.value,
59
+ invalid_input_error_code
60
+ )
61
+
62
+ def is_expired(token, logger = None):
63
+ if token is None:
64
+ return True
65
+ if len(token) == 0:
66
+ log_error_log(SkyflowMessages.ErrorLogs.INVALID_BEARER_TOKEN.value)
67
+ return True
68
+
69
+ try:
70
+ decoded = jwt.decode(
71
+ token, options={OptionField.VERIFY_SIGNATURE: False, OptionField.VERIFY_AUD: False})
72
+ if time.time() >= decoded[JwtField.EXP]:
73
+ log_info(SkyflowMessages.Info.BEARER_TOKEN_EXPIRED.value, logger)
74
+ log_error_log(SkyflowMessages.ErrorLogs.INVALID_BEARER_TOKEN.value)
75
+ return True
76
+ return False
77
+ except jwt.ExpiredSignatureError:
78
+ return True
79
+ except Exception:
80
+ log_error_log(SkyflowMessages.Error.JWT_DECODE_ERROR.value, logger)
81
+ return True
82
+
83
+ def generate_bearer_token(credentials_file_path, options = None, logger = None):
84
+ log_info(SkyflowMessages.Info.GET_BEARER_TOKEN_TRIGGERED.value, logger)
85
+ try:
86
+ with open(credentials_file_path, 'r') as credentials_file:
87
+ try:
88
+ credentials = json.load(credentials_file)
89
+ except Exception:
90
+ log_error_log(SkyflowMessages.ErrorLogs.INVALID_CREDENTIALS_FILE.value, logger=logger)
91
+ raise SkyflowError(SkyflowMessages.Error.FILE_INVALID_JSON.value.format(credentials_file_path), invalid_input_error_code)
92
+ except SkyflowError:
93
+ raise
94
+ except Exception:
95
+ raise SkyflowError(SkyflowMessages.Error.INVALID_CREDENTIAL_FILE_PATH.value, invalid_input_error_code)
96
+ result = get_service_account_token(credentials, options, logger)
97
+ return result
98
+
99
+ def generate_bearer_token_from_creds(credentials, options = None, logger = None):
100
+ log_info(SkyflowMessages.Info.GET_BEARER_TOKEN_TRIGGERED.value, logger)
101
+ credentials = credentials.strip()
102
+ try:
103
+ json_credentials = json.loads(credentials.replace('\n', '\\n'))
104
+ except Exception:
105
+ raise SkyflowError(SkyflowMessages.Error.INVALID_CREDENTIALS_STRING.value, invalid_input_error_code)
106
+ result = get_service_account_token(json_credentials, options, logger)
107
+ return result
108
+
109
+ def get_service_account_token(credentials, options, logger):
110
+ credentials = _normalize_credentials(credentials)
111
+ try:
112
+ private_key = credentials[CredentialField.PRIVATE_KEY]
113
+ except KeyError:
114
+ log_error_log(SkyflowMessages.ErrorLogs.PRIVATE_KEY_IS_REQUIRED.value, logger=logger)
115
+ raise SkyflowError(SkyflowMessages.Error.MISSING_PRIVATE_KEY.value, invalid_input_error_code)
116
+ try:
117
+ client_id = credentials[CredentialField.CLIENT_ID]
118
+ except KeyError:
119
+ log_error_log(SkyflowMessages.ErrorLogs.CLIENT_ID_IS_REQUIRED.value, logger=logger)
120
+ raise SkyflowError(SkyflowMessages.Error.MISSING_CLIENT_ID.value, invalid_input_error_code)
121
+ try:
122
+ key_id = credentials[CredentialField.KEY_ID]
123
+ except KeyError:
124
+ log_error_log(SkyflowMessages.ErrorLogs.KEY_ID_IS_REQUIRED.value, logger=logger)
125
+ raise SkyflowError(SkyflowMessages.Error.MISSING_KEY_ID.value, invalid_input_error_code)
126
+ try:
127
+ token_uri = credentials[CredentialField.TOKEN_URI]
128
+ except KeyError:
129
+ log_error_log(SkyflowMessages.ErrorLogs.TOKEN_URI_IS_REQUIRED.value, logger=logger)
130
+ raise SkyflowError(SkyflowMessages.Error.MISSING_TOKEN_URI.value, invalid_input_error_code)
131
+
132
+ if not isinstance(token_uri, str) or not is_valid_url(token_uri):
133
+ log_error_log(SkyflowMessages.ErrorLogs.INVALID_TOKEN_URI.value, logger=logger)
134
+ raise SkyflowError(SkyflowMessages.Error.INVALID_TOKEN_URI.value, invalid_input_error_code)
135
+
136
+ if options and CredentialField.TOKEN_URI_OPTION in options:
137
+ token_uri = options[CredentialField.TOKEN_URI_OPTION]
138
+ if not isinstance(token_uri, str) or not is_valid_url(token_uri):
139
+ log_error_log(SkyflowMessages.ErrorLogs.INVALID_TOKEN_URI.value, logger=logger)
140
+ raise SkyflowError(SkyflowMessages.Error.INVALID_TOKEN_URI.value, invalid_input_error_code)
141
+
142
+ signed_token = get_signed_jwt(options, client_id, key_id, token_uri, private_key, logger)
143
+ base_url = get_base_url(token_uri)
144
+ auth_client = AuthClient(base_url)
145
+ auth_api = auth_client.get_auth_api()
146
+
147
+ formatted_scope = None
148
+ if options and OptionField.ROLE_IDS in options:
149
+ formatted_scope = format_scope(options.get(OptionField.ROLE_IDS))
150
+
151
+ try:
152
+ response = auth_api.authentication_service_get_auth_token(assertion = signed_token,
153
+ grant_type=JWT.GRANT_TYPE_JWT_BEARER,
154
+ scope=formatted_scope)
155
+ log_info(SkyflowMessages.Info.GET_BEARER_TOKEN_SUCCESS.value, logger)
156
+ except UnauthorizedError:
157
+ log_error_log(SkyflowMessages.ErrorLogs.UNAUTHORIZED_ERROR_IN_GETTING_BEARER_TOKEN.value, logger=logger)
158
+ raise SkyflowError(SkyflowMessages.Error.UNAUTHORIZED_ERROR_IN_GETTING_BEARER_TOKEN.value, invalid_input_error_code)
159
+ except Exception:
160
+ log_error_log(SkyflowMessages.ErrorLogs.FAILED_TO_GET_BEARER_TOKEN.value, logger=logger)
161
+ raise SkyflowError(SkyflowMessages.Error.FAILED_TO_GET_BEARER_TOKEN.value, invalid_input_error_code)
162
+ return response.access_token, response.token_type
163
+
164
+ def get_signed_jwt(options, client_id, key_id, token_uri, private_key, logger):
165
+ payload = {
166
+ JwtField.ISS: client_id,
167
+ JwtField.KEY: key_id,
168
+ JwtField.AUD: token_uri,
169
+ JwtField.SUB: client_id,
170
+ JwtField.EXP: datetime.datetime.utcnow() + datetime.timedelta(minutes=60)
171
+ }
172
+ if options and OptionField.CTX in options:
173
+ resolved_ctx = _validate_and_resolve_ctx(options.get(OptionField.CTX))
174
+ if resolved_ctx is not None:
175
+ payload[JwtField.CTX] = resolved_ctx
176
+ try:
177
+ return jwt.encode(payload=payload, key=private_key, algorithm=JWT.ALGORITHM_RS256)
178
+ except Exception:
179
+ raise SkyflowError(SkyflowMessages.Error.JWT_INVALID_FORMAT.value, invalid_input_error_code)
180
+
181
+
182
+
183
+ def get_signed_tokens(credentials_obj, options):
184
+ options = options if options is not None else {}
185
+ credentials_obj = _normalize_credentials(credentials_obj)
186
+ expiry_time = int(time.time()) + options.get(OptionField.TIME_TO_LIVE, 60)
187
+ prefix = JWT.SIGNED_TOKEN_PREFIX
188
+
189
+ token_uri = credentials_obj.get(CredentialField.TOKEN_URI)
190
+ if not isinstance(token_uri, str) or not is_valid_url(token_uri):
191
+ log_error_log(SkyflowMessages.ErrorLogs.INVALID_TOKEN_URI.value)
192
+ raise SkyflowError(SkyflowMessages.Error.INVALID_TOKEN_URI.value, invalid_input_error_code)
193
+
194
+ resolved_ctx = None
195
+ if OptionField.CTX in options:
196
+ resolved_ctx = _validate_and_resolve_ctx(options[OptionField.CTX])
197
+
198
+ results = []
199
+ if options and options.get(OptionField.DATA_TOKENS):
200
+ for token in options[OptionField.DATA_TOKENS]:
201
+ claims = {
202
+ JwtField.ISS: JWT.ISSUER_SDK,
203
+ JwtField.KEY: credentials_obj.get(CredentialField.KEY_ID),
204
+ JwtField.EXP: expiry_time,
205
+ JwtField.SUB: credentials_obj.get(CredentialField.CLIENT_ID),
206
+ JwtField.TOK: token,
207
+ JwtField.IAT: int(time.time()),
208
+ }
209
+ if resolved_ctx is not None:
210
+ claims[JwtField.CTX] = resolved_ctx
211
+ private_key = credentials_obj.get(CredentialField.PRIVATE_KEY)
212
+ try:
213
+ signed_jwt = jwt.encode(claims, private_key, algorithm=JWT.ALGORITHM_RS256)
214
+ except Exception:
215
+ raise SkyflowError(SkyflowMessages.Error.INVALID_CREDENTIALS.value, invalid_input_error_code)
216
+ results.append(get_signed_data_token_response_object(prefix + signed_jwt, token))
217
+ log_info(SkyflowMessages.Info.GET_SIGNED_DATA_TOKEN_SUCCESS.value)
218
+ return results
219
+
220
+
221
+ def generate_signed_data_tokens(credentials_file_path, options):
222
+ log_info(SkyflowMessages.Info.GET_SIGNED_DATA_TOKENS_TRIGGERED.value)
223
+ try:
224
+ with open(credentials_file_path, 'r') as credentials_file:
225
+ try:
226
+ credentials = json.load(credentials_file)
227
+ except Exception:
228
+ raise SkyflowError(SkyflowMessages.Error.FILE_INVALID_JSON.value.format(credentials_file_path),
229
+ invalid_input_error_code)
230
+ except SkyflowError:
231
+ raise
232
+ except Exception:
233
+ raise SkyflowError(SkyflowMessages.Error.INVALID_CREDENTIAL_FILE_PATH.value, invalid_input_error_code)
234
+ return get_signed_tokens(credentials, options)
235
+
236
+ def generate_signed_data_tokens_from_creds(credentials, options):
237
+ log_info(SkyflowMessages.Info.GET_SIGNED_DATA_TOKENS_TRIGGERED.value)
238
+ credentials = credentials.strip()
239
+ try:
240
+ json_credentials = json.loads(credentials.replace('\n', '\\n'))
241
+ except Exception:
242
+ log_error_log(SkyflowMessages.ErrorLogs.INVALID_CREDENTIALS_FILE.value)
243
+ raise SkyflowError(SkyflowMessages.Error.INVALID_CREDENTIALS_STRING.value, invalid_input_error_code)
244
+ return get_signed_tokens(json_credentials, options)
245
+
246
+
247
+ def get_signed_data_token_response_object(signed_token, actual_token):
248
+ return actual_token, signed_token
File without changes
@@ -0,0 +1,13 @@
1
+ from common.generated.rest.client import SkyflowAuth
2
+ from common.utils.constants import OPTIONAL_TOKEN
3
+
4
+ class AuthClient:
5
+ def __init__(self, url):
6
+ self.__url = url
7
+ self.__api_client = self.initialize_api_client()
8
+
9
+ def initialize_api_client(self):
10
+ return SkyflowAuth(base_url=self.__url, token=OPTIONAL_TOKEN)
11
+
12
+ def get_auth_api(self):
13
+ return self.__api_client.authentication
@@ -0,0 +1,4 @@
1
+ from .enums import LogLevel, Env, TokenType
2
+ from ._skyflow_messages import SkyflowMessages
3
+ from ._helpers import get_base_url, format_scope, is_valid_url
4
+ from ._utils import get_credentials, get_vault_url, validate_api_key
@@ -0,0 +1,18 @@
1
+ from urllib.parse import urlparse
2
+
3
+ def get_base_url(url):
4
+ parsed_url = urlparse(url)
5
+ base_url = f"{parsed_url.scheme}://{parsed_url.netloc}"
6
+ return base_url
7
+
8
+ def format_scope(scopes):
9
+ if not scopes:
10
+ return None
11
+ return " ".join([f"role:{scope}" for scope in scopes])
12
+
13
+ def is_valid_url(url):
14
+ try:
15
+ result = urlparse(url)
16
+ return all([result.scheme == "https", result.netloc])
17
+ except Exception:
18
+ return False