def _retrieve_discovery_doc(url,
                            http,
                            cache_discovery,
                            cache=None,
                            developerKey=None):
    """Retrieves the discovery_doc from cache or the internet.

  Args:
    url: string, the URL of the discovery document.
    http: httplib2.Http, An instance of httplib2.Http or something that acts
      like it through which HTTP requests will be made.
    cache_discovery: Boolean, whether or not to cache the discovery doc.
    cache: googleapiclient.discovery_cache.base.Cache, an optional cache
      object for the discovery documents.

  Returns:
    A unicode string representation of the discovery document.
  """
    if cache_discovery:
        from . import discovery_cache
        from .discovery_cache import base

        if cache is None:
            cache = discovery_cache.autodetect()
        if cache:
            content = cache.get(url)
            if content:
                return content

    actual_url = url
    # REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment
    # variable that contains the network address of the client sending the
    # request. If it exists then add that to the request for the discovery
    # document to avoid exceeding the quota on discovery requests.
    if "REMOTE_ADDR" in os.environ:
        actual_url = _add_query_parameter(url, "userIp",
                                          os.environ["REMOTE_ADDR"])
    if developerKey:
        actual_url = _add_query_parameter(url, "key", developerKey)
    logger.info("URL being requested: GET %s", actual_url)

    resp, content = http.request(actual_url)

    if resp.status >= 400:
        raise HttpError(resp, content, uri=actual_url)

    try:
        content = content.decode("utf-8")
    except AttributeError:
        pass

    try:
        service = json.loads(content)
    except ValueError as e:
        logger.error("Failed to parse as JSON: " + content)
        raise InvalidJsonError()
    if cache_discovery and cache:
        cache.set(url, content)
    return content
Beispiel #2
0
def build(serviceName,
          version,
          http=None,
          discoveryServiceUrl=DISCOVERY_URI,
          developerKey=None,
          model=None,
          requestBuilder=HttpRequest):
    """Construct a Resource for interacting with an API.

  Construct a Resource object for interacting with an API. The serviceName and
  version are the names from the Discovery service.

  Args:
    serviceName: string, name of the service.
    version: string, the version of the service.
    http: httplib2.Http, An instance of httplib2.Http or something that acts
      like it that HTTP requests will be made through.
    discoveryServiceUrl: string, a URI Template that points to the location of
      the discovery service. It should have two parameters {api} and
      {apiVersion} that when filled in produce an absolute URI to the discovery
      document for that service.
    developerKey: string, key obtained from
      https://code.google.com/apis/console.
    model: googleapiclient.Model, converts to and from the wire format.
    requestBuilder: googleapiclient.http.HttpRequest, encapsulator for an HTTP
      request.

  Returns:
    A Resource object with methods for interacting with the service.
  """
    params = {'api': serviceName, 'apiVersion': version}

    if http is None:
        http = httplib2.Http()

    requested_url = uritemplate.expand(discoveryServiceUrl, params)

    # REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment
    # variable that contains the network address of the client sending the
    # request. If it exists then add that to the request for the discovery
    # document to avoid exceeding the quota on discovery requests.
    if 'REMOTE_ADDR' in os.environ:
        requested_url = _add_query_parameter(requested_url, 'userIp',
                                             os.environ['REMOTE_ADDR'])
    logger.info('URL being requested: GET %s' % requested_url)

    resp, content = http.request(requested_url)

    if resp.status == 404:
        raise UnknownApiNameOrVersion("name: %s  version: %s" %
                                      (serviceName, version))
    if resp.status >= 400:
        raise HttpError(resp, content, uri=requested_url)

    try:
        service = simplejson.loads(content)
    except ValueError, e:
        logger.error('Failed to parse as JSON: ' + content)
        raise InvalidJsonError()
def build_from_document(service,
                        base=None,
                        future=None,
                        http=None,
                        developerKey=None,
                        model=None,
                        requestBuilder=HttpRequest,
                        credentials=None):
    """Create a Resource for interacting with an API.

  Same as `build()`, but constructs the Resource object from a discovery
  document that is it given, as opposed to retrieving one over HTTP.

  Args:
    service: string or object, the JSON discovery document describing the API.
      The value passed in may either be the JSON string or the deserialized
      JSON.
    base: string, base URI for all HTTP requests, usually the discovery URI.
      This parameter is no longer used as rootUrl and servicePath are included
      within the discovery document. (deprecated)
    future: string, discovery document with future capabilities (deprecated).
    http: httplib2.Http, An instance of httplib2.Http or something that acts
      like it that HTTP requests will be made through.
    developerKey: string, Key for controlling API usage, generated
      from the API Console.
    model: Model class instance that serializes and de-serializes requests and
      responses.
    requestBuilder: Takes an http request and packages it up to be executed.
    credentials: oauth2client.Credentials or
      google.auth.credentials.Credentials, credentials to be used for
      authentication.

  Returns:
    A Resource object with methods for interacting with the service.
  """

    if http is not None and credentials is not None:
        raise ValueError(
            'Arguments http and credentials are mutually exclusive.')

    if isinstance(service, six.string_types):
        service = json.loads(service)

    if 'rootUrl' not in service and (isinstance(http,
                                                (HttpMock, HttpMockSequence))):
        logger.error(
            "You are using HttpMock or HttpMockSequence without" +
            "having the service discovery doc in cache. Try calling " +
            "build() without mocking once first to populate the " + "cache.")
        raise InvalidJsonError()

    base = urljoin(service['rootUrl'], service['servicePath'])
    schema = Schemas(service)

    # If the http client is not specified, then we must construct an http client
    # to make requests. If the service has scopes, then we also need to setup
    # authentication.
    if http is None:
        # Does the service require scopes?
        scopes = list(
            service.get('auth', {}).get('oauth2', {}).get('scopes', {}).keys())

        # If so, then the we need to setup authentication if no developerKey is
        # specified.
        if scopes and not developerKey:
            # If the user didn't pass in credentials, attempt to acquire application
            # default credentials.
            if credentials is None:
                credentials = _auth.default_credentials()

            # The credentials need to be scoped.
            credentials = _auth.with_scopes(credentials, scopes)

            # Create an authorized http instance
            http = _auth.authorized_http(credentials)

        # If the service doesn't require scopes then there is no need for
        # authentication.
        else:
            http = build_http()

    if model is None:
        features = service.get('features', [])
        model = JsonModel('dataWrapper' in features)

    return Resource(http=http,
                    baseUrl=base,
                    model=model,
                    developerKey=developerKey,
                    requestBuilder=requestBuilder,
                    resourceDesc=service,
                    rootDesc=service,
                    schema=schema)
Beispiel #4
0
def build_from_document(service,
                        base=None,
                        future=None,
                        http=None,
                        developerKey=None,
                        model=None,
                        requestBuilder=HttpRequest,
                        credentials=None):
    """Create a Resource for interacting with an API.

  Same as `build()`, but constructs the Resource object from a discovery
  document that is it given, as opposed to retrieving one over HTTP.

  Args:
    service: string or object, the JSON discovery document describing the API.
      The value passed in may either be the JSON string or the deserialized
      JSON.
    base: string, base URI for all HTTP requests, usually the discovery URI.
      This parameter is no longer used as rootUrl and servicePath are included
      within the discovery document. (deprecated)
    future: string, discovery document with future capabilities (deprecated).
    http: httplib2.Http, An instance of httplib2.Http or something that acts
      like it that HTTP requests will be made through.
    developerKey: string, Key for controlling API usage, generated
      from the API Console.
    model: Model class instance that serializes and de-serializes requests and
      responses.
    requestBuilder: Takes an http request and packages it up to be executed.
    credentials: object, credentials to be used for authentication.

  Returns:
    A Resource object with methods for interacting with the service.
  """

    if http is None:
        http = httplib2.Http()

    # future is no longer used.
    future = {}

    if isinstance(service, six.string_types):
        service = json.loads(service)

    if 'rootUrl' not in service and (isinstance(http,
                                                (HttpMock, HttpMockSequence))):
        logger.error(
            "You are using HttpMock or HttpMockSequence without" +
            "having the service discovery doc in cache. Try calling " +
            "build() without mocking once first to populate the " + "cache.")
        raise InvalidJsonError()

    base = urljoin(service['rootUrl'], service['servicePath'])
    schema = Schemas(service)

    if credentials:
        # If credentials were passed in, we could have two cases:
        # 1. the scopes were specified, in which case the given credentials
        #    are used for authorizing the http;
        # 2. the scopes were not provided (meaning the Application Default
        #    Credentials are to be used). In this case, the Application Default
        #    Credentials are built and used instead of the original credentials.
        #    If there are no scopes found (meaning the given service requires no
        #    authentication), there is no authorization of the http.
        if (isinstance(credentials, GoogleCredentials)
                and credentials.create_scoped_required()):
            scopes = service.get('auth', {}).get('oauth2',
                                                 {}).get('scopes', {})
            if scopes:
                credentials = credentials.create_scoped(list(scopes.keys()))
            else:
                # No need to authorize the http object
                # if the service does not require authentication.
                credentials = None

        if credentials:
            http = credentials.authorize(http)

    if model is None:
        features = service.get('features', [])
        model = JsonModel('dataWrapper' in features)
    return Resource(http=http,
                    baseUrl=base,
                    model=model,
                    developerKey=developerKey,
                    requestBuilder=requestBuilder,
                    resourceDesc=service,
                    rootDesc=service,
                    schema=schema)
Beispiel #5
0
def build_from_document(
    service,
    base=None,
    future=None,
    http=None,
    developerKey=None,
    model=None,
    requestBuilder=HttpRequest,
    credentials=None,
    client_options=None,
    adc_cert_path=None,
    adc_key_path=None,
):
    if http is not None and credentials is not None:
        raise ValueError(
            "Arguments http and credentials are mutually exclusive.")

    if isinstance(service, six.string_types):
        service = json.loads(service)
    elif isinstance(service, six.binary_type):
        service = json.loads(service.decode("utf-8"))

    if "rootUrl" not in service and isinstance(http,
                                               (HttpMock, HttpMockSequence)):
        logger.error(
            "You are using HttpMock or HttpMockSequence without" +
            "having the service discovery doc in cache. Try calling " +
            "build() without mocking once first to populate the " + "cache.")
        raise InvalidJsonError()

    base = urljoin(service["rootUrl"], service["servicePath"])
    if client_options:
        if isinstance(client_options, six.moves.collections_abc.Mapping):
            client_options = google.api_core.client_options.from_dict(
                client_options)
        if client_options.api_endpoint:
            base = client_options.api_endpoint

    schema = Schemas(service)

    if http is None:
        scopes = list(
            service.get("auth", {}).get("oauth2", {}).get("scopes", {}).keys())

        if scopes and not developerKey:

            if credentials is None:
                credentials = _auth.default_credentials()

            credentials = _auth.with_scopes(credentials, scopes)

        if credentials:
            http = _auth.authorized_http(credentials)

        else:
            http = build_http()

        client_cert_to_use = None
        if client_options and client_options.client_cert_source:
            raise MutualTLSChannelError(
                "ClientOptions.client_cert_source is not supported, please use ClientOptions.client_encrypted_cert_source."
            )
        if (client_options
                and hasattr(client_options, "client_encrypted_cert_source")
                and client_options.client_encrypted_cert_source):
            client_cert_to_use = client_options.client_encrypted_cert_source
        elif adc_cert_path and adc_key_path and mtls.has_default_client_cert_source(
        ):
            client_cert_to_use = mtls.default_client_encrypted_cert_source(
                adc_cert_path, adc_key_path)
        if client_cert_to_use:
            cert_path, key_path, passphrase = client_cert_to_use()

            http_channel = (http.http if google_auth_httplib2 and isinstance(
                http, google_auth_httplib2.AuthorizedHttp) else http)
            http_channel.add_certificate(key_path, cert_path, "", passphrase)

        if "mtlsRootUrl" in service and (not client_options
                                         or not client_options.api_endpoint):
            mtls_endpoint = urljoin(service["mtlsRootUrl"],
                                    service["servicePath"])
            use_mtls_env = os.getenv("GOOGLE_API_USE_MTLS", "never")

            if not use_mtls_env in ("never", "auto", "always"):
                raise MutualTLSChannelError(
                    "Unsupported GOOGLE_API_USE_MTLS value. Accepted values: never, auto, always"
                )

            if use_mtls_env == "always" or (use_mtls_env == "auto"
                                            and client_cert_to_use):
                base = mtls_endpoint

    if model is None:
        features = service.get("features", [])
        model = JsonModel("dataWrapper" in features)

    return {
        'http': http,
        'baseUrl': base,
        'model': model,
        'developerKey': developerKey,
        'requestBuilder': requestBuilder,
        'resourceDesc': service,
        'rootDesc': service,
        'schema': schema,
    }