<commit_before># Copyright 2014 Google Inc. All rights reserved.
#
# 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.

"""An OAuth 2.0 client.

Tools for interacting with OAuth 2.0 protected resources.
"""

import collections
import copy
import datetime
import json
import logging
import os
import shutil
import socket
import sys
import tempfile

import six
from six.moves import http_client
from six.moves import urllib

import oauth2client
from oauth2client import _helpers
from oauth2client import _pkce
from oauth2client import clientsecrets
from oauth2client import transport


HAS_OPENSSL = False
HAS_CRYPTO = False
try:
    from oauth2client import crypt
    HAS_CRYPTO = True
    HAS_OPENSSL = crypt.OpenSSLVerifier is not None
except ImportError:  # pragma: NO COVER
    pass


logger = logging.getLogger(__name__)

# Expiry is stored in RFC3339 UTC format
EXPIRY_FORMAT = '%Y-%m-%dT%H:%M:%SZ'

# Which certs to use to validate id_tokens received.
ID_TOKEN_VERIFICATION_CERTS = 'https://www.googleapis.com/oauth2/v1/certs'
# This symbol previously had a typo in the name; we keep the old name
# around for now, but will remove it in the future.
ID_TOKEN_VERIFICATON_CERTS = ID_TOKEN_VERIFICATION_CERTS

# Constant to use for the out of band OAuth 2.0 flow.
OOB_CALLBACK_URN = 'urn:ietf:wg:oauth:2.0:oob'

# The value representing user credentials.
AUTHORIZED_USER = 'authorized_user'

# The value representing service account credentials.
SERVICE_ACCOUNT = 'service_account'

# The environment variable pointing the file with local
# Application Default Credentials.
GOOGLE_APPLICATION_CREDENTIALS = 'GOOGLE_APPLICATION_CREDENTIALS'
# The ~/.config subdirectory containing gcloud credentials. Intended
# to be swapped out in tests.
_CLOUDSDK_CONFIG_DIRECTORY = 'gcloud'
# The environment variable name which can replace ~/.config if set.
_CLOUDSDK_CONFIG_ENV_VAR = 'CLOUDSDK_CONFIG'

# The error message we show users when we can't find the Application
# Default Credentials.
ADC_HELP_MSG = (
    'The Application Default Credentials are not available. They are '
    'available if running in Google Compute Engine. Otherwise, the '
    'environment variable ' +
    GOOGLE_APPLICATION_CREDENTIALS +
    ' must be defined pointing to a file defining the credentials. See '
    'https://developers.google.com/accounts/docs/'
    'application-default-credentials for more information.')

_WELL_KNOWN_CREDENTIALS_FILE = 'application_default_credentials.json'

# The access token along with the seconds in which it expires.
AccessTokenInfo = collections.namedtuple(
    'AccessTokenInfo', ['access_token', 'expires_in'])

DEFAULT_ENV_NAME = 'UNKNOWN'

# If set to True _get_environment avoid GCE check (_detect_gce_environment)
NO_GCE_CHECK = os.getenv('NO_GCE_CHECK', 'False')

# Timeout in seconds to wait for the GCE metadata server when detecting the
# GCE environment.
try:
    GCE_METADATA_TIMEOUT = int(os.getenv('GCE_METADATA_TIMEOUT', 3))
except ValueError:  # pragma: NO COVER
    GCE_METADATA_TIMEOUT = 3

_SERVER_SOFTWARE = 'SERVER_SOFTWARE'
_GCE_METADATA_URI = 'http://169.254.169.254'
_METADATA_FLAVOR_HEADER = 'metadata-flavor'  # lowercase header
_DESIRED_METADATA_FLAVOR = 'Google'
_GCE_HEADERS = {_METADATA_FLAVOR_HEADER: _DESIRED_METADATA_FLAVOR}

# Expose utcnow() at module level to allow for
# easier testing (by replacing with a stub).
_UTCNOW = datetime.datetime.utcnow

# NOTE: These names were previously defined in this module but have been
#       moved into `oauth2client.transport`,
clean_headers = transport.clean_headers
MemoryCache = transport.MemoryCache
REFRESH_STATUS_CODES = transport.REFRESH_STATUS_CODES


class SETTINGS(object):
    """Settings namespace for globally defined values."""
    env_name = None


class Error(Exception):
    """Base error for this module."""


class FlowExchangeError(Error):
    """Error trying to exchange an authorization grant for an access token."""


class AccessTokenRefreshError(Error):
    """Error trying to refresh an expired access token."""


class HttpAccessTokenRefreshError(AccessTokenRefreshError):
    """Error (with HTTP status) trying to refresh an expired access token."""
    def __init__(self, *args, **kwargs):
        super(HttpAccessTokenRefreshError, self).__init__(*args)
        self.status = kwargs.get('status')


class TokenRevokeError(Error):
    """Error trying to revoke a token."""


class UnknownClientSecretsFlowError(Error):
    """The client secrets file called for an unknown type of OAuth 2.0 flow."""


class AccessTokenCredentialsError(Error):
    """Having only the access_token means no refresh is possible."""


class VerifyJwtTokenError(Error):
    """Could not retrieve certificates for validation."""


class NonAsciiHeaderError(Error):
    """Header names and values must be ASCII strings."""


class ApplicationDefaultCredentialsError(Error):
    """Error retrieving the Application Default Credentials."""


class OAuth2DeviceCodeError(Error):
    """Error trying to retrieve a device code."""


class CryptoUnavailableError(Error, NotImplementedError):
    """Raised when a crypto library is required, but none is available."""


def _parse_expiry(expiry):
    if expiry and isinstance(expiry, datetime.datetime):
        return expiry.strftime(EXPIRY_FORMAT)
    else:
        return None


class Credentials(object):
    """Base class for all Credentials objects.

    Subclasses must define an authorize() method that applies the credentials
    to an HTTP transport.

    Subclasses must also specify a classmethod named 'from_json' that takes a
    JSON string as input and returns an instantiated Credentials object.
    """

    NON_SERIALIZED_MEMBERS = frozenset(['store'])

    def authorize(self, http):
        """Take an httplib2.Http instance (or equivalent) and authorizes it.

        Authorizes it for the set of credentials, usually by replacing
        http.request() with a method that adds in the appropriate headers and
        then delegates to the original Http.request() method.

        Args:
            http: httplib2.Http, an http object to be used to make the refresh
                  request.
        """
        raise NotImplementedError

    def refresh(self, http):
        """Forces a refresh of the access_token.

        Args:
            http: httplib2.Http, an http object to be used to make the refresh
                  request.
        """
        raise NotImplementedError

    def revoke(self, http):
        """Revokes a refresh_token and makes the credentials void.

        Args:
            http: httplib2.Http, an http object to be used to make the revoke
                  request.
        """
        raise NotImplementedError

    def apply(self, headers):
        """Add the authorization to the headers.

        Args:
            headers: dict, the headers to add the Authorization header to.
        """
        raise NotImplementedError

    def _to_json(self, strip, to_serialize=None):
        """Utility function that creates JSON repr. of a Credentials object.

        Args:
            strip: array, An array of names of members to exclude from the
                   JSON.
            to_serialize: dict, (Optional) The properties for this object
                          that will be serialized. This allows callers to
                          modify before serializing.

        Returns:
            string, a JSON representation of this instance, suitable to pass to
            from_json().
        """
        curr_type = self.__class__
        if to_serialize is None:
            to_serialize = copy.copy(self.__dict__)
        else:
            # Assumes it is a str->str dictionary, so we don't deep copy.
            to_serialize = copy.copy(to_serialize)
        for member in strip:
            if member in to_serialize:
                del to_serialize[member]
        to_serialize['token_expiry'] = _parse_expiry(
            to_serialize.get('token_expiry'))
        # Add in information we will need later to reconstitute this instance.
        to_serialize['_class'] = curr_type.__name__
        to_serialize['_module'] = curr_type.__module__
        for key, val in to_serialize.items():
            if isinstance(val, bytes):
                to_serialize[key] = val.decode('utf-8')
            if isinstance(val, set):
                to_serialize[key] = list(val)
        return json.dumps(to_serialize)

    def to_json(self):
        """Creating a JSON representation of an instance of Credentials.

        Returns:<commit_msg>prettify oauth2.txt<commit_after># Copyright 2014 Google Inc. All rights reserved.
#
# 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.

"""An OAuth 2.0 client.

Tools for interacting with OAuth 2.0 protected resources.
"""

import collections
import copy
import datetime
import json
import logging
import os
import shutil
import socket
import sys
import tempfile

import six
from six.moves import http_client
from six.moves import urllib

import oauth2client
from oauth2client import _helpers
from oauth2client import _pkce
from oauth2client import clientsecrets
from oauth2client import transport


HAS_OPENSSL = False
HAS_CRYPTO = False
try:
    from oauth2client import crypt
    HAS_CRYPTO = True
    HAS_OPENSSL = crypt.OpenSSLVerifier is not None
except ImportError:  # pragma: NO COVER
    pass


logger = logging.getLogger(__name__)

# Expiry is stored in RFC3339 UTC format
EXPIRY_FORMAT = '%Y-%m-%dT%H:%M:%SZ'

# Which certs to use to validate id_tokens received.
ID_TOKEN_VERIFICATION_CERTS = 'https://www.googleapis.com/oauth2/v1/certs'
# This symbol previously had a typo in the name; we keep the old name
# around for now, but will remove it in the future.
ID_TOKEN_VERIFICATON_CERTS = ID_TOKEN_VERIFICATION_CERTS

# Constant to use for the out of band OAuth 2.0 flow.
OOB_CALLBACK_URN = 'urn:ietf:wg:oauth:2.0:oob'

# The value representing user credentials.
AUTHORIZED_USER = 'authorized_user'

# The value representing service account credentials.
SERVICE_ACCOUNT = 'service_account'

# The environment variable pointing the file with local
# Application Default Credentials.
GOOGLE_APPLICATION_CREDENTIALS = 'GOOGLE_APPLICATION_CREDENTIALS'
# The ~/.config subdirectory containing gcloud credentials. Intended
# to be swapped out in tests.
_CLOUDSDK_CONFIG_DIRECTORY = 'gcloud'
# The environment variable name which can replace ~/.config if set.
_CLOUDSDK_CONFIG_ENV_VAR = 'CLOUDSDK_CONFIG'

# The error message we show users when we can't find the Application
# Default Credentials.
ADC_HELP_MSG = (
    'The Application Default Credentials are not available. They are '
    'available if running in Google Compute Engine. Otherwise, the '
    'environment variable ' +
    GOOGLE_APPLICATION_CREDENTIALS +
    ' must be defined pointing to a file defining the credentials. See '
    'https://developers.google.com/accounts/docs/'
    'application-default-credentials for more information.')

_WELL_KNOWN_CREDENTIALS_FILE = 'application_default_credentials.json'

# The access token along with the seconds in which it expires.
AccessTokenInfo = collections.namedtuple(
    'AccessTokenInfo', ['access_token', 'expires_in'])

DEFAULT_ENV_NAME = 'UNKNOWN'

# If set to True _get_environment avoid GCE check (_detect_gce_environment)
NO_GCE_CHECK = os.getenv('NO_GCE_CHECK', 'False')

# Timeout in seconds to wait for the GCE metadata server when detecting the
# GCE environment.
try:
    GCE_METADATA_TIMEOUT = int(os.getenv('GCE_METADATA_TIMEOUT', 3))
except ValueError:  # pragma: NO COVER
    GCE_METADATA_TIMEOUT = 3

_SERVER_SOFTWARE = 'SERVER_SOFTWARE'
_GCE_METADATA_URI = 'http://169.254.169.254'
_METADATA_FLAVOR_HEADER = 'metadata-flavor'  # lowercase header
_DESIRED_METADATA_FLAVOR = 'Google'
_GCE_HEADERS = {_METADATA_FLAVOR_HEADER: _DESIRED_METADATA_FLAVOR}

# Expose utcnow() at module level to allow for
# easier testing (by replacing with a stub).
_UTCNOW = datetime.datetime.utcnow

# NOTE: These names were previously defined in this module but have been
#       moved into `oauth2client.transport`,
clean_headers = transport.clean_headers
MemoryCache = transport.MemoryCache
REFRESH_STATUS_CODES = transport.REFRESH_STATUS_CODES


class SETTINGS(object):
    """Settings namespace for globally defined values."""
    env_name = None


class Error(Exception):
    """Base error for this module."""


class FlowExchangeError(Error):
    """Error trying to exchange an authorization grant for an access token."""


class AccessTokenRefreshError(Error):
    """Error trying to refresh an expired access token."""


class HttpAccessTokenRefreshError(AccessTokenRefreshError):
    """Error (with HTTP status) trying to refresh an expired access token."""
    def __init__(self, *args, **kwargs):
        super(HttpAccessTokenRefreshError, self).__init__(*args)
        self.status = kwargs.get('status')


class TokenRevokeError(Error):
    """Error trying to revoke a token."""


class UnknownClientSecretsFlowError(Error):
    """The client secrets file called for an unknown type of OAuth 2.0 flow."""


class AccessTokenCredentialsError(Error):
    """Having only the access_token means no refresh is possible."""


class VerifyJwtTokenError(Error):
    """Could not retrieve certificates for validation."""


class NonAsciiHeaderError(Error):
    """Header names and values must be ASCII strings."""


class ApplicationDefaultCredentialsError(Error):
    """Error retrieving the Application Default Credentials."""


class OAuth2DeviceCodeError(Error):
    """Error trying to retrieve a device code."""


class CryptoUnavailableError(Error, NotImplementedError):
    """Raised when a crypto library is required, but none is available."""


def _parse_expiry(expiry):
    if expiry and isinstance(expiry, datetime.datetime):
        return expiry.strftime(EXPIRY_FORMAT)
    else:
        return None


class Credentials(object):
    """Base class for all Credentials objects.

    Subclasses must define an authorize() method that applies the credentials
    to an HTTP transport.

    Subclasses must also specify a classmethod named 'from_json' that takes a
    JSON string as input and returns an instantiated Credentials object.
    """

    NON_SERIALIZED_MEMBERS = frozenset(['store'])

    def authorize(self, http):
        """Take an httplib2.Http instance (or equivalent) and authorizes it.

        Authorizes it for the set of credentials, usually by replacing
        http.request() with a method that adds in the appropriate headers and
        then delegates to the original Http.request() method.

        Args:
            http: httplib2.Http, an http object to be used to make the refresh
                  request.
        """
        raise NotImplementedError

    def refresh(self, http):
        """Forces a refresh of the access_token.

        Args:
            http: httplib2.Http, an http object to be used to make the refresh
                  request.
        """
        raise NotImplementedError

    def revoke(self, http):
        """Revokes a refresh_token and makes the credentials void.

        Args:
            http: httplib2.Http, an http object to be used to make the revoke
                  request.
        """
        raise NotImplementedError

    def apply(self, headers):
        """Add the authorization to the headers.

        Args:
            headers: dict, the headers to add the Authorization header to.
        """
        raise NotImplementedError

    def _to_json(self, strip, to_serialize=None):
        """Utility function that creates JSON repr. of a Credentials object.

        Args:
            strip: array, An array of names of members to exclude from the
                   JSON.
            to_serialize: dict, (Optional) The properties for this object
                          that will be serialized. This allows callers to
                          modify before serializing.

        Returns:
            string, a JSON representation of this instance, suitable to pass to
            from_json().
        """
        curr_type = self.__class__
        if to_serialize is None:
            to_serialize = copy.copy(self.__dict__)
        else:
            # Assumes it is a str->str dictionary, so we don't deep copy.
            to_serialize = copy.copy(to_serialize)
        for member in strip:
            if member in to_serialize:
                del to_serialize[member]
        to_serialize['token_expiry'] = _parse_expiry(
            to_serialize.get('token_expiry'))
        # Add in information we will need later to reconstitute this instance.
        to_serialize['_class'] = curr_type.__name__
        to_serialize['_module'] = curr_type.__module__
        for key, val in to_serialize.items():
            if isinstance(val, bytes):
                to_serialize[key] = val.decode('utf-8')
            if isinstance(val, set):
                to_serialize[key] = list(val)
        return json.dumps(to_serialize, indent=4, sort_keys=True)

    def to_json(self):
        """Creating a JSON representation of an instance of Credentials.

        Returns:
{'fraction_non_alphanumeric': 0.07371617890668139, 'fraction_numerical': 0.005742683600220872, 'mean_word_length': 3.3672534362189537, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 4, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3365881', 'n_tokens_mistral': 5172, 'n_tokens_neox': 4939, 'n_words': 1830}