Skip to content

Commit

Permalink
Incremental updates to providers
Browse files Browse the repository at this point in the history
  • Loading branch information
ib-lundgren committed Dec 16, 2012
1 parent 8a5c7d2 commit eee4b60
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 131 deletions.
21 changes: 21 additions & 0 deletions oauthlib/oauth1/rfc5849/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,27 @@ def validate_verifier(self, client_key, request_token, verifier):
"""
raise NotImplementedError("Subclasses must implement this function.")

def verify_request_token_request(self, uri, http_method='GET', body=None,
headers=None):
"""Verify the initial request in the OAuth workflow.
During this step the client obtains a request token for use during
resource owner authorization (which is outside the scope of oauthlib).
"""
return self.verify_request(uri, http_method=http_method, body=body,
headers=headers, require_resource_owner=False,
require_realm=True)

def verify_access_token_request(self, uri, http_method='GET', body=None,
headers=None):
"""Verify the second request in the OAuth workflow.
During this step the client obtains the access token for use when
accessing protected resources.
"""
return self.verify_request(uri, http_method=http_method, body=body,
headers=headers, require_verifier=True)

def verify_request(self, uri, http_method='GET', body=None,
headers=None, require_resource_owner=True, require_verifier=False,
require_realm=False, required_realm=None):
Expand Down
101 changes: 46 additions & 55 deletions oauthlib/oauth2/draft25/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
for signing and checking OAuth 2.0 draft 25 requests.
"""
from oauthlib.common import Request
from oauthlib.oauth2.draft25 import errors, tokens
from oauthlib.oauth2.draft25 import tokens
from .parameters import prepare_grant_uri, prepare_token_request
from .parameters import parse_authorization_code_response
from .parameters import parse_implicit_response, parse_token_response
from .utils import params_from_uri


AUTH_HEADER = 'auth_header'
Expand Down Expand Up @@ -564,14 +563,26 @@ class AuthorizationEndpoint(object):
MUST NOT be included more than once.
"""

def __init__(self, default_token=None, response_types=None):
def __init__(self, default_response_type, default_token=None,
response_types=None):
self._response_types = response_types or {}
self._default_response_type = default_response_type
self._default_token = default_token or tokens.BearerToken()

assert self.default_response_type in self.response_types

@property
def response_types(self):
return self._response_types

@property
def default_response_type(self):
return self._default_response_type

@property
def default_response_type_handler(self):
return self.response_types.get(self.default_response_type)

@property
def default_token(self):
return self._default_token
Expand All @@ -580,74 +591,59 @@ def create_authorization_response(self, uri, http_method='GET', body=None,
headers=None):
"""Extract response_type and route to the designated handler."""
request = Request(uri, http_method=http_method, body=body, headers=headers)
query_params = params_from_uri(request.uri)
body_params = request.decoded_body

# Prioritize response_type defined as query param over those in body.
# Chosen because the two core grant types utilizing the response type
# parameter both supply it in the uri. However it is not specified
# explicitely in RFC 6748.
if 'response_type' in query_params:
request.response_type = query_params.get('response_type')
elif 'response_type' in body_params:
request.response_type = body_params.get('response_type')
else:
raise errors.InvalidRequestError(
description='The response_type parameter is missing.')

if not request.response_type in self.response_types:
raise errors.UnsupportedResponseTypeError(
description='Invalid response type')

return self.response_types.get(
request.response_type).create_authorization_response(
response_type_handler = self.response_types.get(
request.response_type, self.default_response_type_handler)
return response_type_handler.create_authorization_response(
request, self.default_token)


class TokenEndpoint(object):

def __init__(self, default_token=None, grant_types=None):
def __init__(self, default_grant_type, default_token=None,
grant_types=None):
self._grant_types = grant_types or {}
self._default_token = default_token or tokens.BearerToken()
self._default_grant_type = default_grant_type

@property
def grant_types(self):
return self._grant_types

@property
def default_grant_type(self):
return self._default_grant_type

@property
def default_grant_type_handler(self):
return self.grant_types.get(self.default_grant_type)

@property
def default_token(self):
return self._default_token

def create_token_response(self, uri, http_method='GET', body=None, headers=None):
"""Extract grant_type and route to the designated handler."""
request = Request(uri, http_method=http_method, body=body, headers=headers)
query_params = params_from_uri(self.request.uri)
body_params = self.request.decoded_body

# Prioritize grant_type defined as body param over those in uri.
# Chosen because all three core grant types supply this parameter
# in the body. However it is not specified explicitely in RFC 6748.
if 'grant_type' in body_params:
request.grant_type = query_params.get('grant_type')
elif 'grant_type' in query_params:
request.grant_type = body_params.get('grant_type')
else:
raise errors.InvalidRequestError(
description='The grant_type parameter is missing.')

if not request.grant_type in self.grant_types:
raise errors.UnsupportedGrantTypeError(
description='Invalid response type')
grant_type_handler = self.grant_types.get(request.grant_type,
self.default_grant_type_handler)

return self.grant_types.get(
request.grant_type).create_token_response(
request, self.default_token)
return grant_type_handler.create_token_response(request, self.default_token)


class ResourceEndpoint(object):

def __init__(self, token_types=None):
def __init__(self, default_token_type, token_types=None):
self._tokens = token_types or {'Bearer': tokens.BearerToken()}
self._default_token_type = default_token_type

@property
def default_token_type(self):
return self._default_token_type

@property
def default_token_type_handler(self):
return self.tokens.get(self.default_token_type)

@property
def tokens(self):
Expand All @@ -658,15 +654,10 @@ def verify_request(self, uri, http_method='GET', body=None, headers=None):
request = Request(uri, http_method, body, headers)
request.token_type = self.find_token_type(request)

# TODO(ib-lundgren): How to return errors is not strictly defined and
# should allow for customization.
if not request.token_type:
raise ValueError('Could not determine the token type.')

if not request.token_type in self.tokens:
raise ValueError('Unsupported token type.')
token_type_handler = self.tokens.get(request.token_type,
self.default_token_type_handler)

return self.tokens.get(request.token_type).validate_request(request)
return token_type_handler.validate_request(request)

def find_token_type(self, request):
"""Token type identification.
Expand All @@ -676,8 +667,8 @@ def find_token_type(self, request):
the most likely token type (if any) by asking each known token type
to give an estimation based on the request.
"""
estimates = sorted((t.estimate_type(request) for t in self.tokens))
return estimates[0] if len(estimates) else None
estimates = sorted(((t.estimate_type(request), n) for n, t in self.tokens.items()))
return estimates[0][1] if len(estimates) else None


class Server(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoint):
Expand Down
17 changes: 15 additions & 2 deletions oauthlib/oauth2/draft25/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class OAuth2Error(Exception):

def __init__(self, description=None, uri=None, state=None):
def __init__(self, description=None, uri=None, state=None, status_code=400):
"""
description: A human-readable ASCII [USASCII] text providing
additional information, used to assist the client
Expand All @@ -30,6 +30,7 @@ def __init__(self, description=None, uri=None, state=None):
self.description = description
self.uri = uri
self.state = state
self.status_code = status_code

@property
def twotuples(self):
Expand All @@ -48,7 +49,19 @@ def urlencoded(self):

@property
def json(self):
return json.dumps(self.twotuples)
return json.dumps(dict(self.twotuples))


class FatalClientError(OAuth2Error):
pass


class RedirectURIError(FatalClientError):
error = 'invalid_redirect_uri'


class ClientIDError(FatalClientError):
error = 'invalid_client_id'


class InvalidRequestError(OAuth2Error):
Expand Down
66 changes: 49 additions & 17 deletions oauthlib/oauth2/draft25/grant_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"""
from __future__ import unicode_literals
import json
from oauthlib.common import generate_token, add_params_to_uri
from oauthlib import common
from oauthlib.oauth2.draft25 import errors
from oauthlib.uri_validate import is_absolute_uri

Expand Down Expand Up @@ -100,7 +100,7 @@ def __init__(self, request_validator=None):

def create_authorization_code(self, request):
"""Generates an authorization grant represented as a dictionary."""
grant = {'code': generate_token()}
grant = {'code': common.generate_token()}
if hasattr(request, 'state') and request.state:
grant['state'] = request.state
return grant
Expand All @@ -113,14 +113,27 @@ def create_authorization_response(self, request, token_handler):
try:
self.request_validator.validate_request(request)

# If the request fails due to a missing, invalid, or mismatching
# redirection URI, or if the client identifier is missing or invalid,
# the authorization server SHOULD inform the resource owner of the
# error and MUST NOT automatically redirect the user-agent to the
# invalid redirection URI.
except errors.FatalClientError:
raise

# If the resource owner denies the access request or if the request
# fails for reasons other than a missing or invalid redirection URI,
# the authorization server informs the client by adding the following
# parameters to the query component of the redirection URI using the
# "application/x-www-form-urlencoded" format, per Appendix B:
# http://tools.ietf.org/html/rfc6749#appendix-B
except errors.OAuth2Error as e:
request.redirect_uri = getattr(request, 'redirect_uri',
self.error_uri)
return add_params_to_uri(request.redirect_uri, e.twotuples)
request.redirect_uri = request.redirect_uri or self.error_uri
return common.add_params_to_uri(request.redirect_uri, e.twotuples), None, None, e.status_code

grant = self.create_authorization_code(request)
self.save_authorization_code(request.client_id, grant)
return add_params_to_uri(request.redirect_uri, grant.items()), None, None
return common.add_params_to_uri(request.redirect_uri, grant.items()), None, None, 200

def create_token_response(self, request, token_handler):
"""Validate the authorization code.
Expand All @@ -134,8 +147,9 @@ def create_token_response(self, request, token_handler):
try:
self.validate_token_request(request)
except errors.OAuth2Error as e:
return e.json
return json.dumps(token_handler(request, refresh_token=True))
return None, None, e.json, e.status_code

return None, None, json.dumps(token_handler.create_token(request, refresh_token=True)), 200

def validate_token_request(self, request):

Expand Down Expand Up @@ -267,12 +281,28 @@ def create_token_response(self, request, token_handler):
"""
try:
self.request_validator.validate_request(request)

# If the request fails due to a missing, invalid, or mismatching
# redirection URI, or if the client identifier is missing or invalid,
# the authorization server SHOULD inform the resource owner of the
# error and MUST NOT automatically redirect the user-agent to the
# invalid redirection URI.
except errors.FatalClientError:
raise

# If the resource owner denies the access request or if the request
# fails for reasons other than a missing or invalid redirection URI,
# the authorization server informs the client by adding the following
# parameters to the fragment component of the redirection URI using the
# "application/x-www-form-urlencoded" format, per Appendix B:
# http://tools.ietf.org/html/rfc6749#appendix-B
except errors.OAuth2Error as e:
return add_params_to_uri(request.redirect_uri, e.twotuples,
fragment=True)
token = token_handler(request, refresh_token=False)
return add_params_to_uri(request.redirect_uri, token.items(),
fragment=True), {}, None
return common.add_params_to_uri(request.redirect_uri, e.twotuples,
fragment=True), None, None, e.status_code

token = token_handler.create_token(request, refresh_token=False)
return common.add_params_to_uri(request.redirect_uri, token.items(),
fragment=True), None, None, 200


class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
Expand Down Expand Up @@ -354,8 +384,9 @@ def create_token_response(self, request, token_handler,
self.request_validator.authenticate_client(request)
self.validate_token_request(request)
except errors.OAuth2Error as e:
return None, {}, e.json
return None, {}, json.dumps(token_handler(request, refresh_token=True))
return None, {}, e.json, e.status_code

return None, {}, json.dumps(token_handler.create_token(request, refresh_token=True)), 200

def validate_token_request(self, request):
for param in ('grant_type', 'username', 'password'):
Expand Down Expand Up @@ -430,8 +461,9 @@ def create_token_response(self, request, token_handler):
self.request_validator.authenticate_client(request)
self.validate_token_request(request)
except errors.OAuth2Error as e:
return None, {}, e.json
return None, {}, json.dumps(token_handler(request, refresh_token=True))
return None, {}, e.json, e.status_code

return None, {}, json.dumps(token_handler.create_token(request, refresh_token=False)), 200

def validate_token_request(self, request):
if not getattr(request, 'grant_type'):
Expand Down
Loading

0 comments on commit eee4b60

Please sign in to comment.