Skip to content
Snippets Groups Projects
Commit 9df1fa33 authored by Julian's avatar Julian
Browse files

Fix regression: OAuth2 token endpoint does not support Basic-Auth

Fixes #114

Regression was introduced by 45d4598e (Replace flask_oauthlib with plain
oauthlib). Support for HTTP Basic authentication scheme for client
authentication is actually required by RFC6749.
parent eba71ac7
No related branches found
No related tags found
No related merge requests found
......@@ -172,6 +172,16 @@ class TestViews(UffdTestCase):
self.assertEqual(r.json['token_type'], 'Bearer')
self.assertEqual(r.json['scope'], 'profile')
# Regression test for #114 (OAuth2 token endpoint does not support Basic-Auth)
def test_token_basicauth(self):
r = self.client.post(path=url_for('oauth2.token'),
data={'grant_type': 'authorization_code', 'code': self.get_auth_code(), 'redirect_uri': 'http://localhost:5009/callback'},
headers={'Authorization': f'Basic dGVzdDp0ZXN0c2VjcmV0'}, follow_redirects=True)
self.assertEqual(r.status_code, 200)
self.assertEqual(r.content_type, 'application/json')
self.assertEqual(r.json['token_type'], 'Bearer')
self.assertEqual(r.json['scope'], 'profile')
def test_token_invalid_code(self):
r = self.client.post(path=url_for('oauth2.token'),
data={'grant_type': 'authorization_code', 'code': 'abcdef', 'redirect_uri': 'http://localhost:5009/callback', 'client_id': 'test', 'client_secret': 'testsecret'}, follow_redirects=True)
......
......
import datetime
import functools
import secrets
import urllib.parse
from flask import Blueprint, request, jsonify, render_template, session, redirect, url_for, flash, abort
import oauthlib.oauth2
......@@ -29,6 +30,16 @@ class UffdRequestValidator(oauthlib.oauth2.RequestValidator):
return False
def authenticate_client(self, oauthreq, *args, **kwargs):
authorization = oauthreq.extra_credentials.get('authorization')
if authorization:
# From RFC6749 2.3.1:
# Clients in possession of a client password MAY use the HTTP Basic authentication
# scheme as defined in [RFC2617] to authenticate with the authorization server.
# The client identifier is encoded using the "application/x-www-form-urlencoded"
# encoding algorithm per Appendix B, and the encoded value is used as the username
# the client password is encoded using the same algorithm and used as the password.
oauthreq.client_id = urllib.parse.unquote(authorization.username)
oauthreq.client_secret = urllib.parse.unquote(authorization.password)
if oauthreq.client_secret is None:
return False
try:
......@@ -203,7 +214,8 @@ def authorize():
@bp.route('/token', methods=['GET', 'POST'])
def token():
headers, body, status = server.create_token_response(request.url, request.method, request.form, request.headers)
headers, body, status = server.create_token_response(request.url, request.method, request.form,
request.headers, {'authorization': request.authorization})
return body, status, headers
def oauth_required(*scopes):
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment