GithubHelp home page GithubHelp logo

googleapis / google-auth-library-python Goto Github PK

View Code? Open in Web Editor NEW
745.0 76.0 296.0 5.03 MB

Google Auth Python Library

Home Page: https://googleapis.dev/python/google-auth/latest/

License: Apache License 2.0

Python 97.57% Shell 2.30% Dockerfile 0.13%

google-auth-library-python's Introduction

Google Auth Python Library

pypi

This library simplifies using Google's various server-to-server authentication mechanisms to access Google APIs.

Installing

You can install using pip:

$ pip install google-auth

For more information on setting up your Python development environment, please refer to Python Development Environment Setup Guide for Google Cloud Platform.

Extras

google-auth has few extras that you can install. For example:

$ pip install google-auth[pyopenssl]

Note that the extras pyopenssl and enterprise_cert should not be used together because they use conflicting versions of cryptography.

Supported Python Versions

Python >= 3.7

NOTE: Python 3.7 was marked as unsupported by the python community in June 2023. We recommend that all developers upgrade to Python 3.8 and newer as soon as they can. Support for Python 3.7 will be removed from this library after January 1 2024. Previous releases that support Python 3.7 will continue to be available for download, but releases after January 1 2024 will only target Python 3.8 and newer.

Unsupported Python Versions

  • Python == 2.7: The last version of this library with support for Python 2.7 was google.auth == 1.34.0.
  • Python 3.5: The last version of this library with support for Python 3.5 was google.auth == 1.23.0.
  • Python 3.6: The last version of this library with support for Python 3.6 was google.auth == 2.22.0.

Documentation

Google Auth Python Library has usage and reference documentation at https://googleapis.dev/python/google-auth/latest/index.html.

Current Maintainers

Authors

Contributing

Contributions to this library are always welcome and highly encouraged.

See CONTRIBUTING.rst for more information on how to get started.

License

Apache 2.0 - See the LICENSE for more information.

google-auth-library-python's People

Contributors

aeitzman avatar akx avatar anguillanneuf avatar arithmetic1728 avatar bigtailwolf avatar bojeil-google avatar busunkim96 avatar clundin25 avatar crwilcox avatar dandhlee avatar davidwtbuxton avatar dhermes avatar gcf-owl-bot[bot] avatar hilts-vaughan avatar hiranya911 avatar juzna avatar lidizheng avatar liuchaoren avatar matthewhughes934 avatar parthea avatar plamut avatar release-please[bot] avatar renovate-bot avatar sai-sunder-s avatar salrashid123 avatar scruffyprodigy avatar theacodes avatar tseaver avatar wangyutongg avatar yoshi-automation avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

google-auth-library-python's Issues

Determine how to deal with multiple audiences for jwt.Credentials

JWT bearer credentials require an audience that matches the service URL to work.

Right now, JWT credentials don't require an audience when constructing, but instead can generate a one-time token during before_request. This works, but unfortunately this is pretty awful performance-wise.

My best as to why we did this is because within one client we may actually be talking to two different audiences. Consider pubusb - there is the publisher audience (https://pubsub.googleapis.com/google.pubsub.v1.Publisher) and the subscriber audience (https://pubsub.googleapis.com/google.pubsub.v1.Subscriber).

I see two options for making this better:

  1. Store a cache of tokens for every given audience. This has lots of problems.
  2. Make our clients pass in credentials.with_claims(audience='...') (example here) instead of just credentials. This means that we'll essentially be using a copy of the credentials for each audience (pubsub will have two), so they will likely refresh at different times (which I don't consider a problem).

@dhermes @lukesneeringer thoughts?

Figure out what to do about the relationship between ADC and JWT credentials.

We have jwt.Credentials in order to support the small set of APIs that support using directly using a JWT as the bearer token (only BigTable right now, as far as I know).

In oauth2client, _JWTAccessCredentials (the equivalent of our jwt.Credentials) will actually return an instance of ServiceAccountCredentials if create_scoped is called (here). This was done so that GoogleCredentials.get_application_default can return a class that works for all APIs (here).

For some reference, the Java library just returns regular service account credentials with ADC (here). The other auth libraries also seem to just return service account credentials.

So what should we do here? I see a few options:

  1. Just make ADC return service account credentials (google.oauth2.service_account.Credentials), make users explicitly construct jwt.Credentials if that's what they want. Optionally provide an easy way to convert service account credentials to jwt credentials.
  2. Make ADC return a new class that inherits from jwt.Credentials and Scoped that behaves like oauth2client.

Determine how to handle before_request for gRPC

I discovered that I did something totally wrong when I implemented our grpc transport.

All of our HTTP transports call credentials.before_request to get the authorization header populated (here). However, the gRPC transport instead calls credentials.refresh directly and constructs the header itself (here).

I think the gRPC transport needs to do the same as the others, but that's where it gets tricky. before_request takes 4 arguments request, method, url, request_headers. gRPC provides our auth plugin with a context that looks like AuthMetadataContext(service_url='https://pubsub.googleapis.com/google.pubsub.v1.Publisher', method_name='ListTopics'). Does it make sense to call before_request(http_request, context.method_name, context.service_url, headers) even though context.method_name is not an HTTP method? It it okay to overload the term method for different transports?

@dhermes @lukesneeringer thoughts?

Consider allowing Signer.key_id to be None

#108 and #109 added a "hack" to allow the key id to be determined when signing with IAM and App Engine. The reasoning for this is that the key id is needed to populate the kid claim in the JWT header.

It turns out, the kid field is optional according to the JWT spec. If it's absent, it's undefined what to do with it, but it seems that most clients will try all available certs (which is what we do as well).

@dhermes @lukesneeringer what do you think about allowing key_id to be None for iam.Signer and app_engine.Signer?

release 0.6.0 timeline

What's the timeline for release v0.6.0, I'd love to leverage the new oauth2.flow module.

Let me know if I can do anything to help!

External transport discussion

Continuing from #1, we need to figure out the story for use case (2):

It needs to allow users to attach credentials to an HTTP object of their choosing.

The usage of this is external-only. This is the means by which users will make authenticated requests. We want to initially support urllib3, but we should be aware of anything that will cause issues with a requests implementation.

How oauth2client does this

oauth2client only supports httplib2. The way that it accomplishes this is by monkeypatching an existing httplib2.Http object's request method.

  1. The user must construct the http object themselves (this gives them the opportunity to configure settings such as SSL and proxies).
  2. oauth2client modifies the object in place and returns it. The original request method is only available as a closure (via http.request.func_closure[0].cell_contents, which is insanity).

How oauth2client's transport refactor did it.

In the transport refactor, I modified this behavior slightly. Instead of monkeypatching, it wrapped the http object using an AuthedHttp wrapper class that has a common interface with httplib2.Http.

  1. The user still must construct the http object themselves.
  2. oauth2client returns a AuthedHttp wrapper instance that uses the original http object under the covers. The original http object is not modified in any way.

What we could do

We could largely adopt the second method without much heartache, as long a we're still okay with the wrapper pattern:

import google.auth
from google.auth.transport.urllib3 import AuthedHttp
import urllib3

http = urllib3.PoolManager()
credentials, _ = google.auth.default()
authed_http = AuthedHttp(credentials, http)

Similarly with requests:

import google.auth
from google.auth.transport.requests import AuthedSession
import urllib3

session = requests.Session()
credentials, _ = google.auth.default()
authed_session = AuthedSession(credentials, session)

We could also have these items construct their own underlying object using sane defaults if none is specified:

# Creates a PoolManager behind the scenes
authed_http = AuthedHttp(credentials)
# Creates a Session behind the scenes.
authed_session = AuthedSession(credentials)

The only concern I have about this is the long import path (google.auth.transport.urllib3). I can't think of a good, clean way to do something like oauth2client's authorize and I'm not sure that I want to.

Thoughts? Concerns? Alternatives?

1.0.0 Roadmap

This is largely based on the featureset needed by google-cloud-python and the features provided by google-auth-library-nodejs.

Required features:

  • JWT signing and verification using PEM keys. (#6, #7)
  • JWT credentials. (#21)
  • Compute Engine credentials. (#11, #22)
  • App Engine credentials. (#
  • Service Account (JWT Grant for OAuth 2.0) credentials. (#13, #25)
  • OAuth 2.0 Access Token credentials (no flows, credentials only for ADC). (#13, #24)
  • Implementation of application default credentials, along with the ability to determine the project ID. (#32)
  • Well-defined transport interface, with ability for users to build their own. (#10)
  • urllib3 support. (#14)
  • Ability to convert oauth2client credentials. (#36)

Nice to have:

oauth2client features explicitly not in scope for 1.0.0:

  • OAuth 2.0 flows.
  • Storage. (Discussion at #33)
  • Devshell credentials (seems to only be used by the gcloud cli).
  • Django, Flask, and Webapp2 helpers.
  • httplib2 support. (Temporary support in #34)

Add interactive installed app flow

Create a helper method for running an interactive installed app flow, similar to:

def credentials_flow_interactive(client_secrets_file, scopes):
    """Initiate an interactive OAuth2InstalledApp flow.

    - Display a URL for the user to visit.
    - URL displays a code for the user to copy.
    - Wait on standard input for the user to enter the provided code.
    - Exchange OAuth2 tokens.

    Args:
      client_secrets_file: The path to the client secrets JSON file.
      scopes: The list of scopes to request during the flow.
    """
    flow = google.oauth2.flow.Flow.from_client_secrets_file(
        client_secrets_file,
        scopes=scopes,
        redirect_uri='urn:ietf:wg:oauth:2.0:oob')
    auth_url, _ = flow.authorization_url(prompt='consent')
    print('Please go to this URL: %s' % auth_url)
    code = input('Enter the authorization code: ')
    flow.fetch_token(code=code)
    return flow.credentials

Re-enable certificate verification for system tests on Travis

See #51 for context.

With our Python runtime (debian8) using both certifi.where() and OS certs work with SNI. (This is what we do by default in _make_default_http)

With Travis (Ubuntu 12.04 LTS) using certifi.old_where() works but generates an InsecurePlatformWarning. Using OS certs works but generates an SNIMissingWarning. Using OS certs with PyOpenSSL works without warnings.

Use PEP420 valid tags

If you want RTD to build a stable version of docs on a tag, the tag needs to be PEP420 valid, so v0.0.1 is a no-go.

From their documentation, a stable build is only done when a semver-valid tag is pushed:

You should push a tag for each version of your project. These tags should be numbered in a way that is consistent with semantic versioning. This will map to your stable branch by default.

Internal transport discussion

This library needs to satisfy two orthogonal goals related to HTTP:

  1. It needs to be able to make HTTP requests internally (e.g., in refresh())
  2. It needs to allow users to attach credentials to an HTTP object of their choosing.

If there were only one Python HTTP library this would all be trivial. If the library was called unicorn, we could just use unicorn.request directly everywhere internally for (1). For (2), we would just write a single function to attach the credentials to unicorn.

This discussion is exclusively about (1), but care should be made not to limit our options for (2).

Use Case (1)

Use case (1) boils down to the need for a consistent way to make an http request and get response information. This use-case is only for library internals.

What's done today

transport.request takes any http object and then uses isinstance to figure out which transport should be used to call. Basically:

# Calling code
credentials.refresh(http, ...)

# credentials.py
def refresh(http):
    ...
    r = transport.request(http, ...)
    ...

# transport.py
def request(http, method, uri, ...):
    transport_module = get_transport_for_http(http)
    return transport_module.request(http, method, uri, ...)

# urllib3_transport.py
def request(http, method, uri, ...):
    return http.request(method, uri)

The indirection has the benefit that we can accept any supported http object at the call sites of methods like refresh(). The drawback is the indirection and the cost of the lookup for every request.

What we could do

Use http.client

We could easily use the built-in http.client - but urlilb3 and requests have significant benefits, and properly doing ssl with http.client can be error prone. It also leads us to situation where the http client the user is using and the http client we're using can be different.

Set credentials.http

Presently credentials are completely independent of http. Any methods that need to make requests must accept an http parameter. This proposes adding credentials.http that is set to a new private interface transport._HTTP. None of the request-making methods need http as an argument anymore.

This has the distinct drawback that credentials can now only be associated with a single http object. It also introduces a new interface (and subclasses for every transport).

Just pass in transport_impl.request

Instead of passing in an http object and letting the lookup happen, make the argument to refresh() et al be an interface that matches transport.request like this:

def request(method, uri, ...)

Since the caller of refresh knows the transport implementation that's currently being used it can just pass in, for example, functools.partial(urlilb3_transport.request, bare_http). The call stack would then look like this:

# Calling code
bound_request = functools.partial(urllib3_transport.request, self)
credentials.refresh(bound_request)

# credentials.py
def refresh(request):
    ...
    r = request(...)
    ...

# urllib3_transport.py
# http provided by functools.partial above.
def request(http, method, uri, ...):
    return http.request(method, uri)

This has a lot of benefits:

  1. The interface for request can be made public without making any other part of our transport implementation public.
  2. No lookup penalty.
  3. refresh() et al will have well defined argument types.
  4. Gives implementors of use case (2) the option of passing in something else for request. :)

Make oauth2.Credentials attributes public

To facilitate serialization, token, refresh_token, token_uri, client_id, and client_secret should all be publicly readable.

attrs = {
    'access_token': credentials.token,
    'refresh_token': credentials.refresh_token,
    'token_uri': credentials.token_uri,
    'client_id': credentials.client_id,
    'client_secret': credentials.client_secret,
}

New default grpc channel for google?

Right now, to create a new gprc channel to google, our API users have to do:

import google.auth.transport.grpc
import google.auth.transport.requests

http_request = google.auth.transport.requests.Request()

channel = google.auth.transport.grpc.secure_authorized_channel(
    credentials, http_request, 'pubsub.googleapis.com:443')

It seems that we should be able to factor all these lines by providing an API like this:

import google.auth.transport.grpc
channel  = google.auth.transport.grpc.default_authenticated_channel('pubsub.googleapis.com:443')

oauth2client deprecation plan

In order to deprecate oauth2client:

  1. Add support for google-auth to google-gax.
  2. Add support for google-auth to google-cloud-python.
  3. Add support for google-auth to google-api-python-client.
  4. Release v1.0.0.
  5. Figure out a story for obtaining user auth credentials (oauthlib integration?).
  6. Update auth documentation on developers.google.com and cloud.google.com to point to google-auth.

Am I forgetting anything?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.