From 8e835d546b569302302678fd565644d4dd8c7288 Mon Sep 17 00:00:00 2001 From: John Bradley Date: Thu, 19 Nov 2020 11:19:29 -0500 Subject: [PATCH] Remove 2 hour download limit (#242) Adds code to refresh DDS token using OAuth token. Upgrades DukeDSClient requirement for Duke-GCB/DukeDSClient#314 changes. --- download_service/tests_utils.py | 46 ++++++++++++++++++++++++++------- download_service/utils.py | 35 +++++++++++++++++++++---- requirements.txt | 2 +- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/download_service/tests_utils.py b/download_service/tests_utils.py index d545080e..fdf81b1a 100644 --- a/download_service/tests_utils.py +++ b/download_service/tests_utils.py @@ -1,5 +1,5 @@ from django.test.testcases import TestCase -from download_service.utils import make_client +from download_service.utils import make_client, CustomOAuthDataServiceAuth from gcb_web_auth.models import DDSUserCredential, DDSEndpoint from django.contrib.auth.models import User from unittest.mock import patch, call, Mock @@ -30,17 +30,45 @@ def test_makes_client_when_from_existing_dds_user_credential(self, mock_client, self.assertEqual(mock_client.call_args, call(config=mock_get_dds_config_for_credentials.return_value)) self.assertEqual(client, mock_client.return_value) - @patch('download_service.utils.get_dds_token') - @patch('download_service.utils.make_auth_config') + @patch('download_service.utils.CustomOAuthDataServiceAuth') + @patch('download_service.utils.get_dds_config_for_credentials') + @patch('download_service.utils.get_oauth_token') + @patch('download_service.utils.get_default_dds_endpoint') @patch('download_service.utils.Client') - def test_makes_client_from_dds_token_when_no_dds_user_credential(self, mock_client, mock_make_auth_config, mock_get_dds_token): + def test_makes_client_from_dds_token_when_no_dds_user_credential(self, mock_client, mock_get_default_dds_endpoint, + mock_get_oauth_token, + mock_get_dds_config_for_credentials, + mock_custom_oauth_data_service_auth): + mock_get_default_dds_endpoint.return_value = Mock( + api_root='somehost', + openid_provider_service_id='12345' + ) self.assertEqual(DDSUserCredential.objects.count(), 0) - mock_key = Mock() - mock_get_dds_token.return_value.key = mock_key client = make_client(self.user) - self.assertEqual(mock_get_dds_token.call_args, call(self.user)) - self.assertEqual(mock_make_auth_config.call_args, call(mock_key)) - self.assertEqual(mock_client.call_args, call(config=mock_make_auth_config.return_value)) self.assertEqual(client, mock_client.return_value) + client_config = mock_client.call_args[1]['config'] + self.assertEqual(client_config.url, 'somehost') + create_data_service_auth = mock_client.call_args[1]['create_data_service_auth'] + data_service_auth = create_data_service_auth(None) + self.assertEqual(data_service_auth, mock_custom_oauth_data_service_auth.return_value) + mock_custom_oauth_data_service_auth.assert_called_with(self.user, '12345', None, set_status_msg=print) + + +class TestCustomOAuthDataServiceAuth(TestCase): + def setUp(self): + self.user = Mock() + self.authentication_service_id = '1234' + self.config = Mock() + @patch('download_service.utils.get_oauth_token') + def test_create_oauth_access_token(self, mock_get_oauth_token): + mock_get_oauth_token.return_value.token_dict = { + 'access_token': '5678' + } + auth = CustomOAuthDataServiceAuth(self.user, self.authentication_service_id, self.config) + token = auth.create_oauth_access_token() + self.assertEqual(token, '5678') + def test_get_authentication_service_id(self): + auth = CustomOAuthDataServiceAuth(self.user, self.authentication_service_id, self.config) + self.assertEqual(auth.get_authentication_service_id(), '1234') diff --git a/download_service/utils.py b/download_service/utils.py index 9b5f5264..3a023a69 100644 --- a/download_service/utils.py +++ b/download_service/utils.py @@ -1,16 +1,41 @@ from ddsc.sdk.client import Client +from ddsc.core.ddsapi import OAuthDataServiceAuth +from ddsc.config import Config from gcb_web_auth.models import DDSUserCredential -from gcb_web_auth.utils import get_dds_config_for_credentials, get_dds_token, make_auth_config +from gcb_web_auth.utils import get_dds_config_for_credentials, get_oauth_token, get_default_dds_endpoint def make_client(user): try: dds_credential = DDSUserCredential.objects.get(user=user) config = get_dds_config_for_credentials(dds_credential) + return Client(config=config) except DDSUserCredential.DoesNotExist: # No DDSUserCredential configured for this user, fall back to OAuth # May raise an OAuthConfigurationException - dds_token = get_dds_token(user) - config = make_auth_config(dds_token.key) - client = Client(config=config) - return client + endpoint = get_default_dds_endpoint() + config = Config() + config.update_properties({ + Config.URL: endpoint.api_root, + }) + authentication_service_id = endpoint.openid_provider_service_id + + def create_data_service_auth(config, set_status_msg=print): + return CustomOAuthDataServiceAuth(user, authentication_service_id, config, set_status_msg=set_status_msg) + + return Client(config=config, create_data_service_auth=create_data_service_auth) + + +class CustomOAuthDataServiceAuth(OAuthDataServiceAuth): + def __init__(self, user, authentication_service_id, config, set_status_msg=print): + super().__init__(config, set_status_msg) + self._auth = None + self.user = user + self.authentication_service_id = authentication_service_id + + def create_oauth_access_token(self): + oauth_token = get_oauth_token(self.user) + return oauth_token.token_dict.get('access_token') + + def get_authentication_service_id(self): + return self.authentication_service_id diff --git a/requirements.txt b/requirements.txt index 141da182..47a0a27f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ django-simple-history==1.9.1 django-sslserver==0.19 djangorestframework==3.9.1 drf-ember-backend==1.1 -DukeDSClient==3.0.0 +DukeDSClient==3.1.0 enum34==1.1.6 funcsigs==0.4 future==0.16.0