Do not burn auth codes by authenticating before requesting an access

token

This broke authorization for endpoints that only allow a code to be
used once (e.g. Known).

A side effect is that authorization no longer falls back to authentication
if the token endpoint does not exist or returns an error.
This commit is contained in:
Kyle Mahan 2016-01-27 07:24:55 -08:00
parent cc9c7dfd21
commit 9fdd45a0de
3 changed files with 37 additions and 14 deletions

View File

@ -1,6 +1,14 @@
# Change Log
All notable changes to this project will be documented in this file.
## 0.2.5 - 2016-01-27
### Changed
- Bugfix: authorization_handler was burning the auth code by
delegating to authentication_handler. This broke authorization for
endpoints that only allow codes to be used once. A side effect of
this is that authorization no longer falls back to authentication
when there is no token_endpoint or the token_endpoint request fails.
## 0.2.4 - 2015-12-13
### Changed
- Replace `next_url` parameter with more general `state`

View File

@ -224,28 +224,37 @@ class MicropubClient:
return AuthResponse(me=confirmed_me, state=state)
def _handle_authorize_response(self):
authenticate_response = self._handle_authenticate_response()
code = flask.request.args.get('code')
wrapped_state = flask.request.args.get('state')
me = flask.request.args.get('me')
redirect_uri = flask.url_for(flask.request.endpoint, _external=True)
if authenticate_response.error:
return authenticate_response
if wrapped_state and '|' in wrapped_state:
csrf_token, state = wrapped_state.split('|', 1)
else:
csrf_token = state = None
if not csrf_token:
return AuthResponse(
state=state, error='no CSRF token in response')
if csrf_token != flask.session.get('_micropub_csrf_token'):
return AuthResponse(
state=state, error='mismatched CSRF token')
token_url, micropub_url = self._discover_endpoints(me)[1:]
if not token_url or not micropub_url:
# successfully auth'ed user, no micropub endpoint
return AuthResponse(
me=authenticate_response.me,
state=authenticate_response.state,
me=me,
state=state,
error='no micropub endpoint found.')
# request an access token
token_data = {
'code': code,
'me': authenticate_response.me,
'me': me,
'redirect_uri': redirect_uri,
'client_id': self.client_id,
'state': wrapped_state,
@ -260,26 +269,29 @@ class MicropubClient:
if token_response.status_code != 200:
return AuthResponse(
me=authenticate_response.me,
state=authenticate_response.state,
me=me,
state=state,
error='bad response from token endpoint: {}'
.format(token_response))
tdata = parse_qs(token_response.text)
if 'access_token' not in tdata:
return AuthResponse(
me=authenticate_response.me,
state=authenticate_response.state,
me=me,
state=state,
error='response from token endpoint missing access_token: {}'
.format(tdata))
# success!
access_token = tdata.get('access_token')[0]
confirmed_me = tdata.get('me')[0]
confirmed_scope = tdata.get('scope')[0]
return AuthResponse(
me=authenticate_response.me,
me=confirmed_me,
micropub_endpoint=micropub_url,
access_token=access_token,
state=authenticate_response.state)
scope=confirmed_scope,
state=state)
def _discover_endpoints(self, me):
me_response = requests.get(me)
@ -311,15 +323,18 @@ class AuthResponse:
micropub_endpoint (string): The endpoint to POST micropub requests to.
access_token (string): The authorized user's micropub access token.
state (string): The optional state that was passed to authorize.
scope (string): The scope that comes with the micropub access token
error (string): describes the error encountered if any. It is possible
that the authentication step will succeed but the access token step
will fail, in which case me will be non-None, and error will describe
this condition.
"""
def __init__(self, me=None, micropub_endpoint=None,
access_token=None, state=None, error=None):
access_token=None, state=None, scope=None,
error=None):
self.me = me
self.micropub_endpoint = micropub_endpoint
self.access_token = access_token
self.next_url = self.state = state
self.scope = scope
self.error = error

View File

@ -11,7 +11,7 @@ from setuptools import setup
setup(
name='Flask-Micropub',
version='0.2.4',
version='0.2.5',
url='https://github.com/kylewm/flask-micropub/',
license='BSD',
author='Kyle Mahan',