From cf672c2c749d9a2c33408ec92d5d8d679dcf80d6 Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Wed, 26 Oct 2016 09:41:00 -0700 Subject: [PATCH] Add oauth2.credentials system tests (#56) * Add script to generate user auth tokens. * Add oauth2.credentials system tests --- .travis.yml | 2 +- scripts/obtain_user_auth.py | 65 ++++++++++++++++++++++++ system_tests/conftest.py | 6 +++ system_tests/secrets.tar.enc | Bin 11808 -> 18464 bytes system_tests/test_oauth2_credentials.py | 43 ++++++++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 scripts/obtain_user_auth.py create mode 100644 system_tests/test_oauth2_credentials.py diff --git a/.travis.yml b/.travis.yml index a56fb349b..315f7c14c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,4 +38,4 @@ deploy: repo: GoogleCloudPlatform/google-auth-library-python env: global: - secure: KjV9daSNZsM3/jth2d87MEu4irHtwNwUcdIUVglz3QrIX7fAcbFqHu/2Ux3yGC+iPJd5/i2jZWWz9F6iyuKdhyMySz2WaBsbySmCs1pREcRYWcK5GL49yPb3ZOZucprD/n0VIer0+eublQeBQRMxNdxfJEs6tgkHxTeiOJ3mHaeLa/nE1PXW9Ih6fgS5NT/7CE7SO0fw1th9ZdLdRyo3a9fphDWqiGlt0oRURRnoJ7qctLYAZ7uXDn3c6oXJ/dZsio6Hjx16dPNjn0dpkpCBFYN3D7wXD02Ysm/7u+SGl2FjqA76FmmnJsqJ5Nog1QV4v7YpJdTtpfXBOuXAov4Fz9xHVssX4dYZkW5JKsfVFFIilo1vQbO4mBjYw58/gJswJygD5smwO2GawAfm62mGpdx4mFv2lwZoqJbLg1qcuI/qc8DqPrc3Y1nVNu3oGdMcts5q2IeuZgI1yzdb/Qz0gtkkIDtPzoyBlAZE9hsylBI7SdoP7VpmP+vIW21yC3GpE3TajbVD8p53c70fV4YH0LSX6pFF6RBuSFLwarG+WYtPTEy2k3d0ATMdH0gBaf19FJ04RTwsbYZPqAy328Dl3RLioZffm8BHAeKzuVsocrIiiHjJM6PqtL4II0UfbiKahxLcI7t1cGTWVhUtqrnZKZwJrbLYGd08aBvioTne/Nk= + secure: s6GdhJklftl8w/9WoETwLtvtKL4ledPA/TuBuqCXQxSuYWaPuTdRVcvoejGkHJpp7i/7v2T/0etYl+5koyskKm5+QZZweaaL7MAyjPGp+hmIaIlWQRz6w481NOf3i9uSmoQycssT0mNmwScNIqo+igbA2y14mr/e9aBuOcxNNzNzFQp2vaRMEju6q7xZMjYdcudUWL48vq9CoNa3X2ZArpqjkApR/TfYlG7glOj43NxuVDN4z9wIyUjaMHBfPgEhjaOaRyEFgEYITRwX1qDoXqcZdTVIq4Cn0uCH+Mvrz6Y+oUJGTJqH1k7N/DhzbSN9lJnVYaQW/yuvGHiGAwbb6Tcxiq2UqqhA9MfbPpmstDECs46v9Z3BT252KvYEQY7Q1v9g2gFhHvFGWISUxs80rnnPhEYfa11JoLvj2t8cowkE4pvj4OH32Eoyvc5H07hW3F5xpuF7Jt7N09TNZkUrpmiRJEhfrVNgjsrWO77/q5h8mXGd+9vYmz++yzKu+63x8x1MpeigGCG73Dpu9Otm5eydOZfpJ39ZfZWUb7G2JahgHaGweM9dmnpJtzHQgijmHjjfAx9jgnQ8IQz9nkFmyMI8H7HouwalnrJtpSSbvMqOQ0kiZhMzdBKH5pD3tjLgSlgA0pKelBwlooY6jGlj4LrtbDAxa6cZyXiFoqWpT1w= diff --git a/scripts/obtain_user_auth.py b/scripts/obtain_user_auth.py new file mode 100644 index 000000000..fd2afd878 --- /dev/null +++ b/scripts/obtain_user_auth.py @@ -0,0 +1,65 @@ +# Copyright 2016 Google Inc. +# +# 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. + +"""This program obtains a set of user credentials. + +These credentials are needed to run the system test for OAuth2 credentials. +It's expected that a developer will run this program manually once to obtain +a refresh token. It's highly recommended to use a Google account created +specifically created for testing. +""" + +import json +import os + +from oauth2client import client +from oauth2client import tools + +HERE = os.path.dirname(__file__) +CLIENT_SECRETS_PATH = os.path.abspath(os.path.join( + HERE, '..', 'system_tests', 'data', 'client_secret.json')) +AUTHORIZED_USER_PATH = os.path.abspath(os.path.join( + HERE, '..', 'system_tests', 'data', 'authorized_user.json')) +SCOPES = ['email', 'profile'] + + +class NullStorage(client.Storage): + """Null storage implementation to prevent oauth2client from failing + on storage.put.""" + def locked_put(self, credentials): + pass + + +def main(): + flow = client.flow_from_clientsecrets(CLIENT_SECRETS_PATH, SCOPES) + + print('Starting credentials flow...') + credentials = tools.run_flow(flow, NullStorage()) + + # Save the credentials in the same format as the Cloud SDK's authorized + # user file. + data = { + 'type': 'authorized_user', + 'client_id': flow.client_id, + 'client_secret': flow.client_secret, + 'refresh_token': credentials.refresh_token + } + + with open(AUTHORIZED_USER_PATH, 'w') as fh: + json.dump(data, fh, indent=4) + + print('Created {}.'.format(AUTHORIZED_USER_PATH)) + +if __name__ == '__main__': + main() diff --git a/system_tests/conftest.py b/system_tests/conftest.py index 066f80531..ebbae4842 100644 --- a/system_tests/conftest.py +++ b/system_tests/conftest.py @@ -33,6 +33,12 @@ def service_account_file(): yield os.path.join(DATA_DIR, 'service_account.json') +@pytest.fixture +def authorized_user_file(): + """The full path to a valid authorized user file.""" + yield os.path.join(DATA_DIR, 'authorized_user.json') + + @pytest.fixture def request(): """A transport.request object.""" diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index bbe290fc27fb0556b6b4032b0a5e1d78482471dc..e61707e5aac970b93b67a68c63927aa862875efc 100644 GIT binary patch literal 18464 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 T?j`+JzSN(>jVck@!DaJx-Xsx3 literal 11808 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 OdGC0ssEfhEg0G~Cf#2Q$ diff --git a/system_tests/test_oauth2_credentials.py b/system_tests/test_oauth2_credentials.py new file mode 100644 index 000000000..e268519b5 --- /dev/null +++ b/system_tests/test_oauth2_credentials.py @@ -0,0 +1,43 @@ +# Copyright 2016 Google Inc. +# +# 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 + +from google.auth import _helpers +import google.oauth2.credentials + +GOOGLE_OAUTH2_TOKEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token' + + +def test_refresh(authorized_user_file, request, token_info): + with open(authorized_user_file, 'r') as fh: + info = json.load(fh) + + credentials = google.oauth2.credentials.Credentials( + None, # No access token, must be refreshed. + refresh_token=info['refresh_token'], + token_uri=GOOGLE_OAUTH2_TOKEN_ENDPOINT, + client_id=info['client_id'], + client_secret=info['client_secret']) + + credentials.refresh(request) + + assert credentials.token + + info = token_info(credentials.token) + + info_scopes = _helpers.string_to_scopes(info['scope']) + assert set(info_scopes) == set([ + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile'])