Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding scope to credentials in Connection constructors. #840

Merged
merged 1 commit into from
May 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 19 additions & 18 deletions gcloud/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import httplib2

from gcloud.credentials import get_credentials
from gcloud.exceptions import make_exception


Expand Down Expand Up @@ -94,6 +93,25 @@ def http(self):
self._http = self._credentials.authorize(self._http)
return self._http

@staticmethod
def _create_scoped_credentials(credentials, scope):
"""Create a scoped set of credentials if it is required.

:type credentials: :class:`oauth2client.client.OAuth2Credentials` or
:class:`NoneType`
:param credentials: The OAuth2 Credentials to add a scope to.

:type scope: list of URLs
:param scope: the effective service auth scopes for the connection.

:rtype: :class:`oauth2client.client.OAuth2Credentials` or
:class:`NoneType`
:returns: A new credentials object that has a scope added (if needed).
"""
if credentials and credentials.create_scoped_required():

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

credentials = credentials.create_scoped(scope)
return credentials


class JSONConnection(Connection):
"""A connection to a Google JSON-based API.
Expand Down Expand Up @@ -320,20 +338,3 @@ def api_request(self, method, path, query_params=None,
return json.loads(content)

return content


def get_scoped_connection(klass, scopes):
"""Create a scoped connection to GCloud.

:type klass: subclass of :class:`gcloud.connection.Connection`
:param klass: the specific ``Connection`` class to instantiate.

:type scopes: list of URLs
:param scopes: the effective service auth scopes for the connection.

:rtype: instance of ``klass``
:returns: A connection defined with the proper credentials.
"""
implicit_credentials = get_credentials()
scoped_credentials = implicit_credentials.create_scoped(scopes)
return klass(credentials=scoped_credentials)
2 changes: 1 addition & 1 deletion gcloud/datastore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
when race conditions may occur.
"""

from gcloud.datastore._implicit_environ import SCOPE
from gcloud.datastore._implicit_environ import get_connection
from gcloud.datastore._implicit_environ import get_default_connection
from gcloud.datastore._implicit_environ import get_default_dataset_id
Expand All @@ -59,6 +58,7 @@
from gcloud.datastore.api import get
from gcloud.datastore.api import put
from gcloud.datastore.batch import Batch
from gcloud.datastore.connection import SCOPE
from gcloud.datastore.connection import Connection
from gcloud.datastore.dataset import Dataset
from gcloud.datastore.entity import Entity
Expand Down
9 changes: 3 additions & 6 deletions gcloud/datastore/_implicit_environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,10 @@
from gcloud._helpers import _app_engine_id
from gcloud._helpers import _compute_engine_id
from gcloud._helpers import _lazy_property_deco
from gcloud.connection import get_scoped_connection
from gcloud.credentials import get_credentials
from gcloud.datastore.connection import Connection


SCOPE = ('https://www.googleapis.com/auth/datastore',
'https://www.googleapis.com/auth/userinfo.email')
"""The scopes required for authenticating as a Cloud Datastore consumer."""

_DATASET_ENV_VAR_NAME = 'GCLOUD_DATASET_ID'
_GCD_DATASET_ENV_VAR_NAME = 'DATASTORE_DATASET'

Expand Down Expand Up @@ -126,7 +122,8 @@ def get_connection():
:rtype: :class:`gcloud.datastore.connection.Connection`
:returns: A connection defined with the proper credentials.
"""
return get_scoped_connection(Connection, SCOPE)
credentials = get_credentials()

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

return Connection(credentials=credentials)


def set_default_connection(connection=None):
Expand Down
5 changes: 5 additions & 0 deletions gcloud/datastore/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
from gcloud.datastore import _datastore_v1_pb2 as datastore_pb


SCOPE = ('https://www.googleapis.com/auth/datastore',
'https://www.googleapis.com/auth/userinfo.email')
"""The scopes required for authenticating as a Cloud Datastore consumer."""

_GCD_HOST_ENV_VAR_NAME = 'DATASTORE_HOST'


Expand All @@ -46,6 +50,7 @@ class Connection(connection.Connection):
"""A template for the URL of a particular API call."""

def __init__(self, credentials=None, http=None, api_base_url=None):
credentials = self._create_scoped_credentials(credentials, SCOPE)
super(Connection, self).__init__(credentials=credentials, http=http)
if api_base_url is None:
api_base_url = os.getenv(_GCD_HOST_ENV_VAR_NAME,
Expand Down
2 changes: 1 addition & 1 deletion gcloud/datastore/test__implicit_environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ def _callFUT(self):

def test_it(self):
from gcloud import credentials
from gcloud.datastore._implicit_environ import SCOPE
from gcloud.datastore.connection import SCOPE
from gcloud.datastore.connection import Connection
from gcloud.test_credentials import _Client
from gcloud._testing import _Monkey
Expand Down
11 changes: 10 additions & 1 deletion gcloud/datastore/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ def test_ctor_defaults(self):
self.assertEqual(conn.credentials, None)

def test_ctor_explicit(self):
creds = object()
class Creds(object):

def create_scoped_required(self):
return False

creds = Creds()
conn = self._makeOne(creds)
self.assertTrue(conn.credentials is creds)

Expand All @@ -122,6 +127,10 @@ class Creds(object):
def authorize(self, http):
self._called_with = http
return authorized

def create_scoped_required(self):
return False

creds = Creds()
conn = self._makeOne(creds)
self.assertTrue(conn.http is authorized)
Expand Down
10 changes: 4 additions & 6 deletions gcloud/pubsub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,17 @@

from gcloud._helpers import get_default_project
from gcloud._helpers import set_default_project
from gcloud.connection import get_scoped_connection
from gcloud.credentials import get_credentials
from gcloud.pubsub import _implicit_environ
from gcloud.pubsub._implicit_environ import get_default_connection
from gcloud.pubsub.api import list_subscriptions
from gcloud.pubsub.api import list_topics
from gcloud.pubsub.connection import SCOPE
from gcloud.pubsub.connection import Connection
from gcloud.pubsub.subscription import Subscription
from gcloud.pubsub.topic import Topic


SCOPE = ('https://www.googleapis.com/auth/pubsub',
'https://www.googleapis.com/auth/cloud-platform')


def set_default_connection(connection=None):
"""Set default connection either explicitly or implicitly as fall-back.

Expand Down Expand Up @@ -78,4 +75,5 @@ def get_connection():
:rtype: :class:`gcloud.pubsub.connection.Connection`
:returns: A connection defined with the proper credentials.
"""
return get_scoped_connection(Connection, SCOPE)
credentials = get_credentials()

This comment was marked as spam.

This comment was marked as spam.

return Connection(credentials=credentials)
9 changes: 9 additions & 0 deletions gcloud/pubsub/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
from gcloud import connection as base_connection


SCOPE = ('https://www.googleapis.com/auth/pubsub',
'https://www.googleapis.com/auth/cloud-platform')

This comment was marked as spam.

"""The scopes required for authenticating as a Cloud Pub/Sub consumer."""


class Connection(base_connection.JSONConnection):
"""A connection to Google Cloud Pubsub via the JSON REST API."""

Expand All @@ -28,3 +33,7 @@ class Connection(base_connection.JSONConnection):

API_URL_TEMPLATE = '{api_base_url}/{api_version}{path}'
"""A template for the URL of a particular API call."""

def __init__(self, credentials=None, http=None):
credentials = self._create_scoped_credentials(credentials, SCOPE)
super(Connection, self).__init__(credentials=credentials, http=http)
2 changes: 1 addition & 1 deletion gcloud/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
from gcloud._helpers import get_default_project
from gcloud._helpers import set_default_project
from gcloud.storage import _implicit_environ
from gcloud.storage._implicit_environ import SCOPE
from gcloud.storage._implicit_environ import get_connection
from gcloud.storage._implicit_environ import get_default_bucket
from gcloud.storage._implicit_environ import get_default_connection
Expand All @@ -55,6 +54,7 @@
from gcloud.storage.batch import Batch
from gcloud.storage.blob import Blob
from gcloud.storage.bucket import Bucket
from gcloud.storage.connection import SCOPE
from gcloud.storage.connection import Connection


Expand Down
10 changes: 3 additions & 7 deletions gcloud/storage/_implicit_environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,10 @@


from gcloud._helpers import _lazy_property_deco
from gcloud.connection import get_scoped_connection
from gcloud.credentials import get_credentials
from gcloud.storage.connection import Connection


SCOPE = ('https://www.googleapis.com/auth/devstorage.full_control',
'https://www.googleapis.com/auth/devstorage.read_only',
'https://www.googleapis.com/auth/devstorage.read_write')


class _DefaultsContainer(object):
"""Container for defaults.

Expand Down Expand Up @@ -83,7 +78,8 @@ def get_connection():
:rtype: :class:`gcloud.storage.connection.Connection`
:returns: A connection defined with the proper credentials.
"""
return get_scoped_connection(Connection, SCOPE)
credentials = get_credentials()
return Connection(credentials=credentials)


def set_default_connection(connection=None):
Expand Down
10 changes: 10 additions & 0 deletions gcloud/storage/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
from gcloud import connection as base_connection


SCOPE = ('https://www.googleapis.com/auth/devstorage.full_control',
'https://www.googleapis.com/auth/devstorage.read_only',
'https://www.googleapis.com/auth/devstorage.read_write')

This comment was marked as spam.

"""The scopes required for authenticating as a Cloud Storage consumer."""


class Connection(base_connection.JSONConnection):
"""A connection to Google Cloud Storage via the JSON REST API."""

Expand All @@ -28,3 +34,7 @@ class Connection(base_connection.JSONConnection):

API_URL_TEMPLATE = '{api_base_url}/storage/{api_version}{path}'
"""A template for the URL of a particular API call."""

def __init__(self, credentials=None, http=None):
credentials = self._create_scoped_credentials(credentials, SCOPE)
super(Connection, self).__init__(credentials=credentials, http=http)
28 changes: 0 additions & 28 deletions gcloud/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,31 +372,3 @@ def __init__(self, headers, content):
def request(self, **kw):
self._called_with = kw
return self._response, self._content


class Test_get_scoped_connection(unittest2.TestCase):

def _callFUT(self, klass, scopes):
from gcloud.connection import get_scoped_connection
return get_scoped_connection(klass, scopes)

def test_it(self):
from gcloud import credentials
from gcloud.test_credentials import _Client
from gcloud._testing import _Monkey

class _Connection(object):
def __init__(self, credentials):
self._credentials = credentials

SCOPES = ('https://www.googleapis.com/auth/example',
'https://www.googleapis.com/auth/userinfo.email')

client = _Client()
with _Monkey(credentials, client=client):
found = self._callFUT(_Connection, SCOPES)

self.assertTrue(isinstance(found, _Connection))
self.assertTrue(found._credentials is client._signed)
self.assertEqual(found._credentials._scopes, SCOPES)
self.assertTrue(client._get_app_default_called)
3 changes: 3 additions & 0 deletions gcloud/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,9 @@ def create_scoped(self, scopes):
self._scopes = scopes
return self

def create_scoped_required(self):
return True


class _Client(object):
def __init__(self):
Expand Down