From 806daab06ddf0fe51a9a2e08a34c07b855173e33 Mon Sep 17 00:00:00 2001 From: tcezard Date: Thu, 18 Jan 2024 10:39:31 +0000 Subject: [PATCH] Allow Webin to be used with username and password from the command line or environment variables --- bin/eva-sub-cli.py | 10 ++++++++-- eva_sub_cli/auth.py | 46 +++++++++++++++++++++++++------------------ eva_sub_cli/submit.py | 4 ++-- tests/test_auth.py | 31 +++++++++++++++++++++++++---- 4 files changed, 64 insertions(+), 27 deletions(-) diff --git a/bin/eva-sub-cli.py b/bin/eva-sub-cli.py index e03684b..6f20326 100755 --- a/bin/eva-sub-cli.py +++ b/bin/eva-sub-cli.py @@ -41,6 +41,10 @@ def get_vcf_files(mapping_file): help="Json file that describe the project, analysis, samples and files") group.add_argument("--metadata_xlsx", help="Excel spreadsheet that describe the project, analysis, samples and files") + group.add_argument("--username", + help="Username used for connecting to the ENA webin account") + group.add_argument("--password", + help="Password used for connecting to the ENA webin account") args = argparser.parse_args() @@ -57,7 +61,8 @@ def get_vcf_files(mapping_file): args.task = SUBMIT else: # if validation is passed, upload files without validating again - with StudySubmitter(args.submission_dir, vcf_files, metadata_file, submission_config=sub_config) as submitter: + with StudySubmitter(args.submission_dir, vcf_files, metadata_file, submission_config=sub_config, + username=args.username, password=args.password) as submitter: submitter.upload_submission() if args.task == VALIDATE or args.task == SUBMIT: @@ -68,5 +73,6 @@ def get_vcf_files(mapping_file): validator.update_config_with_validation_result() if args.task == SUBMIT: - with StudySubmitter(args.submission_dir, vcf_files, metadata_file, submission_config=sub_config) as submitter: + with StudySubmitter(args.submission_dir, vcf_files, metadata_file, submission_config=sub_config, + username=args.username, password=args.password) as submitter: submitter.submit() diff --git a/eva_sub_cli/auth.py b/eva_sub_cli/auth.py index 32b85a8..ee0f35c 100644 --- a/eva_sub_cli/auth.py +++ b/eva_sub_cli/auth.py @@ -1,4 +1,5 @@ import json +import os from functools import cached_property from getpass import getpass @@ -9,12 +10,13 @@ from eva_sub_cli import LSRI_CLIENT_ID ENA_AUTH_URL = "https://www.ebi.ac.uk/ena/submit/webin/auth/token" -LSRI_AUTH_URL = "http://www.ebi.ac.uk/eva/v1/submission/auth/lsri" -DEVICE_AUTHORISATION_URL ="https://login.elixir-czech.org/oidc/devicecode" +LSRI_AUTH_URL = "https://www.ebi.ac.uk/eva/v1/submission/auth/lsri" +DEVICE_AUTHORISATION_URL = "https://login.elixir-czech.org/oidc/devicecode" class LSRIAuth(AppLogger): - def __init__(self, client_id=LSRI_CLIENT_ID, device_authorization_url=DEVICE_AUTHORISATION_URL, auth_url=LSRI_AUTH_URL): + def __init__(self, client_id=LSRI_CLIENT_ID, device_authorization_url=DEVICE_AUTHORISATION_URL, + auth_url=LSRI_AUTH_URL): self.client_id = client_id self.device_authorization_url = device_authorization_url self.auth_url = auth_url @@ -51,12 +53,14 @@ def token(self): class WebinAuth(AppLogger): - def __init__(self, ena_auth_url=ENA_AUTH_URL): + def __init__(self, ena_auth_url=ENA_AUTH_URL, username=None, password=None): self.ena_auth_url = ena_auth_url + self.cmd_line_username = username + self.cmd_line_password = password @cached_property def token(self): - self.info("Proceeding with ENA Webin authentication...") + self.info("ENA Webin authentication") username, password = self._get_webin_username_password() headers = {"accept": "*/*", "Content-Type": "application/json"} data = {"authRealms": ["ENA"], "username": username, "password": password} @@ -69,6 +73,22 @@ def token(self): raise ResponseError('Webin Authentication Error') def _get_webin_username_password(self): + username = self.cmd_line_username + password = self.cmd_line_password + if not username or not password: + self.debug('No username and password provided on the command line') + username, password = self._get_webin_username_password_from_env() + if not username or not password: + self.debug('No username and password provided in environment variables') + username, password = self._get_webin_username_password_from_stdin() + return username, password + + def _get_webin_username_password_from_env(self): + username = os.environ.get('ENAWEBINACCOUNT') + password = os.environ.get('ENAWEBINPASSWORD') + return username, password + + def _get_webin_username_password_from_stdin(self): username = input("Enter your ENA Webin username: ") password = getpass("Enter your ENA Webin password: ") return username, password @@ -78,21 +98,9 @@ def _get_webin_username_password(self): auth = None -def get_auth(): +def get_auth(username=None, password=None): global auth if auth: return auth - print("Choose an authentication method:") - print("1. ENA Webin") - print("2. LSRI") - - choice = int(input("Enter the number corresponding to your choice: ")) - - if choice == 1: - auth = WebinAuth() - elif choice == 2: - auth = LSRIAuth() - else: - print("Invalid choice! Try again!") - get_auth() + auth = WebinAuth(username, password) return auth diff --git a/eva_sub_cli/submit.py b/eva_sub_cli/submit.py index eb49919..e652253 100644 --- a/eva_sub_cli/submit.py +++ b/eva_sub_cli/submit.py @@ -18,8 +18,8 @@ class StudySubmitter(AppLogger): def __init__(self, submission_dir, vcf_files, metadata_file, submission_initiate_url=SUBMISSION_INITIATE_URL, - submission_config: WritableConfig = None): - self.auth = get_auth() + submission_config: WritableConfig = None, username=None, password=None): + self.auth = get_auth(username, password) self.submission_initiate_url = submission_initiate_url self.submission_dir = submission_dir self.vcf_files = vcf_files diff --git a/tests/test_auth.py b/tests/test_auth.py index d0ca671..3cabf70 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,4 +1,5 @@ import json +import os import unittest from unittest.mock import MagicMock, patch @@ -7,10 +8,9 @@ class TestWebinAuth(unittest.TestCase): - def setUp(self): - self.auth = WebinAuth() def test_webin_auth(self): + auth = WebinAuth() # Mock the response for ENA authentication mock_auth_response = MagicMock() mock_auth_response.status_code = 200 @@ -19,16 +19,39 @@ def test_webin_auth(self): # Call the submit_with_webin_auth method with patch.object(WebinAuth, '_get_webin_username_password', return_value=("mock_username", "mock_password")), \ patch("eva_sub_cli.auth.requests.post", return_value=mock_auth_response) as mock_post: - token = self.auth.token + token = auth.token # Check if the ENA_AUTH_URL was called with the correct parameters mock_post.assert_any_call( - self.auth.ena_auth_url, + auth.ena_auth_url, headers={"accept": "*/*", "Content-Type": "application/json"}, data=json.dumps({"authRealms": ["ENA"], "username": "mock_username", "password": "mock_password"}), ) assert token == 'mock_webin_token' + def test_get_webin_username_password_cmd_line(self): + auth = WebinAuth(username='username', password='password') + username, password = auth._get_webin_username_password() + assert username == 'username' + assert password == 'password' + + def test_get_webin_username_password_environ(self): + os.environ['ENAWEBINACCOUNT'] = 'username' + os.environ['ENAWEBINPASSWORD'] = 'password' + auth = WebinAuth() + username, password = auth._get_webin_username_password() + assert username == 'username' + assert password == 'password' + + def test_get_webin_username_password_stdin(self): + auth = WebinAuth() + with patch("builtins.input", return_value="username"), \ + patch("eva_sub_cli.auth.getpass", return_value="password"): + username, password = auth._get_webin_username_password() + assert username == 'username' + assert password == 'password' + + class TestLSRIAuth(unittest.TestCase): def setUp(self):