diff --git a/certbot-dns-google/certbot_dns_google/_internal/dns_google.py b/certbot-dns-google/certbot_dns_google/_internal/dns_google.py index a3fe7c0e7..3128b3703 100644 --- a/certbot-dns-google/certbot_dns_google/_internal/dns_google.py +++ b/certbot-dns-google/certbot_dns_google/_internal/dns_google.py @@ -5,7 +5,7 @@ import logging from googleapiclient import discovery from googleapiclient import errors as googleapiclient_errors import httplib2 -from google.oauth2 import ServiceAccountCredentials +from google.oauth2.service_account import Credentials import zope.interface from certbot import errors @@ -82,7 +82,7 @@ class _GoogleClient: scopes = ['https://www.googleapis.com/auth/ndev.clouddns.readwrite'] if account_json is not None: try: - credentials = ServiceAccountCredentials.from_json_keyfile_name(account_json, scopes) + credentials = Credentials.from_json_keyfile_name(account_json, scopes) with open(account_json) as account: self.project_id = json.load(account)['project_id'] except Exception as e: diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index fd3bb4559..2d629f649 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -8,7 +8,7 @@ version = '1.17.0.dev0' install_requires = [ 'google-api-python-client>=1.5.5', - 'oauth2client>=4.0', + 'google-auth>=1.32.1', 'setuptools>=39.0.1', 'zope.interface', # already a dependency of google-api-python-client, but added for consistency diff --git a/certbot-dns-google/tests/dns_google_test.py b/certbot-dns-google/tests/dns_google_test.py index 83fa29b41..cba98c03b 100644 --- a/certbot-dns-google/tests/dns_google_test.py +++ b/certbot-dns-google/tests/dns_google_test.py @@ -107,7 +107,7 @@ class GoogleClientTest(unittest.TestCase): return client, mock_changes @mock.patch('googleapiclient.discovery.build') - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google._GoogleClient.get_project_id') def test_client_without_credentials(self, get_project_id_mock, credential_mock, unused_discovery_mock): @@ -116,18 +116,18 @@ class GoogleClientTest(unittest.TestCase): self.assertFalse(credential_mock.called) self.assertTrue(get_project_id_mock.called) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') def test_client_bad_credentials_file(self, credential_mock): - credential_mock.side_effect = ValueError('Some exception buried in oauth2client') + credential_mock.side_effect = ValueError('Some exception buried in google-auth') with self.assertRaises(errors.PluginError) as cm: self._setUp_client_with_mock([]) self.assertEqual( str(cm.exception), "Error parsing credentials file '/not/a/real/path.json': " - "Some exception buried in oauth2client" + "Some exception buried in google-auth" ) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) @mock.patch('certbot_dns_google._internal.dns_google._GoogleClient.get_project_id') @@ -155,7 +155,7 @@ class GoogleClientTest(unittest.TestCase): managedZone=self.zone, project=PROJECT_ID) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_add_txt_record_and_poll(self, unused_credential_mock): @@ -173,7 +173,7 @@ class GoogleClientTest(unittest.TestCase): managedZone=self.zone, project=PROJECT_ID) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_add_txt_record_delete_old(self, unused_credential_mock): @@ -189,7 +189,7 @@ class GoogleClientTest(unittest.TestCase): self.assertTrue("sample-txt-contents" in deletions["rrdatas"]) self.assertEqual(self.record_ttl, deletions["ttl"]) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_add_txt_record_delete_old_ttl_case(self, unused_credential_mock): @@ -206,7 +206,7 @@ class GoogleClientTest(unittest.TestCase): self.assertTrue("sample-txt-contents" in deletions["rrdatas"]) self.assertEqual(custom_ttl, deletions["ttl"]) #otherwise HTTP 412 - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_add_txt_record_noop(self, unused_credential_mock): @@ -216,7 +216,7 @@ class GoogleClientTest(unittest.TestCase): "example-txt-contents", self.record_ttl) self.assertFalse(changes.create.called) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_add_txt_record_error_during_zone_lookup(self, unused_credential_mock): @@ -225,7 +225,7 @@ class GoogleClientTest(unittest.TestCase): self.assertRaises(errors.PluginError, client.add_txt_record, DOMAIN, self.record_name, self.record_content, self.record_ttl) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_add_txt_record_zone_not_found(self, unused_credential_mock): @@ -235,7 +235,7 @@ class GoogleClientTest(unittest.TestCase): self.assertRaises(errors.PluginError, client.add_txt_record, DOMAIN, self.record_name, self.record_content, self.record_ttl) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_add_txt_record_error_during_add(self, unused_credential_mock): @@ -245,7 +245,7 @@ class GoogleClientTest(unittest.TestCase): self.assertRaises(errors.PluginError, client.add_txt_record, DOMAIN, self.record_name, self.record_content, self.record_ttl) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_del_txt_record_multi_rrdatas(self, unused_credential_mock): @@ -284,7 +284,7 @@ class GoogleClientTest(unittest.TestCase): managedZone=self.zone, project=PROJECT_ID) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_del_txt_record_single_rrdatas(self, unused_credential_mock): @@ -313,7 +313,7 @@ class GoogleClientTest(unittest.TestCase): managedZone=self.zone, project=PROJECT_ID) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_del_txt_record_error_during_zone_lookup(self, unused_credential_mock): @@ -321,7 +321,7 @@ class GoogleClientTest(unittest.TestCase): client.del_txt_record(DOMAIN, self.record_name, self.record_content, self.record_ttl) changes.create.assert_not_called() - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_del_txt_record_zone_not_found(self, unused_credential_mock): @@ -330,7 +330,7 @@ class GoogleClientTest(unittest.TestCase): client.del_txt_record(DOMAIN, self.record_name, self.record_content, self.record_ttl) changes.create.assert_not_called() - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_del_txt_record_error_during_delete(self, unused_credential_mock): @@ -339,7 +339,7 @@ class GoogleClientTest(unittest.TestCase): client.del_txt_record(DOMAIN, self.record_name, self.record_content, self.record_ttl) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_get_existing_found(self, unused_credential_mock): @@ -350,7 +350,7 @@ class GoogleClientTest(unittest.TestCase): self.assertEqual(found["rrdatas"], ["\"example-txt-contents\""]) self.assertEqual(found["ttl"], 60) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_get_existing_not_found(self, unused_credential_mock): @@ -359,7 +359,7 @@ class GoogleClientTest(unittest.TestCase): not_found = client.get_existing_txt_rrset(self.zone, "nonexistent.tld") self.assertEqual(not_found, None) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_get_existing_with_error(self, unused_credential_mock): @@ -369,7 +369,7 @@ class GoogleClientTest(unittest.TestCase): found = client.get_existing_txt_rrset(self.zone, "_acme-challenge.example.org") self.assertEqual(found, None) - @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + @mock.patch('googleoauth2.service_account.Credentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) def test_get_existing_fallback(self, unused_credential_mock): diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 7d82559b6..c65ba8a30 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -509,7 +509,7 @@ More details about these changes can be found on our GitHub repo. * `--dry-run` now requests fresh authorizations every time, fixing the issue where it was prone to falsely reporting success. * Updated certbot-dns-google to depend on newer versions of - google-api-python-client and oauth2client. + google-api-python-client and google-auth. * The OS detection logic again uses distro library for Linux OSes * certbot.plugins.common.TLSSNI01 has been deprecated and will be removed in a future release. diff --git a/tools/dev_constraints.txt b/tools/dev_constraints.txt index 50b52222d..bfe7efb22 100644 --- a/tools/dev_constraints.txt +++ b/tools/dev_constraints.txt @@ -63,7 +63,7 @@ msrest==0.6.18 mypy==0.812 mypy-extensions==0.4.3 ndg-httpsclient==0.3.2 -oauth2client==4.0.0 +google-auth==1.32.1 oauthlib==3.1.0 packaging==19.2 paramiko==2.4.2 diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt index c31c5d4f8..ccd505f10 100644 --- a/tools/oldest_constraints.txt +++ b/tools/oldest_constraints.txt @@ -24,7 +24,7 @@ pyasn1==0.1.9 pycparser==2.14 pyRFC3339==1.0 python-augeas==0.5.0 -oauth2client==4.0.0 +google-auth==1.32.1 urllib3==1.10.2 zope.component==4.1.0 zope.event==4.0.3 diff --git a/tools/requirements.txt b/tools/requirements.txt index 7190c9c81..1de680f0b 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -92,7 +92,7 @@ msgpack==1.0.2; python_version >= "3.6" and python_full_version < "3.0.0" and py msrest==0.6.21; python_version >= "3.6" mypy-extensions==0.4.3; python_version >= "3.6" mypy==0.812; python_version >= "3.5" -oauth2client==4.1.3; python_version >= "3.6" +google-auth==1.32.1; python_version >= "3.6" oauthlib==3.1.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" packaging==20.9; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_full_version >= "3.6.0" and python_version >= "3.6" paramiko==2.7.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_version >= "3.6"