rucio 37.0.0rc1__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 rucio might be problematic. Click here for more details.
- rucio/__init__.py +17 -0
- rucio/alembicrevision.py +15 -0
- rucio/cli/__init__.py +14 -0
- rucio/cli/account.py +216 -0
- rucio/cli/bin_legacy/__init__.py +13 -0
- rucio/cli/bin_legacy/rucio.py +2825 -0
- rucio/cli/bin_legacy/rucio_admin.py +2500 -0
- rucio/cli/command.py +272 -0
- rucio/cli/config.py +72 -0
- rucio/cli/did.py +191 -0
- rucio/cli/download.py +128 -0
- rucio/cli/lifetime_exception.py +33 -0
- rucio/cli/replica.py +162 -0
- rucio/cli/rse.py +293 -0
- rucio/cli/rule.py +158 -0
- rucio/cli/scope.py +40 -0
- rucio/cli/subscription.py +73 -0
- rucio/cli/upload.py +60 -0
- rucio/cli/utils.py +226 -0
- rucio/client/__init__.py +15 -0
- rucio/client/accountclient.py +432 -0
- rucio/client/accountlimitclient.py +183 -0
- rucio/client/baseclient.py +983 -0
- rucio/client/client.py +120 -0
- rucio/client/configclient.py +126 -0
- rucio/client/credentialclient.py +59 -0
- rucio/client/didclient.py +868 -0
- rucio/client/diracclient.py +56 -0
- rucio/client/downloadclient.py +1783 -0
- rucio/client/exportclient.py +44 -0
- rucio/client/fileclient.py +50 -0
- rucio/client/importclient.py +42 -0
- rucio/client/lifetimeclient.py +90 -0
- rucio/client/lockclient.py +109 -0
- rucio/client/metaconventionsclient.py +140 -0
- rucio/client/pingclient.py +44 -0
- rucio/client/replicaclient.py +452 -0
- rucio/client/requestclient.py +125 -0
- rucio/client/richclient.py +317 -0
- rucio/client/rseclient.py +746 -0
- rucio/client/ruleclient.py +294 -0
- rucio/client/scopeclient.py +90 -0
- rucio/client/subscriptionclient.py +173 -0
- rucio/client/touchclient.py +82 -0
- rucio/client/uploadclient.py +969 -0
- rucio/common/__init__.py +13 -0
- rucio/common/bittorrent.py +234 -0
- rucio/common/cache.py +111 -0
- rucio/common/checksum.py +168 -0
- rucio/common/client.py +122 -0
- rucio/common/config.py +788 -0
- rucio/common/constants.py +217 -0
- rucio/common/constraints.py +17 -0
- rucio/common/didtype.py +237 -0
- rucio/common/dumper/__init__.py +342 -0
- rucio/common/dumper/consistency.py +497 -0
- rucio/common/dumper/data_models.py +362 -0
- rucio/common/dumper/path_parsing.py +75 -0
- rucio/common/exception.py +1208 -0
- rucio/common/extra.py +31 -0
- rucio/common/logging.py +420 -0
- rucio/common/pcache.py +1409 -0
- rucio/common/plugins.py +185 -0
- rucio/common/policy.py +93 -0
- rucio/common/schema/__init__.py +200 -0
- rucio/common/schema/generic.py +416 -0
- rucio/common/schema/generic_multi_vo.py +395 -0
- rucio/common/stomp_utils.py +423 -0
- rucio/common/stopwatch.py +55 -0
- rucio/common/test_rucio_server.py +154 -0
- rucio/common/types.py +483 -0
- rucio/common/utils.py +1688 -0
- rucio/core/__init__.py +13 -0
- rucio/core/account.py +496 -0
- rucio/core/account_counter.py +236 -0
- rucio/core/account_limit.py +425 -0
- rucio/core/authentication.py +620 -0
- rucio/core/config.py +437 -0
- rucio/core/credential.py +224 -0
- rucio/core/did.py +3004 -0
- rucio/core/did_meta_plugins/__init__.py +252 -0
- rucio/core/did_meta_plugins/did_column_meta.py +331 -0
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +165 -0
- rucio/core/did_meta_plugins/elasticsearch_meta.py +407 -0
- rucio/core/did_meta_plugins/filter_engine.py +672 -0
- rucio/core/did_meta_plugins/json_meta.py +240 -0
- rucio/core/did_meta_plugins/mongo_meta.py +229 -0
- rucio/core/did_meta_plugins/postgres_meta.py +352 -0
- rucio/core/dirac.py +237 -0
- rucio/core/distance.py +187 -0
- rucio/core/exporter.py +59 -0
- rucio/core/heartbeat.py +363 -0
- rucio/core/identity.py +301 -0
- rucio/core/importer.py +260 -0
- rucio/core/lifetime_exception.py +377 -0
- rucio/core/lock.py +577 -0
- rucio/core/message.py +288 -0
- rucio/core/meta_conventions.py +203 -0
- rucio/core/monitor.py +448 -0
- rucio/core/naming_convention.py +195 -0
- rucio/core/nongrid_trace.py +136 -0
- rucio/core/oidc.py +1463 -0
- rucio/core/permission/__init__.py +161 -0
- rucio/core/permission/generic.py +1124 -0
- rucio/core/permission/generic_multi_vo.py +1144 -0
- rucio/core/quarantined_replica.py +224 -0
- rucio/core/replica.py +4483 -0
- rucio/core/replica_sorter.py +362 -0
- rucio/core/request.py +3091 -0
- rucio/core/rse.py +2079 -0
- rucio/core/rse_counter.py +185 -0
- rucio/core/rse_expression_parser.py +459 -0
- rucio/core/rse_selector.py +304 -0
- rucio/core/rule.py +4484 -0
- rucio/core/rule_grouping.py +1620 -0
- rucio/core/scope.py +181 -0
- rucio/core/subscription.py +362 -0
- rucio/core/topology.py +490 -0
- rucio/core/trace.py +375 -0
- rucio/core/transfer.py +1531 -0
- rucio/core/vo.py +169 -0
- rucio/core/volatile_replica.py +151 -0
- rucio/daemons/__init__.py +13 -0
- rucio/daemons/abacus/__init__.py +13 -0
- rucio/daemons/abacus/account.py +116 -0
- rucio/daemons/abacus/collection_replica.py +124 -0
- rucio/daemons/abacus/rse.py +117 -0
- rucio/daemons/atropos/__init__.py +13 -0
- rucio/daemons/atropos/atropos.py +242 -0
- rucio/daemons/auditor/__init__.py +289 -0
- rucio/daemons/auditor/hdfs.py +97 -0
- rucio/daemons/auditor/srmdumps.py +355 -0
- rucio/daemons/automatix/__init__.py +13 -0
- rucio/daemons/automatix/automatix.py +304 -0
- rucio/daemons/badreplicas/__init__.py +13 -0
- rucio/daemons/badreplicas/minos.py +322 -0
- rucio/daemons/badreplicas/minos_temporary_expiration.py +171 -0
- rucio/daemons/badreplicas/necromancer.py +196 -0
- rucio/daemons/bb8/__init__.py +13 -0
- rucio/daemons/bb8/bb8.py +353 -0
- rucio/daemons/bb8/common.py +759 -0
- rucio/daemons/bb8/nuclei_background_rebalance.py +153 -0
- rucio/daemons/bb8/t2_background_rebalance.py +153 -0
- rucio/daemons/cache/__init__.py +13 -0
- rucio/daemons/cache/consumer.py +133 -0
- rucio/daemons/common.py +405 -0
- rucio/daemons/conveyor/__init__.py +13 -0
- rucio/daemons/conveyor/common.py +562 -0
- rucio/daemons/conveyor/finisher.py +529 -0
- rucio/daemons/conveyor/poller.py +394 -0
- rucio/daemons/conveyor/preparer.py +205 -0
- rucio/daemons/conveyor/receiver.py +179 -0
- rucio/daemons/conveyor/stager.py +133 -0
- rucio/daemons/conveyor/submitter.py +403 -0
- rucio/daemons/conveyor/throttler.py +532 -0
- rucio/daemons/follower/__init__.py +13 -0
- rucio/daemons/follower/follower.py +101 -0
- rucio/daemons/hermes/__init__.py +13 -0
- rucio/daemons/hermes/hermes.py +534 -0
- rucio/daemons/judge/__init__.py +13 -0
- rucio/daemons/judge/cleaner.py +159 -0
- rucio/daemons/judge/evaluator.py +185 -0
- rucio/daemons/judge/injector.py +162 -0
- rucio/daemons/judge/repairer.py +154 -0
- rucio/daemons/oauthmanager/__init__.py +13 -0
- rucio/daemons/oauthmanager/oauthmanager.py +198 -0
- rucio/daemons/reaper/__init__.py +13 -0
- rucio/daemons/reaper/dark_reaper.py +282 -0
- rucio/daemons/reaper/reaper.py +739 -0
- rucio/daemons/replicarecoverer/__init__.py +13 -0
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +626 -0
- rucio/daemons/rsedecommissioner/__init__.py +13 -0
- rucio/daemons/rsedecommissioner/config.py +81 -0
- rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
- rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
- rucio/daemons/rsedecommissioner/profiles/generic.py +452 -0
- rucio/daemons/rsedecommissioner/profiles/types.py +93 -0
- rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
- rucio/daemons/storage/__init__.py +13 -0
- rucio/daemons/storage/consistency/__init__.py +13 -0
- rucio/daemons/storage/consistency/actions.py +848 -0
- rucio/daemons/tracer/__init__.py +13 -0
- rucio/daemons/tracer/kronos.py +511 -0
- rucio/daemons/transmogrifier/__init__.py +13 -0
- rucio/daemons/transmogrifier/transmogrifier.py +762 -0
- rucio/daemons/undertaker/__init__.py +13 -0
- rucio/daemons/undertaker/undertaker.py +137 -0
- rucio/db/__init__.py +13 -0
- rucio/db/sqla/__init__.py +52 -0
- rucio/db/sqla/constants.py +206 -0
- rucio/db/sqla/migrate_repo/__init__.py +13 -0
- rucio/db/sqla/migrate_repo/env.py +110 -0
- rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +70 -0
- rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +91 -0
- rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +43 -0
- rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +50 -0
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +68 -0
- rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +45 -0
- rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +60 -0
- rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +40 -0
- rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +140 -0
- rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +73 -0
- rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +74 -0
- rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +43 -0
- rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +134 -0
- rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +64 -0
- rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +39 -0
- rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +64 -0
- rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +51 -0
- rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +41 -0
- rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +43 -0
- rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +53 -0
- rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +38 -0
- rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +47 -0
- rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +69 -0
- rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +42 -0
- rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +46 -0
- rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +40 -0
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +67 -0
- rucio/db/sqla/migrate_repo/versions/30d5206e9cad_increase_oauthrequest_redirect_msg_.py +37 -0
- rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +44 -0
- rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +77 -0
- rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +42 -0
- rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +65 -0
- rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +133 -0
- rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +76 -0
- rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +60 -0
- rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +44 -0
- rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +64 -0
- rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +43 -0
- rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +44 -0
- rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +78 -0
- rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +41 -0
- rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +59 -0
- rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +44 -0
- rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +49 -0
- rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +40 -0
- rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +63 -0
- rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +43 -0
- rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
- rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +45 -0
- rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +43 -0
- rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +43 -0
- rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +45 -0
- rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +47 -0
- rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +58 -0
- rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +45 -0
- rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +106 -0
- rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +55 -0
- rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +50 -0
- rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +47 -0
- rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +43 -0
- rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +41 -0
- rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +91 -0
- rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +72 -0
- rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +49 -0
- rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +53 -0
- rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +45 -0
- rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +68 -0
- rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +45 -0
- rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +94 -0
- rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +72 -0
- rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +76 -0
- rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +47 -0
- rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +121 -0
- rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +59 -0
- rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +52 -0
- rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +54 -0
- rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +64 -0
- rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +49 -0
- rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
- rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +91 -0
- rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +40 -0
- rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +143 -0
- rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +76 -0
- rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +50 -0
- rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +72 -0
- rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +43 -0
- rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +65 -0
- rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +47 -0
- rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +146 -0
- rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +104 -0
- rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +44 -0
- rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +43 -0
- rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +103 -0
- rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +49 -0
- rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +104 -0
- rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +29 -0
- rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +74 -0
- rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +47 -0
- rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +37 -0
- rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +43 -0
- rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +43 -0
- rucio/db/sqla/models.py +1743 -0
- rucio/db/sqla/sautils.py +55 -0
- rucio/db/sqla/session.py +529 -0
- rucio/db/sqla/types.py +206 -0
- rucio/db/sqla/util.py +543 -0
- rucio/gateway/__init__.py +13 -0
- rucio/gateway/account.py +345 -0
- rucio/gateway/account_limit.py +363 -0
- rucio/gateway/authentication.py +381 -0
- rucio/gateway/config.py +227 -0
- rucio/gateway/credential.py +70 -0
- rucio/gateway/did.py +987 -0
- rucio/gateway/dirac.py +83 -0
- rucio/gateway/exporter.py +60 -0
- rucio/gateway/heartbeat.py +76 -0
- rucio/gateway/identity.py +189 -0
- rucio/gateway/importer.py +46 -0
- rucio/gateway/lifetime_exception.py +121 -0
- rucio/gateway/lock.py +153 -0
- rucio/gateway/meta_conventions.py +98 -0
- rucio/gateway/permission.py +74 -0
- rucio/gateway/quarantined_replica.py +79 -0
- rucio/gateway/replica.py +538 -0
- rucio/gateway/request.py +330 -0
- rucio/gateway/rse.py +632 -0
- rucio/gateway/rule.py +437 -0
- rucio/gateway/scope.py +100 -0
- rucio/gateway/subscription.py +280 -0
- rucio/gateway/vo.py +126 -0
- rucio/rse/__init__.py +96 -0
- rucio/rse/protocols/__init__.py +13 -0
- rucio/rse/protocols/bittorrent.py +194 -0
- rucio/rse/protocols/cache.py +111 -0
- rucio/rse/protocols/dummy.py +100 -0
- rucio/rse/protocols/gfal.py +708 -0
- rucio/rse/protocols/globus.py +243 -0
- rucio/rse/protocols/http_cache.py +82 -0
- rucio/rse/protocols/mock.py +123 -0
- rucio/rse/protocols/ngarc.py +209 -0
- rucio/rse/protocols/posix.py +250 -0
- rucio/rse/protocols/protocol.py +361 -0
- rucio/rse/protocols/rclone.py +365 -0
- rucio/rse/protocols/rfio.py +145 -0
- rucio/rse/protocols/srm.py +338 -0
- rucio/rse/protocols/ssh.py +414 -0
- rucio/rse/protocols/storm.py +195 -0
- rucio/rse/protocols/webdav.py +594 -0
- rucio/rse/protocols/xrootd.py +302 -0
- rucio/rse/rsemanager.py +881 -0
- rucio/rse/translation.py +260 -0
- rucio/tests/__init__.py +13 -0
- rucio/tests/common.py +280 -0
- rucio/tests/common_server.py +149 -0
- rucio/transfertool/__init__.py +13 -0
- rucio/transfertool/bittorrent.py +200 -0
- rucio/transfertool/bittorrent_driver.py +50 -0
- rucio/transfertool/bittorrent_driver_qbittorrent.py +134 -0
- rucio/transfertool/fts3.py +1600 -0
- rucio/transfertool/fts3_plugins.py +152 -0
- rucio/transfertool/globus.py +201 -0
- rucio/transfertool/globus_library.py +181 -0
- rucio/transfertool/mock.py +89 -0
- rucio/transfertool/transfertool.py +221 -0
- rucio/vcsversion.py +11 -0
- rucio/version.py +45 -0
- rucio/web/__init__.py +13 -0
- rucio/web/rest/__init__.py +13 -0
- rucio/web/rest/flaskapi/__init__.py +13 -0
- rucio/web/rest/flaskapi/authenticated_bp.py +27 -0
- rucio/web/rest/flaskapi/v1/__init__.py +13 -0
- rucio/web/rest/flaskapi/v1/accountlimits.py +236 -0
- rucio/web/rest/flaskapi/v1/accounts.py +1103 -0
- rucio/web/rest/flaskapi/v1/archives.py +102 -0
- rucio/web/rest/flaskapi/v1/auth.py +1644 -0
- rucio/web/rest/flaskapi/v1/common.py +426 -0
- rucio/web/rest/flaskapi/v1/config.py +304 -0
- rucio/web/rest/flaskapi/v1/credentials.py +213 -0
- rucio/web/rest/flaskapi/v1/dids.py +2340 -0
- rucio/web/rest/flaskapi/v1/dirac.py +116 -0
- rucio/web/rest/flaskapi/v1/export.py +75 -0
- rucio/web/rest/flaskapi/v1/heartbeats.py +127 -0
- rucio/web/rest/flaskapi/v1/identities.py +285 -0
- rucio/web/rest/flaskapi/v1/import.py +132 -0
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +312 -0
- rucio/web/rest/flaskapi/v1/locks.py +358 -0
- rucio/web/rest/flaskapi/v1/main.py +91 -0
- rucio/web/rest/flaskapi/v1/meta_conventions.py +241 -0
- rucio/web/rest/flaskapi/v1/metrics.py +36 -0
- rucio/web/rest/flaskapi/v1/nongrid_traces.py +97 -0
- rucio/web/rest/flaskapi/v1/ping.py +88 -0
- rucio/web/rest/flaskapi/v1/redirect.py +366 -0
- rucio/web/rest/flaskapi/v1/replicas.py +1894 -0
- rucio/web/rest/flaskapi/v1/requests.py +998 -0
- rucio/web/rest/flaskapi/v1/rses.py +2250 -0
- rucio/web/rest/flaskapi/v1/rules.py +854 -0
- rucio/web/rest/flaskapi/v1/scopes.py +159 -0
- rucio/web/rest/flaskapi/v1/subscriptions.py +650 -0
- rucio/web/rest/flaskapi/v1/templates/auth_crash.html +80 -0
- rucio/web/rest/flaskapi/v1/templates/auth_granted.html +82 -0
- rucio/web/rest/flaskapi/v1/traces.py +137 -0
- rucio/web/rest/flaskapi/v1/types.py +20 -0
- rucio/web/rest/flaskapi/v1/vos.py +278 -0
- rucio/web/rest/main.py +18 -0
- rucio/web/rest/metrics.py +27 -0
- rucio/web/rest/ping.py +27 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic.ini.template +71 -0
- rucio-37.0.0rc1.data/data/rucio/etc/alembic_offline.ini.template +74 -0
- rucio-37.0.0rc1.data/data/rucio/etc/globus-config.yml.template +5 -0
- rucio-37.0.0rc1.data/data/rucio/etc/ldap.cfg.template +30 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approval_request.tmpl +38 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +4 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_approved_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +6 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_denied_user.tmpl +17 -0
- rucio-37.0.0rc1.data/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +19 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rse-accounts.cfg.template +25 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.atlas.client.template +43 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio.cfg.template +241 -0
- rucio-37.0.0rc1.data/data/rucio/etc/rucio_multi_vo.cfg.template +217 -0
- rucio-37.0.0rc1.data/data/rucio/requirements.server.txt +297 -0
- rucio-37.0.0rc1.data/data/rucio/tools/bootstrap.py +34 -0
- rucio-37.0.0rc1.data/data/rucio/tools/merge_rucio_configs.py +144 -0
- rucio-37.0.0rc1.data/data/rucio/tools/reset_database.py +40 -0
- rucio-37.0.0rc1.data/scripts/rucio +133 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-account +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-collection-replica +46 -0
- rucio-37.0.0rc1.data/scripts/rucio-abacus-rse +78 -0
- rucio-37.0.0rc1.data/scripts/rucio-admin +97 -0
- rucio-37.0.0rc1.data/scripts/rucio-atropos +60 -0
- rucio-37.0.0rc1.data/scripts/rucio-auditor +206 -0
- rucio-37.0.0rc1.data/scripts/rucio-automatix +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-bb8 +57 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-client +141 -0
- rucio-37.0.0rc1.data/scripts/rucio-cache-consumer +42 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-finisher +58 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-poller +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-preparer +37 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-receiver +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-stager +76 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-submitter +139 -0
- rucio-37.0.0rc1.data/scripts/rucio-conveyor-throttler +104 -0
- rucio-37.0.0rc1.data/scripts/rucio-dark-reaper +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-dumper +160 -0
- rucio-37.0.0rc1.data/scripts/rucio-follower +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-hermes +54 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-cleaner +89 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-evaluator +137 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-injector +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-judge-repairer +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-kronos +44 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos +53 -0
- rucio-37.0.0rc1.data/scripts/rucio-minos-temporary-expiration +50 -0
- rucio-37.0.0rc1.data/scripts/rucio-necromancer +120 -0
- rucio-37.0.0rc1.data/scripts/rucio-oauth-manager +63 -0
- rucio-37.0.0rc1.data/scripts/rucio-reaper +83 -0
- rucio-37.0.0rc1.data/scripts/rucio-replica-recoverer +248 -0
- rucio-37.0.0rc1.data/scripts/rucio-rse-decommissioner +66 -0
- rucio-37.0.0rc1.data/scripts/rucio-storage-consistency-actions +74 -0
- rucio-37.0.0rc1.data/scripts/rucio-transmogrifier +77 -0
- rucio-37.0.0rc1.data/scripts/rucio-undertaker +76 -0
- rucio-37.0.0rc1.dist-info/METADATA +92 -0
- rucio-37.0.0rc1.dist-info/RECORD +487 -0
- rucio-37.0.0rc1.dist-info/WHEEL +5 -0
- rucio-37.0.0rc1.dist-info/licenses/AUTHORS.rst +100 -0
- rucio-37.0.0rc1.dist-info/licenses/LICENSE +201 -0
- rucio-37.0.0rc1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1644 @@
|
|
|
1
|
+
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import logging
|
|
17
|
+
import time
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
from urllib.parse import urlparse
|
|
20
|
+
|
|
21
|
+
from flask import Blueprint, Flask, Response, redirect, render_template, request
|
|
22
|
+
from werkzeug.datastructures import Headers
|
|
23
|
+
|
|
24
|
+
from rucio.common.config import config_get
|
|
25
|
+
from rucio.common.exception import AccessDenied, CannotAuthenticate, CannotAuthorize, IdentityError, IdentityNotFound
|
|
26
|
+
from rucio.common.extra import import_extras
|
|
27
|
+
from rucio.common.utils import date_to_str
|
|
28
|
+
from rucio.core.authentication import strip_x509_proxy_attributes
|
|
29
|
+
from rucio.gateway.authentication import (
|
|
30
|
+
get_auth_oidc,
|
|
31
|
+
get_auth_token_gss,
|
|
32
|
+
get_auth_token_saml,
|
|
33
|
+
get_auth_token_ssh,
|
|
34
|
+
get_auth_token_user_pass,
|
|
35
|
+
get_auth_token_x509,
|
|
36
|
+
get_ssh_challenge_token,
|
|
37
|
+
get_token_oidc,
|
|
38
|
+
redirect_auth_oidc,
|
|
39
|
+
refresh_cli_auth_token,
|
|
40
|
+
validate_auth_token,
|
|
41
|
+
)
|
|
42
|
+
from rucio.web.rest.flaskapi.v1.common import ErrorHandlingMethodView, check_accept_header_wrapper_flask, error_headers, extract_vo, generate_http_error_flask, get_account_from_verified_identity
|
|
43
|
+
|
|
44
|
+
if TYPE_CHECKING:
|
|
45
|
+
|
|
46
|
+
from flask.typing import ResponseReturnValue
|
|
47
|
+
|
|
48
|
+
EXTRA_MODULES = import_extras(['onelogin'])
|
|
49
|
+
|
|
50
|
+
if EXTRA_MODULES['onelogin']:
|
|
51
|
+
from onelogin.saml2.auth import OneLogin_Saml2_Auth # pylint: disable=import-error
|
|
52
|
+
|
|
53
|
+
from rucio.web.ui.flask.common.utils import prepare_saml_request
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class UserPass(ErrorHandlingMethodView):
|
|
57
|
+
"""
|
|
58
|
+
Authenticate a Rucio account temporarily via username and password.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def get_headers(self) -> Headers:
|
|
62
|
+
headers = Headers()
|
|
63
|
+
headers['Access-Control-Allow-Origin'] = request.environ.get('HTTP_ORIGIN') # type: ignore (value could be None)
|
|
64
|
+
headers['Access-Control-Allow-Headers'] = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') # type: ignore (value could be None)
|
|
65
|
+
headers['Access-Control-Allow-Methods'] = '*'
|
|
66
|
+
headers['Access-Control-Allow-Credentials'] = 'true'
|
|
67
|
+
headers['Access-Control-Expose-Headers'] = 'X-Rucio-Auth-Token, X-Rucio-Auth-Token-Expires, X-Rucio-Auth-Account, X-Rucio-Auth-Accounts'
|
|
68
|
+
return headers
|
|
69
|
+
|
|
70
|
+
def options(self) -> 'ResponseReturnValue':
|
|
71
|
+
"""
|
|
72
|
+
---
|
|
73
|
+
summary: UserPass Allow cross-site scripting
|
|
74
|
+
description: UserPass Allow cross-site scripting. Explicit for Authentication.
|
|
75
|
+
tags:
|
|
76
|
+
- Auth
|
|
77
|
+
responses:
|
|
78
|
+
200:
|
|
79
|
+
description: OK
|
|
80
|
+
headers:
|
|
81
|
+
Access-Control-Allow-Origin:
|
|
82
|
+
schema:
|
|
83
|
+
type: string
|
|
84
|
+
Access-Control-Allow-Headers:
|
|
85
|
+
schema:
|
|
86
|
+
type: string
|
|
87
|
+
Access-Control-Allow-Methods:
|
|
88
|
+
schema:
|
|
89
|
+
type: string
|
|
90
|
+
enum: ['*']
|
|
91
|
+
Access-Control-Allow-Credentials:
|
|
92
|
+
schema:
|
|
93
|
+
type: string
|
|
94
|
+
enum: ['true']
|
|
95
|
+
Access-Control-Expose-Headers:
|
|
96
|
+
schema:
|
|
97
|
+
type: string
|
|
98
|
+
enum: ['X-Rucio-Auth-Token']
|
|
99
|
+
404:
|
|
100
|
+
description: Not found
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
return '', 200, self.get_headers()
|
|
104
|
+
|
|
105
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
106
|
+
def get(self) -> 'ResponseReturnValue':
|
|
107
|
+
"""
|
|
108
|
+
---
|
|
109
|
+
summary: UserPass
|
|
110
|
+
description: Authenticate a Rucio account temporarily via username and password.
|
|
111
|
+
tags:
|
|
112
|
+
- Auth
|
|
113
|
+
parameters:
|
|
114
|
+
- name: X-Rucio-Account
|
|
115
|
+
in: header
|
|
116
|
+
description: Account identifier as a string.
|
|
117
|
+
schema:
|
|
118
|
+
type: string
|
|
119
|
+
required: true
|
|
120
|
+
- name: X-Rucio-Username
|
|
121
|
+
in: header
|
|
122
|
+
description: Username as a string.
|
|
123
|
+
schema:
|
|
124
|
+
type: string
|
|
125
|
+
required: true
|
|
126
|
+
- name: X-Rucio-Password
|
|
127
|
+
in: header
|
|
128
|
+
description: password as a text-plain string.
|
|
129
|
+
schema:
|
|
130
|
+
type: string
|
|
131
|
+
required: true
|
|
132
|
+
- name: X-Rucio-AppID
|
|
133
|
+
in: header
|
|
134
|
+
description: Application identifier as a string.
|
|
135
|
+
schema:
|
|
136
|
+
type: string
|
|
137
|
+
- name: X-Forwarded-For
|
|
138
|
+
in: header
|
|
139
|
+
description: The forward ip address.
|
|
140
|
+
schema:
|
|
141
|
+
type: string
|
|
142
|
+
responses:
|
|
143
|
+
200:
|
|
144
|
+
description: OK
|
|
145
|
+
headers:
|
|
146
|
+
Access-Control-Allow-Origin:
|
|
147
|
+
schema:
|
|
148
|
+
type: string
|
|
149
|
+
Access-Control-Allow-Headers:
|
|
150
|
+
schema:
|
|
151
|
+
type: string
|
|
152
|
+
Access-Control-Allow-Methods:
|
|
153
|
+
schema:
|
|
154
|
+
type: string
|
|
155
|
+
Access-Control-Allow-Credentials:
|
|
156
|
+
schema:
|
|
157
|
+
type: string
|
|
158
|
+
Access-Control-Expose-Headers:
|
|
159
|
+
schema:
|
|
160
|
+
type: string
|
|
161
|
+
X-Rucio-Auth-Token:
|
|
162
|
+
schema:
|
|
163
|
+
type: string
|
|
164
|
+
X-Rucio-Auth-Token-Expires:
|
|
165
|
+
schema:
|
|
166
|
+
type: string
|
|
167
|
+
X-Rucio-Auth-Account:
|
|
168
|
+
schema:
|
|
169
|
+
type: string
|
|
170
|
+
description: The rucio account used for authentication
|
|
171
|
+
206:
|
|
172
|
+
description: Partial content containing X-Rucio-Auth-Accounts header
|
|
173
|
+
headers:
|
|
174
|
+
X-Rucio-Auth-Accounts:
|
|
175
|
+
schema:
|
|
176
|
+
type: string
|
|
177
|
+
description: The rucio accounts corresponding to the provided identity as a csv string
|
|
178
|
+
|
|
179
|
+
401:
|
|
180
|
+
description: Cannot authenticate
|
|
181
|
+
"""
|
|
182
|
+
headers = self.get_headers()
|
|
183
|
+
|
|
184
|
+
headers['Content-Type'] = 'application/octet-stream'
|
|
185
|
+
headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
|
186
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
187
|
+
headers['Pragma'] = 'no-cache'
|
|
188
|
+
vo = extract_vo(request.headers)
|
|
189
|
+
account = request.headers.get('X-Rucio-Account', default=None)
|
|
190
|
+
username = request.headers.get('X-Rucio-Username', default=None)
|
|
191
|
+
password = request.headers.get('X-Rucio-Password', default=None)
|
|
192
|
+
appid = request.headers.get('X-Rucio-AppID', default='unknown')
|
|
193
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
194
|
+
if not username or not password:
|
|
195
|
+
return generate_http_error_flask(401, CannotAuthenticate.__name__, 'Cannot authenticate without passing all required arguments', headers=headers)
|
|
196
|
+
|
|
197
|
+
accounts: list[str] = []
|
|
198
|
+
if not account:
|
|
199
|
+
try:
|
|
200
|
+
accounts = get_account_from_verified_identity(identity_key=username, id_type='USERPASS', password=password)
|
|
201
|
+
except IdentityNotFound:
|
|
202
|
+
return generate_http_error_flask(401, IdentityNotFound.__name__, 'Cannot authenticate. Username/Password pair does not exist.', headers=headers)
|
|
203
|
+
except IdentityError:
|
|
204
|
+
return generate_http_error_flask(401, IdentityError.__name__, 'Cannot authenticate. The identity does not exist.', headers=headers)
|
|
205
|
+
else:
|
|
206
|
+
accounts = [account]
|
|
207
|
+
|
|
208
|
+
if len(accounts) > 1:
|
|
209
|
+
account_names: list[str] = []
|
|
210
|
+
for account in accounts:
|
|
211
|
+
if isinstance(account, str):
|
|
212
|
+
account_names.append(account)
|
|
213
|
+
else:
|
|
214
|
+
account_names.append(account.external)
|
|
215
|
+
headers['X-Rucio-Auth-Accounts'] = ','.join(accounts)
|
|
216
|
+
return json.dumps(account_names), 206, headers
|
|
217
|
+
|
|
218
|
+
account = accounts[0]
|
|
219
|
+
account_name = account if isinstance(account, str) else account.external
|
|
220
|
+
try:
|
|
221
|
+
result = get_auth_token_user_pass(account_name, username, password, appid, ip, vo=vo)
|
|
222
|
+
if not result:
|
|
223
|
+
return generate_http_error_flask(401, CannotAuthenticate.__name__, f'Cannot authenticate to account {account} with given credentials', headers=headers)
|
|
224
|
+
headers['X-Rucio-Auth-Account'] = account_name
|
|
225
|
+
headers['X-Rucio-Auth-Token'] = result['token']
|
|
226
|
+
headers['X-Rucio-Auth-Token-Expires'] = date_to_str(result['expires_at']) # type: ignore (value could be None)
|
|
227
|
+
return '', 200, headers
|
|
228
|
+
except AccessDenied:
|
|
229
|
+
return generate_http_error_flask(401, CannotAuthenticate.__name__, f'Cannot authenticate to account {account} with given credentials', headers=headers)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class OIDC(ErrorHandlingMethodView):
|
|
233
|
+
"""
|
|
234
|
+
Requests a user specific Authorization URL (assigning a user session state,
|
|
235
|
+
nonce, Rucio OIDC Client ID with the correct issuers authentication endpoint).
|
|
236
|
+
"""
|
|
237
|
+
|
|
238
|
+
def get_headers(self) -> Headers:
|
|
239
|
+
headers = Headers()
|
|
240
|
+
headers['Access-Control-Allow-Origin'] = request.environ.get('HTTP_ORIGIN') # type: ignore (value could be None)
|
|
241
|
+
headers['Access-Control-Allow-Headers'] = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') # type: ignore (value could be None)
|
|
242
|
+
headers['Access-Control-Allow-Methods'] = '*'
|
|
243
|
+
headers['Access-Control-Allow-Credentials'] = 'true'
|
|
244
|
+
return headers
|
|
245
|
+
|
|
246
|
+
def options(self) -> 'ResponseReturnValue':
|
|
247
|
+
"""
|
|
248
|
+
---
|
|
249
|
+
summary: OIDC Allow cross-site scripting
|
|
250
|
+
description: OIDC Allow cross-site scripting. Explicit for Authentication.
|
|
251
|
+
tags:
|
|
252
|
+
- Auth
|
|
253
|
+
responses:
|
|
254
|
+
200:
|
|
255
|
+
description: OK
|
|
256
|
+
headers:
|
|
257
|
+
Access-Control-Allow-Origin:
|
|
258
|
+
schema:
|
|
259
|
+
type: string
|
|
260
|
+
Access-Control-Allow-Headers:
|
|
261
|
+
schema:
|
|
262
|
+
type: string
|
|
263
|
+
Access-Control-Allow-Methods:
|
|
264
|
+
schema:
|
|
265
|
+
type: string
|
|
266
|
+
enum: ['*']
|
|
267
|
+
Access-Control-Allow-Credentials:
|
|
268
|
+
schema:
|
|
269
|
+
type: string
|
|
270
|
+
enum: ['true']
|
|
271
|
+
404:
|
|
272
|
+
description: Not found
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
return '', 200, self.get_headers()
|
|
276
|
+
|
|
277
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
278
|
+
def get(self) -> 'ResponseReturnValue':
|
|
279
|
+
"""
|
|
280
|
+
---
|
|
281
|
+
summary: OIDC
|
|
282
|
+
description: Authenticate a Rucio account via OIDC.
|
|
283
|
+
tags:
|
|
284
|
+
- Auth
|
|
285
|
+
parameters:
|
|
286
|
+
- name: HTTP_X_RUCIO_ACCOUNT
|
|
287
|
+
in: header
|
|
288
|
+
description: Account identifier as a string.
|
|
289
|
+
schema:
|
|
290
|
+
type: string
|
|
291
|
+
- name: HTTP_X_RUCIO_CLIENT_AUTHORIZE_SCOPE
|
|
292
|
+
in: header
|
|
293
|
+
schema:
|
|
294
|
+
type: string
|
|
295
|
+
- name: HTTP_X_RUCIO_CLIENT_AUTHORIZE_AUDIENCE
|
|
296
|
+
in: header
|
|
297
|
+
schema:
|
|
298
|
+
type: string
|
|
299
|
+
- name: HTTP_X_RUCIO_CLIENT_AUTHORIZE_AUTO
|
|
300
|
+
in: header
|
|
301
|
+
schema:
|
|
302
|
+
type: string
|
|
303
|
+
- name: HTTP_X_RUCIO_CLIENT_AUTHORIZE_ISSUER
|
|
304
|
+
in: header
|
|
305
|
+
schema:
|
|
306
|
+
type: string
|
|
307
|
+
- name: HTTP_X_RUCIO_CLIENT_AUTHORIZE_POLLING
|
|
308
|
+
in: header
|
|
309
|
+
schema:
|
|
310
|
+
type: string
|
|
311
|
+
- name: HTTP_X_RUCIO_CLIENT_AUTHORIZE_REFRESH_LIFETIME
|
|
312
|
+
in: header
|
|
313
|
+
schema:
|
|
314
|
+
type: string
|
|
315
|
+
- name: X-Forwarded-For
|
|
316
|
+
in: header
|
|
317
|
+
schema:
|
|
318
|
+
type: string
|
|
319
|
+
responses:
|
|
320
|
+
200:
|
|
321
|
+
description: OK
|
|
322
|
+
headers:
|
|
323
|
+
X-Rucio-OIDC-Auth-URL:
|
|
324
|
+
description: User & Rucio OIDC Client specific Authorization URL
|
|
325
|
+
schema:
|
|
326
|
+
type: string
|
|
327
|
+
401:
|
|
328
|
+
description: Cannot authenticate
|
|
329
|
+
"""
|
|
330
|
+
headers = self.get_headers()
|
|
331
|
+
|
|
332
|
+
headers.set('Content-Type', 'application/octet-stream')
|
|
333
|
+
headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
|
|
334
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
335
|
+
headers.set('Pragma', 'no-cache')
|
|
336
|
+
|
|
337
|
+
vo = extract_vo(request.headers)
|
|
338
|
+
account = request.environ.get('HTTP_X_RUCIO_ACCOUNT', 'webui')
|
|
339
|
+
auth_scope = request.environ.get('HTTP_X_RUCIO_CLIENT_AUTHORIZE_SCOPE', "")
|
|
340
|
+
audience = request.environ.get('HTTP_X_RUCIO_CLIENT_AUTHORIZE_AUDIENCE', "")
|
|
341
|
+
auto = request.environ.get('HTTP_X_RUCIO_CLIENT_AUTHORIZE_AUTO', False)
|
|
342
|
+
issuer = request.environ.get('HTTP_X_RUCIO_CLIENT_AUTHORIZE_ISSUER', None)
|
|
343
|
+
polling = request.environ.get('HTTP_X_RUCIO_CLIENT_AUTHORIZE_POLLING', False)
|
|
344
|
+
refresh_lifetime = request.environ.get('HTTP_X_RUCIO_CLIENT_AUTHORIZE_REFRESH_LIFETIME', None)
|
|
345
|
+
auto = (auto == 'True' or auto == 'true')
|
|
346
|
+
polling = (polling == 'True' or polling == 'true')
|
|
347
|
+
if refresh_lifetime == 'None':
|
|
348
|
+
refresh_lifetime = None
|
|
349
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
350
|
+
try:
|
|
351
|
+
kwargs = {'auth_scope': auth_scope,
|
|
352
|
+
'audience': audience,
|
|
353
|
+
'issuer': issuer,
|
|
354
|
+
'auto': auto,
|
|
355
|
+
'polling': polling,
|
|
356
|
+
'refresh_lifetime': refresh_lifetime,
|
|
357
|
+
'ip': ip}
|
|
358
|
+
result = get_auth_oidc(account, vo=vo, **kwargs)
|
|
359
|
+
except AccessDenied:
|
|
360
|
+
return generate_http_error_flask(
|
|
361
|
+
status_code=401,
|
|
362
|
+
exc=CannotAuthenticate.__name__,
|
|
363
|
+
exc_msg=f'Cannot get authentication URL from Rucio Authentication Server for account {account}',
|
|
364
|
+
headers=headers
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
if not result:
|
|
368
|
+
return generate_http_error_flask(
|
|
369
|
+
status_code=401,
|
|
370
|
+
exc=CannotAuthenticate.__name__,
|
|
371
|
+
exc_msg=f'Cannot get authentication URL from Rucio Authentication Server for account {account}',
|
|
372
|
+
headers=headers
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
headers.set('X-Rucio-OIDC-Auth-URL', result)
|
|
376
|
+
return '', 200, headers
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
class RedirectOIDC(ErrorHandlingMethodView):
|
|
380
|
+
"""
|
|
381
|
+
Authenticate a Rucio account via
|
|
382
|
+
an Identity Provider (XDC IAM as of June 2019).
|
|
383
|
+
"""
|
|
384
|
+
|
|
385
|
+
def get_headers(self) -> Headers:
|
|
386
|
+
headers = Headers()
|
|
387
|
+
headers.set('Access-Control-Allow-Origin', request.environ.get('HTTP_ORIGIN')) # type: ignore (value could be None)
|
|
388
|
+
headers.set('Access-Control-Allow-Headers', request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) # type: ignore (value could be None)
|
|
389
|
+
headers.set('Access-Control-Allow-Methods', '*')
|
|
390
|
+
headers.set('Access-Control-Allow-Credentials', 'true')
|
|
391
|
+
return headers
|
|
392
|
+
|
|
393
|
+
def options(self) -> 'ResponseReturnValue':
|
|
394
|
+
"""
|
|
395
|
+
---
|
|
396
|
+
summary: RedirectOIDC Allow cross-site scripting
|
|
397
|
+
description: RedirectOIDC Allow cross-site scripting. Explicit for Authentication.
|
|
398
|
+
tags:
|
|
399
|
+
- Auth
|
|
400
|
+
responses:
|
|
401
|
+
200:
|
|
402
|
+
description: OK
|
|
403
|
+
headers:
|
|
404
|
+
Access-Control-Allow-Origin:
|
|
405
|
+
schema:
|
|
406
|
+
type: string
|
|
407
|
+
Access-Control-Allow-Headers:
|
|
408
|
+
schema:
|
|
409
|
+
type: string
|
|
410
|
+
Access-Control-Allow-Methods:
|
|
411
|
+
schema:
|
|
412
|
+
type: string
|
|
413
|
+
enum: ['*']
|
|
414
|
+
Access-Control-Allow-Credentials:
|
|
415
|
+
schema:
|
|
416
|
+
type: string
|
|
417
|
+
enum: ['true']
|
|
418
|
+
404:
|
|
419
|
+
description: Not found
|
|
420
|
+
"""
|
|
421
|
+
return '', 200, self.get_headers()
|
|
422
|
+
|
|
423
|
+
@check_accept_header_wrapper_flask(['application/octet-stream', 'text/html'])
|
|
424
|
+
def get(self) -> 'ResponseReturnValue':
|
|
425
|
+
"""
|
|
426
|
+
---
|
|
427
|
+
summary: RedirectOIDC
|
|
428
|
+
description: Authenticate a Rucio account via RedirectOIDC.
|
|
429
|
+
tags:
|
|
430
|
+
- Auth
|
|
431
|
+
parameters:
|
|
432
|
+
- name: X-Rucio-Client-Fetch-Token
|
|
433
|
+
in: header
|
|
434
|
+
schema:
|
|
435
|
+
type: string
|
|
436
|
+
responses:
|
|
437
|
+
200:
|
|
438
|
+
description: OK
|
|
439
|
+
headers:
|
|
440
|
+
X-Rucio-Auth-Token:
|
|
441
|
+
description: The authentication token
|
|
442
|
+
schema:
|
|
443
|
+
type: string
|
|
444
|
+
Content-Type:
|
|
445
|
+
schema:
|
|
446
|
+
type: string
|
|
447
|
+
enum: ['application/octet-stream']
|
|
448
|
+
303:
|
|
449
|
+
description: Redirect
|
|
450
|
+
401:
|
|
451
|
+
description: Cannot authenticate
|
|
452
|
+
"""
|
|
453
|
+
headers = self.get_headers()
|
|
454
|
+
|
|
455
|
+
# interaction with web browser - display response in html format
|
|
456
|
+
headers.set('Content-Type', 'text/html')
|
|
457
|
+
headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
|
|
458
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
459
|
+
headers.set('Pragma', 'no-cache')
|
|
460
|
+
|
|
461
|
+
try:
|
|
462
|
+
fetchtoken = (request.headers.get('X-Rucio-Client-Fetch-Token', default=None) == 'True')
|
|
463
|
+
query_string = request.query_string.decode(encoding='utf-8')
|
|
464
|
+
result = redirect_auth_oidc(query_string, fetchtoken)
|
|
465
|
+
except AccessDenied:
|
|
466
|
+
headers.extend(error_headers(CannotAuthenticate.__name__, 'Cannot authorize your access, please check your access credentials'))
|
|
467
|
+
return render_template('auth_crash.html', crashtype='contact'), 401, headers
|
|
468
|
+
except Exception as error:
|
|
469
|
+
logging.exception("Internal Error")
|
|
470
|
+
headers.extend(error_headers(error.__class__.__name__, str(error.args[0])))
|
|
471
|
+
return render_template('auth_crash.html', crashtype='internal_error'), 500, headers
|
|
472
|
+
|
|
473
|
+
if not result:
|
|
474
|
+
headers.extend(error_headers(CannotAuthenticate.__name__, 'Cannot finalize your token request, no authorization content returned from the auth server'))
|
|
475
|
+
return render_template('auth_crash.html', crashtype='no_result'), 401, headers
|
|
476
|
+
|
|
477
|
+
if fetchtoken:
|
|
478
|
+
# this is only a case of returning the final token to the Rucio Client polling
|
|
479
|
+
# or requesting token after copy-pasting the Rucio code from the web page page
|
|
480
|
+
headers.set('Content-Type', 'application/octet-stream')
|
|
481
|
+
headers.set('X-Rucio-Auth-Token', result)
|
|
482
|
+
return '', 200, headers
|
|
483
|
+
else:
|
|
484
|
+
response = redirect(result, code=303)
|
|
485
|
+
response.headers.extend(headers)
|
|
486
|
+
return response
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
class CodeOIDC(ErrorHandlingMethodView):
|
|
490
|
+
"""
|
|
491
|
+
IdP redirects to this endpoint with the AuthZ code
|
|
492
|
+
Rucio Auth server will request new token. This endpoint should be reached
|
|
493
|
+
only if the request/ IdP login has been made through web browser. Then the response
|
|
494
|
+
content will be in html (including the potential errors displayed).
|
|
495
|
+
The token will be saved in the Rucio DB, but only Rucio code will
|
|
496
|
+
be returned on the web page, or, in case of polling is True, successful
|
|
497
|
+
operation is confirmed waiting for the Rucio client to get the token automatically.
|
|
498
|
+
"""
|
|
499
|
+
|
|
500
|
+
def get_headers(self) -> Headers:
|
|
501
|
+
headers = Headers()
|
|
502
|
+
headers.set('Access-Control-Allow-Origin', request.environ.get('HTTP_ORIGIN')) # type: ignore (value could be None)
|
|
503
|
+
headers.set('Access-Control-Allow-Headers', request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) # type: ignore (value could be None)
|
|
504
|
+
headers.set('Access-Control-Allow-Methods', '*')
|
|
505
|
+
headers.set('Access-Control-Allow-Credentials', 'true')
|
|
506
|
+
return headers
|
|
507
|
+
|
|
508
|
+
def options(self) -> 'ResponseReturnValue':
|
|
509
|
+
"""
|
|
510
|
+
---
|
|
511
|
+
summary: CodeOIDC Allow cross-site scripting
|
|
512
|
+
description: CodeOIDC Allow cross-site scripting. Explicit for Authentication.
|
|
513
|
+
tags:
|
|
514
|
+
- Auth
|
|
515
|
+
responses:
|
|
516
|
+
200:
|
|
517
|
+
description: OK
|
|
518
|
+
headers:
|
|
519
|
+
Access-Control-Allow-Origin:
|
|
520
|
+
schema:
|
|
521
|
+
type: string
|
|
522
|
+
Access-Control-Allow-Headers:
|
|
523
|
+
schema:
|
|
524
|
+
type: string
|
|
525
|
+
Access-Control-Allow-Methods:
|
|
526
|
+
schema:
|
|
527
|
+
type: string
|
|
528
|
+
enum: ['*']
|
|
529
|
+
Access-Control-Allow-Credentials:
|
|
530
|
+
schema:
|
|
531
|
+
type: string
|
|
532
|
+
enum: ['true']
|
|
533
|
+
404:
|
|
534
|
+
description: Not found
|
|
535
|
+
"""
|
|
536
|
+
return '', 200, self.get_headers()
|
|
537
|
+
|
|
538
|
+
@check_accept_header_wrapper_flask(['application/octet-stream', 'text/html'])
|
|
539
|
+
def get(self) -> 'ResponseReturnValue':
|
|
540
|
+
"""
|
|
541
|
+
---
|
|
542
|
+
summary: CodeOIDC
|
|
543
|
+
description: Authenticate a Rucio account via CodeOIDC.
|
|
544
|
+
tags:
|
|
545
|
+
- Auth
|
|
546
|
+
parameters:
|
|
547
|
+
- name: X-Forwarded-For
|
|
548
|
+
in: header
|
|
549
|
+
schema:
|
|
550
|
+
type: string
|
|
551
|
+
responses:
|
|
552
|
+
200:
|
|
553
|
+
description: OK
|
|
554
|
+
400:
|
|
555
|
+
description: Invalid request
|
|
556
|
+
"""
|
|
557
|
+
headers = self.get_headers()
|
|
558
|
+
|
|
559
|
+
headers.set('Content-Type', 'text/html')
|
|
560
|
+
headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
|
|
561
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
562
|
+
headers.set('Pragma', 'no-cache')
|
|
563
|
+
|
|
564
|
+
query_string = request.query_string.decode(encoding='utf-8')
|
|
565
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
566
|
+
|
|
567
|
+
try:
|
|
568
|
+
result = get_token_oidc(query_string, ip)
|
|
569
|
+
except AccessDenied:
|
|
570
|
+
headers.extend(error_headers(CannotAuthenticate.__name__, 'Cannot authorize your access, please check your access credentials'))
|
|
571
|
+
return render_template('auth_crash.html', crashtype='contact'), 401, headers
|
|
572
|
+
except Exception as error:
|
|
573
|
+
logging.exception("Internal Error")
|
|
574
|
+
headers.extend(error_headers(error.__class__.__name__, str(error.args[0])))
|
|
575
|
+
return render_template('auth_crash.html', crashtype='internal_error'), 500, headers
|
|
576
|
+
|
|
577
|
+
if not result:
|
|
578
|
+
headers.extend(error_headers(CannotAuthenticate.__name__, 'Cannot finalize your token request, no authorization content returned from the auth server'))
|
|
579
|
+
return render_template('auth_crash.html', crashtype='no_result'), 401, headers
|
|
580
|
+
|
|
581
|
+
if 'fetchcode' in result:
|
|
582
|
+
return render_template('auth_granted.html', authcode=result['fetchcode']), 200, headers
|
|
583
|
+
elif 'polling' in result and result['polling'] is True:
|
|
584
|
+
return render_template('auth_granted.html', authcode='allok'), 200, headers
|
|
585
|
+
else:
|
|
586
|
+
headers.extend(error_headers('InvalidRequest', 'Cannot recognize and process your request'))
|
|
587
|
+
return render_template('auth_crash.html', crashtype='bad_request'), 400, headers
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
class TokenOIDC(ErrorHandlingMethodView):
|
|
591
|
+
"""
|
|
592
|
+
Authenticate a Rucio account temporarily via ID,
|
|
593
|
+
access (eventually save new refresh token)
|
|
594
|
+
received from an Identity Provider.
|
|
595
|
+
"""
|
|
596
|
+
|
|
597
|
+
def get_headers(self) -> Headers:
|
|
598
|
+
headers = Headers()
|
|
599
|
+
headers.set('Access-Control-Allow-Origin', request.environ.get('HTTP_ORIGIN')) # type: ignore (value could be None)
|
|
600
|
+
headers.set('Access-Control-Allow-Headers', request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) # type: ignore (value could be None)
|
|
601
|
+
headers.set('Access-Control-Allow-Methods', '*')
|
|
602
|
+
headers.set('Access-Control-Allow-Credentials', 'true')
|
|
603
|
+
return headers
|
|
604
|
+
|
|
605
|
+
def options(self) -> 'ResponseReturnValue':
|
|
606
|
+
"""
|
|
607
|
+
---
|
|
608
|
+
summary: TokenOIDC Allow cross-site scripting
|
|
609
|
+
description: TokenOIDC Allow cross-site scripting. Explicit for Authentication.
|
|
610
|
+
tags:
|
|
611
|
+
- Auth
|
|
612
|
+
responses:
|
|
613
|
+
200:
|
|
614
|
+
description: OK
|
|
615
|
+
headers:
|
|
616
|
+
Access-Control-Allow-Origin:
|
|
617
|
+
schema:
|
|
618
|
+
type: string
|
|
619
|
+
Access-Control-Allow-Headers:
|
|
620
|
+
schema:
|
|
621
|
+
type: string
|
|
622
|
+
Access-Control-Allow-Methods:
|
|
623
|
+
schema:
|
|
624
|
+
type: string
|
|
625
|
+
enum: ['*']
|
|
626
|
+
Access-Control-Allow-Credentials:
|
|
627
|
+
schema:
|
|
628
|
+
type: string
|
|
629
|
+
enum: ['true']
|
|
630
|
+
404:
|
|
631
|
+
description: Not found
|
|
632
|
+
"""
|
|
633
|
+
return '', 200, self.get_headers()
|
|
634
|
+
|
|
635
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
636
|
+
def get(self) -> 'ResponseReturnValue':
|
|
637
|
+
"""
|
|
638
|
+
---
|
|
639
|
+
summary: TokenOIDC
|
|
640
|
+
description: Authenticate a Rucio account via TokenOIDC.
|
|
641
|
+
tags:
|
|
642
|
+
- Auth
|
|
643
|
+
parameters:
|
|
644
|
+
- name: X-Forwarded-For
|
|
645
|
+
in: header
|
|
646
|
+
schema:
|
|
647
|
+
type: string
|
|
648
|
+
responses:
|
|
649
|
+
200:
|
|
650
|
+
description: OK
|
|
651
|
+
headers:
|
|
652
|
+
X-Rucio-Auth-Token:
|
|
653
|
+
description: The authentication token
|
|
654
|
+
schema:
|
|
655
|
+
type: string
|
|
656
|
+
X-Rucio-Auth-Token-Expires:
|
|
657
|
+
description: The time when the token expires
|
|
658
|
+
schema:
|
|
659
|
+
type: string
|
|
660
|
+
401:
|
|
661
|
+
description: Cannot authenticate
|
|
662
|
+
"""
|
|
663
|
+
headers = self.get_headers()
|
|
664
|
+
|
|
665
|
+
headers.set('Content-Type', 'application/octet-stream')
|
|
666
|
+
headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
|
|
667
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
668
|
+
headers.set('Pragma', 'no-cache')
|
|
669
|
+
|
|
670
|
+
query_string = request.query_string.decode(encoding='utf-8')
|
|
671
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
672
|
+
|
|
673
|
+
try:
|
|
674
|
+
result = get_token_oidc(query_string, ip)
|
|
675
|
+
except AccessDenied:
|
|
676
|
+
return generate_http_error_flask(401, CannotAuthorize.__name__, 'Cannot authorize token request.', headers=headers)
|
|
677
|
+
|
|
678
|
+
if not result:
|
|
679
|
+
return generate_http_error_flask(401, CannotAuthorize.__name__, 'Cannot authorize token request.', headers=headers)
|
|
680
|
+
if 'token' in result and 'webhome' not in result:
|
|
681
|
+
headers.set('X-Rucio-Auth-Token', result['token']['token'])
|
|
682
|
+
headers.set('X-Rucio-Auth-Token-Expires', date_to_str(result['token']['expires_at'])) # type: ignore (value could be None)
|
|
683
|
+
return '', 200, headers
|
|
684
|
+
elif 'webhome' in result:
|
|
685
|
+
webhome = result['webhome']
|
|
686
|
+
if webhome is None:
|
|
687
|
+
headers.extend(error_headers(CannotAuthenticate.__name__, 'Cannot find your OIDC identity linked to any Rucio account'))
|
|
688
|
+
headers.set('Content-Type', 'text/html')
|
|
689
|
+
return render_template('auth_crash.html', crashtype='unknown_identity'), 401, headers
|
|
690
|
+
# domain setting is necessary so that the token gets distributed also to the webui server
|
|
691
|
+
domain = '.'.join(urlparse(webhome).netloc.split('.')[1:])
|
|
692
|
+
response = redirect(webhome, code=303)
|
|
693
|
+
response.headers.extend(headers)
|
|
694
|
+
response.set_cookie('x-rucio-auth-token', value=result['token']['token'], domain=domain, path='/')
|
|
695
|
+
response.set_cookie('rucio-auth-token-created-at', value=str(time.time()), domain=domain, path='/')
|
|
696
|
+
# response.set_cookie('x-rucio-auth-token', value=result['token']['token'])
|
|
697
|
+
# response.set_cookie('rucio-auth-token-created-at', value=str(time.time()))
|
|
698
|
+
return response
|
|
699
|
+
else:
|
|
700
|
+
return '', 400, headers
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
class RefreshOIDC(ErrorHandlingMethodView):
|
|
704
|
+
"""
|
|
705
|
+
For a presented and access token which has equivalent in Rucio DB
|
|
706
|
+
(and also has refrech token in the Rucio DB) the class will attempt
|
|
707
|
+
token refresh and return a user a new refreshed token. If the presented token
|
|
708
|
+
is a result of a previous refresh happening in the last 10 min, the same token will be returned.
|
|
709
|
+
"""
|
|
710
|
+
|
|
711
|
+
def get_headers(self) -> Headers:
|
|
712
|
+
headers = Headers()
|
|
713
|
+
headers.set('Access-Control-Allow-Origin', request.environ.get('HTTP_ORIGIN')) # type: ignore (value could be None)
|
|
714
|
+
headers.set('Access-Control-Allow-Headers', request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) # type: ignore (value could be None)
|
|
715
|
+
headers.set('Access-Control-Allow-Methods', '*')
|
|
716
|
+
headers.set('Access-Control-Allow-Credentials', 'true')
|
|
717
|
+
headers.set('Access-Control-Expose-Headers', 'X-Rucio-Auth-Token')
|
|
718
|
+
return headers
|
|
719
|
+
|
|
720
|
+
def options(self) -> 'ResponseReturnValue':
|
|
721
|
+
"""
|
|
722
|
+
---
|
|
723
|
+
summary: RefreshOIDC Allow cross-site scripting
|
|
724
|
+
description: RefreshOIDC Allow cross-site scripting. Explicit for Authentication.
|
|
725
|
+
tags:
|
|
726
|
+
- Auth
|
|
727
|
+
responses:
|
|
728
|
+
200:
|
|
729
|
+
description: OK
|
|
730
|
+
headers:
|
|
731
|
+
Access-Control-Allow-Origin:
|
|
732
|
+
schema:
|
|
733
|
+
type: string
|
|
734
|
+
Access-Control-Allow-Headers:
|
|
735
|
+
schema:
|
|
736
|
+
type: string
|
|
737
|
+
Access-Control-Allow-Methods:
|
|
738
|
+
schema:
|
|
739
|
+
type: string
|
|
740
|
+
enum: ['*']
|
|
741
|
+
Access-Control-Allow-Credentials:
|
|
742
|
+
schema:
|
|
743
|
+
type: string
|
|
744
|
+
enum: ['true']
|
|
745
|
+
Access-Control-Expose-Headers:
|
|
746
|
+
schema:
|
|
747
|
+
type: string
|
|
748
|
+
enum: ['X-Rucio-Auth-Token']
|
|
749
|
+
404:
|
|
750
|
+
description: Not found
|
|
751
|
+
"""
|
|
752
|
+
return '', 200, self.get_headers()
|
|
753
|
+
|
|
754
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
755
|
+
def get(self) -> 'ResponseReturnValue':
|
|
756
|
+
"""
|
|
757
|
+
---
|
|
758
|
+
summary: RefreshOIDC
|
|
759
|
+
description: Authenticate a Rucio account via RefreshOIDC.
|
|
760
|
+
tags:
|
|
761
|
+
- Auth
|
|
762
|
+
parameters:
|
|
763
|
+
- name: X-Rucio-Account
|
|
764
|
+
in: header
|
|
765
|
+
schema:
|
|
766
|
+
type: string
|
|
767
|
+
required: true
|
|
768
|
+
- name: X-Rucio-Auth-Token
|
|
769
|
+
in: header
|
|
770
|
+
schema:
|
|
771
|
+
type: string
|
|
772
|
+
required: true
|
|
773
|
+
responses:
|
|
774
|
+
200:
|
|
775
|
+
description: OK
|
|
776
|
+
headers:
|
|
777
|
+
X-Rucio-Auth-Token:
|
|
778
|
+
description: The authentication token
|
|
779
|
+
schema:
|
|
780
|
+
type: string
|
|
781
|
+
X-Rucio-Auth-Token-Expires:
|
|
782
|
+
description: The time when the token expires
|
|
783
|
+
schema:
|
|
784
|
+
type: string
|
|
785
|
+
401:
|
|
786
|
+
description: Cannot authenticate
|
|
787
|
+
"""
|
|
788
|
+
headers = self.get_headers()
|
|
789
|
+
|
|
790
|
+
headers.set('Content-Type', 'application/octet-stream')
|
|
791
|
+
headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
|
|
792
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
793
|
+
headers.set('Pragma', 'no-cache')
|
|
794
|
+
|
|
795
|
+
vo = extract_vo(request.headers)
|
|
796
|
+
account = request.headers.get('X-Rucio-Account', default=None)
|
|
797
|
+
token = request.headers.get('X-Rucio-Auth-Token', default=None)
|
|
798
|
+
if token is None or account is None:
|
|
799
|
+
return generate_http_error_flask(401, CannotAuthorize.__name__, 'Cannot authorize token request.', headers=headers)
|
|
800
|
+
|
|
801
|
+
try:
|
|
802
|
+
result = refresh_cli_auth_token(token, account, vo=vo)
|
|
803
|
+
except AccessDenied:
|
|
804
|
+
return generate_http_error_flask(401, CannotAuthorize.__name__, 'Cannot authorize token request.', headers=headers)
|
|
805
|
+
|
|
806
|
+
if result is not None and len(result) > 1:
|
|
807
|
+
headers.set('X-Rucio-Auth-Token', str(result[0]))
|
|
808
|
+
headers.set('X-Rucio-Auth-Token-Expires', str(result[1]))
|
|
809
|
+
else:
|
|
810
|
+
headers.set('X-Rucio-Auth-Token', '')
|
|
811
|
+
headers.set('X-Rucio-Auth-Token-Expires', '')
|
|
812
|
+
return '', 200, headers
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
class GSS(ErrorHandlingMethodView):
|
|
816
|
+
"""
|
|
817
|
+
Authenticate a Rucio account temporarily via a GSS token.
|
|
818
|
+
"""
|
|
819
|
+
|
|
820
|
+
def get_headers(self) -> Headers:
|
|
821
|
+
headers = Headers()
|
|
822
|
+
headers['Access-Control-Allow-Origin'] = request.environ.get('HTTP_ORIGIN') # type: ignore (value could be None)
|
|
823
|
+
headers['Access-Control-Allow-Headers'] = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') # type: ignore (value could be None)
|
|
824
|
+
headers['Access-Control-Allow-Methods'] = '*'
|
|
825
|
+
headers['Access-Control-Allow-Credentials'] = 'true'
|
|
826
|
+
headers['Access-Control-Expose-Headers'] = 'X-Rucio-Auth-Token'
|
|
827
|
+
return headers
|
|
828
|
+
|
|
829
|
+
def options(self) -> 'ResponseReturnValue':
|
|
830
|
+
"""
|
|
831
|
+
---
|
|
832
|
+
summary: GSS Allow cross-site scripting
|
|
833
|
+
description: GSS Allow cross-site scripting. Explicit for Authentication.
|
|
834
|
+
tags:
|
|
835
|
+
- Auth
|
|
836
|
+
responses:
|
|
837
|
+
200:
|
|
838
|
+
description: OK
|
|
839
|
+
headers:
|
|
840
|
+
Access-Control-Allow-Origin:
|
|
841
|
+
schema:
|
|
842
|
+
type: string
|
|
843
|
+
Access-Control-Allow-Headers:
|
|
844
|
+
schema:
|
|
845
|
+
type: string
|
|
846
|
+
Access-Control-Allow-Methods:
|
|
847
|
+
schema:
|
|
848
|
+
type: string
|
|
849
|
+
enum: ['*']
|
|
850
|
+
Access-Control-Allow-Credentials:
|
|
851
|
+
schema:
|
|
852
|
+
type: string
|
|
853
|
+
enum: ['true']
|
|
854
|
+
Access-Control-Expose-Headers:
|
|
855
|
+
schema:
|
|
856
|
+
type: string
|
|
857
|
+
enum: ['X-Rucio-Auth-Token']
|
|
858
|
+
404:
|
|
859
|
+
description: Not found
|
|
860
|
+
"""
|
|
861
|
+
return '', 200, self.get_headers()
|
|
862
|
+
|
|
863
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
864
|
+
def get(self) -> 'ResponseReturnValue':
|
|
865
|
+
"""
|
|
866
|
+
---
|
|
867
|
+
summary: GSS
|
|
868
|
+
description: Authenticate a Rucio account via GSS.
|
|
869
|
+
tags:
|
|
870
|
+
- Auth
|
|
871
|
+
parameters:
|
|
872
|
+
- name: X-Rucio-Account
|
|
873
|
+
in: header
|
|
874
|
+
schema:
|
|
875
|
+
type: string
|
|
876
|
+
required: true
|
|
877
|
+
- name: REMOTE_USER
|
|
878
|
+
in: header
|
|
879
|
+
schema:
|
|
880
|
+
type: string
|
|
881
|
+
required: true
|
|
882
|
+
- name: X-Rucio-AppID
|
|
883
|
+
in: header
|
|
884
|
+
schema:
|
|
885
|
+
type: string
|
|
886
|
+
- name: X-Forwarded-For
|
|
887
|
+
in: header
|
|
888
|
+
schema:
|
|
889
|
+
type: string
|
|
890
|
+
responses:
|
|
891
|
+
200:
|
|
892
|
+
description: OK
|
|
893
|
+
headers:
|
|
894
|
+
X-Rucio-Auth-Token:
|
|
895
|
+
description: The authentication token
|
|
896
|
+
schema:
|
|
897
|
+
type: string
|
|
898
|
+
X-Rucio-Auth-Token-Expires:
|
|
899
|
+
description: The time when the token expires
|
|
900
|
+
schema:
|
|
901
|
+
type: string
|
|
902
|
+
401:
|
|
903
|
+
description: Cannot authenticate
|
|
904
|
+
"""
|
|
905
|
+
|
|
906
|
+
headers = self.get_headers()
|
|
907
|
+
|
|
908
|
+
headers['Content-Type'] = 'application/octet-stream'
|
|
909
|
+
headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
|
910
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
911
|
+
headers['Pragma'] = 'no-cache'
|
|
912
|
+
|
|
913
|
+
vo = extract_vo(request.headers)
|
|
914
|
+
account = request.headers.get('X-Rucio-Account', default=None)
|
|
915
|
+
gsscred = request.environ.get('REMOTE_USER')
|
|
916
|
+
appid = request.headers.get('X-Rucio-AppID', default='unknown')
|
|
917
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
918
|
+
|
|
919
|
+
try:
|
|
920
|
+
result = get_auth_token_gss(account, gsscred, appid, ip, vo=vo)
|
|
921
|
+
except AccessDenied:
|
|
922
|
+
return generate_http_error_flask(
|
|
923
|
+
status_code=401,
|
|
924
|
+
exc=CannotAuthenticate.__name__,
|
|
925
|
+
exc_msg=f'Cannot authenticate to account {account} with given credentials',
|
|
926
|
+
headers=headers
|
|
927
|
+
)
|
|
928
|
+
|
|
929
|
+
if result is None:
|
|
930
|
+
return generate_http_error_flask(
|
|
931
|
+
status_code=401,
|
|
932
|
+
exc=CannotAuthenticate.__name__,
|
|
933
|
+
exc_msg=f'Cannot authenticate to account {account} with given credentials',
|
|
934
|
+
headers=headers
|
|
935
|
+
)
|
|
936
|
+
|
|
937
|
+
headers['X-Rucio-Auth-Token'] = result['token']
|
|
938
|
+
headers['X-Rucio-Auth-Token-Expires'] = date_to_str(result['expires_at']) # type: ignore (value could be None)
|
|
939
|
+
return '', 200, headers
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
class x509(ErrorHandlingMethodView): # noqa: N801
|
|
943
|
+
"""
|
|
944
|
+
Authenticate a Rucio account temporarily via an x509 certificate.
|
|
945
|
+
"""
|
|
946
|
+
|
|
947
|
+
def get_headers(self) -> Headers:
|
|
948
|
+
headers = Headers()
|
|
949
|
+
headers['Access-Control-Allow-Origin'] = request.environ.get('HTTP_ORIGIN') # type: ignore (value could be None)
|
|
950
|
+
headers['Access-Control-Allow-Headers'] = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') # type: ignore (value could be None)
|
|
951
|
+
headers['Access-Control-Allow-Methods'] = '*'
|
|
952
|
+
headers['Access-Control-Allow-Credentials'] = 'true'
|
|
953
|
+
headers['Access-Control-Expose-Headers'] = 'X-Rucio-Auth-Token, X-Rucio-Auth-Token-Expires, X-Rucio-Auth-Account, X-Rucio-Auth-Accounts'
|
|
954
|
+
return headers
|
|
955
|
+
|
|
956
|
+
def options(self) -> 'ResponseReturnValue':
|
|
957
|
+
"""
|
|
958
|
+
---
|
|
959
|
+
summary: x509 Allow cross-site scripting
|
|
960
|
+
description: x509 Allow cross-site scripting. Explicit for Authentication.
|
|
961
|
+
tags:
|
|
962
|
+
- Auth
|
|
963
|
+
responses:
|
|
964
|
+
200:
|
|
965
|
+
description: OK
|
|
966
|
+
headers:
|
|
967
|
+
Access-Control-Allow-Origin:
|
|
968
|
+
schema:
|
|
969
|
+
type: string
|
|
970
|
+
Access-Control-Allow-Headers:
|
|
971
|
+
schema:
|
|
972
|
+
type: string
|
|
973
|
+
Access-Control-Allow-Methods:
|
|
974
|
+
schema:
|
|
975
|
+
type: string
|
|
976
|
+
enum: ['*']
|
|
977
|
+
Access-Control-Allow-Credentials:
|
|
978
|
+
schema:
|
|
979
|
+
type: string
|
|
980
|
+
enum: ['true']
|
|
981
|
+
Access-Control-Expose-Headers:
|
|
982
|
+
schema:
|
|
983
|
+
type: string
|
|
984
|
+
enum: ['X-Rucio-Auth-Token']
|
|
985
|
+
404:
|
|
986
|
+
description: Not found
|
|
987
|
+
"""
|
|
988
|
+
return '', 200, self.get_headers()
|
|
989
|
+
|
|
990
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
991
|
+
def get(self) -> 'ResponseReturnValue':
|
|
992
|
+
"""
|
|
993
|
+
---
|
|
994
|
+
summary: x509
|
|
995
|
+
description: Authenticate a Rucio account via x509.
|
|
996
|
+
tags:
|
|
997
|
+
- Auth
|
|
998
|
+
parameters:
|
|
999
|
+
- name: X-Rucio-Account
|
|
1000
|
+
in: header
|
|
1001
|
+
schema:
|
|
1002
|
+
type: string
|
|
1003
|
+
required: true
|
|
1004
|
+
- name: X-Rucio-AppID
|
|
1005
|
+
in: header
|
|
1006
|
+
schema:
|
|
1007
|
+
type: string
|
|
1008
|
+
- name: X-Forwarded-For
|
|
1009
|
+
in: header
|
|
1010
|
+
schema:
|
|
1011
|
+
type: string
|
|
1012
|
+
- name: X-Rucio-Allow-Return-Multiple-Accounts
|
|
1013
|
+
in: header
|
|
1014
|
+
schema:
|
|
1015
|
+
type: boolean
|
|
1016
|
+
description: If set to true, a HTTP 206 response will be returned if the identity is associated with multiple accounts.
|
|
1017
|
+
responses:
|
|
1018
|
+
200:
|
|
1019
|
+
description: OK
|
|
1020
|
+
headers:
|
|
1021
|
+
X-Rucio-Auth-Token:
|
|
1022
|
+
description: The authentication token
|
|
1023
|
+
schema:
|
|
1024
|
+
type: string
|
|
1025
|
+
X-Rucio-Auth-Token-Expires:
|
|
1026
|
+
description: The time when the token expires
|
|
1027
|
+
schema:
|
|
1028
|
+
type: string
|
|
1029
|
+
X-Rucio-Auth-Account:
|
|
1030
|
+
description: The rucio account corresponding to the provided identity
|
|
1031
|
+
schema:
|
|
1032
|
+
type: string
|
|
1033
|
+
206:
|
|
1034
|
+
description: Partial content containing X-Rucio-Auth-Accounts header
|
|
1035
|
+
headers:
|
|
1036
|
+
X-Rucio-Auth-Accounts:
|
|
1037
|
+
schema:
|
|
1038
|
+
type: string
|
|
1039
|
+
description: The rucio accounts corresponding to the provided identity as a csv string
|
|
1040
|
+
401:
|
|
1041
|
+
description: Cannot authenticate
|
|
1042
|
+
"""
|
|
1043
|
+
headers = self.get_headers()
|
|
1044
|
+
headers['Content-Type'] = 'application/octet-stream'
|
|
1045
|
+
headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
|
1046
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
1047
|
+
headers['Pragma'] = 'no-cache'
|
|
1048
|
+
|
|
1049
|
+
vo = extract_vo(request.headers)
|
|
1050
|
+
account = request.headers.get('X-Rucio-Account', default=None)
|
|
1051
|
+
dn = request.environ.get('SSL_CLIENT_S_DN')
|
|
1052
|
+
if not dn:
|
|
1053
|
+
return generate_http_error_flask(401, CannotAuthenticate.__name__, 'Cannot get DN', headers=headers)
|
|
1054
|
+
dn = strip_x509_proxy_attributes(dn)
|
|
1055
|
+
appid = request.headers.get('X-Rucio-AppID', default='unknown')
|
|
1056
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
1057
|
+
return_multiple_accounts = request.headers.get('X-Rucio-Allow-Return-Multiple-Accounts', default=None)
|
|
1058
|
+
|
|
1059
|
+
accounts: list[str] = []
|
|
1060
|
+
if not account:
|
|
1061
|
+
try:
|
|
1062
|
+
accounts = get_account_from_verified_identity(identity_key=dn, id_type='X509')
|
|
1063
|
+
except IdentityError as e:
|
|
1064
|
+
return generate_http_error_flask(401, IdentityError.__name__, str(e), headers=headers)
|
|
1065
|
+
else:
|
|
1066
|
+
accounts = [account]
|
|
1067
|
+
|
|
1068
|
+
if len(accounts) > 1:
|
|
1069
|
+
if return_multiple_accounts is None or return_multiple_accounts.lower() != 'true':
|
|
1070
|
+
return generate_http_error_flask(401, CannotAuthenticate.__name__, 'Multiple accounts associated with the provided identity', headers=headers)
|
|
1071
|
+
account_names: list[str] = []
|
|
1072
|
+
for account in accounts:
|
|
1073
|
+
if isinstance(account, str):
|
|
1074
|
+
account_names.append(account)
|
|
1075
|
+
else:
|
|
1076
|
+
account_names.append(account.external)
|
|
1077
|
+
headers['X-Rucio-Auth-Accounts'] = ','.join(accounts)
|
|
1078
|
+
return json.dumps(account_names), 206, headers
|
|
1079
|
+
account = accounts[0]
|
|
1080
|
+
account_name = account if isinstance(account, str) else account.external
|
|
1081
|
+
result = None
|
|
1082
|
+
try:
|
|
1083
|
+
result = get_auth_token_x509(account_name, dn, appid, ip, vo=vo)
|
|
1084
|
+
except AccessDenied:
|
|
1085
|
+
return generate_http_error_flask(
|
|
1086
|
+
status_code=401,
|
|
1087
|
+
exc=CannotAuthenticate.__name__,
|
|
1088
|
+
exc_msg=f'Cannot authenticate to account {account_name} with given credentials',
|
|
1089
|
+
headers=headers
|
|
1090
|
+
)
|
|
1091
|
+
except IdentityError as e:
|
|
1092
|
+
return generate_http_error_flask(
|
|
1093
|
+
status_code=401,
|
|
1094
|
+
exc=CannotAuthenticate.__name__,
|
|
1095
|
+
exc_msg=str(e),
|
|
1096
|
+
headers=headers
|
|
1097
|
+
)
|
|
1098
|
+
|
|
1099
|
+
if not result:
|
|
1100
|
+
return generate_http_error_flask(
|
|
1101
|
+
status_code=401,
|
|
1102
|
+
exc=CannotAuthenticate.__name__,
|
|
1103
|
+
exc_msg=f'Cannot authenticate to account {account} with given credentials',
|
|
1104
|
+
headers=headers
|
|
1105
|
+
)
|
|
1106
|
+
headers['X-Rucio-Auth-Token'] = result['token']
|
|
1107
|
+
headers['X-Rucio-Auth-Token-Expires'] = date_to_str(result['expires_at']) # type: ignore (value could be None)
|
|
1108
|
+
headers['X-Rucio-Auth-Account'] = account
|
|
1109
|
+
return '', 200, headers
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
class SSH(ErrorHandlingMethodView):
|
|
1113
|
+
"""
|
|
1114
|
+
Authenticate a Rucio account temporarily via SSH key exchange.
|
|
1115
|
+
"""
|
|
1116
|
+
|
|
1117
|
+
def get_headers(self) -> Headers:
|
|
1118
|
+
headers = Headers()
|
|
1119
|
+
headers['Access-Control-Allow-Origin'] = request.environ.get('HTTP_ORIGIN') # type: ignore (value could be None)
|
|
1120
|
+
headers['Access-Control-Allow-Headers'] = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') # type: ignore (value could be None)
|
|
1121
|
+
headers['Access-Control-Allow-Methods'] = '*'
|
|
1122
|
+
headers['Access-Control-Allow-Credentials'] = 'true'
|
|
1123
|
+
headers['Access-Control-Expose-Headers'] = 'X-Rucio-Auth-Token'
|
|
1124
|
+
return headers
|
|
1125
|
+
|
|
1126
|
+
def options(self) -> 'ResponseReturnValue':
|
|
1127
|
+
"""
|
|
1128
|
+
---
|
|
1129
|
+
summary: SSH Allow cross-site scripting
|
|
1130
|
+
description: SSH Allow cross-site scripting. Explicit for Authentication.
|
|
1131
|
+
tags:
|
|
1132
|
+
- Auth
|
|
1133
|
+
responses:
|
|
1134
|
+
200:
|
|
1135
|
+
description: OK
|
|
1136
|
+
headers:
|
|
1137
|
+
Access-Control-Allow-Origin:
|
|
1138
|
+
schema:
|
|
1139
|
+
type: string
|
|
1140
|
+
Access-Control-Allow-Headers:
|
|
1141
|
+
schema:
|
|
1142
|
+
type: string
|
|
1143
|
+
Access-Control-Allow-Methods:
|
|
1144
|
+
schema:
|
|
1145
|
+
type: string
|
|
1146
|
+
enum: ['*']
|
|
1147
|
+
Access-Control-Allow-Credentials:
|
|
1148
|
+
schema:
|
|
1149
|
+
type: string
|
|
1150
|
+
enum: ['true']
|
|
1151
|
+
Access-Control-Expose-Headers:
|
|
1152
|
+
schema:
|
|
1153
|
+
type: string
|
|
1154
|
+
enum: ['X-Rucio-Auth-Token']
|
|
1155
|
+
404:
|
|
1156
|
+
description: Not found
|
|
1157
|
+
"""
|
|
1158
|
+
return '', 200, self.get_headers()
|
|
1159
|
+
|
|
1160
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
1161
|
+
def get(self) -> 'ResponseReturnValue':
|
|
1162
|
+
"""
|
|
1163
|
+
---
|
|
1164
|
+
summary: SSH
|
|
1165
|
+
description: Authenticate a Rucio account via SSH.
|
|
1166
|
+
tags:
|
|
1167
|
+
- Auth
|
|
1168
|
+
parameters:
|
|
1169
|
+
- name: X-Rucio-Account
|
|
1170
|
+
in: header
|
|
1171
|
+
schema:
|
|
1172
|
+
type: string
|
|
1173
|
+
required: true
|
|
1174
|
+
- name: X-Rucio-SSH-Signature
|
|
1175
|
+
in: header
|
|
1176
|
+
schema:
|
|
1177
|
+
type: string
|
|
1178
|
+
required: true
|
|
1179
|
+
- name: X-Rucio-AppID
|
|
1180
|
+
in: header
|
|
1181
|
+
schema:
|
|
1182
|
+
type: string
|
|
1183
|
+
- name: X-Forwarded-For
|
|
1184
|
+
in: header
|
|
1185
|
+
schema:
|
|
1186
|
+
type: string
|
|
1187
|
+
responses:
|
|
1188
|
+
200:
|
|
1189
|
+
description: OK
|
|
1190
|
+
headers:
|
|
1191
|
+
X-Rucio-Auth-Token:
|
|
1192
|
+
description: The authentication token
|
|
1193
|
+
schema:
|
|
1194
|
+
type: string
|
|
1195
|
+
X-Rucio-Auth-Token-Expires:
|
|
1196
|
+
description: The time when the token expires
|
|
1197
|
+
schema:
|
|
1198
|
+
type: string
|
|
1199
|
+
401:
|
|
1200
|
+
description: Cannot authenticate
|
|
1201
|
+
"""
|
|
1202
|
+
headers = self.get_headers()
|
|
1203
|
+
|
|
1204
|
+
headers['Content-Type'] = 'application/octet-stream'
|
|
1205
|
+
headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
|
1206
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
1207
|
+
headers['Pragma'] = 'no-cache'
|
|
1208
|
+
|
|
1209
|
+
vo = extract_vo(request.headers)
|
|
1210
|
+
account = request.headers.get('X-Rucio-Account', default=None)
|
|
1211
|
+
signature = request.headers.get('X-Rucio-SSH-Signature', default=None)
|
|
1212
|
+
appid = request.headers.get('X-Rucio-AppID', default='unknown')
|
|
1213
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
1214
|
+
|
|
1215
|
+
try:
|
|
1216
|
+
result = get_auth_token_ssh(account, signature, appid, ip, vo=vo)
|
|
1217
|
+
except AccessDenied:
|
|
1218
|
+
return generate_http_error_flask(
|
|
1219
|
+
status_code=401,
|
|
1220
|
+
exc=CannotAuthenticate.__name__,
|
|
1221
|
+
exc_msg=f'Cannot authenticate to account {account} with given credentials',
|
|
1222
|
+
headers=headers
|
|
1223
|
+
)
|
|
1224
|
+
|
|
1225
|
+
if not result:
|
|
1226
|
+
return generate_http_error_flask(
|
|
1227
|
+
status_code=401,
|
|
1228
|
+
exc=CannotAuthenticate.__name__,
|
|
1229
|
+
exc_msg=f'Cannot authenticate to account {account} with given credentials',
|
|
1230
|
+
headers=headers
|
|
1231
|
+
)
|
|
1232
|
+
|
|
1233
|
+
headers['X-Rucio-Auth-Token'] = result['token']
|
|
1234
|
+
headers['X-Rucio-Auth-Token-Expires'] = date_to_str(result['expires_at']) # type: ignore (value could be None)
|
|
1235
|
+
return '', 200, headers
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
class SSHChallengeToken(ErrorHandlingMethodView):
|
|
1239
|
+
"""
|
|
1240
|
+
Request a challenge token for SSH authentication
|
|
1241
|
+
"""
|
|
1242
|
+
|
|
1243
|
+
def get_headers(self) -> Headers:
|
|
1244
|
+
headers = Headers()
|
|
1245
|
+
headers['Access-Control-Allow-Origin'] = request.environ.get('HTTP_ORIGIN') # type: ignore (value could be None)
|
|
1246
|
+
headers['Access-Control-Allow-Headers'] = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') # type: ignore (value could be None)
|
|
1247
|
+
headers['Access-Control-Allow-Methods'] = '*'
|
|
1248
|
+
headers['Access-Control-Allow-Credentials'] = 'true'
|
|
1249
|
+
headers['Access-Control-Expose-Headers'] = 'X-Rucio-Auth-Token'
|
|
1250
|
+
return headers
|
|
1251
|
+
|
|
1252
|
+
def options(self) -> 'ResponseReturnValue':
|
|
1253
|
+
"""
|
|
1254
|
+
---
|
|
1255
|
+
summary: SSHChallengeToken Allow cross-site scripting
|
|
1256
|
+
description: SSHChallengeToken Allow cross-site scripting. Explicit for Authentication.
|
|
1257
|
+
tags:
|
|
1258
|
+
- Auth
|
|
1259
|
+
responses:
|
|
1260
|
+
200:
|
|
1261
|
+
description: OK
|
|
1262
|
+
headers:
|
|
1263
|
+
Access-Control-Allow-Origin:
|
|
1264
|
+
schema:
|
|
1265
|
+
type: string
|
|
1266
|
+
Access-Control-Allow-Headers:
|
|
1267
|
+
schema:
|
|
1268
|
+
type: string
|
|
1269
|
+
Access-Control-Allow-Methods:
|
|
1270
|
+
schema:
|
|
1271
|
+
type: string
|
|
1272
|
+
enum: ['*']
|
|
1273
|
+
Access-Control-Allow-Credentials:
|
|
1274
|
+
schema:
|
|
1275
|
+
type: string
|
|
1276
|
+
enum: ['true']
|
|
1277
|
+
Access-Control-Expose-Headers:
|
|
1278
|
+
schema:
|
|
1279
|
+
type: string
|
|
1280
|
+
enum: ['X-Rucio-Auth-Token']
|
|
1281
|
+
404:
|
|
1282
|
+
description: Not found
|
|
1283
|
+
"""
|
|
1284
|
+
return '', 200, self.get_headers()
|
|
1285
|
+
|
|
1286
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
1287
|
+
def get(self) -> 'ResponseReturnValue':
|
|
1288
|
+
"""
|
|
1289
|
+
---
|
|
1290
|
+
summary: SSHChallengeToken
|
|
1291
|
+
description: Authenticate a Rucio account via SSHChallengeToken.
|
|
1292
|
+
tags:
|
|
1293
|
+
- Auth
|
|
1294
|
+
parameters:
|
|
1295
|
+
- name: X-Rucio-Account
|
|
1296
|
+
in: header
|
|
1297
|
+
schema:
|
|
1298
|
+
type: string
|
|
1299
|
+
required: true
|
|
1300
|
+
- name: X-Rucio-AppID
|
|
1301
|
+
in: header
|
|
1302
|
+
schema:
|
|
1303
|
+
type: string
|
|
1304
|
+
- name: X-Forwarded-For
|
|
1305
|
+
in: header
|
|
1306
|
+
schema:
|
|
1307
|
+
type: string
|
|
1308
|
+
responses:
|
|
1309
|
+
200:
|
|
1310
|
+
description: OK
|
|
1311
|
+
headers:
|
|
1312
|
+
X-Rucio-SSH-Challenge-Token:
|
|
1313
|
+
description: The authentication token
|
|
1314
|
+
schema:
|
|
1315
|
+
type: string
|
|
1316
|
+
X-Rucio-SSH-Challenge-Token-Expires:
|
|
1317
|
+
description: The time when the token expires
|
|
1318
|
+
schema:
|
|
1319
|
+
type: string
|
|
1320
|
+
401:
|
|
1321
|
+
description: Cannot authenticate
|
|
1322
|
+
"""
|
|
1323
|
+
headers = self.get_headers()
|
|
1324
|
+
|
|
1325
|
+
headers['Content-Type'] = 'application/octet-stream'
|
|
1326
|
+
headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
|
1327
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
1328
|
+
headers['Pragma'] = 'no-cache'
|
|
1329
|
+
|
|
1330
|
+
vo = extract_vo(request.headers)
|
|
1331
|
+
account = request.headers.get('X-Rucio-Account', default=None)
|
|
1332
|
+
appid = request.headers.get('X-Rucio-AppID', default='unknown')
|
|
1333
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
1334
|
+
|
|
1335
|
+
result = get_ssh_challenge_token(account, appid, ip, vo=vo)
|
|
1336
|
+
|
|
1337
|
+
if not result:
|
|
1338
|
+
return generate_http_error_flask(
|
|
1339
|
+
status_code=401,
|
|
1340
|
+
exc=CannotAuthenticate.__name__,
|
|
1341
|
+
exc_msg=f'Cannot generate challenge for account {account}',
|
|
1342
|
+
headers=headers
|
|
1343
|
+
)
|
|
1344
|
+
|
|
1345
|
+
headers['X-Rucio-SSH-Challenge-Token'] = result['token']
|
|
1346
|
+
headers['X-Rucio-SSH-Challenge-Token-Expires'] = date_to_str(result['expires_at']) # type: ignore (value could be None)
|
|
1347
|
+
return '', 200, headers
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
class SAML(ErrorHandlingMethodView):
|
|
1351
|
+
"""
|
|
1352
|
+
Authenticate a Rucio account temporarily via CERN SSO.
|
|
1353
|
+
"""
|
|
1354
|
+
|
|
1355
|
+
def get_headers(self) -> Headers:
|
|
1356
|
+
headers = Headers()
|
|
1357
|
+
headers.set('Access-Control-Allow-Origin', request.environ.get('HTTP_ORIGIN')) # type: ignore (value could be None)
|
|
1358
|
+
headers.set('Access-Control-Allow-Headers', request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) # type: ignore (value could be None)
|
|
1359
|
+
headers.set('Access-Control-Allow-Methods', '*')
|
|
1360
|
+
headers.set('Access-Control-Allow-Credentials', 'true')
|
|
1361
|
+
headers.set('Access-Control-Expose-Headers', 'X-Rucio-Auth-Token')
|
|
1362
|
+
return headers
|
|
1363
|
+
|
|
1364
|
+
def options(self) -> 'ResponseReturnValue':
|
|
1365
|
+
"""
|
|
1366
|
+
---
|
|
1367
|
+
summary: SAML Allow cross-site scripting
|
|
1368
|
+
description: SAML Allow cross-site scripting. Explicit for Authentication.
|
|
1369
|
+
tags:
|
|
1370
|
+
- Auth
|
|
1371
|
+
responses:
|
|
1372
|
+
200:
|
|
1373
|
+
description: OK
|
|
1374
|
+
headers:
|
|
1375
|
+
Access-Control-Allow-Origin:
|
|
1376
|
+
schema:
|
|
1377
|
+
type: string
|
|
1378
|
+
Access-Control-Allow-Headers:
|
|
1379
|
+
schema:
|
|
1380
|
+
type: string
|
|
1381
|
+
Access-Control-Allow-Methods:
|
|
1382
|
+
schema:
|
|
1383
|
+
type: string
|
|
1384
|
+
enum: ['*']
|
|
1385
|
+
Access-Control-Allow-Credentials:
|
|
1386
|
+
schema:
|
|
1387
|
+
type: string
|
|
1388
|
+
enum: ['true']
|
|
1389
|
+
Access-Control-Expose-Headers:
|
|
1390
|
+
schema:
|
|
1391
|
+
type: string
|
|
1392
|
+
enum: ['X-Rucio-Auth-Token']
|
|
1393
|
+
404:
|
|
1394
|
+
description: Not found
|
|
1395
|
+
"""
|
|
1396
|
+
return '', 200, self.get_headers()
|
|
1397
|
+
|
|
1398
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
1399
|
+
def get(self) -> 'ResponseReturnValue':
|
|
1400
|
+
"""
|
|
1401
|
+
---
|
|
1402
|
+
summary: SAML
|
|
1403
|
+
description: Authenticate a Rucio account via SAML.
|
|
1404
|
+
tags:
|
|
1405
|
+
- Auth
|
|
1406
|
+
parameters:
|
|
1407
|
+
- name: X-Rucio-Account
|
|
1408
|
+
in: header
|
|
1409
|
+
schema:
|
|
1410
|
+
type: string
|
|
1411
|
+
required: true
|
|
1412
|
+
- name: X-Rucio-AppID
|
|
1413
|
+
in: header
|
|
1414
|
+
schema:
|
|
1415
|
+
type: string
|
|
1416
|
+
- name: X-Forwarded-For
|
|
1417
|
+
in: header
|
|
1418
|
+
schema:
|
|
1419
|
+
type: string
|
|
1420
|
+
responses:
|
|
1421
|
+
200:
|
|
1422
|
+
description: OK
|
|
1423
|
+
headers:
|
|
1424
|
+
X-Rucio-Auth-Token:
|
|
1425
|
+
description: The authentication token
|
|
1426
|
+
schema:
|
|
1427
|
+
type: string
|
|
1428
|
+
X-Rucio-Auth-Token-Expires:
|
|
1429
|
+
description: The time when the token expires
|
|
1430
|
+
schema:
|
|
1431
|
+
type: string
|
|
1432
|
+
X-Rucio-SAML-Auth-URL:
|
|
1433
|
+
description: The time when the token expires
|
|
1434
|
+
schema:
|
|
1435
|
+
type: string
|
|
1436
|
+
401:
|
|
1437
|
+
description: Cannot authenticate
|
|
1438
|
+
"""
|
|
1439
|
+
headers = self.get_headers()
|
|
1440
|
+
|
|
1441
|
+
headers.set('Content-Type', 'application/octet-stream')
|
|
1442
|
+
headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate')
|
|
1443
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
1444
|
+
headers.set('Pragma', 'no-cache')
|
|
1445
|
+
|
|
1446
|
+
if not EXTRA_MODULES['onelogin']:
|
|
1447
|
+
return "SAML not configured on the server side.", 400, headers
|
|
1448
|
+
|
|
1449
|
+
saml_nameid = request.cookies.get('saml-nameid', default=None)
|
|
1450
|
+
vo = extract_vo(request.headers)
|
|
1451
|
+
account = request.headers.get('X-Rucio-Account', default=None)
|
|
1452
|
+
appid = request.headers.get('X-Rucio-AppID', default='unknown')
|
|
1453
|
+
ip = request.headers.get('X-Forwarded-For', default=request.remote_addr)
|
|
1454
|
+
|
|
1455
|
+
if saml_nameid:
|
|
1456
|
+
try:
|
|
1457
|
+
result = get_auth_token_saml(account, saml_nameid, appid, ip, vo=vo)
|
|
1458
|
+
except AccessDenied:
|
|
1459
|
+
return generate_http_error_flask(
|
|
1460
|
+
status_code=401,
|
|
1461
|
+
exc=CannotAuthenticate.__name__,
|
|
1462
|
+
exc_msg=f'Cannot authenticate to account {account} with given credentials',
|
|
1463
|
+
headers=headers
|
|
1464
|
+
)
|
|
1465
|
+
|
|
1466
|
+
if not result:
|
|
1467
|
+
return generate_http_error_flask(
|
|
1468
|
+
status_code=401,
|
|
1469
|
+
exc=CannotAuthenticate.__name__,
|
|
1470
|
+
exc_msg=f'Cannot authenticate to account {account} with given credentials',
|
|
1471
|
+
headers=headers
|
|
1472
|
+
)
|
|
1473
|
+
|
|
1474
|
+
headers.set('X-Rucio-Auth-Token', result['token'])
|
|
1475
|
+
headers.set('X-Rucio-Auth-Token-Expires', date_to_str(result['expires_at'])) # type: ignore (value could be None)
|
|
1476
|
+
return '', 200, headers
|
|
1477
|
+
|
|
1478
|
+
# Path to the SAML config folder
|
|
1479
|
+
saml_path = config_get('saml', 'config_path')
|
|
1480
|
+
|
|
1481
|
+
req = prepare_saml_request(request.environ, dict(request.args.items(multi=False)))
|
|
1482
|
+
auth = OneLogin_Saml2_Auth(req, custom_base_path=saml_path)
|
|
1483
|
+
|
|
1484
|
+
headers.set('X-Rucio-SAML-Auth-URL', auth.login())
|
|
1485
|
+
return '', 200, headers
|
|
1486
|
+
|
|
1487
|
+
def post(self) -> 'ResponseReturnValue':
|
|
1488
|
+
"""
|
|
1489
|
+
---
|
|
1490
|
+
summary: Post a SAML request
|
|
1491
|
+
description: Post a SAML request
|
|
1492
|
+
tags:
|
|
1493
|
+
- Auth
|
|
1494
|
+
responses:
|
|
1495
|
+
200:
|
|
1496
|
+
description: OK
|
|
1497
|
+
401:
|
|
1498
|
+
description: Invalid Auth Token
|
|
1499
|
+
"""
|
|
1500
|
+
if not EXTRA_MODULES['onelogin']:
|
|
1501
|
+
return "SAML not configured on the server side.", 200, [('X-Rucio-Auth-Token', '')]
|
|
1502
|
+
|
|
1503
|
+
saml_path = config_get('saml', 'config_path')
|
|
1504
|
+
req = prepare_saml_request(request.environ, dict(request.args.items(multi=False)))
|
|
1505
|
+
auth = OneLogin_Saml2_Auth(req, custom_base_path=saml_path)
|
|
1506
|
+
|
|
1507
|
+
auth.process_response()
|
|
1508
|
+
errors = auth.get_errors()
|
|
1509
|
+
if not errors:
|
|
1510
|
+
if auth.is_authenticated():
|
|
1511
|
+
response = Response()
|
|
1512
|
+
response.set_cookie('saml-nameid', value=auth.get_nameid(), path='/')
|
|
1513
|
+
return response
|
|
1514
|
+
return '', 200
|
|
1515
|
+
|
|
1516
|
+
|
|
1517
|
+
class Validate(ErrorHandlingMethodView):
|
|
1518
|
+
"""
|
|
1519
|
+
Validate a Rucio Auth Token.
|
|
1520
|
+
"""
|
|
1521
|
+
|
|
1522
|
+
def get_headers(self) -> Headers:
|
|
1523
|
+
headers = Headers()
|
|
1524
|
+
headers['Access-Control-Allow-Origin'] = request.environ.get('HTTP_ORIGIN') # type: ignore (value could be None)
|
|
1525
|
+
headers['Access-Control-Allow-Headers'] = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') # type: ignore (value could be None)
|
|
1526
|
+
headers['Access-Control-Allow-Methods'] = '*'
|
|
1527
|
+
headers['Access-Control-Allow-Credentials'] = 'true'
|
|
1528
|
+
headers['Access-Control-Expose-Headers'] = 'X-Rucio-Auth-Token'
|
|
1529
|
+
return headers
|
|
1530
|
+
|
|
1531
|
+
def options(self) -> 'ResponseReturnValue':
|
|
1532
|
+
"""
|
|
1533
|
+
---
|
|
1534
|
+
summary: Validate Allow cross-site scripting
|
|
1535
|
+
description: Validate Allow cross-site scripting. Explicit for Authentication.
|
|
1536
|
+
tags:
|
|
1537
|
+
- Auth
|
|
1538
|
+
responses:
|
|
1539
|
+
200:
|
|
1540
|
+
description: OK
|
|
1541
|
+
headers:
|
|
1542
|
+
Access-Control-Allow-Origin:
|
|
1543
|
+
schema:
|
|
1544
|
+
type: string
|
|
1545
|
+
Access-Control-Allow-Headers:
|
|
1546
|
+
schema:
|
|
1547
|
+
type: string
|
|
1548
|
+
Access-Control-Allow-Methods:
|
|
1549
|
+
schema:
|
|
1550
|
+
type: string
|
|
1551
|
+
enum: ['*']
|
|
1552
|
+
Access-Control-Allow-Credentials:
|
|
1553
|
+
schema:
|
|
1554
|
+
type: string
|
|
1555
|
+
enum: ['true']
|
|
1556
|
+
Access-Control-Expose-Headers:
|
|
1557
|
+
schema:
|
|
1558
|
+
type: string
|
|
1559
|
+
enum: ['X-Rucio-Auth-Token']
|
|
1560
|
+
404:
|
|
1561
|
+
description: Not found
|
|
1562
|
+
"""
|
|
1563
|
+
return '', 200, self.get_headers()
|
|
1564
|
+
|
|
1565
|
+
@check_accept_header_wrapper_flask(['application/octet-stream'])
|
|
1566
|
+
def get(self) -> 'ResponseReturnValue':
|
|
1567
|
+
"""
|
|
1568
|
+
---
|
|
1569
|
+
summary: Validate
|
|
1570
|
+
description: Validate a Rucio auth token.
|
|
1571
|
+
tags:
|
|
1572
|
+
- Auth
|
|
1573
|
+
parameters:
|
|
1574
|
+
- name: X-Rucio-Account
|
|
1575
|
+
in: header
|
|
1576
|
+
schema:
|
|
1577
|
+
type: string
|
|
1578
|
+
required: true
|
|
1579
|
+
responses:
|
|
1580
|
+
200:
|
|
1581
|
+
description: OK
|
|
1582
|
+
401:
|
|
1583
|
+
description: Cannot authenticate
|
|
1584
|
+
"""
|
|
1585
|
+
|
|
1586
|
+
headers = self.get_headers()
|
|
1587
|
+
|
|
1588
|
+
headers['Content-Type'] = 'application/octet-stream'
|
|
1589
|
+
headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
|
|
1590
|
+
headers.add('Cache-Control', 'post-check=0, pre-check=0')
|
|
1591
|
+
headers['Pragma'] = 'no-cache'
|
|
1592
|
+
|
|
1593
|
+
token = request.headers.get('X-Rucio-Auth-Token', default=None)
|
|
1594
|
+
|
|
1595
|
+
result = validate_auth_token(token)
|
|
1596
|
+
if not result:
|
|
1597
|
+
return generate_http_error_flask(
|
|
1598
|
+
status_code=401,
|
|
1599
|
+
exc=CannotAuthenticate.__name__,
|
|
1600
|
+
exc_msg='Cannot authenticate with given credentials',
|
|
1601
|
+
headers=headers
|
|
1602
|
+
)
|
|
1603
|
+
|
|
1604
|
+
return str(result), 200, headers
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
def blueprint() -> Blueprint:
|
|
1608
|
+
bp = Blueprint('auth', __name__, url_prefix='/auth')
|
|
1609
|
+
|
|
1610
|
+
user_pass_view = UserPass.as_view('user_pass')
|
|
1611
|
+
bp.add_url_rule('/userpass', view_func=user_pass_view, methods=['get', 'options'])
|
|
1612
|
+
gss_view = GSS.as_view('gss')
|
|
1613
|
+
bp.add_url_rule('/gss', view_func=gss_view, methods=['get', 'options'])
|
|
1614
|
+
x509_view = x509.as_view('x509')
|
|
1615
|
+
bp.add_url_rule('/x509', view_func=x509_view, methods=['get', 'options'])
|
|
1616
|
+
bp.add_url_rule('/x509/webui', view_func=x509_view, methods=['get', 'options'])
|
|
1617
|
+
bp.add_url_rule('/x509_proxy', view_func=x509_view, methods=['get', 'options'])
|
|
1618
|
+
ssh_view = SSH.as_view('ssh')
|
|
1619
|
+
bp.add_url_rule('/ssh', view_func=ssh_view, methods=['get', 'options'])
|
|
1620
|
+
ssh_challenge_token_view = SSHChallengeToken.as_view('ssh_challenge_token')
|
|
1621
|
+
bp.add_url_rule('/ssh_challenge_token', view_func=ssh_challenge_token_view, methods=['get', 'options'])
|
|
1622
|
+
saml_view = SAML.as_view('saml')
|
|
1623
|
+
bp.add_url_rule('/saml', view_func=saml_view, methods=['get', 'post', 'options'])
|
|
1624
|
+
validate_view = Validate.as_view('validate')
|
|
1625
|
+
bp.add_url_rule('/validate', view_func=validate_view, methods=['get', 'options'])
|
|
1626
|
+
oidc_view = OIDC.as_view('oidc_view')
|
|
1627
|
+
bp.add_url_rule('/oidc', view_func=oidc_view, methods=['get', 'options'])
|
|
1628
|
+
token_oidc_view = TokenOIDC.as_view('token_oidc_view')
|
|
1629
|
+
bp.add_url_rule('/oidc_token', view_func=token_oidc_view, methods=['get', 'options'])
|
|
1630
|
+
code_oidc_view = CodeOIDC.as_view('code_oidc_view')
|
|
1631
|
+
bp.add_url_rule('/oidc_code', view_func=code_oidc_view, methods=['get', 'options'])
|
|
1632
|
+
redirect_oidc_view = RedirectOIDC.as_view('redirect_oidc_view')
|
|
1633
|
+
bp.add_url_rule('/oidc_redirect', view_func=redirect_oidc_view, methods=['get', 'options'])
|
|
1634
|
+
refresh_oidc_view = RefreshOIDC.as_view('refresh_oidc_view')
|
|
1635
|
+
bp.add_url_rule('/oidc_refresh', view_func=refresh_oidc_view, methods=['get', 'options'])
|
|
1636
|
+
|
|
1637
|
+
return bp
|
|
1638
|
+
|
|
1639
|
+
|
|
1640
|
+
def make_doc() -> Flask:
|
|
1641
|
+
""" Only used for sphinx documentation """
|
|
1642
|
+
doc_app = Flask(__name__)
|
|
1643
|
+
doc_app.register_blueprint(blueprint())
|
|
1644
|
+
return doc_app
|