Skip to content

Commit

Permalink
Allow unauthenticated OPTIONS request to /userinfo
Browse files Browse the repository at this point in the history
Implements the solution suggested by @defgsus in #304
  • Loading branch information
zvyn committed May 25, 2019
1 parent a7b07e2 commit 7048f29
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 6 deletions.
13 changes: 11 additions & 2 deletions oidc_provider/lib/utils/oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,26 @@ def extract_client_auth(request):
return (client_id, client_secret)


def protected_resource_view(scopes=None):
def protected_resource_view(scopes=None, unprotected_methods=None):
"""
View decorator. The client accesses protected resources by presenting the
access token to the resource server.
https://tools.ietf.org/html/rfc6749#section-7
See: https://tools.ietf.org/html/rfc6749#section-7
Skips all checks if the request-method is in unprotected_methods. This can
be useful to authorize unauthenticated OPTIONS requests.
"""
if scopes is None:
scopes = []

if unprotected_methods is None:
unprotected_methods = []

def wrapper(view):
def view_wrapper(request, *args, **kwargs):
if request.method in unprotected_methods: # skip checking token
return view(request, *args, **kwargs)

access_token = extract_access_token(request)

try:
Expand Down
20 changes: 17 additions & 3 deletions oidc_provider/tests/cases/test_userinfo_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def setUp(self):
self.factory = RequestFactory()
self.user = create_fake_user()
self.client = create_fake_client(response_type='code')
self.url = reverse('oidc_provider:userinfo')

def _create_token(self, extra_scope=None):
"""
Expand Down Expand Up @@ -65,9 +66,7 @@ def _post_request(self, access_token, schema='Bearer'):
`post_data` parameters using the 'multipart/form-data'
format.
"""
url = reverse('oidc_provider:userinfo')

request = self.factory.post(url, data={}, content_type='multipart/form-data')
request = self.factory.post(self.url, data={}, content_type='multipart/form-data')

request.META['HTTP_AUTHORIZATION'] = schema + ' ' + access_token

Expand Down Expand Up @@ -164,3 +163,18 @@ def test_user_claims_in_response(self):
self.assertIn('address', response_dic, msg='"address" claim should be in response.')
self.assertIn(
'country', response_dic['address'], msg='"country" claim should be in response.')

def test_options_request_without_token(self):
request = self.factory.options(self.url)
request.META['HTTP_ORIGIN'] = "test.example.com"
response = userinfo(request)

expected_headers = {
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Origin": "test.example.com",
}

self.assertEqual(response.status_code, 200)
for key, value in expected_headers.items():
self.assertEqual(response[key], value)
2 changes: 1 addition & 1 deletion oidc_provider/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def post(self, request, *args, **kwargs):


@require_http_methods(['GET', 'POST', 'OPTIONS'])
@protected_resource_view(['openid'])
@protected_resource_view(['openid'], unprotected_methods=['OPTIONS'])
def userinfo(request, *args, **kwargs):
"""
Create a dictionary with all the requested claims about the End-User.
Expand Down

0 comments on commit 7048f29

Please sign in to comment.