feat: Add new gcloud commands, API clients, and third-party libraries across various services.

This commit is contained in:
2026-01-01 20:26:35 +01:00
parent 5e23cbece0
commit a19e592eb7
25221 changed files with 8324611 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
"""oauthlib.oopenid.core ~~~~~~~~~~~~~~~~~~~~~~~
This module is an implementation of various logic needed
for consuming and providing OpenID Connect
"""
from __future__ import absolute_import, unicode_literals
from .pre_configured import Server

View File

@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
"""oauthlib.openid.connect.core.endpoints.pre_configured ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This module is an implementation of various endpoints needed
for providing OpenID Connect servers.
"""
from __future__ import absolute_import, unicode_literals
from oauthlib.oauth2.rfc6749.endpoints import (AuthorizationEndpoint,
IntrospectEndpoint,
ResourceEndpoint,
RevocationEndpoint,
TokenEndpoint)
from oauthlib.oauth2.rfc6749.grant_types import (
AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant, ImplicitGrant as
OAuth2ImplicitGrant, ClientCredentialsGrant, RefreshTokenGrant,
ResourceOwnerPasswordCredentialsGrant)
from oauthlib.oauth2.rfc6749.tokens import BearerToken
from ..grant_types import (
AuthorizationCodeGrant,
ImplicitGrant,
HybridGrant,
)
from ..grant_types.dispatchers import (AuthorizationCodeGrantDispatcher,
ImplicitTokenGrantDispatcher,
AuthorizationTokenGrantDispatcher)
from ..tokens import JWTToken
class Server(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint,
ResourceEndpoint, RevocationEndpoint):
"""An all-in-one endpoint featuring all four major grant types."""
def __init__(self,
request_validator,
token_expires_in=None,
token_generator=None,
refresh_token_generator=None,
*args,
**kwargs):
"""Construct a new all-grants-in-one server.
:param request_validator: An implementation of
oauthlib.oauth2.RequestValidator.
:param token_expires_in: An int or a function to generate a token
expiration offset (in seconds) given a
oauthlib.common.Request object.
:param token_generator: A function to generate a token from a request.
:param refresh_token_generator: A function to generate a token from a
request for the refresh token.
:param kwargs: Extra parameters to pass to authorization-,
token-, resource-, and revocation-endpoint constructors.
"""
auth_grant = OAuth2AuthorizationCodeGrant(request_validator)
implicit_grant = OAuth2ImplicitGrant(request_validator)
password_grant = ResourceOwnerPasswordCredentialsGrant(request_validator)
credentials_grant = ClientCredentialsGrant(request_validator)
refresh_grant = RefreshTokenGrant(request_validator)
openid_connect_auth = AuthorizationCodeGrant(request_validator)
openid_connect_implicit = ImplicitGrant(request_validator)
openid_connect_hybrid = HybridGrant(request_validator)
bearer = BearerToken(request_validator, token_generator, token_expires_in,
refresh_token_generator)
jwt = JWTToken(request_validator, token_generator, token_expires_in,
refresh_token_generator)
auth_grant_choice = AuthorizationCodeGrantDispatcher(
default_grant=auth_grant, oidc_grant=openid_connect_auth)
implicit_grant_choice = ImplicitTokenGrantDispatcher(
default_grant=implicit_grant, oidc_grant=openid_connect_implicit)
# See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations for valid combinations
# internally our AuthorizationEndpoint will ensure they can appear in any order for any valid combination
AuthorizationEndpoint.__init__(
self,
default_response_type='code',
response_types={
'code': auth_grant_choice,
'token': implicit_grant_choice,
'id_token': openid_connect_implicit,
'id_token token': openid_connect_implicit,
'code token': openid_connect_hybrid,
'code id_token': openid_connect_hybrid,
'code id_token token': openid_connect_hybrid,
'none': auth_grant
},
default_token_type=bearer)
token_grant_choice = AuthorizationTokenGrantDispatcher(
request_validator,
default_grant=auth_grant,
oidc_grant=openid_connect_auth)
TokenEndpoint.__init__(
self,
default_grant_type='authorization_code',
grant_types={
'authorization_code': token_grant_choice,
'password': password_grant,
'client_credentials': credentials_grant,
'refresh_token': refresh_grant,
},
default_token_type=bearer)
ResourceEndpoint.__init__(
self,
default_token='Bearer',
token_types={
'Bearer': bearer,
'JWT': jwt
})
RevocationEndpoint.__init__(self, request_validator)
IntrospectEndpoint.__init__(self, request_validator)

View File

@@ -0,0 +1,150 @@
# coding=utf-8
"""oauthlib.oauth2.rfc6749.errors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error used both by OAuth 2 clients and providers to represent the spec
defined error responses for all four core grant types.
"""
from __future__ import unicode_literals
from oauthlib.oauth2.rfc6749.errors import FatalClientError, OAuth2Error
class FatalOpenIDClientError(FatalClientError):
pass
class OpenIDClientError(OAuth2Error):
pass
class InteractionRequired(OpenIDClientError):
"""
The Authorization Server requires End-User interaction to proceed.
This error MAY be returned when the prompt parameter value in the
Authentication Request is none, but the Authentication Request cannot be
completed without displaying a user interface for End-User interaction.
"""
error = 'interaction_required'
status_code = 401
class LoginRequired(OpenIDClientError):
"""
The Authorization Server requires End-User authentication.
This error MAY be returned when the prompt parameter value in the
Authentication Request is none, but the Authentication Request cannot be
completed without displaying a user interface for End-User authentication.
"""
error = 'login_required'
status_code = 401
class AccountSelectionRequired(OpenIDClientError):
"""
The End-User is REQUIRED to select a session at the Authorization Server.
The End-User MAY be authenticated at the Authorization Server with
different associated accounts, but the End-User did not select a session.
This error MAY be returned when the prompt parameter value in the
Authentication Request is none, but the Authentication Request cannot be
completed without displaying a user interface to prompt for a session to
use.
"""
error = 'account_selection_required'
class ConsentRequired(OpenIDClientError):
"""
The Authorization Server requires End-User consent.
This error MAY be returned when the prompt parameter value in the
Authentication Request is none, but the Authentication Request cannot be
completed without displaying a user interface for End-User consent.
"""
error = 'consent_required'
status_code = 401
class InvalidRequestURI(OpenIDClientError):
"""
The request_uri in the Authorization Request returns an error or
contains invalid data.
"""
error = 'invalid_request_uri'
description = 'The request_uri in the Authorization Request returns an ' \
'error or contains invalid data.'
class InvalidRequestObject(OpenIDClientError):
"""
The request parameter contains an invalid Request Object.
"""
error = 'invalid_request_object'
description = 'The request parameter contains an invalid Request Object.'
class RequestNotSupported(OpenIDClientError):
"""
The OP does not support use of the request parameter.
"""
error = 'request_not_supported'
description = 'The request parameter is not supported.'
class RequestURINotSupported(OpenIDClientError):
"""
The OP does not support use of the request_uri parameter.
"""
error = 'request_uri_not_supported'
description = 'The request_uri parameter is not supported.'
class RegistrationNotSupported(OpenIDClientError):
"""
The OP does not support use of the registration parameter.
"""
error = 'registration_not_supported'
description = 'The registration parameter is not supported.'
class InvalidTokenError(OAuth2Error):
"""
The access token provided is expired, revoked, malformed, or
invalid for other reasons. The resource SHOULD respond with
the HTTP 401 (Unauthorized) status code. The client MAY
request a new access token and retry the protected resource
request.
"""
error = 'invalid_token'
status_code = 401
description = ('The access token provided is expired, revoked, malformed, '
'or invalid for other reasons.')
class InsufficientScopeError(OAuth2Error):
"""
The request requires higher privileges than provided by the
access token. The resource server SHOULD respond with the HTTP
403 (Forbidden) status code and MAY include the "scope"
attribute with the scope necessary to access the protected
resource.
"""
error = 'insufficient_scope'
status_code = 403
description = ('The request requires higher privileges than provided by '
'the access token.')
def raise_from_error(error, params=None):
import inspect
import sys
kwargs = {
'description': params.get('error_description'),
'uri': params.get('error_uri'),
'state': params.get('state')
}
for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass):
if cls.error == error:
raise cls(**kwargs)

View File

@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
"""oauthlib.openid.connect.core.grant_types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import unicode_literals, absolute_import
from .authorization_code import AuthorizationCodeGrant
from .implicit import ImplicitGrant
from .base import GrantTypeBase
from .hybrid import HybridGrant
from .exceptions import OIDCNoPrompt
from .dispatchers import (AuthorizationCodeGrantDispatcher,
ImplicitTokenGrantDispatcher,
AuthorizationTokenGrantDispatcher)

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
"""oauthlib.openid.connect.core.grant_types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, unicode_literals
import logging
from oauthlib.oauth2.rfc6749.grant_types.authorization_code import AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant
from .base import GrantTypeBase
log = logging.getLogger(__name__)
class AuthorizationCodeGrant(GrantTypeBase):
def __init__(self, request_validator=None, **kwargs):
self.proxy_target = OAuth2AuthorizationCodeGrant(
request_validator=request_validator, **kwargs)
self.custom_validators.post_auth.append(self.openid_authorization_validator)
self.register_token_modifier(self.add_id_token)

View File

@@ -0,0 +1,254 @@
from .exceptions import OIDCNoPrompt
import datetime
import logging
from json import loads
from oauthlib.oauth2.rfc6749.errors import ConsentRequired, InvalidRequestError, LoginRequired
log = logging.getLogger(__name__)
class GrantTypeBase(object):
# Just proxy the majority of method calls through to the
# proxy_target grant type handler, which will usually be either
# the standard OAuth2 AuthCode or Implicit grant types.
def __getattr__(self, attr):
return getattr(self.proxy_target, attr)
def __setattr__(self, attr, value):
proxied_attrs = set(('refresh_token', 'response_types'))
if attr in proxied_attrs:
setattr(self.proxy_target, attr, value)
else:
super(OpenIDConnectBase, self).__setattr__(attr, value)
def validate_authorization_request(self, request):
"""Validates the OpenID Connect authorization request parameters.
:returns: (list of scopes, dict of request info)
"""
# If request.prompt is 'none' then no login/authorization form should
# be presented to the user. Instead, a silent login/authorization
# should be performed.
if request.prompt == 'none':
raise OIDCNoPrompt()
else:
return self.proxy_target.validate_authorization_request(request)
def _inflate_claims(self, request):
# this may be called multiple times in a single request so make sure we only de-serialize the claims once
if request.claims and not isinstance(request.claims, dict):
# specific claims are requested during the Authorization Request and may be requested for inclusion
# in either the id_token or the UserInfo endpoint response
# see http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
try:
request.claims = loads(request.claims)
except Exception as ex:
raise InvalidRequestError(
description='Malformed claims parameter',
uri='http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter'
)
def add_id_token(self, token, token_handler, request):
# Treat it as normal OAuth 2 auth code request if openid is not present
if not request.scopes or 'openid' not in request.scopes:
return token
# Only add an id token on auth/token step if asked for.
if request.response_type and 'id_token' not in request.response_type:
return token
if request.max_age:
d = datetime.datetime.utcnow()
token['auth_time'] = d.isoformat('T') + 'Z'
# TODO: acr claims (probably better handled by server code using oauthlib in get_id_token)
token['id_token'] = self.request_validator.get_id_token(
token, token_handler, request)
return token
def openid_authorization_validator(self, request):
"""Perform OpenID Connect specific authorization request validation.
nonce
OPTIONAL. String value used to associate a Client session with
an ID Token, and to mitigate replay attacks. The value is
passed through unmodified from the Authentication Request to
the ID Token. Sufficient entropy MUST be present in the nonce
values used to prevent attackers from guessing values
display
OPTIONAL. ASCII string value that specifies how the
Authorization Server displays the authentication and consent
user interface pages to the End-User. The defined values are:
page - The Authorization Server SHOULD display the
authentication and consent UI consistent with a full User
Agent page view. If the display parameter is not specified,
this is the default display mode.
popup - The Authorization Server SHOULD display the
authentication and consent UI consistent with a popup User
Agent window. The popup User Agent window should be of an
appropriate size for a login-focused dialog and should not
obscure the entire window that it is popping up over.
touch - The Authorization Server SHOULD display the
authentication and consent UI consistent with a device that
leverages a touch interface.
wap - The Authorization Server SHOULD display the
authentication and consent UI consistent with a "feature
phone" type display.
The Authorization Server MAY also attempt to detect the
capabilities of the User Agent and present an appropriate
display.
prompt
OPTIONAL. Space delimited, case sensitive list of ASCII string
values that specifies whether the Authorization Server prompts
the End-User for reauthentication and consent. The defined
values are:
none - The Authorization Server MUST NOT display any
authentication or consent user interface pages. An error is
returned if an End-User is not already authenticated or the
Client does not have pre-configured consent for the
requested Claims or does not fulfill other conditions for
processing the request. The error code will typically be
login_required, interaction_required, or another code
defined in Section 3.1.2.6. This can be used as a method to
check for existing authentication and/or consent.
login - The Authorization Server SHOULD prompt the End-User
for reauthentication. If it cannot reauthenticate the
End-User, it MUST return an error, typically
login_required.
consent - The Authorization Server SHOULD prompt the
End-User for consent before returning information to the
Client. If it cannot obtain consent, it MUST return an
error, typically consent_required.
select_account - The Authorization Server SHOULD prompt the
End-User to select a user account. This enables an End-User
who has multiple accounts at the Authorization Server to
select amongst the multiple accounts that they might have
current sessions for. If it cannot obtain an account
selection choice made by the End-User, it MUST return an
error, typically account_selection_required.
The prompt parameter can be used by the Client to make sure
that the End-User is still present for the current session or
to bring attention to the request. If this parameter contains
none with any other value, an error is returned.
max_age
OPTIONAL. Maximum Authentication Age. Specifies the allowable
elapsed time in seconds since the last time the End-User was
actively authenticated by the OP. If the elapsed time is
greater than this value, the OP MUST attempt to actively
re-authenticate the End-User. (The max_age request parameter
corresponds to the OpenID 2.0 PAPE [OpenID.PAPE] max_auth_age
request parameter.) When max_age is used, the ID Token returned
MUST include an auth_time Claim Value.
ui_locales
OPTIONAL. End-User's preferred languages and scripts for the
user interface, represented as a space-separated list of BCP47
[RFC5646] language tag values, ordered by preference. For
instance, the value "fr-CA fr en" represents a preference for
French as spoken in Canada, then French (without a region
designation), followed by English (without a region
designation). An error SHOULD NOT result if some or all of the
requested locales are not supported by the OpenID Provider.
id_token_hint
OPTIONAL. ID Token previously issued by the Authorization
Server being passed as a hint about the End-User's current or
past authenticated session with the Client. If the End-User
identified by the ID Token is logged in or is logged in by the
request, then the Authorization Server returns a positive
response; otherwise, it SHOULD return an error, such as
login_required. When possible, an id_token_hint SHOULD be
present when prompt=none is used and an invalid_request error
MAY be returned if it is not; however, the server SHOULD
respond successfully when possible, even if it is not present.
The Authorization Server need not be listed as an audience of
the ID Token when it is used as an id_token_hint value. If the
ID Token received by the RP from the OP is encrypted, to use it
as an id_token_hint, the Client MUST decrypt the signed ID
Token contained within the encrypted ID Token. The Client MAY
re-encrypt the signed ID token to the Authentication Server
using a key that enables the server to decrypt the ID Token,
and use the re-encrypted ID token as the id_token_hint value.
login_hint
OPTIONAL. Hint to the Authorization Server about the login
identifier the End-User might use to log in (if necessary).
This hint can be used by an RP if it first asks the End-User
for their e-mail address (or other identifier) and then wants
to pass that value as a hint to the discovered authorization
service. It is RECOMMENDED that the hint value match the value
used for discovery. This value MAY also be a phone number in
the format specified for the phone_number Claim. The use of
this parameter is left to the OP's discretion.
acr_values
OPTIONAL. Requested Authentication Context Class Reference
values. Space-separated string that specifies the acr values
that the Authorization Server is being requested to use for
processing this Authentication Request, with the values
appearing in order of preference. The Authentication Context
Class satisfied by the authentication performed is returned as
the acr Claim Value, as specified in Section 2. The acr Claim
is requested as a Voluntary Claim by this parameter.
"""
# Treat it as normal OAuth 2 auth code request if openid is not present
if not request.scopes or 'openid' not in request.scopes:
return {}
prompt = request.prompt if request.prompt else []
if hasattr(prompt, 'split'):
prompt = prompt.strip().split()
prompt = set(prompt)
if 'none' in prompt:
if len(prompt) > 1:
msg = 'Prompt none is mutually exclusive with other values.'
raise InvalidRequestError(request=request, description=msg)
if not self.request_validator.validate_silent_login(request):
raise LoginRequired(request=request)
if not self.request_validator.validate_silent_authorization(request):
raise ConsentRequired(request=request)
self._inflate_claims(request)
if not self.request_validator.validate_user_match(
request.id_token_hint, request.scopes, request.claims, request):
msg = 'Session user does not match client supplied user.'
raise LoginRequired(request=request, description=msg)
request_info = {
'display': request.display,
'nonce': request.nonce,
'prompt': prompt,
'ui_locales': request.ui_locales.split() if request.ui_locales else [],
'id_token_hint': request.id_token_hint,
'login_hint': request.login_hint,
'claims': request.claims
}
return request_info
OpenIDConnectBase = GrantTypeBase

View File

@@ -0,0 +1,105 @@
import logging
log = logging.getLogger(__name__)
class Dispatcher(object):
default_grant = None
oidc_grant = None
class AuthorizationCodeGrantDispatcher(Dispatcher):
"""
This is an adapter class that will route simple Authorization Code requests,
those that have response_type=code and a scope
including 'openid' to either the default_grant or the oidc_grant based on
the scopes requested.
"""
def __init__(self, default_grant=None, oidc_grant=None):
self.default_grant = default_grant
self.oidc_grant = oidc_grant
def _handler_for_request(self, request):
handler = self.default_grant
if request.scopes and 'openid' in request.scopes:
handler = self.oidc_grant
log.debug('Selecting handler for request %r.', handler)
return handler
def create_authorization_response(self, request, token_handler):
return self._handler_for_request(request).create_authorization_response(
request, token_handler)
def validate_authorization_request(self, request):
return self._handler_for_request(request).validate_authorization_request(
request)
class ImplicitTokenGrantDispatcher(Dispatcher):
"""
This is an adapter class that will route simple Authorization Code requests,
those that have response_type=code and a scope
including 'openid' to either the default_grant or the oidc_grant based on
the scopes requested.
"""
def __init__(self, default_grant=None, oidc_grant=None):
self.default_grant = default_grant
self.oidc_grant = oidc_grant
def _handler_for_request(self, request):
handler = self.default_grant
if request.scopes and 'openid' in request.scopes and 'id_token' in request.response_type:
handler = self.oidc_grant
log.debug('Selecting handler for request %r.', handler)
return handler
def create_authorization_response(self, request, token_handler):
return self._handler_for_request(request).create_authorization_response(
request, token_handler)
def validate_authorization_request(self, request):
return self._handler_for_request(request).validate_authorization_request(
request)
class AuthorizationTokenGrantDispatcher(Dispatcher):
"""
This is an adapter class that will route simple Token requests, those that
authorization_code have a scope
including 'openid' to either the default_grant or the oidc_grant based on
the scopes requested.
"""
def __init__(self, request_validator, default_grant=None, oidc_grant=None):
self.default_grant = default_grant
self.oidc_grant = oidc_grant
self.request_validator = request_validator
def _handler_for_request(self, request):
handler = self.default_grant
scopes = ()
parameters = dict(request.decoded_body)
client_id = parameters.get('client_id', None)
code = parameters.get('code', None)
redirect_uri = parameters.get('redirect_uri', None)
# If code is not pressent fallback to `default_grant` wich will
# raise an error for the missing `code` in `create_token_response` step.
if code:
scopes = self.request_validator.get_authorization_code_scopes(
client_id, code, redirect_uri, request)
if 'openid' in scopes:
handler = self.oidc_grant
log.debug('Selecting handler for request %r.', handler)
return handler
def create_token_response(self, request, token_handler):
handler = self._handler_for_request(request)
return handler.create_token_response(request, token_handler)

View File

@@ -0,0 +1,32 @@
class OIDCNoPrompt(Exception):
"""Exception used to inform users that no explicit authorization is needed.
Normally users authorize requests after validation of the request is done.
Then post-authorization validation is again made and a response containing
an auth code or token is created. However, when OIDC clients request
no prompting of user authorization the final response is created directly.
Example (without the shortcut for no prompt)
scopes, req_info = endpoint.validate_authorization_request(url, ...)
authorization_view = create_fancy_auth_form(scopes, req_info)
return authorization_view
Example (with the no prompt shortcut)
try:
scopes, req_info = endpoint.validate_authorization_request(url, ...)
authorization_view = create_fancy_auth_form(scopes, req_info)
return authorization_view
except OIDCNoPrompt:
# Note: Location will be set for you
headers, body, status = endpoint.create_authorization_response(url, ...)
redirect_view = create_redirect(headers, body, status)
return redirect_view
"""
def __init__(self):
msg = ("OIDC request for no user interaction received. Do not ask user "
"for authorization, it should been done using silent "
"authentication through create_authorization_response. "
"See OIDCNoPrompt.__doc__ for more details.")
super(OIDCNoPrompt, self).__init__(msg)

View File

@@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
"""oauthlib.openid.connect.core.grant_types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, unicode_literals
import logging
from oauthlib.oauth2.rfc6749.grant_types.authorization_code import AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant
from oauthlib.oauth2.rfc6749.errors import InvalidRequestError
from .base import GrantTypeBase
from ..request_validator import RequestValidator
log = logging.getLogger(__name__)
class HybridGrant(GrantTypeBase):
def __init__(self, request_validator=None, **kwargs):
self.request_validator = request_validator or RequestValidator()
self.proxy_target = OAuth2AuthorizationCodeGrant(
request_validator=request_validator, **kwargs)
# All hybrid response types should be fragment-encoded.
self.proxy_target.default_response_mode = 'fragment'
self.register_response_type('code id_token')
self.register_response_type('code token')
self.register_response_type('code id_token token')
self.custom_validators.post_auth.append(self.openid_authorization_validator)
# Hybrid flows can return the id_token from the authorization
# endpoint as part of the 'code' response
self.register_code_modifier(self.add_token)
self.register_code_modifier(self.add_id_token)
self.register_token_modifier(self.add_id_token)
def openid_authorization_validator(self, request):
"""Additional validation when following the Authorization Code flow."""
request_info = super(HybridGrant,
self).openid_authorization_validator(request)
if not request_info: # returns immediately if OAuth2.0
return request_info
# REQUIRED if the Response Type of the request is `code
# id_token` or `code id_token token` and OPTIONAL when the
# Response Type of the request is `code token`. It is a string
# value used to associate a Client session with an ID Token,
# and to mitigate replay attacks. The value is passed through
# unmodified from the Authentication Request to the ID
# Token. Sufficient entropy MUST be present in the `nonce`
# values used to prevent attackers from guessing values. For
# implementation notes, see Section 15.5.2.
if request.response_type in ['code id_token', 'code id_token token']:
if not request.nonce:
raise InvalidRequestError(
request=request,
description='Request is missing mandatory nonce parameter.')
return request_info

View File

@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
"""oauthlib.openid.connect.core.grant_types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, unicode_literals
import logging
from .base import GrantTypeBase
from oauthlib.oauth2.rfc6749.grant_types.implicit import ImplicitGrant as OAuth2ImplicitGrant
from oauthlib.oauth2.rfc6749.errors import InvalidRequestError
log = logging.getLogger(__name__)
class ImplicitGrant(GrantTypeBase):
def __init__(self, request_validator=None, **kwargs):
self.proxy_target = OAuth2ImplicitGrant(
request_validator=request_validator, **kwargs)
self.register_response_type('id_token')
self.register_response_type('id_token token')
self.custom_validators.post_auth.append(self.openid_authorization_validator)
self.register_token_modifier(self.add_id_token)
def add_id_token(self, token, token_handler, request):
if 'state' not in token:
token['state'] = request.state
return super(ImplicitGrant, self).add_id_token(token, token_handler,
request)
def openid_authorization_validator(self, request):
"""Additional validation when following the implicit flow."""
request_info = super(ImplicitGrant,
self).openid_authorization_validator(request)
if not request_info: # returns immediately if OAuth2.0
return request_info
# REQUIRED. String value used to associate a Client session with an ID
# Token, and to mitigate replay attacks. The value is passed through
# unmodified from the Authentication Request to the ID Token.
# Sufficient entropy MUST be present in the nonce values used to
# prevent attackers from guessing values. For implementation notes, see
# Section 15.5.2.
if not request.nonce:
raise InvalidRequestError(
request=request,
description='Request is missing mandatory nonce parameter.')
return request_info

View File

@@ -0,0 +1,218 @@
# -*- coding: utf-8 -*-
"""oauthlib.openid.connect.core.request_validator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, unicode_literals
import logging
from oauthlib.oauth2.rfc6749.request_validator import RequestValidator as OAuth2RequestValidator
log = logging.getLogger(__name__)
class RequestValidator(OAuth2RequestValidator):
def get_authorization_code_scopes(self, client_id, code, redirect_uri,
request):
""" Extracts scopes from saved authorization code.
The scopes returned by this method is used to route token requests
based on scopes passed to Authorization Code requests.
With that the token endpoint knows when to include OpenIDConnect
id_token in token response only based on authorization code scopes.
Only code param should be sufficient to retrieve grant code from
any storage you are using, `client_id` and `redirect_uri` can gave a
blank value `""` don't forget to check it before using those values
in a select query if a database is used.
:param client_id: Unicode client identifier
:param code: Unicode authorization code grant
:param redirect_uri: Unicode absolute URI
:return: A list of scope
Method is used by:
- Authorization Token Grant Dispatcher
"""
raise NotImplementedError('Subclasses must implement this method.')
def get_jwt_bearer_token(self, token, token_handler, request):
"""Get JWT Bearer token or OpenID Connect ID token
If using OpenID Connect this SHOULD call
`oauthlib.oauth2.RequestValidator.get_id_token`
:param token: A Bearer token dict
:param token_handler: the token handler (BearerToken class)
:param request: OAuthlib request.
:type request: oauthlib.common.Request
:return: The JWT Bearer token or OpenID Connect ID token (a JWS signed
JWT)
Method is used by JWT Bearer and OpenID Connect tokens:
- JWTToken.create_token
"""
raise NotImplementedError('Subclasses must implement this method.')
def get_id_token(self, token, token_handler, request):
"""Get OpenID Connect ID token
In the OpenID Connect workflows when an ID Token is requested this
method is called.
Subclasses should implement the construction, signing and optional
encryption of the
ID Token as described in the OpenID Connect spec.
In addition to the standard OAuth2 request properties, the request may
also contain
these OIDC specific properties which are useful to this method:
- nonce, if workflow is implicit or hybrid and it was provided
- claims, if provided to the original Authorization Code request
The token parameter is a dict which may contain an ``access_token``
entry, in which
case the resulting ID Token *should* include a calculated ``at_hash``
claim.
Similarly, when the request parameter has a ``code`` property defined,
the ID Token
*should* include a calculated ``c_hash`` claim.
http://openid.net/specs/openid-connect-core-1_0.html (sections
`3.1.3.6`_, `3.2.2.10`_, `3.3.2.11`_)
.. _`3.1.3.6`:
http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
.. _`3.2.2.10`:
http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDToken
.. _`3.3.2.11`:
http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken
:param token: A Bearer token dict
:param token_handler: the token handler (BearerToken class)
:param request: OAuthlib request.
:type request: oauthlib.common.Request
:return: The ID Token (a JWS signed JWT)
"""
# the request.scope should be used by the get_id_token() method to determine which claims to include in the resulting id_token
raise NotImplementedError('Subclasses must implement this method.')
def validate_jwt_bearer_token(self, token, scopes, request):
"""Ensure the JWT Bearer token or OpenID Connect ID token are valids and authorized access to scopes.
If using OpenID Connect this SHOULD call
`oauthlib.oauth2.RequestValidator.get_id_token`
If not using OpenID Connect this can `return None` to avoid 5xx rather
401/3 response.
OpenID connect core 1.0 describe how to validate an id_token:
-
http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
-
http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDTValidation
-
http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation
-
http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation2
:param token: Unicode Bearer token
:param scopes: List of scopes (defined by you)
:param request: OAuthlib request.
:type request: oauthlib.common.Request
:rtype: True or False
Method is indirectly used by all core OpenID connect JWT token issuing
grant types:
- Authorization Code Grant
- Implicit Grant
- Hybrid Grant
"""
raise NotImplementedError('Subclasses must implement this method.')
def validate_id_token(self, token, scopes, request):
"""Ensure the id token is valid and authorized access to scopes.
OpenID connect core 1.0 describe how to validate an id_token:
-
http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
-
http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDTValidation
-
http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation
-
http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation2
:param token: Unicode Bearer token
:param scopes: List of scopes (defined by you)
:param request: OAuthlib request.
:type request: oauthlib.common.Request
:rtype: True or False
Method is indirectly used by all core OpenID connect JWT token issuing
grant types:
- Authorization Code Grant
- Implicit Grant
- Hybrid Grant
"""
raise NotImplementedError('Subclasses must implement this method.')
def validate_silent_authorization(self, request):
"""Ensure the logged in user has authorized silent OpenID authorization.
Silent OpenID authorization allows access tokens and id tokens to be
granted to clients without any user prompt or interaction.
:param request: OAuthlib request.
:type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
- OpenIDConnectAuthCode
- OpenIDConnectImplicit
- OpenIDConnectHybrid
"""
raise NotImplementedError('Subclasses must implement this method.')
def validate_silent_login(self, request):
"""Ensure session user has authorized silent OpenID login.
If no user is logged in or has not authorized silent login, this
method should return False.
If the user is logged in but associated with multiple accounts and
not selected which one to link to the token then this method should
raise an oauthlib.oauth2.AccountSelectionRequired error.
:param request: OAuthlib request.
:type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
- OpenIDConnectAuthCode
- OpenIDConnectImplicit
- OpenIDConnectHybrid
"""
raise NotImplementedError('Subclasses must implement this method.')
def validate_user_match(self, id_token_hint, scopes, claims, request):
"""Ensure client supplied user id hint matches session user.
If the sub claim or id_token_hint is supplied then the session
user must match the given ID.
:param id_token_hint: User identifier string.
:param scopes: List of OAuth 2 scopes and OpenID claims (strings).
:param claims: OpenID Connect claims dict.
:param request: OAuthlib request.
:type request: oauthlib.common.Request
:rtype: True or False
Method is used by:
- OpenIDConnectAuthCode
- OpenIDConnectImplicit
- OpenIDConnectHybrid
"""
raise NotImplementedError('Subclasses must implement this method.')

View File

@@ -0,0 +1,51 @@
"""authlib.openid.connect.core.tokens ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This module contains methods for adding JWT tokens to requests.
"""
from __future__ import absolute_import, unicode_literals
from oauthlib.oauth2.rfc6749.tokens import TokenBase, random_token_generator
class JWTToken(TokenBase):
__slots__ = ('request_validator', 'token_generator',
'refresh_token_generator', 'expires_in')
def __init__(self,
request_validator=None,
token_generator=None,
expires_in=None,
refresh_token_generator=None):
self.request_validator = request_validator
self.token_generator = token_generator or random_token_generator
self.refresh_token_generator = (
refresh_token_generator or self.token_generator)
self.expires_in = expires_in or 3600
def create_token(self, request, refresh_token=False):
"""Create a JWT Token, using requestvalidator method."""
if callable(self.expires_in):
expires_in = self.expires_in(request)
else:
expires_in = self.expires_in
request.expires_in = expires_in
return self.request_validator.get_jwt_bearer_token(None, None, request)
def validate_request(self, request):
token = None
if 'Authorization' in request.headers:
token = request.headers.get('Authorization')[7:]
else:
token = request.access_token
return self.request_validator.validate_jwt_bearer_token(
token, request.scopes, request)
def estimate_type(self, request):
token = request.headers.get('Authorization', '')[7:]
if token.startswith('ey') and token.count('.') in (2, 4):
return 10
else:
return 0