From fc42aedd3a39a96b5b9a9fe7eb0fe0f229eb6af5 Mon Sep 17 00:00:00 2001 From: John Chilton Date: Thu, 26 Sep 2024 09:57:03 -0400 Subject: [PATCH] Allow oauth2 file sources with Dropbox initial implementation. --- client/src/api/schema/schema.ts | 281 ++++++++++++++++-- .../ConfigurationTestSummary.vue | 3 + .../useConfigurationTesting.ts | 4 + .../FileSources/FileSourceTypeSpan.vue | 4 +- .../FileSources/Instances/CreateForm.vue | 2 + .../FileSources/Instances/CreateInstance.vue | 33 +- .../FileSources/Instances/services.ts | 4 + .../ObjectStore/Instances/CreateForm.vue | 2 + client/src/entry/analysis/router.js | 5 +- doc/source/admin/data.md | 148 +++++++++ doc/source/admin/dropbox_callback.png | Bin 0 -> 33083 bytes doc/source/admin/dropbox_client_creds.png | Bin 0 -> 25403 bytes .../admin/dropbox_create_app_options_1.png | Bin 0 -> 223520 bytes doc/source/admin/dropbox_create_button.png | Bin 0 -> 66003 bytes doc/source/admin/dropbox_scopes.png | Bin 0 -> 252834 bytes .../file_source_dropbox_configuration.png | Bin 0 -> 15944 bytes ..._source_dropbox_configuration_template.png | Bin 0 -> 26877 bytes doc/source/admin/file_source_templates.png | Bin 323201 -> 409046 bytes doc/source/admin/gen_diagrams.py | 4 + lib/galaxy/app_unittest_utils/galaxy_mock.py | 2 +- lib/galaxy/files/sources/dropbox.py | 2 + lib/galaxy/files/sources/googledrive.py | 3 + lib/galaxy/files/templates/__init__.py | 4 + .../dropbox_client_secrets_explicit.yml | 7 + .../dropbox_client_secrets_in_vault.yml | 15 + .../templates/examples/production_dropbox.yml | 15 + .../examples/production_google_drive.yml | 15 + lib/galaxy/files/templates/models.py | 92 +++++- lib/galaxy/managers/_config_templates.py | 188 +++++++++++- lib/galaxy/managers/file_source_instances.py | 195 ++++++++++-- lib/galaxy/managers/object_store_instances.py | 15 +- lib/galaxy/model/__init__.py | 12 +- lib/galaxy/objectstore/templates/models.py | 8 + lib/galaxy/schema/schema.py | 13 + lib/galaxy/util/config_templates.py | 130 ++++++++ lib/galaxy/webapps/galaxy/api/file_sources.py | 31 +- .../webapps/galaxy/api/oauth2_callback.py | 50 ++++ lib/galaxy/webapps/galaxy/api/object_store.py | 4 +- lib/galaxy/work/context.py | 5 + .../app/managers/test_user_file_sources.py | 180 +++++++++++ test/unit/files/test_template_models.py | 3 + test/unit/schema/test_schema.py | 8 + .../util/test_config_template_validation.py | 1 + 43 files changed, 1409 insertions(+), 79 deletions(-) create mode 100644 doc/source/admin/dropbox_callback.png create mode 100644 doc/source/admin/dropbox_client_creds.png create mode 100644 doc/source/admin/dropbox_create_app_options_1.png create mode 100644 doc/source/admin/dropbox_create_button.png create mode 100644 doc/source/admin/dropbox_scopes.png create mode 100644 doc/source/admin/file_source_dropbox_configuration.png create mode 100644 doc/source/admin/file_source_dropbox_configuration_template.png create mode 100644 lib/galaxy/files/templates/examples/dropbox_client_secrets_explicit.yml create mode 100644 lib/galaxy/files/templates/examples/dropbox_client_secrets_in_vault.yml create mode 100644 lib/galaxy/files/templates/examples/production_dropbox.yml create mode 100644 lib/galaxy/files/templates/examples/production_google_drive.yml create mode 100644 lib/galaxy/webapps/galaxy/api/oauth2_callback.py diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index cfe270edf373..b1c70fab2d91 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -926,10 +926,22 @@ export interface paths { trace?: never; }; "/api/file_source_instances/{user_file_source_id}/test": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; /** Test a file source instance and return status. */ get: operations["file_sources__instances_test_instance"]; + put?: never; /** Test updating or upgrading user file source instance. */ post: operations["file_sources__test_instances_update"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; "/api/file_source_templates": { parameters: { @@ -948,6 +960,23 @@ export interface paths { patch?: never; trace?: never; }; + "/api/file_source_templates/{template_id}/{template_version}/oauth2": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Template Oauth2 */ + get: operations["file_sources__template_oauth2"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/api/folders/{folder_id}/contents": { parameters: { query?: never; @@ -3313,10 +3342,22 @@ export interface paths { trace?: never; }; "/api/object_store_instances/{user_object_store_id}/test": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; /** Get a persisted user object store instance. */ get: operations["object_stores__instances_test_instance"]; + put?: never; /** Test updating or upgrading user object source instance. */ post: operations["object_stores__test_instances_update"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; }; "/api/object_store_templates": { parameters: { @@ -5551,6 +5592,23 @@ export interface paths { patch?: never; trace?: never; }; + "/oauth2_callback": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Callback entry point for remote resource responses with OAuth2 authorization codes */ + get: operations["oauth2_callback_oauth2_callback_get"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { @@ -6643,6 +6701,8 @@ export interface components { template_id: string; /** Template Version */ template_version: number; + /** Uuid */ + uuid?: string | null; /** Variables */ variables: { [key: string]: string | boolean | number; @@ -8823,7 +8883,7 @@ export interface components { * Type * @enum {string} */ - type: "ftp" | "posix" | "s3fs" | "azure" | "onedata"; + type: "ftp" | "posix" | "s3fs" | "azure" | "onedata" | "dropbox" | "googledrive"; /** Variables */ variables?: | ( @@ -13738,6 +13798,11 @@ export interface components { */ updated_count: number; }; + /** OAuth2Info */ + OAuth2Info: { + /** Authorize Url */ + authorize_url: string; + }; /** ObjectExportTaskResponse */ ObjectExportTaskResponse: { /** @@ -14261,6 +14326,7 @@ export interface components { /** PluginStatus */ PluginStatus: { connection?: components["schemas"]["PluginAspectStatus"] | null; + oauth2_access_token_generation?: components["schemas"]["PluginAspectStatus"] | null; template_definition: components["schemas"]["PluginAspectStatus"]; template_settings?: components["schemas"]["PluginAspectStatus"] | null; }; @@ -15791,20 +15857,20 @@ export interface components { TestUpdateInstancePayload: { /** Variables */ variables?: { - [key: string]: (string | boolean | number) | undefined; + [key: string]: string | boolean | number; } | null; }; /** TestUpgradeInstancePayload */ TestUpgradeInstancePayload: { /** Secrets */ secrets: { - [key: string]: string | undefined; + [key: string]: string; }; /** Template Version */ template_version: number; /** Variables */ variables: { - [key: string]: (string | boolean | number) | undefined; + [key: string]: string | boolean | number; }; }; /** ToolDataDetails */ @@ -16645,7 +16711,7 @@ export interface components { * Type * @enum {string} */ - type: "ftp" | "posix" | "s3fs" | "azure" | "onedata"; + type: "ftp" | "posix" | "s3fs" | "azure" | "onedata" | "dropbox" | "googledrive"; /** Uri Root */ uri_root: string; /** @@ -20133,43 +20199,61 @@ export interface operations { }; }; file_sources__instances_test_instance: { - /** Test a file source instance and return status. */ parameters: { - /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + query?: never; header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ "run-as"?: string | null; }; - /** @description The UUID index for a persisted UserFileSourceStore object. */ path: { + /** @description The UUID index for a persisted UserFileSourceStore object. */ user_file_source_id: string; }; + cookie?: never; }; + requestBody?: never; responses: { /** @description Successful Response */ 200: { + headers: { + [name: string]: unknown; + }; content: { "application/json": components["schemas"]["PluginStatus"]; }; }; - /** @description Validation Error */ - 422: { + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; content: { - "application/json": components["schemas"]["HTTPValidationError"]; + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; }; }; }; }; file_sources__test_instances_update: { - /** Test updating or upgrading user file source instance. */ parameters: { - /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + query?: never; header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ "run-as"?: string | null; }; - /** @description The UUID index for a persisted UserFileSourceStore object. */ path: { + /** @description The UUID index for a persisted UserFileSourceStore object. */ user_file_source_id: string; }; + cookie?: never; }; requestBody: { content: { @@ -20181,14 +20265,29 @@ export interface operations { responses: { /** @description Successful Response */ 200: { + headers: { + [name: string]: unknown; + }; content: { "application/json": components["schemas"]["PluginStatus"]; }; }; - /** @description Validation Error */ - 422: { + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; content: { - "application/json": components["schemas"]["HTTPValidationError"]; + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; }; }; }; @@ -20234,6 +20333,52 @@ export interface operations { }; }; }; + file_sources__template_oauth2: { + parameters: { + query?: never; + header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + "run-as"?: string | null; + }; + path: { + /** @description The template ID of the target file source template. */ + template_id: string; + /** @description The template version of the target file source template. */ + template_version: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OAuth2 authorization url to redirect user to prior to creation. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["OAuth2Info"]; + }; + }; + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + }; + }; index_api_folders__folder_id__contents_get: { parameters: { query?: { @@ -28525,43 +28670,61 @@ export interface operations { }; }; object_stores__instances_test_instance: { - /** Get a persisted user object store instance. */ parameters: { - /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + query?: never; header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ "run-as"?: string | null; }; - /** @description The UUID used to identify a persisted UserObjectStore object. */ path: { + /** @description The UUID used to identify a persisted UserObjectStore object. */ user_object_store_id: string; }; + cookie?: never; }; + requestBody?: never; responses: { /** @description Successful Response */ 200: { + headers: { + [name: string]: unknown; + }; content: { "application/json": components["schemas"]["PluginStatus"]; }; }; - /** @description Validation Error */ - 422: { + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; content: { - "application/json": components["schemas"]["HTTPValidationError"]; + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; }; }; }; }; object_stores__test_instances_update: { - /** Test updating or upgrading user object source instance. */ parameters: { - /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + query?: never; header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ "run-as"?: string | null; }; - /** @description The UUID used to identify a persisted UserObjectStore object. */ path: { + /** @description The UUID used to identify a persisted UserObjectStore object. */ user_object_store_id: string; }; + cookie?: never; }; requestBody: { content: { @@ -28573,14 +28736,29 @@ export interface operations { responses: { /** @description Successful Response */ 200: { + headers: { + [name: string]: unknown; + }; content: { "application/json": components["schemas"]["PluginStatus"]; }; }; - /** @description Validation Error */ - 422: { + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; content: { - "application/json": components["schemas"]["HTTPValidationError"]; + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; }; }; }; @@ -35465,4 +35643,49 @@ export interface operations { }; }; }; + oauth2_callback_oauth2_callback_get: { + parameters: { + query: { + /** @description Base-64 encoded JSON used to route request within Galaxy. */ + state: string; + code: string; + }; + header?: { + /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ + "run-as"?: string | null; + }; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successful Response */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": unknown; + }; + }; + /** @description Request Error */ + "4XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + /** @description Server Error */ + "5XX": { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MessageExceptionModel"]; + }; + }; + }; + }; } diff --git a/client/src/components/ConfigTemplates/ConfigurationTestSummary.vue b/client/src/components/ConfigTemplates/ConfigurationTestSummary.vue index be17f1593821..b781c6eae665 100644 --- a/client/src/components/ConfigTemplates/ConfigurationTestSummary.vue +++ b/client/src/components/ConfigTemplates/ConfigurationTestSummary.vue @@ -15,6 +15,9 @@ defineProps();