From 27a0b0f4e5da1524460a0c68c829e2a9dd58df46 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 6 Mar 2020 01:32:59 +0000 Subject: [PATCH 1/9] fix: only add IAM scope to credentials that can change scopes --- google/auth/impersonated_credentials.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/google/auth/impersonated_credentials.py b/google/auth/impersonated_credentials.py index bc7031e78..b86e25320 100644 --- a/google/auth/impersonated_credentials.py +++ b/google/auth/impersonated_credentials.py @@ -205,7 +205,13 @@ def __init__( super(Credentials, self).__init__() self._source_credentials = copy.copy(source_credentials) - self._source_credentials._scopes = _IAM_SCOPE + # Service account source credentials must have the _IAM_SCOPE + # added to refresh correctly. User credentials cannot have + # their original scopes modified. + try: + self._source_credentials = self._source_credentials.with_scopes(_IAM_SCOPE) + except AttributeError: + pass self._target_principal = target_principal self._target_scopes = target_scopes self._delegates = delegates From 1a78d82fb212425b13e5a40bab47c5b63fca3ada Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 6 Mar 2020 20:38:35 +0000 Subject: [PATCH 2/9] test: add systest for impersonated creds --- system_tests/conftest.py | 9 ++ system_tests/noxfile.py | 10 +- system_tests/secrets.tar.enc | Bin 10323 -> 10323 bytes system_tests/test_impersonated_credentials.py | 104 ++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 system_tests/test_impersonated_credentials.py diff --git a/system_tests/conftest.py b/system_tests/conftest.py index 189300707..02de84664 100644 --- a/system_tests/conftest.py +++ b/system_tests/conftest.py @@ -25,6 +25,9 @@ HERE = os.path.dirname(__file__) DATA_DIR = os.path.join(HERE, "data") +IMPERSONATED_SERVICE_ACCOUNT_FILE = os.path.join( + DATA_DIR, "impersonated_service_account.json" +) SERVICE_ACCOUNT_FILE = os.path.join(DATA_DIR, "service_account.json") AUTHORIZED_USER_FILE = os.path.join(DATA_DIR, "authorized_user.json") URLLIB3_HTTP = urllib3.PoolManager(retries=False) @@ -39,6 +42,12 @@ def service_account_file(): yield SERVICE_ACCOUNT_FILE +@pytest.fixture +def impersonated_service_account_file(): + """The full path to a valid service account key file.""" + yield IMPERSONATED_SERVICE_ACCOUNT_FILE + + @pytest.fixture def authorized_user_file(): """The full path to a valid authorized user file.""" diff --git a/system_tests/noxfile.py b/system_tests/noxfile.py index e37049e52..811063223 100644 --- a/system_tests/noxfile.py +++ b/system_tests/noxfile.py @@ -170,7 +170,8 @@ def configure_cloud_sdk(session, application_default_credentials, project=False) # Test sesssions TEST_DEPENDENCIES = ["pytest", "requests"] -PYTHON_VERSIONS=['2.7', '3.7'] +PYTHON_VERSIONS = ["2.7", "3.7"] + @nox.session(python=PYTHON_VERSIONS) def service_account(session): @@ -186,6 +187,13 @@ def oauth2_credentials(session): session.run("pytest", "test_oauth2_credentials.py") +@nox.session(python=PYTHON_VERSIONS) +def impersonated_credentials(session): + session.install(*TEST_DEPENDENCIES) + session.install(LIBRARY_DIR) + session.run("pytest", "test_impersonated_credentials.py") + + @nox.session(python=PYTHON_VERSIONS) def default_explicit_service_account(session): session.env[EXPLICIT_CREDENTIALS_ENV] = SERVICE_ACCOUNT_FILE diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index 1106f8a9154dada1eda23da37373f78eeb683bd9..dcb43ebde486f2e5afe3b08babd9a70e08acf267 100644 GIT binary patch literal 10323 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
Z9MR#0sZe#l85O)h#mFvR)-?n81puA2G`pVn?1A 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 literal 10323 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 ln#y2j*5ExtA`Jil diff --git a/system_tests/test_impersonated_credentials.py b/system_tests/test_impersonated_credentials.py new file mode 100644 index 000000000..089d29135 --- /dev/null +++ b/system_tests/test_impersonated_credentials.py @@ -0,0 +1,104 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import pytest + +import google.oauth2.credentials +from google.oauth2 import service_account +import google.auth.impersonated_credentials +from google.auth import _helpers + + +GOOGLE_OAUTH2_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token" + + +@pytest.fixture +def service_account_credentials(service_account_file): + yield service_account.Credentials.from_service_account_file(service_account_file) + + +@pytest.fixture +def impersonated_service_account_credentials(impersonated_service_account_file): + yield service_account.Credentials.from_service_account_file( + impersonated_service_account_file + ) + + +def test_refresh_with_user_credentials_as_source( + authorized_user_file, + impersonated_service_account_credentials, + http_request, + token_info, +): + with open(authorized_user_file, "r") as fh: + info = json.load(fh) + + source_credentials = google.oauth2.credentials.Credentials( + None, + refresh_token=info["refresh_token"], + token_uri=GOOGLE_OAUTH2_TOKEN_ENDPOINT, + client_id=info["client_id"], + client_secret=info["client_secret"], + # The source credential needs this scope for the generateAccessToken request + # The user must also have `Service Account Token Creator` on the project + # that owns the impersonated service account. + # See https://cloud.google.com/iam/docs/creating-short-lived-service-account-credentials + scopes=["https://www.googleapis.com/auth/cloud-platform"], + ) + + source_credentials.refresh(http_request) + + target_scopes = [ + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/analytics", + ] + target_credentials = google.auth.impersonated_credentials.Credentials( + source_credentials=source_credentials, + target_principal=impersonated_service_account_credentials.service_account_email, + target_scopes=target_scopes, + lifetime=100, + ) + + target_credentials.refresh(http_request) + assert target_credentials.token + + +def test_refresh_with_service_account_credentials_as_source( + http_request, + service_account_credentials, + impersonated_service_account_credentials, + token_info, +): + # the specific scopes here are unimportant, but a SA + # needs scopes + source_credentials = service_account_credentials.with_scopes(["email"]) + + source_credentials.refresh(http_request) + + assert source_credentials.token + + # use the user credential as a donor credential + target_scopes = [ + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/analytics", + ] + target_credentials = google.auth.impersonated_credentials.Credentials( + source_credentials=source_credentials, + target_principal=impersonated_service_account_credentials.service_account_email, + target_scopes=target_scopes, + ) + + target_credentials.refresh(http_request) + assert target_credentials.token From f61a9a6688c6cf403c6c33ed3668b5e2af95939a Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 6 Mar 2020 21:01:01 +0000 Subject: [PATCH 3/9] test: update unit tests --- system_tests/test_impersonated_credentials.py | 5 ----- tests/test_impersonated_credentials.py | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/system_tests/test_impersonated_credentials.py b/system_tests/test_impersonated_credentials.py index 089d29135..6689e8943 100644 --- a/system_tests/test_impersonated_credentials.py +++ b/system_tests/test_impersonated_credentials.py @@ -81,15 +81,10 @@ def test_refresh_with_service_account_credentials_as_source( impersonated_service_account_credentials, token_info, ): - # the specific scopes here are unimportant, but a SA - # needs scopes source_credentials = service_account_credentials.with_scopes(["email"]) - source_credentials.refresh(http_request) - assert source_credentials.token - # use the user credential as a donor credential target_scopes = [ "https://www.googleapis.com/auth/devstorage.read_only", "https://www.googleapis.com/auth/analytics", diff --git a/tests/test_impersonated_credentials.py b/tests/test_impersonated_credentials.py index 1cfcc7c6c..34b85b308 100644 --- a/tests/test_impersonated_credentials.py +++ b/tests/test_impersonated_credentials.py @@ -27,6 +27,7 @@ from google.auth import transport from google.auth.impersonated_credentials import Credentials from google.oauth2 import service_account +from google.oauth2 import credentials DATA_DIR = os.path.join(os.path.dirname(__file__), "", "data") @@ -102,17 +103,30 @@ class TestImpersonatedCredentials(object): SOURCE_CREDENTIALS = service_account.Credentials( SIGNER, SERVICE_ACCOUNT_EMAIL, TOKEN_URI ) + USER_SOURCE_CREDENTIALS = credentials.Credentials(token="ABCDE") - def make_credentials(self, lifetime=LIFETIME, target_principal=TARGET_PRINCIPAL): + def make_credentials( + self, + source_credentials=SOURCE_CREDENTIALS, + lifetime=LIFETIME, + target_principal=TARGET_PRINCIPAL, + ): return Credentials( - source_credentials=self.SOURCE_CREDENTIALS, + source_credentials=source_credentials, target_principal=target_principal, target_scopes=self.TARGET_SCOPES, delegates=self.DELEGATES, lifetime=lifetime, ) + def test_make_from_user_credentials(self): + credentials = self.make_credentials( + source_credentials=self.USER_SOURCE_CREDENTIALS + ) + assert not credentials.valid + assert credentials.expired + def test_default_state(self): credentials = self.make_credentials() assert not credentials.valid From 8dff1c6465bc284ac5c4533bfd49139c70423124 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 6 Mar 2020 21:10:52 +0000 Subject: [PATCH 4/9] chore: fix lint --- tests/test_impersonated_credentials.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_impersonated_credentials.py b/tests/test_impersonated_credentials.py index 34b85b308..31075ca84 100644 --- a/tests/test_impersonated_credentials.py +++ b/tests/test_impersonated_credentials.py @@ -26,8 +26,8 @@ from google.auth import impersonated_credentials from google.auth import transport from google.auth.impersonated_credentials import Credentials -from google.oauth2 import service_account from google.oauth2 import credentials +from google.oauth2 import service_account DATA_DIR = os.path.join(os.path.dirname(__file__), "", "data") From 5a318f6d7aba163e873791edc0fca7ee72435804 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Fri, 6 Mar 2020 22:17:07 +0000 Subject: [PATCH 5/9] build: update secrets --- system_tests/secrets.tar.enc | Bin 10323 -> 10323 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index dcb43ebde486f2e5afe3b08babd9a70e08acf267..ee933891cc95819e29843d308323468676be1334 100644 GIT binary patch literal 10323 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 literal 10323 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
Z9MR#0sZe#l85O)h#mFvR)-?n81puA2G`pVn?1A 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 From ff0aed96412bf3565a30301cec9c83fcf9eafc91 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Sat, 7 Mar 2020 00:06:10 +0000 Subject: [PATCH 6/9] docs: update contributing.rst with impersonated creds --- CONTRIBUTING.rst | 48 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index f95b1f1dc..d49158843 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -43,21 +43,27 @@ To run a single session, specify it with ``nox -s``:: $ nox -f system_tests/noxfile.py -s service_account + +Project and Credentials Setup +------------------------------- + +Enable the IAM Service Account Credentials API on the project. + To run system tests locally, you will need to set up a data directory :: $ mkdir system_tests/data -Add a service account file and authorized user file to the data directory. -Your directory should look like this :: +Your directory should look like this. Follow the instructions below for creating each file. :: system_tests/ data/ - service_account.json authorized_user.json + impersonated_service_account.json + service_account.json -The files must be named exactly ``service_account.json`` -and ``authorized_user.json``. See `Creating and Managing Service Account Keys`_ for how to -obtain a service account. + +``authorized_user.json`` +~~~~~~~~~~~~~~~~~~~~~~~~ Use the `gcloud CLI`_ to get an authorized user file :: @@ -69,11 +75,37 @@ You will see something like:: Copy the contents of the file to ``authorized_user.json``. -.. _Creating and Managing Service Account Keys: https://cloud.google.com/iam/docs/creating-managing-service-account-keys +Open the IAM page of the Google Cloud Console. Grant the user the `Service Account Token Creator Role`. +This will allow the user to impersonate service accounts on the project. + .. _gcloud CLI: https://cloud.google.com/sdk/gcloud/ + +``service_account.json`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +Follow `Creating and Managing Service Account Keys`_ to create a service account. + +Copy the credentials file to ``service_account.json``. + +Grant the account associated with ``service_account.json`` the following roles. + +- App Engine Admin (for App Engine tests) +- Service Account Token Creator (for impersonated credentials tests) +- Pub/Sub Viewer (for gRPC tests) +- Storage Object Viewer (for impersonated credentials tests) + +``impersonated_service_account.json`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Follow `Creating and Managing Service Account Keys`_ to create a service account. + +Copy the credentials file to ``impersonated_service_account.json``. + +.. _Creating and Managing Service Account Keys: https://cloud.google.com/iam/docs/creating-managing-service-account-keys + App Engine System Tests -^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~ To run the App Engine tests, you wil need to deploy a default App Engine service. If you already have a default service associated with your project, you can skip this step. From 3144b0a59d6cf5ef1e8a6a9e815aed5745801ee7 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim Date: Sat, 7 Mar 2020 00:25:03 +0000 Subject: [PATCH 7/9] docs: fix formatting --- CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d49158843..bd92ca8d4 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -71,7 +71,7 @@ Use the `gcloud CLI`_ to get an authorized user file :: You will see something like:: - Credentials saved to file: [/usr/local/home/.config/gcloud/application_default_credentials.json]``` + Credentials saved to file: [/usr/local/home/.config/gcloud/application_default_credentials.json] Copy the contents of the file to ``authorized_user.json``. From 6c35e85124bc7ed7923c2a1091b3fede1de8159e Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Fri, 13 Mar 2020 12:56:03 -0700 Subject: [PATCH 8/9] fix: use if credentials.Scoped instead of try/except --- google/auth/impersonated_credentials.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google/auth/impersonated_credentials.py b/google/auth/impersonated_credentials.py index b86e25320..c69e1ddf9 100644 --- a/google/auth/impersonated_credentials.py +++ b/google/auth/impersonated_credentials.py @@ -208,7 +208,7 @@ def __init__( # Service account source credentials must have the _IAM_SCOPE # added to refresh correctly. User credentials cannot have # their original scopes modified. - try: + if isinstance(self._source_credentials, credentials.Scoped): self._source_credentials = self._source_credentials.with_scopes(_IAM_SCOPE) except AttributeError: pass From 61064aae3ab16b6b7e6f808675a221daa6763009 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Fri, 13 Mar 2020 13:02:36 -0700 Subject: [PATCH 9/9] fix: remove except caluse --- google/auth/impersonated_credentials.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/google/auth/impersonated_credentials.py b/google/auth/impersonated_credentials.py index c69e1ddf9..1bb6b8268 100644 --- a/google/auth/impersonated_credentials.py +++ b/google/auth/impersonated_credentials.py @@ -210,8 +210,6 @@ def __init__( # their original scopes modified. if isinstance(self._source_credentials, credentials.Scoped): self._source_credentials = self._source_credentials.with_scopes(_IAM_SCOPE) - except AttributeError: - pass self._target_principal = target_principal self._target_scopes = target_scopes self._delegates = delegates