mage-ai 0.9.65__py3-none-any.whl → 0.9.67__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.

Potentially problematic release.


This version of mage-ai might be problematic. Click here for more details.

Files changed (242) hide show
  1. mage_ai/api/monitors/BaseMonitor.py +38 -16
  2. mage_ai/api/policies/BackfillPolicy.py +1 -0
  3. mage_ai/api/resources/OauthResource.py +13 -5
  4. mage_ai/api/resources/SessionResource.py +6 -4
  5. mage_ai/authentication/ldap.py +19 -9
  6. mage_ai/authentication/oauth/constants.py +8 -14
  7. mage_ai/authentication/oauth/utils.py +18 -6
  8. mage_ai/authentication/providers/active_directory.py +21 -16
  9. mage_ai/authentication/providers/azure_devops.py +18 -0
  10. mage_ai/authentication/providers/bitbucket.py +10 -9
  11. mage_ai/authentication/providers/constants.py +2 -0
  12. mage_ai/authentication/providers/ghe.py +5 -9
  13. mage_ai/authentication/providers/gitlab.py +6 -9
  14. mage_ai/authentication/providers/google.py +9 -6
  15. mage_ai/authentication/providers/oidc.py +6 -4
  16. mage_ai/authentication/providers/okta.py +9 -6
  17. mage_ai/cluster_manager/kubernetes/workload_manager.py +10 -0
  18. mage_ai/cluster_manager/workspace/base.py +6 -1
  19. mage_ai/cluster_manager/workspace/kubernetes.py +3 -0
  20. mage_ai/data_preparation/decorators.py +15 -0
  21. mage_ai/data_preparation/executors/streaming_pipeline_executor.py +22 -12
  22. mage_ai/data_preparation/git/__init__.py +10 -1
  23. mage_ai/data_preparation/git/api.py +3 -0
  24. mage_ai/data_preparation/git/clients/azure_devops.py +106 -0
  25. mage_ai/data_preparation/git/clients/base.py +6 -0
  26. mage_ai/data_preparation/git/clients/gitlab.py +3 -2
  27. mage_ai/data_preparation/git/utils.py +31 -29
  28. mage_ai/data_preparation/models/block/__init__.py +27 -18
  29. mage_ai/data_preparation/models/block/dbt/block_sql.py +164 -0
  30. mage_ai/data_preparation/models/block/dynamic/variables.py +1 -2
  31. mage_ai/data_preparation/models/pipeline.py +3 -3
  32. mage_ai/data_preparation/models/triggers/__init__.py +6 -1
  33. mage_ai/data_preparation/preferences.py +42 -37
  34. mage_ai/data_preparation/repo_manager.py +21 -0
  35. mage_ai/data_preparation/storage/gcs_storage.py +27 -2
  36. mage_ai/data_preparation/storage/local_storage.py +18 -3
  37. mage_ai/data_preparation/storage/s3_storage.py +7 -2
  38. mage_ai/data_preparation/templates/data_loaders/streaming/generic_python.py +23 -0
  39. mage_ai/data_preparation/templates/main/metadata.yaml +6 -0
  40. mage_ai/data_preparation/templates/template.py +6 -2
  41. mage_ai/data_preparation/variable_manager.py +2 -1
  42. mage_ai/io/base.py +3 -0
  43. mage_ai/io/bigquery.py +2 -0
  44. mage_ai/io/export_utils.py +14 -9
  45. mage_ai/io/mssql.py +104 -25
  46. mage_ai/io/mysql.py +10 -9
  47. mage_ai/io/oracledb.py +14 -2
  48. mage_ai/io/postgres.py +3 -0
  49. mage_ai/io/sql.py +14 -6
  50. mage_ai/io/trino.py +10 -8
  51. mage_ai/orchestration/db/migrations/versions/90d978a8aef8_update_unique_constraint_for_secret.py +11 -5
  52. mage_ai/orchestration/db/models/schedules.py +25 -1
  53. mage_ai/orchestration/db/models/schedules_project_platform.py +24 -1
  54. mage_ai/orchestration/job_manager.py +6 -1
  55. mage_ai/orchestration/pipeline_scheduler_original.py +16 -10
  56. mage_ai/server/constants.py +1 -1
  57. mage_ai/server/file_observer.py +10 -0
  58. mage_ai/server/frontend_dist/404.html +2 -2
  59. mage_ai/server/frontend_dist/_next/static/chunks/{1557-a754b04510d50b80.js → 1557-01f0843dc6ac4971.js} +1 -1
  60. mage_ai/server/frontend_dist/_next/static/chunks/9440-4069842b90d4b801.js +1 -0
  61. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +1 -0
  62. mage_ai/server/frontend_dist/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +1 -0
  63. mage_ai/server/frontend_dist/_next/static/chunks/pages/oauth-30e34ee15d410331.js +1 -0
  64. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +1 -0
  65. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +1 -0
  66. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{edit-8d32ac7e8f023779.js → edit-36377e679da2cd91.js} +1 -1
  67. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-3f5c14076ddde20e.js +1 -0
  68. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-fe08120d9a6fb1b0.js → triggers-f508c2f261297724.js} +1 -1
  69. mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-bcdb4ad41dd4c7d5.js → frontend_dist/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js} +1 -1
  70. mage_ai/server/frontend_dist/_next/static/chunks/pages/{sign-in-19b36600d908b711.js → sign-in-7d38b2f7c3e918a1.js} +1 -1
  71. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +1 -0
  72. mage_ai/server/frontend_dist/_next/static/chunks/{webpack-ac7fdc472bedf682.js → webpack-d079359c241db804.js} +1 -1
  73. mage_ai/server/frontend_dist/_next/static/{ZMrJfDouIX5AMb_RteRbL → vPsMu6Fi2zrHaf2fRXKRO}/_buildManifest.js +1 -1
  74. mage_ai/server/frontend_dist/block-layout.html +2 -2
  75. mage_ai/server/frontend_dist/compute.html +2 -2
  76. mage_ai/server/frontend_dist/files.html +2 -2
  77. mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
  78. mage_ai/server/frontend_dist/global-data-products.html +2 -2
  79. mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
  80. mage_ai/server/frontend_dist/global-hooks.html +2 -2
  81. mage_ai/server/frontend_dist/index.html +2 -2
  82. mage_ai/server/frontend_dist/manage/files.html +2 -2
  83. mage_ai/server/frontend_dist/manage/settings.html +2 -2
  84. mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
  85. mage_ai/server/frontend_dist/manage/users/new.html +2 -2
  86. mage_ai/server/frontend_dist/manage/users.html +2 -2
  87. mage_ai/server/frontend_dist/manage.html +2 -2
  88. mage_ai/server/frontend_dist/oauth.html +2 -2
  89. mage_ai/server/frontend_dist/overview.html +2 -2
  90. mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
  91. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  92. mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
  93. mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
  94. mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
  95. mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
  96. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  97. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  98. mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
  99. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
  100. mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
  101. mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
  102. mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
  103. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  104. mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
  105. mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
  106. mage_ai/server/frontend_dist/pipelines.html +2 -2
  107. mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
  108. mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
  109. mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
  110. mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
  111. mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
  112. mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
  113. mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
  114. mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
  115. mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
  116. mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
  117. mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
  118. mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
  119. mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
  120. mage_ai/server/frontend_dist/settings.html +2 -2
  121. mage_ai/server/frontend_dist/sign-in.html +2 -2
  122. mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
  123. mage_ai/server/frontend_dist/templates.html +2 -2
  124. mage_ai/server/frontend_dist/terminal.html +2 -2
  125. mage_ai/server/frontend_dist/test.html +2 -2
  126. mage_ai/server/frontend_dist/triggers.html +2 -2
  127. mage_ai/server/frontend_dist/version-control.html +2 -2
  128. mage_ai/server/frontend_dist_base_path_template/404.html +2 -2
  129. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{1557-a754b04510d50b80.js → 1557-01f0843dc6ac4971.js} +1 -1
  130. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-4069842b90d4b801.js +1 -0
  131. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-1c1ffd928f5a00f7.js +1 -0
  132. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-b7b8695a7f9efde2.js +1 -0
  133. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/oauth-30e34ee15d410331.js +1 -0
  134. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +1 -0
  135. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-aaf393c86fc1bda3.js +1 -0
  136. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{edit-8d32ac7e8f023779.js → edit-36377e679da2cd91.js} +1 -1
  137. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-3f5c14076ddde20e.js +1 -0
  138. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-fe08120d9a6fb1b0.js → triggers-f508c2f261297724.js} +1 -1
  139. mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipelines-bcdb4ad41dd4c7d5.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-f99e99aa8f45529c.js} +1 -1
  140. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/{sign-in-19b36600d908b711.js → sign-in-7d38b2f7c3e918a1.js} +1 -1
  141. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +1 -0
  142. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/{webpack-481689d9989710cd.js → webpack-68c003fb6a175cd7.js} +1 -1
  143. mage_ai/server/frontend_dist_base_path_template/_next/static/{QYwFH4sievaq5XyUjRriy → khKiaJtwrslgMmp4YSa1f}/_buildManifest.js +1 -1
  144. mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
  145. mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
  146. mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
  147. mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
  148. mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
  149. mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
  150. mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
  151. mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
  152. mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
  153. mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
  154. mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
  155. mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
  156. mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
  157. mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
  158. mage_ai/server/frontend_dist_base_path_template/oauth.html +2 -2
  159. mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
  160. mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
  161. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
  162. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
  163. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
  164. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
  165. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
  166. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
  167. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
  168. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
  169. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
  170. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
  171. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
  172. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
  173. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
  174. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
  175. mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
  176. mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
  177. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
  178. mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
  179. mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
  180. mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
  181. mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
  182. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
  183. mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
  184. mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
  185. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
  186. mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
  187. mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
  188. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
  189. mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
  190. mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
  191. mage_ai/server/frontend_dist_base_path_template/sign-in.html +2 -2
  192. mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
  193. mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
  194. mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
  195. mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
  196. mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
  197. mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
  198. mage_ai/server/server.py +117 -87
  199. mage_ai/server/utils/output_display.py +6 -1
  200. mage_ai/services/aws/s3/s3.py +8 -2
  201. mage_ai/services/slack/slack.py +8 -8
  202. mage_ai/settings/__init__.py +36 -186
  203. mage_ai/settings/backends.py +95 -0
  204. mage_ai/settings/keys/__init__.py +1 -0
  205. mage_ai/settings/keys/auth.py +76 -0
  206. mage_ai/settings/server.py +187 -0
  207. mage_ai/shared/io.py +2 -2
  208. mage_ai/shared/logger.py +12 -6
  209. mage_ai/streaming/sources/base_python.py +30 -0
  210. mage_ai/streaming/sources/source_factory.py +25 -0
  211. mage_ai/tests/api/endpoints/test_oauths.py +13 -5
  212. mage_ai/tests/api/operations/test_operations.py +2 -2
  213. mage_ai/tests/api/operations/test_sessions.py +83 -48
  214. mage_ai/tests/authentication/oauth/test_utils.py +56 -6
  215. mage_ai/tests/authentication/providers/test_active_directory.py +9 -15
  216. mage_ai/tests/data_preparation/models/test_block.py +39 -2
  217. mage_ai/tests/orchestration/db/models/test_schedules.py +33 -1
  218. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/METADATA +2 -1
  219. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/RECORD +225 -217
  220. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/WHEEL +1 -1
  221. mage_ai/server/frontend_dist/_next/static/chunks/9440-2bcbdc765ed82062.js +0 -1
  222. mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-2ae1d919333f01fe.js +0 -1
  223. mage_ai/server/frontend_dist/_next/static/chunks/pages/index-64851458dde54ad9.js +0 -1
  224. mage_ai/server/frontend_dist/_next/static/chunks/pages/oauth-abe5ba687cb93509.js +0 -1
  225. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-22e49726eeed16ae.js +0 -1
  226. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c74507dce89b41a2.js +0 -1
  227. mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/logs-cf656cbe37ecaacc.js +0 -1
  228. mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-690206d30d8b412b.js +0 -1
  229. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9440-2bcbdc765ed82062.js +0 -1
  230. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-2ae1d919333f01fe.js +0 -1
  231. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-64851458dde54ad9.js +0 -1
  232. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/oauth-abe5ba687cb93509.js +0 -1
  233. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-22e49726eeed16ae.js +0 -1
  234. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-c74507dce89b41a2.js +0 -1
  235. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/logs-cf656cbe37ecaacc.js +0 -1
  236. mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-690206d30d8b412b.js +0 -1
  237. mage_ai/settings/sso.py +0 -27
  238. /mage_ai/server/frontend_dist/_next/static/{ZMrJfDouIX5AMb_RteRbL → vPsMu6Fi2zrHaf2fRXKRO}/_ssgManifest.js +0 -0
  239. /mage_ai/server/frontend_dist_base_path_template/_next/static/{QYwFH4sievaq5XyUjRriy → khKiaJtwrslgMmp4YSa1f}/_ssgManifest.js +0 -0
  240. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/LICENSE +0 -0
  241. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/entry_points.txt +0 -0
  242. {mage_ai-0.9.65.dist-info → mage_ai-0.9.67.dist-info}/top_level.txt +0 -0
@@ -6,7 +6,7 @@ from mage_ai.usage_statistics.constants import EventNameType
6
6
  from mage_ai.usage_statistics.logger import UsageStatisticLogger
7
7
 
8
8
 
9
- class BaseMonitor():
9
+ class BaseMonitor:
10
10
  def __init__(self, resource, user, error, **kwargs):
11
11
  self.error = error
12
12
  self.options = kwargs
@@ -24,21 +24,43 @@ class BaseMonitor():
24
24
  if self.error.type:
25
25
  data['type'] = self.error.type
26
26
 
27
- asyncio.run(UsageStatisticLogger().error(
28
- event_name=EventNameType.API_ERROR,
27
+ loop = asyncio.get_event_loop()
28
+
29
+ kwargs = dict(
29
30
  resource=self.resource,
30
- **extract(data, [
31
- 'code',
32
- 'errors',
33
- 'message',
34
- 'type',
35
- ]),
36
- **extract(self.options, [
37
- 'operation',
38
- 'resource_id',
39
- 'resource_parent',
40
- 'resource_parent_id',
41
- ]),
42
- ))
31
+ **extract(
32
+ data,
33
+ [
34
+ 'code',
35
+ 'errors',
36
+ 'message',
37
+ 'type',
38
+ ],
39
+ ),
40
+ **extract(
41
+ self.options,
42
+ [
43
+ 'operation',
44
+ 'resource_id',
45
+ 'resource_parent',
46
+ 'resource_parent_id',
47
+ ],
48
+ ),
49
+ )
50
+
51
+ if loop is not None:
52
+ loop.create_task(
53
+ UsageStatisticLogger().error(
54
+ EventNameType.API_ERROR,
55
+ **kwargs
56
+ )
57
+ )
58
+ else:
59
+ asyncio.run(
60
+ UsageStatisticLogger().error(
61
+ EventNameType.API_ERROR,
62
+ **kwargs
63
+ )
64
+ )
43
65
 
44
66
  return data
@@ -62,6 +62,7 @@ BackfillPolicy.allow_write([
62
62
  'interval_type',
63
63
  'interval_units',
64
64
  'name',
65
+ 'settings',
65
66
  'start_datetime',
66
67
  'status',
67
68
  'variables',
@@ -69,7 +69,7 @@ class OauthResource(GenericResource):
69
69
  model.update(**auth_url_response)
70
70
 
71
71
  if authenticated or new_token:
72
- model['authenticated'] = authenticated
72
+ model['authenticated'] = True
73
73
  if new_token:
74
74
  access_tokens = [new_token]
75
75
  model['expires'] = max(
@@ -78,7 +78,7 @@ class OauthResource(GenericResource):
78
78
 
79
79
  oauths.append(model)
80
80
  except Exception:
81
- continue
81
+ pass
82
82
 
83
83
  return self.build_result_set(oauths, user, **kwargs)
84
84
 
@@ -110,12 +110,20 @@ class OauthResource(GenericResource):
110
110
  client_id=client_id,
111
111
  client_type=Oauth2Application.ClientType.PRIVATE,
112
112
  name=provider,
113
- user_id=user.id if user else None,
114
113
  )
115
114
 
116
- access_token = Oauth2AccessToken.query.filter(
115
+ access_token_query = Oauth2AccessToken.query.filter(
117
116
  Oauth2AccessToken.token == token,
118
- ).first()
117
+ )
118
+ if user:
119
+ access_token_query = access_token_query.filter(
120
+ Oauth2AccessToken.user_id == user.id,
121
+ )
122
+ else:
123
+ access_token_query = access_token_query.filter(
124
+ Oauth2AccessToken.user_id.is_(None),
125
+ )
126
+ access_token = access_token_query.first()
119
127
 
120
128
  if expires_in:
121
129
  expire_timedelta = timedelta(seconds=int(expires_in))
@@ -10,9 +10,10 @@ from mage_ai.orchestration.db import safe_db_query
10
10
  from mage_ai.orchestration.db.models.oauth import Role, User
11
11
  from mage_ai.settings import (
12
12
  AUTHENTICATION_MODE,
13
- LDAP_DEFAULT_ACCESS,
14
13
  OAUTH_DEFAULT_ACCESS,
14
+ get_settings_value,
15
15
  )
16
+ from mage_ai.settings.keys import LDAP_DEFAULT_ACCESS
16
17
  from mage_ai.usage_statistics.logger import UsageStatisticLogger
17
18
 
18
19
 
@@ -97,10 +98,11 @@ class SessionResource(BaseResource):
97
98
  role_names = conn.get_user_roles(user_attributes)
98
99
  if role_names:
99
100
  roles = Role.query.filter(Role.name.in_(role_names)).all()
101
+ ldap_default_access = get_settings_value(LDAP_DEFAULT_ACCESS)
100
102
  if not roles and \
101
- LDAP_DEFAULT_ACCESS is not None and \
102
- LDAP_DEFAULT_ACCESS in [r for r in Role.DefaultRole]:
103
- default_role = Role.get_role(LDAP_DEFAULT_ACCESS)
103
+ ldap_default_access is not None and \
104
+ ldap_default_access in [r for r in Role.DefaultRole]:
105
+ default_role = Role.get_role(ldap_default_access)
104
106
  if default_role:
105
107
  roles.append(default_role)
106
108
  user = User.create(
@@ -6,7 +6,8 @@ from ldap3 import Connection, Server
6
6
  from ldap3.core.exceptions import LDAPException
7
7
 
8
8
  from mage_ai.data_preparation.repo_manager import get_repo_config
9
- from mage_ai.settings import (
9
+ from mage_ai.settings import get_settings_value
10
+ from mage_ai.settings.keys import (
10
11
  LDAP_AUTHENTICATION_FILTER,
11
12
  LDAP_AUTHORIZATION_FILTER,
12
13
  LDAP_BASE_DN,
@@ -120,14 +121,23 @@ class LDAPConnection(LDAPAuthenticator):
120
121
 
121
122
  def new_ldap_connection() -> LDAPConnection:
122
123
  ldap_config_from_env_vars = dict(
123
- server_url=LDAP_SERVER,
124
- bind_dn=LDAP_BIND_DN,
125
- bind_password=LDAP_BIND_PASSWORD,
126
- base_dn=LDAP_BASE_DN,
127
- authentication_filter=LDAP_AUTHENTICATION_FILTER,
128
- authorization_filter=LDAP_AUTHORIZATION_FILTER,
129
- group_field=LDAP_GROUP_FIELD,
130
- roles_mapping=LDAP_ROLES_MAPPING,
124
+ server_url=get_settings_value(LDAP_SERVER, 'ldaps://127.0.0.1:1636'),
125
+ bind_dn=get_settings_value(LDAP_BIND_DN, 'cd=admin,dc=example,dc=org'),
126
+ bind_password=get_settings_value(LDAP_BIND_PASSWORD, 'admin_password'),
127
+ base_dn=get_settings_value(LDAP_BASE_DN, 'dc=example,dc=org'),
128
+ authentication_filter=get_settings_value(
129
+ LDAP_AUTHENTICATION_FILTER,
130
+ '(&(|(objectClass=Pers)(objectClass=gro))(cn={username}))'
131
+ ),
132
+ authorization_filter=get_settings_value(
133
+ LDAP_AUTHORIZATION_FILTER,
134
+ '(&(objectClass=groupOfNames)(cn=group)(member={user_dn}))'
135
+ ),
136
+ group_field=get_settings_value(
137
+ LDAP_GROUP_FIELD,
138
+ 'memberOf',
139
+ ),
140
+ roles_mapping=get_settings_value(LDAP_ROLES_MAPPING),
131
141
  )
132
142
  try:
133
143
  ldap_config = get_repo_config().ldap_config
@@ -1,7 +1,9 @@
1
- import os
2
1
  from enum import Enum
3
2
  from typing import Optional
4
3
 
4
+ from mage_ai.settings import get_settings_value
5
+ from mage_ai.settings.keys import GHE_HOSTNAME
6
+
5
7
  ACTIVE_DIRECTORY_CLIENT_ID = '51aec820-9d49-40a9-b046-17c1f28f620d'
6
8
 
7
9
  GITHUB_CLIENT_ID = '8577f13ddc81e2848b07'
@@ -10,6 +12,7 @@ GITHUB_STATE = '1337'
10
12
 
11
13
  class ProviderName(str, Enum):
12
14
  ACTIVE_DIRECTORY = 'active_directory'
15
+ AZURE_DEVOPS = 'azure_devops'
13
16
  BITBUCKET = 'bitbucket'
14
17
  GITHUB = 'github'
15
18
  GITLAB = 'gitlab'
@@ -21,28 +24,19 @@ class ProviderName(str, Enum):
21
24
 
22
25
  VALID_OAUTH_PROVIDERS = [e.value for e in ProviderName]
23
26
 
24
- GHE_CLIENT_ID_ENV_VAR = 'GHE_CLIENT_ID'
25
- GHE_CLIENT_SECRET_ENV_VAR = 'GHE_CLIENT_SECRET'
26
- GHE_HOSTNAME_ENV_VAR = 'GHE_HOSTNAME'
27
-
28
- GITLAB_HOST = os.getenv('GITLAB_HOST')
29
- GITLAB_CLIENT_ID = os.getenv('GITLAB_CLIENT_ID')
30
- GITLAB_CLIENT_SECRET = os.getenv('GITLAB_CLIENT_SECRET')
31
-
32
- BITBUCKET_HOST = os.getenv('BITBUCKET_HOST')
33
- BITBUCKET_OAUTH_KEY = os.getenv('BITBUCKET_OAUTH_KEY')
34
- BITBUCKET_OAUTH_SECRET = os.getenv('BITBUCKET_OAUTH_SECRET')
35
-
36
27
  DEFAULT_GITHUB_HOSTNAME = 'https://github.com'
37
28
 
29
+ # Github and GHE don't need to be added to this list because they are handled
30
+ # separately for now.
38
31
  GIT_OAUTH_PROVIDERS = [
32
+ ProviderName.AZURE_DEVOPS,
39
33
  ProviderName.BITBUCKET,
40
34
  ProviderName.GITLAB,
41
35
  ]
42
36
 
43
37
 
44
38
  def get_ghe_hostname() -> Optional[str]:
45
- ghe_hostname = os.getenv(GHE_HOSTNAME_ENV_VAR)
39
+ ghe_hostname = get_settings_value(GHE_HOSTNAME)
46
40
  if ghe_hostname and not ghe_hostname.startswith('http'):
47
41
  ghe_hostname = f'https://{ghe_hostname}'
48
42
 
@@ -22,8 +22,6 @@ def access_tokens_for_client(
22
22
  ) -> List[Oauth2AccessToken]:
23
23
  query = Oauth2Application.query.filter(Oauth2Application.client_id == client_id)
24
24
  query.cache = True
25
- if user:
26
- query.filter(Oauth2Application.user_id == user.id)
27
25
 
28
26
  oauth_client = query.first()
29
27
 
@@ -31,10 +29,18 @@ def access_tokens_for_client(
31
29
  if oauth_client:
32
30
  access_tokens_query = Oauth2AccessToken.query
33
31
  access_tokens_query.cache = True
34
- access_tokens = access_tokens_query.filter(
32
+ access_tokens_query = access_tokens_query.filter(
35
33
  Oauth2AccessToken.expires > datetime.utcnow(),
36
34
  Oauth2AccessToken.oauth2_application_id == oauth_client.id,
37
35
  )
36
+ if user:
37
+ access_tokens = access_tokens_query.filter(
38
+ Oauth2AccessToken.user_id == user.id
39
+ )
40
+ else:
41
+ access_tokens = access_tokens_query.filter(
42
+ Oauth2AccessToken.user_id.is_(None)
43
+ )
38
44
 
39
45
  return [row for row in access_tokens]
40
46
 
@@ -47,8 +53,6 @@ async def refresh_token_for_client(
47
53
  ) -> Awaitable[Optional[Oauth2AccessToken]]:
48
54
  query = Oauth2Application.query.filter(Oauth2Application.client_id == client_id)
49
55
  query.cache = True
50
- if user:
51
- query.filter(Oauth2Application.user_id == user.id)
52
56
 
53
57
  oauth_client = query.first()
54
58
 
@@ -56,10 +60,18 @@ async def refresh_token_for_client(
56
60
  if oauth_client:
57
61
  access_tokens_query = Oauth2AccessToken.query
58
62
  access_tokens_query.cache = True
59
- refreshable_tokens = access_tokens_query.filter(
63
+ access_tokens_query = access_tokens_query.filter(
60
64
  Oauth2AccessToken.refresh_token.is_not(None),
61
65
  Oauth2AccessToken.oauth2_application_id == oauth_client.id,
62
66
  )
67
+ if user:
68
+ refreshable_tokens = access_tokens_query.filter(
69
+ Oauth2AccessToken.user_id == user.id
70
+ )
71
+ else:
72
+ refreshable_tokens = access_tokens_query.filter(
73
+ Oauth2AccessToken.user_id.is_(None)
74
+ )
63
75
 
64
76
  new_token = None
65
77
  if refreshable_tokens:
@@ -13,10 +13,11 @@ from mage_ai.authentication.providers.oauth import OauthProvider
13
13
  from mage_ai.authentication.providers.sso import SsoProvider
14
14
  from mage_ai.authentication.providers.utils import get_base_url
15
15
  from mage_ai.server.logger import Logger
16
- from mage_ai.settings import ACTIVE_DIRECTORY_DIRECTORY_ID
17
- from mage_ai.settings.sso import (
16
+ from mage_ai.settings import get_settings_value
17
+ from mage_ai.settings.keys import (
18
18
  ACTIVE_DIRECTORY_CLIENT_ID,
19
19
  ACTIVE_DIRECTORY_CLIENT_SECRET,
20
+ ACTIVE_DIRECTORY_DIRECTORY_ID,
20
21
  ACTIVE_DIRECTORY_ROLES_MAPPING,
21
22
  )
22
23
 
@@ -25,24 +26,28 @@ logger = Logger().new_server_logger(__name__)
25
26
 
26
27
  class ADProvider(SsoProvider, OauthProvider):
27
28
  provider = ProviderName.ACTIVE_DIRECTORY
29
+ scope = 'User.Read'
28
30
 
29
31
  def __init__(self):
32
+ self.directory_id = get_settings_value(ACTIVE_DIRECTORY_DIRECTORY_ID)
33
+ self.client_id = get_settings_value(ACTIVE_DIRECTORY_CLIENT_ID)
34
+ self.client_secret = get_settings_value(ACTIVE_DIRECTORY_CLIENT_SECRET)
30
35
  self.__validate()
31
36
 
32
- self.roles_mapping = {}
33
- if ACTIVE_DIRECTORY_ROLES_MAPPING:
37
+ self.roles_mapping = get_settings_value(ACTIVE_DIRECTORY_ROLES_MAPPING)
38
+ if self.roles_mapping:
34
39
  try:
35
- self.roles_mapping = json.loads(ACTIVE_DIRECTORY_ROLES_MAPPING)
40
+ self.roles_mapping = json.loads(self.roles_mapping)
36
41
  except Exception:
37
42
  logger.exception('Failed to parse roles mapping.')
38
43
 
39
44
  def __validate(self):
40
- if not ACTIVE_DIRECTORY_DIRECTORY_ID:
45
+ if not self.directory_id:
41
46
  raise Exception(
42
47
  'AD directory id is empty. '
43
48
  'Make sure the ACTIVE_DIRECTORY_DIRECTORY_ID environment variable is set.'
44
49
  )
45
- if ACTIVE_DIRECTORY_CLIENT_ID and not ACTIVE_DIRECTORY_CLIENT_SECRET:
50
+ if self.client_id and not self.client_secret:
46
51
  raise Exception(
47
52
  'AD client secret is empty. '
48
53
  'Make sure the ACTIVE_DIRECTORY_CLIENT_SECRET environment variable is set.'
@@ -55,20 +60,20 @@ class ADProvider(SsoProvider, OauthProvider):
55
60
  set up in Azure. They can additionally set the ACTIVE_DIRECTORY_CLIENT_ID and
56
61
  ACTIVE_DIRECTORY_CLIENT_SECRET which will use their own Mage application in Azure.
57
62
  """
58
- ad_directory_id = ACTIVE_DIRECTORY_DIRECTORY_ID
59
- if ACTIVE_DIRECTORY_CLIENT_ID:
63
+ ad_directory_id = self.directory_id
64
+ if self.client_id:
60
65
  base_url = get_base_url(redirect_uri)
61
66
  redirect_uri_query = dict(
62
67
  provider=self.provider,
63
68
  redirect_uri=redirect_uri,
64
69
  )
65
70
  query = dict(
66
- client_id=ACTIVE_DIRECTORY_CLIENT_ID,
71
+ client_id=self.client_id,
67
72
  redirect_uri=quote_plus(
68
73
  f'{base_url}/oauth',
69
74
  ),
70
75
  response_type='code',
71
- scope='User.Read',
76
+ scope=self.scope,
72
77
  state=uuid.uuid4().hex,
73
78
  )
74
79
  query_strings = []
@@ -88,7 +93,7 @@ class ADProvider(SsoProvider, OauthProvider):
88
93
  client_id=ACTIVE_DIRECTORY_MAGE_CLIENT_ID,
89
94
  redirect_uri=f'https://api.mage.ai/v1/oauth/{self.provider}',
90
95
  response_type='code',
91
- scope='User.Read',
96
+ scope=self.scope,
92
97
  state=quote_plus(
93
98
  json.dumps(
94
99
  dict(
@@ -116,12 +121,12 @@ class ADProvider(SsoProvider, OauthProvider):
116
121
  'Accept': 'application/json',
117
122
  },
118
123
  data=dict(
119
- client_id=ACTIVE_DIRECTORY_CLIENT_ID,
120
- client_secret=ACTIVE_DIRECTORY_CLIENT_SECRET,
124
+ client_id=self.client_id,
125
+ client_secret=self.client_secret,
121
126
  code=code,
122
127
  grant_type='authorization_code',
123
128
  redirect_uri=f'{base_url}/oauth',
124
- tenant=ACTIVE_DIRECTORY_DIRECTORY_ID,
129
+ tenant=self.directory_id,
125
130
  ),
126
131
  timeout=20,
127
132
  ) as response:
@@ -150,7 +155,7 @@ class ADProvider(SsoProvider, OauthProvider):
150
155
  if self.roles_mapping:
151
156
  try:
152
157
  async with session.get(
153
- f'https://graph.microsoft.com/v1.0/servicePrincipals?$filter=appId eq \'{ACTIVE_DIRECTORY_CLIENT_ID}\'&$select=id', # noqa: E501
158
+ f'https://graph.microsoft.com/v1.0/servicePrincipals?$filter=appId eq \'{self.client_id}\'&$select=id', # noqa: E501
154
159
  headers={
155
160
  'Content-Type': 'application\\json',
156
161
  'Authorization': f'Bearer {access_token}',
@@ -0,0 +1,18 @@
1
+ from mage_ai.authentication.oauth.constants import ProviderName
2
+ from mage_ai.authentication.providers.active_directory import ADProvider
3
+ from mage_ai.settings import get_settings_value
4
+ from mage_ai.settings.keys import AZURE_DEVOPS_ORGANIZATION
5
+
6
+
7
+ class AzureDevopsProvider(ADProvider):
8
+ provider = ProviderName.AZURE_DEVOPS
9
+ # This is a hardcoded scope value that is used to get Git access to the Azure DevOps project.
10
+ # This should not be changed unless this scope stops working properly.
11
+ scope = '499b84ac-1321-427f-aa17-267ca6975798/.default'
12
+
13
+ def __init__(self):
14
+ super().__init__()
15
+ if not get_settings_value(AZURE_DEVOPS_ORGANIZATION):
16
+ raise Exception(
17
+ 'Azure DevOps organization is empty. '
18
+ 'Make sure the AZURE_DEVOPS_ORGANIZATION environment variable is set.')
@@ -5,23 +5,24 @@ from typing import Awaitable, Dict
5
5
  import aiohttp
6
6
  from aiohttp import BasicAuth
7
7
 
8
- from mage_ai.authentication.oauth.constants import (
8
+ from mage_ai.authentication.oauth.constants import ProviderName
9
+ from mage_ai.authentication.providers.oauth import OauthProvider
10
+ from mage_ai.authentication.providers.utils import get_base_url
11
+ from mage_ai.settings import get_settings_value
12
+ from mage_ai.settings.keys import (
9
13
  BITBUCKET_HOST,
10
14
  BITBUCKET_OAUTH_KEY,
11
15
  BITBUCKET_OAUTH_SECRET,
12
- ProviderName,
13
16
  )
14
- from mage_ai.authentication.providers.oauth import OauthProvider
15
- from mage_ai.authentication.providers.utils import get_base_url
16
17
 
17
18
 
18
19
  class BitbucketProvider(OauthProvider):
19
20
  provider = ProviderName.BITBUCKET
20
21
 
21
22
  def __init__(self):
22
- self.hostname = BITBUCKET_HOST or 'https://bitbucket.org'
23
- self.key = BITBUCKET_OAUTH_KEY
24
- self.secret = BITBUCKET_OAUTH_SECRET
23
+ self.hostname = get_settings_value(BITBUCKET_HOST) or 'https://bitbucket.org'
24
+ self.key = get_settings_value(BITBUCKET_OAUTH_KEY)
25
+ self.secret = get_settings_value(BITBUCKET_OAUTH_SECRET)
25
26
  self.__validate()
26
27
 
27
28
  def __validate(self):
@@ -71,7 +72,7 @@ class BitbucketProvider(OauthProvider):
71
72
  code=code,
72
73
  redirect_uri=f'{base_url}/oauth',
73
74
  ),
74
- auth=BasicAuth(BITBUCKET_OAUTH_KEY, BITBUCKET_OAUTH_SECRET),
75
+ auth=BasicAuth(self.key, self.secret),
75
76
  timeout=20,
76
77
  ) as response:
77
78
  data = await response.json()
@@ -91,7 +92,7 @@ class BitbucketProvider(OauthProvider):
91
92
  grant_type='refresh_token',
92
93
  refresh_token=refresh_token,
93
94
  ),
94
- auth=BasicAuth(BITBUCKET_OAUTH_KEY, BITBUCKET_OAUTH_SECRET),
95
+ auth=BasicAuth(self.key, self.secret),
95
96
  timeout=20,
96
97
  ) as response:
97
98
  data = await response.json()
@@ -1,5 +1,6 @@
1
1
  from mage_ai.authentication.oauth.constants import ProviderName
2
2
  from mage_ai.authentication.providers.active_directory import ADProvider
3
+ from mage_ai.authentication.providers.azure_devops import AzureDevopsProvider
3
4
  from mage_ai.authentication.providers.bitbucket import BitbucketProvider
4
5
  from mage_ai.authentication.providers.ghe import GHEProvider
5
6
  from mage_ai.authentication.providers.gitlab import GitlabProvider
@@ -9,6 +10,7 @@ from mage_ai.authentication.providers.okta import OktaProvider
9
10
 
10
11
  NAME_TO_PROVIDER = {
11
12
  ProviderName.ACTIVE_DIRECTORY: ADProvider,
13
+ ProviderName.AZURE_DEVOPS: AzureDevopsProvider,
12
14
  ProviderName.BITBUCKET: BitbucketProvider,
13
15
  ProviderName.GHE: GHEProvider,
14
16
  ProviderName.GITLAB: GitlabProvider,
@@ -1,18 +1,14 @@
1
- import os
2
1
  import urllib.parse
3
2
  import uuid
4
3
  from typing import Awaitable, Dict
5
4
 
6
5
  import aiohttp
7
6
 
8
- from mage_ai.authentication.oauth.constants import (
9
- GHE_CLIENT_ID_ENV_VAR,
10
- GHE_CLIENT_SECRET_ENV_VAR,
11
- ProviderName,
12
- get_ghe_hostname,
13
- )
7
+ from mage_ai.authentication.oauth.constants import ProviderName, get_ghe_hostname
14
8
  from mage_ai.authentication.providers.oauth import OauthProvider
15
9
  from mage_ai.authentication.providers.utils import get_base_url
10
+ from mage_ai.settings import get_settings_value
11
+ from mage_ai.settings.keys import GHE_CLIENT_ID, GHE_CLIENT_SECRET
16
12
 
17
13
 
18
14
  class GHEProvider(OauthProvider):
@@ -20,8 +16,8 @@ class GHEProvider(OauthProvider):
20
16
 
21
17
  def __init__(self):
22
18
  self.hostname = get_ghe_hostname()
23
- self.client_id = os.getenv(GHE_CLIENT_ID_ENV_VAR)
24
- self.client_secret = os.getenv(GHE_CLIENT_SECRET_ENV_VAR)
19
+ self.client_id = get_settings_value(GHE_CLIENT_ID)
20
+ self.client_secret = get_settings_value(GHE_CLIENT_SECRET)
25
21
  self.__validate()
26
22
 
27
23
  def __validate(self):
@@ -4,25 +4,22 @@ from typing import Awaitable, Dict
4
4
 
5
5
  import aiohttp
6
6
 
7
- from mage_ai.authentication.oauth.constants import (
8
- GITLAB_CLIENT_ID,
9
- GITLAB_CLIENT_SECRET,
10
- GITLAB_HOST,
11
- ProviderName,
12
- )
7
+ from mage_ai.authentication.oauth.constants import ProviderName
13
8
  from mage_ai.authentication.providers.oauth import OauthProvider
14
9
  from mage_ai.authentication.providers.utils import get_base_url
10
+ from mage_ai.settings import get_settings_value
11
+ from mage_ai.settings.keys import GITLAB_CLIENT_ID, GITLAB_CLIENT_SECRET, GITLAB_HOST
15
12
 
16
13
 
17
14
  class GitlabProvider(OauthProvider):
18
15
  provider = ProviderName.GITLAB
19
16
 
20
17
  def __init__(self):
21
- self.hostname = GITLAB_HOST or 'https://gitlab.com'
18
+ self.hostname = get_settings_value(GITLAB_HOST) or 'https://gitlab.com'
22
19
  if not self.hostname.startswith('http'):
23
20
  self.hostname = f'https://{self.hostname}'
24
- self.client_id = GITLAB_CLIENT_ID
25
- self.client_secret = GITLAB_CLIENT_SECRET
21
+ self.client_id = get_settings_value(GITLAB_CLIENT_ID)
22
+ self.client_secret = get_settings_value(GITLAB_CLIENT_SECRET)
26
23
  self.__validate()
27
24
 
28
25
  def __validate(self):
@@ -8,18 +8,21 @@ from mage_ai.authentication.oauth.constants import ProviderName
8
8
  from mage_ai.authentication.providers.oauth import OauthProvider
9
9
  from mage_ai.authentication.providers.sso import SsoProvider
10
10
  from mage_ai.authentication.providers.utils import get_base_url
11
- from mage_ai.settings.sso import GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
11
+ from mage_ai.settings import get_settings_value
12
+ from mage_ai.settings.keys import GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET
12
13
 
13
14
 
14
15
  class GoogleProvider(SsoProvider, OauthProvider):
15
16
  provider = ProviderName.GOOGLE
16
17
 
17
18
  def __init__(self):
18
- if not GOOGLE_CLIENT_ID:
19
+ self.client_id = get_settings_value(GOOGLE_CLIENT_ID)
20
+ self.client_secret = get_settings_value(GOOGLE_CLIENT_SECRET)
21
+ if not self.client_id:
19
22
  raise Exception(
20
23
  'Google client id is empty. '
21
24
  'Make sure the GOOGLE_CLIENT_ID environment variable is set.')
22
- if not GOOGLE_CLIENT_SECRET:
25
+ if not self.client_secret:
23
26
  raise Exception(
24
27
  'Google client secret is empty. '
25
28
  'Make sure the GOOGLE_CLIENT_SECRET environment variable is set.')
@@ -31,7 +34,7 @@ class GoogleProvider(SsoProvider, OauthProvider):
31
34
  redirect_uri=redirect_uri,
32
35
  )
33
36
  query = dict(
34
- client_id=GOOGLE_CLIENT_ID,
37
+ client_id=self.client_id,
35
38
  prompt='select_account',
36
39
  redirect_uri=urllib.parse.quote_plus(
37
40
  f'{base_url}/oauth',
@@ -58,8 +61,8 @@ class GoogleProvider(SsoProvider, OauthProvider):
58
61
  'https://oauth2.googleapis.com/token',
59
62
  data=dict(
60
63
  code=code,
61
- client_id=GOOGLE_CLIENT_ID,
62
- client_secret=GOOGLE_CLIENT_SECRET,
64
+ client_id=self.client_id,
65
+ client_secret=self.client_secret,
63
66
  redirect_uri=f'{base_url}/oauth',
64
67
  grant_type='authorization_code',
65
68
  ),
@@ -10,7 +10,8 @@ from mage_ai.authentication.providers.oauth import OauthProvider
10
10
  from mage_ai.authentication.providers.sso import SsoProvider
11
11
  from mage_ai.authentication.providers.utils import get_base_url
12
12
  from mage_ai.server.logger import Logger
13
- from mage_ai.settings.sso import OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_DISCOVERY_URL
13
+ from mage_ai.settings import get_settings_value
14
+ from mage_ai.settings.keys import OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_DISCOVERY_URL
14
15
 
15
16
  logger = Logger().new_server_logger(__name__)
16
17
 
@@ -19,9 +20,9 @@ class OidcProvider(OauthProvider, SsoProvider):
19
20
  provider = ProviderName.OIDC_GENERIC
20
21
 
21
22
  def __init__(self):
22
- self.discovery_url = OIDC_DISCOVERY_URL
23
- self.client_id = OIDC_CLIENT_ID
24
- self.client_secret = OIDC_CLIENT_SECRET
23
+ self.discovery_url = get_settings_value(OIDC_DISCOVERY_URL)
24
+ self.client_id = get_settings_value(OIDC_CLIENT_ID)
25
+ self.client_secret = get_settings_value(OIDC_CLIENT_SECRET)
25
26
  self.__validate()
26
27
 
27
28
  self.discover()
@@ -122,6 +123,7 @@ class OidcProvider(OauthProvider, SsoProvider):
122
123
  },
123
124
  timeout=10,
124
125
  ) as response:
126
+ response.raise_for_status()
125
127
  userinfo_resp = await response.json()
126
128
 
127
129
  email = userinfo_resp.get('email')