From 0adb95d25f122e16227444482223291ca25b00c1 Mon Sep 17 00:00:00 2001 From: Andy Clayton Date: Tue, 19 Jun 2018 11:09:45 -0500 Subject: [PATCH] example fix for userinfo CORS preflight request Example for https://github.com/juanifioren/django-oidc-provider/issues/249. If this approach seems acceptable I can add/update tests. --- oidc_provider/lib/utils/common.py | 24 ++++++++++++++++++++++++ oidc_provider/views.py | 23 ++++++++++++++++------- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/oidc_provider/lib/utils/common.py b/oidc_provider/lib/utils/common.py index 65157bb..9811575 100644 --- a/oidc_provider/lib/utils/common.py +++ b/oidc_provider/lib/utils/common.py @@ -2,6 +2,7 @@ from hashlib import sha224 import django from django.http import HttpResponse +from django.utils.cache import patch_vary_headers from oidc_provider import settings @@ -160,3 +161,26 @@ def run_processing_hook(subject, hook_settings_name, **kwargs): subject = hook(subject, **kwargs) return subject + + +def cors_allow_any(request, response): + """ + Add headers to permit CORS requests from any origin, with or without credentials, + with any headers. + """ + origin = request.META.get('HTTP_ORIGIN') + if not origin: + return response + + # From the CORS spec: The string "*" cannot be used for a resource that supports credentials. + response['Access-Control-Allow-Origin'] = origin + patch_vary_headers(response, ['Origin']) + response['Access-Control-Allow-Credentials'] = 'true' + + if request.method == 'OPTIONS': + if 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' in request.META: + response['Access-Control-Allow-Headers'] \ + = request.META['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'] + response['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS' + + return response diff --git a/oidc_provider/views.py b/oidc_provider/views.py index e6f3ddc..17965f4 100644 --- a/oidc_provider/views.py +++ b/oidc_provider/views.py @@ -19,7 +19,7 @@ try: except ImportError: from django.core.urlresolvers import reverse from django.contrib.auth import logout as django_user_logout -from django.http import JsonResponse +from django.http import JsonResponse, HttpResponse from django.shortcuts import render from django.template.loader import render_to_string from django.utils.decorators import method_decorator @@ -43,6 +43,7 @@ from oidc_provider.lib.utils.common import ( redirect, get_site_url, get_issuer, + cors_allow_any, ) from oidc_provider.lib.utils.oauth2 import protected_resource_view from oidc_provider.lib.utils.token import client_id_from_id_token @@ -231,7 +232,7 @@ class TokenView(View): return TokenEndpoint.response(error.create_dict(), status=403) -@require_http_methods(['GET', 'POST']) +@require_http_methods(['GET', 'POST', 'OPTIONS']) @protected_resource_view(['openid']) def userinfo(request, *args, **kwargs): """ @@ -240,6 +241,16 @@ def userinfo(request, *args, **kwargs): Return a dictionary. """ + + def set_headers(response): + response['Cache-Control'] = 'no-store' + response['Pragma'] = 'no-cache' + cors_allow_any(request, response) + return response + + if request.method == 'OPTIONS': + return set_headers(HttpResponse()) + token = kwargs['token'] dic = { @@ -253,12 +264,10 @@ def userinfo(request, *args, **kwargs): extra_claims = settings.get('OIDC_EXTRA_SCOPE_CLAIMS', import_str=True)(token) dic.update(extra_claims.create_response_dic()) - response = JsonResponse(dic, status=200) - response['Access-Control-Allow-Origin'] = '*' - response['Cache-Control'] = 'no-store' - response['Pragma'] = 'no-cache' + success_response = JsonResponse(dic, status=200) + set_headers(success_response) - return response + return success_response class ProviderInfoView(View):