| Index: client/third_party/google/oauth2/service_account.py
 | 
| diff --git a/client/third_party/google/oauth2/service_account.py b/client/third_party/google/oauth2/service_account.py
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..f8a27bfa7ba7170e553aac74888a48f5b9c09f32
 | 
| --- /dev/null
 | 
| +++ b/client/third_party/google/oauth2/service_account.py
 | 
| @@ -0,0 +1,326 @@
 | 
| +# 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.
 | 
| +
 | 
| +"""Service Accounts: JSON Web Token (JWT) Profile for OAuth 2.0
 | 
| +
 | 
| +This module implements the JWT Profile for OAuth 2.0 Authorization Grants
 | 
| +as defined by `RFC 7523`_ with particular support for how this RFC is
 | 
| +implemented in Google's infrastructure. Google refers to these credentials
 | 
| +as *Service Accounts*.
 | 
| +
 | 
| +Service accounts are used for server-to-server communication, such as
 | 
| +interactions between a web application server and a Google service. The
 | 
| +service account belongs to your application instead of to an individual end
 | 
| +user. In contrast to other OAuth 2.0 profiles, no users are involved and your
 | 
| +application "acts" as the service account.
 | 
| +
 | 
| +Typically an application uses a service account when the application uses
 | 
| +Google APIs to work with its own data rather than a user's data. For example,
 | 
| +an application that uses Google Cloud Datastore for data persistence would use
 | 
| +a service account to authenticate its calls to the Google Cloud Datastore API.
 | 
| +However, an application that needs to access a user's Drive documents would
 | 
| +use the normal OAuth 2.0 profile.
 | 
| +
 | 
| +Additionally, Google Apps domain administrators can grant service accounts
 | 
| +`domain-wide delegation`_ authority to access user data on behalf of users in
 | 
| +the domain.
 | 
| +
 | 
| +This profile uses a JWT to acquire an OAuth 2.0 access token. The JWT is used
 | 
| +in place of the usual authorization token returned during the standard
 | 
| +OAuth 2.0 Authorization Code grant. The JWT is only used for this purpose, as
 | 
| +the acquired access token is used as the bearer token when making requests
 | 
| +using these credentials.
 | 
| +
 | 
| +This profile differs from normal OAuth 2.0 profile because no user consent
 | 
| +step is required. The use of the private key allows this profile to assert
 | 
| +identity directly.
 | 
| +
 | 
| +This profile also differs from the :mod:`google.auth.jwt` authentication
 | 
| +because the JWT credentials use the JWT directly as the bearer token. This
 | 
| +profile instead only uses the JWT to obtain an OAuth 2.0 access token. The
 | 
| +obtained OAuth 2.0 access token is used as the bearer token.
 | 
| +
 | 
| +Domain-wide delegation
 | 
| +----------------------
 | 
| +
 | 
| +Domain-wide delegation allows a service account to access user data on
 | 
| +behalf of any user in a Google Apps domain without consent from the user.
 | 
| +For example, an application that uses the Google Calendar API to add events to
 | 
| +the calendars of all users in a Google Apps domain would use a service account
 | 
| +to access the Google Calendar API on behalf of users.
 | 
| +
 | 
| +The Google Apps administrator must explicitly authorize the service account to
 | 
| +do this. This authorization step is referred to as "delegating domain-wide
 | 
| +authority" to a service account.
 | 
| +
 | 
| +You can use domain-wise delegation by creating a set of credentials with a
 | 
| +specific subject using :meth:`~Credentials.with_subject`.
 | 
| +
 | 
| +.. _RFC 7523: https://tools.ietf.org/html/rfc7523
 | 
| +"""
 | 
| +
 | 
| +import copy
 | 
| +import datetime
 | 
| +
 | 
| +from google.auth import _helpers
 | 
| +from google.auth import _service_account_info
 | 
| +from google.auth import credentials
 | 
| +from google.auth import jwt
 | 
| +from google.oauth2 import _client
 | 
| +
 | 
| +_DEFAULT_TOKEN_LIFETIME_SECS = 3600  # 1 hour in sections
 | 
| +
 | 
| +
 | 
| +class Credentials(credentials.Signing,
 | 
| +                  credentials.Scoped,
 | 
| +                  credentials.Credentials):
 | 
| +    """Service account credentials
 | 
| +
 | 
| +    Usually, you'll create these credentials with one of the helper
 | 
| +    constructors. To create credentials using a Google service account
 | 
| +    private key JSON file::
 | 
| +
 | 
| +        credentials = service_account.Credentials.from_service_account_file(
 | 
| +            'service-account.json')
 | 
| +
 | 
| +    Or if you already have the service account file loaded::
 | 
| +
 | 
| +        service_account_info = json.load(open('service_account.json'))
 | 
| +        credentials = service_account.Credentials.from_service_account_info(
 | 
| +            service_account_info)
 | 
| +
 | 
| +    Both helper methods pass on arguments to the constructor, so you can
 | 
| +    specify additional scopes and a subject if necessary::
 | 
| +
 | 
| +        credentials = service_account.Credentials.from_service_account_file(
 | 
| +            'service-account.json',
 | 
| +            scopes=['email'],
 | 
| +            subject='user@example.com')
 | 
| +
 | 
| +    The credentials are considered immutable. If you want to modify the scopes
 | 
| +    or the subject used for delegation, use :meth:`with_scopes` or
 | 
| +    :meth:`with_subject`::
 | 
| +
 | 
| +        scoped_credentials = credentials.with_scopes(['email'])
 | 
| +        delegated_credentials = credentials.with_subject(subject)
 | 
| +    """
 | 
| +
 | 
| +    def __init__(self, signer, service_account_email, token_uri, scopes=None,
 | 
| +                 subject=None, additional_claims=None):
 | 
| +        """
 | 
| +        Args:
 | 
| +            signer (google.auth.crypt.Signer): The signer used to sign JWTs.
 | 
| +            service_account_email (str): The service account's email.
 | 
| +            scopes (Sequence[str]): Scopes to request during the authorization
 | 
| +                grant.
 | 
| +            token_uri (str): The OAuth 2.0 Token URI.
 | 
| +            subject (str): For domain-wide delegation, the email address of the
 | 
| +                user to for which to request delegated access.
 | 
| +            additional_claims (Mapping[str, str]): Any additional claims for
 | 
| +                the JWT assertion used in the authorization grant.
 | 
| +
 | 
| +        .. note:: Typically one of the helper constructors
 | 
| +            :meth:`from_service_account_file` or
 | 
| +            :meth:`from_service_account_info` are used instead of calling the
 | 
| +            constructor directly.
 | 
| +        """
 | 
| +        super(Credentials, self).__init__()
 | 
| +
 | 
| +        self._scopes = scopes
 | 
| +        self._signer = signer
 | 
| +        self._service_account_email = service_account_email
 | 
| +        self._subject = subject
 | 
| +        self._token_uri = token_uri
 | 
| +
 | 
| +        if additional_claims is not None:
 | 
| +            self._additional_claims = additional_claims
 | 
| +        else:
 | 
| +            self._additional_claims = {}
 | 
| +
 | 
| +    @classmethod
 | 
| +    def _from_signer_and_info(cls, signer, info, **kwargs):
 | 
| +        """Creates a Credentials instance from a signer and service account
 | 
| +        info.
 | 
| +
 | 
| +        Args:
 | 
| +            signer (google.auth.crypt.Signer): The signer used to sign JWTs.
 | 
| +            info (Mapping[str, str]): The service account info.
 | 
| +            kwargs: Additional arguments to pass to the constructor.
 | 
| +
 | 
| +        Returns:
 | 
| +            google.auth.jwt.Credentials: The constructed credentials.
 | 
| +
 | 
| +        Raises:
 | 
| +            ValueError: If the info is not in the expected format.
 | 
| +        """
 | 
| +        return cls(
 | 
| +            signer,
 | 
| +            service_account_email=info['client_email'],
 | 
| +            token_uri=info['token_uri'], **kwargs)
 | 
| +
 | 
| +    @classmethod
 | 
| +    def from_service_account_info(cls, info, **kwargs):
 | 
| +        """Creates a Credentials instance from parsed service account info.
 | 
| +
 | 
| +        Args:
 | 
| +            info (Mapping[str, str]): The service account info in Google
 | 
| +                format.
 | 
| +            kwargs: Additional arguments to pass to the constructor.
 | 
| +
 | 
| +        Returns:
 | 
| +            google.auth.service_account.Credentials: The constructed
 | 
| +                credentials.
 | 
| +
 | 
| +        Raises:
 | 
| +            ValueError: If the info is not in the expected format.
 | 
| +        """
 | 
| +        signer = _service_account_info.from_dict(
 | 
| +            info, require=['client_email', 'token_uri'])
 | 
| +        return cls._from_signer_and_info(signer, info, **kwargs)
 | 
| +
 | 
| +    @classmethod
 | 
| +    def from_service_account_file(cls, filename, **kwargs):
 | 
| +        """Creates a Credentials instance from a service account json file.
 | 
| +
 | 
| +        Args:
 | 
| +            filename (str): The path to the service account json file.
 | 
| +            kwargs: Additional arguments to pass to the constructor.
 | 
| +
 | 
| +        Returns:
 | 
| +            google.auth.service_account.Credentials: The constructed
 | 
| +                credentials.
 | 
| +        """
 | 
| +        info, signer = _service_account_info.from_filename(
 | 
| +            filename, require=['client_email', 'token_uri'])
 | 
| +        return cls._from_signer_and_info(signer, info, **kwargs)
 | 
| +
 | 
| +    @property
 | 
| +    def service_account_email(self):
 | 
| +        """The service account email."""
 | 
| +        return self._service_account_email
 | 
| +
 | 
| +    @property
 | 
| +    def requires_scopes(self):
 | 
| +        """Checks if the credentials requires scopes.
 | 
| +
 | 
| +        Returns:
 | 
| +            bool: True if there are no scopes set otherwise False.
 | 
| +        """
 | 
| +        return True if not self._scopes else False
 | 
| +
 | 
| +    @_helpers.copy_docstring(credentials.Scoped)
 | 
| +    def with_scopes(self, scopes):
 | 
| +        return Credentials(
 | 
| +            self._signer,
 | 
| +            service_account_email=self._service_account_email,
 | 
| +            scopes=scopes,
 | 
| +            token_uri=self._token_uri,
 | 
| +            subject=self._subject,
 | 
| +            additional_claims=self._additional_claims.copy())
 | 
| +
 | 
| +    def with_subject(self, subject):
 | 
| +        """Create a copy of these credentials with the specified subject.
 | 
| +
 | 
| +        Args:
 | 
| +            subject (str): The subject claim.
 | 
| +
 | 
| +        Returns:
 | 
| +            google.auth.service_account.Credentials: A new credentials
 | 
| +                instance.
 | 
| +        """
 | 
| +        return Credentials(
 | 
| +            self._signer,
 | 
| +            service_account_email=self._service_account_email,
 | 
| +            scopes=self._scopes,
 | 
| +            token_uri=self._token_uri,
 | 
| +            subject=subject,
 | 
| +            additional_claims=self._additional_claims.copy())
 | 
| +
 | 
| +    def with_claims(self, additional_claims):
 | 
| +        """Returns a copy of these credentials with modified claims.
 | 
| +
 | 
| +        Args:
 | 
| +            additional_claims (Mapping[str, str]): Any additional claims for
 | 
| +                the JWT payload. This will be merged with the current
 | 
| +                additional claims.
 | 
| +
 | 
| +        Returns:
 | 
| +            google.auth.service_account.Credentials: A new credentials
 | 
| +                instance.
 | 
| +        """
 | 
| +        new_additional_claims = copy.deepcopy(self._additional_claims)
 | 
| +        new_additional_claims.update(additional_claims or {})
 | 
| +
 | 
| +        return Credentials(
 | 
| +            self._signer,
 | 
| +            service_account_email=self._service_account_email,
 | 
| +            scopes=self._scopes,
 | 
| +            token_uri=self._token_uri,
 | 
| +            subject=self._subject,
 | 
| +            additional_claims=new_additional_claims)
 | 
| +
 | 
| +    def _make_authorization_grant_assertion(self):
 | 
| +        """Create the OAuth 2.0 assertion.
 | 
| +
 | 
| +        This assertion is used during the OAuth 2.0 grant to acquire an
 | 
| +        access token.
 | 
| +
 | 
| +        Returns:
 | 
| +            bytes: The authorization grant assertion.
 | 
| +        """
 | 
| +        now = _helpers.utcnow()
 | 
| +        lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
 | 
| +        expiry = now + lifetime
 | 
| +
 | 
| +        payload = {
 | 
| +            'iat': _helpers.datetime_to_secs(now),
 | 
| +            'exp': _helpers.datetime_to_secs(expiry),
 | 
| +            # The issuer must be the service account email.
 | 
| +            'iss': self._service_account_email,
 | 
| +            # The audience must be the auth token endpoint's URI
 | 
| +            'aud': self._token_uri,
 | 
| +            'scope': _helpers.scopes_to_string(self._scopes or ())
 | 
| +        }
 | 
| +
 | 
| +        payload.update(self._additional_claims)
 | 
| +
 | 
| +        # The subject can be a user email for domain-wide delegation.
 | 
| +        if self._subject:
 | 
| +            payload.setdefault('sub', self._subject)
 | 
| +
 | 
| +        token = jwt.encode(self._signer, payload)
 | 
| +
 | 
| +        return token
 | 
| +
 | 
| +    @_helpers.copy_docstring(credentials.Credentials)
 | 
| +    def refresh(self, request):
 | 
| +        assertion = self._make_authorization_grant_assertion()
 | 
| +        access_token, expiry, _ = _client.jwt_grant(
 | 
| +            request, self._token_uri, assertion)
 | 
| +        self.token = access_token
 | 
| +        self.expiry = expiry
 | 
| +
 | 
| +    @_helpers.copy_docstring(credentials.Signing)
 | 
| +    def sign_bytes(self, message):
 | 
| +        return self._signer.sign(message)
 | 
| +
 | 
| +    @property
 | 
| +    @_helpers.copy_docstring(credentials.Signing)
 | 
| +    def signer(self):
 | 
| +        return self._signer
 | 
| +
 | 
| +    @property
 | 
| +    @_helpers.copy_docstring(credentials.Signing)
 | 
| +    def signer_email(self):
 | 
| +        return self._service_account_email
 | 
| 
 |