add CSRF token to state parameter
This commit is contained in:
parent
408bc20956
commit
c8494277a8
|
@ -33,7 +33,7 @@ def index():
|
||||||
if me:
|
if me:
|
||||||
return micropub.authorize(
|
return micropub.authorize(
|
||||||
me, redirect_url=url_for('micropub_callback', _external=True),
|
me, redirect_url=url_for('micropub_callback', _external=True),
|
||||||
scope=request.args.get('scope'))
|
next_url=url_for('index'), scope=request.args.get('scope'))
|
||||||
return """
|
return """
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import requests
|
||||||
import bs4
|
import bs4
|
||||||
import flask
|
import flask
|
||||||
import functools
|
import functools
|
||||||
|
import uuid
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version < '3':
|
if sys.version < '3':
|
||||||
|
@ -76,24 +77,23 @@ class MicropubClient:
|
||||||
if not auth_url:
|
if not auth_url:
|
||||||
auth_url = 'https://indieauth.com/auth'
|
auth_url = 'https://indieauth.com/auth'
|
||||||
|
|
||||||
|
csrf_token = uuid.uuid4().hex
|
||||||
|
flask.session['_micropub_csrf_token'] = csrf_token
|
||||||
# save the endpoints so we don't have to scrape the target page again
|
# save the endpoints so we don't have to scrape the target page again
|
||||||
# right awway
|
# right awway
|
||||||
try:
|
flask.session['_micropub_endpoints'] = (
|
||||||
flask.session['_micropub_endpoints'] = (auth_url, token_url,
|
auth_url, token_url, micropub_url)
|
||||||
micropub_url)
|
|
||||||
except RuntimeError:
|
|
||||||
pass # we'll look it up again later
|
|
||||||
|
|
||||||
auth_params = {
|
auth_url = auth_url + '?' + urlencode({
|
||||||
'me': me,
|
'me': me,
|
||||||
'client_id': self.client_id,
|
'client_id': self.client_id,
|
||||||
'redirect_uri': redirect_url,
|
'redirect_uri': redirect_url,
|
||||||
'scope': scope,
|
'scope': scope,
|
||||||
'state': next_url or '',
|
'state': '{}|{}'.format(csrf_token, next_url or ''),
|
||||||
}
|
})
|
||||||
|
flask.current_app.logger.debug('redirecting to %s', auth_url)
|
||||||
|
|
||||||
return flask.redirect(
|
return flask.redirect(auth_url)
|
||||||
auth_url + '?' + urlencode(auth_params))
|
|
||||||
|
|
||||||
def authorized_handler(self, f):
|
def authorized_handler(self, f):
|
||||||
"""Decorates the authorization callback endpoint. The endpoint should
|
"""Decorates the authorization callback endpoint. The endpoint should
|
||||||
|
@ -106,10 +106,21 @@ class MicropubClient:
|
||||||
return decorated
|
return decorated
|
||||||
|
|
||||||
def _handle_response(self):
|
def _handle_response(self):
|
||||||
redirect_uri = flask.url_for(flask.request.endpoint, _external=True)
|
|
||||||
access_token = None
|
access_token = None
|
||||||
|
redirect_uri = flask.url_for(flask.request.endpoint, _external=True)
|
||||||
state = flask.request.args.get('state')
|
state = flask.request.args.get('state')
|
||||||
next_url = state if state != '' else None
|
if state and '|' in state:
|
||||||
|
csrf_token, next_url = state.split('|', 1)
|
||||||
|
else:
|
||||||
|
csrf_token = next_url = None
|
||||||
|
|
||||||
|
if not csrf_token:
|
||||||
|
return AuthResponse(
|
||||||
|
next_url=next_url, error='no CSRF token in response')
|
||||||
|
|
||||||
|
if csrf_token != flask.session.get('_micropub_csrf_token'):
|
||||||
|
return AuthResponse(
|
||||||
|
next_url=next_url, error='mismatched CSRF token')
|
||||||
|
|
||||||
if '_micropub_endpoints' in flask.session:
|
if '_micropub_endpoints' in flask.session:
|
||||||
auth_url, token_url, micropub_url \
|
auth_url, token_url, micropub_url \
|
||||||
|
@ -126,15 +137,19 @@ class MicropubClient:
|
||||||
code = flask.request.args.get('code')
|
code = flask.request.args.get('code')
|
||||||
|
|
||||||
# validate the authorization code
|
# validate the authorization code
|
||||||
flask.current_app.logger.debug('Flask-Micropub: checking code against auth url: %s', auth_url)
|
auth_data = {
|
||||||
response = requests.post(auth_url, data={
|
|
||||||
'code': code,
|
'code': code,
|
||||||
'client_id': self.client_id,
|
'client_id': self.client_id,
|
||||||
'redirect_uri': redirect_uri,
|
'redirect_uri': redirect_uri,
|
||||||
'state': state,
|
'state': state,
|
||||||
})
|
}
|
||||||
flask.current_app.logger.debug('Flask-Micropub: auth response: %d - %s',
|
flask.current_app.logger.debug(
|
||||||
response.status_code, response.text)
|
'Flask-Micropub: checking code against auth url: %s, data: %s',
|
||||||
|
auth_url, auth_data)
|
||||||
|
response = requests.post(auth_url, data=auth_data)
|
||||||
|
flask.current_app.logger.debug(
|
||||||
|
'Flask-Micropub: auth response: %d - %s', response.status_code,
|
||||||
|
response.text)
|
||||||
|
|
||||||
rdata = parse_qs(response.text)
|
rdata = parse_qs(response.text)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
|
@ -160,15 +175,19 @@ class MicropubClient:
|
||||||
error='no micropub endpoint found.')
|
error='no micropub endpoint found.')
|
||||||
|
|
||||||
# request an access token
|
# request an access token
|
||||||
flask.current_app.logger.debug('Flask-Micropub: requesting access token from: %s', token_url)
|
token_data = {
|
||||||
token_response = requests.post(token_url, data={
|
|
||||||
'code': code,
|
'code': code,
|
||||||
'me': confirmed_me,
|
'me': confirmed_me,
|
||||||
'redirect_uri': redirect_uri,
|
'redirect_uri': redirect_uri,
|
||||||
'client_id': self.client_id,
|
'client_id': self.client_id,
|
||||||
'state': state,
|
'state': state,
|
||||||
})
|
}
|
||||||
flask.current_app.logger.debug('Flask-Micropub: token response: %d - %s',
|
flask.current_app.logger.debug(
|
||||||
|
'Flask-Micropub: requesting access token from: %s, data: %s',
|
||||||
|
token_url, token_data)
|
||||||
|
token_response = requests.post(token_url, data=token_data)
|
||||||
|
flask.current_app.logger.debug(
|
||||||
|
'Flask-Micropub: token response: %d - %s',
|
||||||
token_response.status_code, token_response.text)
|
token_response.status_code, token_response.text)
|
||||||
|
|
||||||
if token_response.status_code != 200:
|
if token_response.status_code != 200:
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -11,7 +11,7 @@ from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='Flask-Micropub',
|
name='Flask-Micropub',
|
||||||
version='0.1.3',
|
version='0.1.4',
|
||||||
url='https://github.com/kylewm/flask-micropub/',
|
url='https://github.com/kylewm/flask-micropub/',
|
||||||
license='BSD',
|
license='BSD',
|
||||||
author='Kyle Mahan',
|
author='Kyle Mahan',
|
||||||
|
|
Loading…
Reference in New Issue