We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
External Auth dashboard view permission denied bug
```
Internal Server Error: /dashboard/auth/sso/
Traceback (most recent call last):
  File "/srv/www/onlineweb4/env/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 204, in get_response
    response = middleware_method(request, response)
  File "/srv/www/onlineweb4/env/local/lib/python2.7/site-packages/django/contrib/sessions/middleware.py", line 30, in process_response
    patch_vary_headers(response, ('Cookie',))
  File "/srv/www/onlineweb4/env/local/lib/python2.7/site-packages/django/utils/cache.py", line 148, in patch_vary_headers
    if response.has_header('Vary'):
AttributeError: type object 'PermissionDenied' has no attribute 'has_header'
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `apps/sso/views.py`
Content:
```
1 # -*- encoding: utf-8 -*-
2 
3 import logging
4 
5 from django.contrib.auth.decorators import login_required
6 from django.http import HttpResponse, JsonResponse
7 from django.shortcuts import render
8 from django.views.decorators.debug import sensitive_post_parameters
9 from django.views.generic import View, FormView
10 from django.utils import timezone
11 from django.utils.decorators import method_decorator
12 
13 from oauthlib.oauth2 import Server
14 
15 from braces.views import LoginRequiredMixin, CsrfExemptMixin
16 
17 from oauth2_provider.settings import oauth2_settings
18 from oauth2_provider.backends import OAuth2Backend
19 from oauth2_provider.decorators import protected_resource
20 from oauth2_provider.oauth2_validators import OAuth2Validator
21 from oauth2_provider.exceptions import OAuthToolkitError
22 from oauth2_provider.forms import AllowForm
23 from oauth2_provider.http import HttpResponseUriRedirect
24 from oauth2_provider.models import get_application_model
25 from oauth2_provider.views.mixins import OAuthLibMixin
26 from oauth2_provider.models import AccessToken
27 
28 from apps.authentication.models import FIELD_OF_STUDY_CHOICES
29 from apps.sso.models import Client
30 
31 log = logging.getLogger('SSO')
32 
33 
34 @login_required
35 def index(request):
36     """
37     This is the main SSO view
38     """
39 
40     context = {}
41 
42     return render(request, 'sso/index.html', context)
43 
44 
45 class BaseAuthorizationView(LoginRequiredMixin, OAuthLibMixin, View):
46     """
47     Implements a generic endpoint to handle *Authorization Requests* as in :rfc:`4.1.1`. The view
48     does not implement any strategy to determine *authorize/do not authorize* logic.
49     The endpoint is used in the following flows:
50     * Authorization code
51     * Implicit grant
52     """
53 
54     def dispatch(self, request, *args, **kwargs):
55         self.oauth2_data = {}
56         return super(BaseAuthorizationView, self).dispatch(request, *args, **kwargs)
57 
58     def error_response(self, error, **kwargs):
59         """
60         Handle errors either by redirecting to redirect_uri with a json in the body containing
61         error details or providing an error response
62         """
63         redirect, error_response = super(BaseAuthorizationView, self).error_response(error, **kwargs)
64 
65         if redirect:
66             return HttpResponseUriRedirect(error_response['url'])
67 
68         status = error_response['error'].status_code
69         return self.render_to_response(error_response, status=status)
70 
71 
72 class AuthorizationView(BaseAuthorizationView, FormView):
73     """
74     Implements and endpoint to handle *Authorization Requests* as in :rfc:`4.1.1` and prompting the
75     user with a form to determine if she authorizes the client application to access her data.
76     This endpoint is reached two times during the authorization process:
77     * first receive a ``GET`` request from user asking authorization for a certain client
78     application, a form is served possibly showing some useful info and prompting for
79     *authorize/do not authorize*.
80     * then receive a ``POST`` request possibly after user authorized the access
81     Some informations contained in the ``GET`` request and needed to create a Grant token during
82     the ``POST`` request would be lost between the two steps above, so they are temporary stored in
83     hidden fields on the form.
84     A possible alternative could be keeping such informations in the session.
85     The endpoint is used in the followin flows:
86     * Authorization code
87     * Implicit grant
88     """
89     template_name = 'sso/authorize.html'
90     form_class = AllowForm
91 
92     server_class = Server
93     validator_class = OAuth2Validator
94     oauthlib_backend_class = OAuth2Backend
95 
96     skip_authorization_completely = False
97 
98     def get_initial(self):
99         scopes = self.oauth2_data.get('scope', self.oauth2_data.get('scopes', []))
100         initial_data = {
101             'redirect_uri': self.oauth2_data.get('redirect_uri', None),
102             'scope': ' '.join(scopes),
103             'client_id': self.oauth2_data.get('client_id', None),
104             'state': self.oauth2_data.get('state', None),
105             'response_type': self.oauth2_data.get('response_type', None),
106         }
107         return initial_data
108 
109     def form_valid(self, form):
110         try:
111             credentials = {
112                 'client_id': form.cleaned_data.get('client_id'),
113                 'redirect_uri': form.cleaned_data.get('redirect_uri'),
114                 'response_type': form.cleaned_data.get('response_type', None),
115                 'state': form.cleaned_data.get('state', None),
116             }
117 
118             scopes = Client.objects.get(client_id=credentials['client_id']).scopes
119             if not scopes:
120                 scopes = 'null'
121             allow = form.cleaned_data.get('allow')
122             uri, headers, body, status = self.create_authorization_response(
123                 request=self.request, scopes=scopes, credentials=credentials, allow=allow)
124             self.success_url = uri
125             log.debug("Success url for the request: {0}".format(self.success_url))
126             return HttpResponseUriRedirect(self.success_url)
127 
128         except OAuthToolkitError as error:
129             return self.error_response(error)
130 
131     def get(self, request, *args, **kwargs):
132         try:
133             scopes, credentials = self.validate_authorization_request(request)
134             scopes = Client.objects.get(client_id=credentials['client_id']).get_scopes()
135             if not scopes:
136                 scopes = ['null']
137             kwargs['scopes_descriptions'] = [oauth2_settings.SCOPES[scope] for scope in scopes]
138             kwargs['scopes'] = scopes
139             # at this point we know an Application instance with such client_id exists in the database
140             application = get_application_model().objects.get(client_id=credentials['client_id'])  # TODO: cache it!
141             kwargs['application'] = application
142             kwargs.update(credentials)
143             self.oauth2_data = kwargs
144             # following two loc are here only because of https://code.djangoproject.com/ticket/17795
145             form = self.get_form(self.get_form_class())
146             kwargs['form'] = form
147 
148             # Check to see if the user has already granted access and return
149             # a successful response depending on 'approval_prompt' url parameter
150             require_approval = request.GET.get('approval_prompt', oauth2_settings.REQUEST_APPROVAL_PROMPT)
151 
152             # If skip_authorization field is True, skip the authorization screen even
153             # if this is the first use of the application and there was no previous authorization.
154             # This is useful for in-house applications-> assume an in-house applications
155             # are already approved.
156             if application.skip_authorization:
157                 uri, headers, body, status = self.create_authorization_response(
158                     request=self.request, scopes=" ".join(scopes),
159                     credentials=credentials, allow=True)
160                 return HttpResponseUriRedirect(uri)
161 
162             elif require_approval == 'auto':
163                 tokens = request.user.accesstoken_set.filter(application=kwargs['application'],
164                                                              expires__gt=timezone.now()).all()
165                 # check past authorizations regarded the same scopes as the current one
166                 for token in tokens:
167                     if token.allow_scopes(scopes):
168                         uri, headers, body, status = self.create_authorization_response(
169                             request=self.request, scopes=" ".join(scopes),
170                             credentials=credentials, allow=True)
171                         return HttpResponseUriRedirect(uri)
172 
173             return self.render_to_response(self.get_context_data(**kwargs))
174 
175         except OAuthToolkitError as error:
176             return self.error_response(error)
177 
178 
179 class TokenView(CsrfExemptMixin, OAuthLibMixin, View):
180     """
181     Implements an endpoint to provide access tokens
182     The endpoint is used in the following flows:
183     * Authorization code
184     * Password
185     * Client credentials
186     """
187     server_class = Server
188     validator_class = OAuth2Validator
189     oauthlib_backend_class = OAuth2Backend
190 
191     @method_decorator(sensitive_post_parameters('password'))
192     def post(self, request, *args, **kwargs):
193         url, headers, body, status = self.create_token_response(request)
194         response = HttpResponse(content=body, status=status)
195 
196         for k, v in headers.items():
197             response[k] = v
198         return response
199 
200 
201 class RevokeTokenView(CsrfExemptMixin, OAuthLibMixin, View):
202     """
203     Implements an endpoint to revoke access or refresh tokens
204     """
205     server_class = Server
206     validator_class = OAuth2Validator
207     oauthlib_backend_class = OAuth2Backend
208 
209     def post(self, request, *args, **kwargs):
210         url, headers, body, status = self.create_revocation_response(request)
211         response = HttpResponse(content=body or '', status=status)
212 
213         for k, v in headers.items():
214             response[k] = v
215         return response
216
```

Path: `apps/sso/dashboard/views.py`
Content:
```
1 # -*- coding: utf8 -*-
2 #
3 # Created by 'myth' on 6/25/15
4 
5 import logging
6 
7 from django.core.urlresolvers import reverse
8 from django.contrib import messages
9 from django.contrib.auth.decorators import login_required
10 from django.core.exceptions import PermissionDenied
11 from django.shortcuts import render, get_object_or_404, redirect
12 
13 from oauth2_provider.settings import oauth2_settings
14 
15 from apps.dashboard.tools import get_base_context
16 from apps.sso.models import Client
17 from apps.sso.dashboard.forms import NewClientForm
18 
19 log = logging.getLogger('SSO')
20 
21 
22 @login_required()
23 def index(request):
24     """
25     Main viewcontroller of the Dashboard SSO module
26     :param request: Django request object
27     :return: An HttpResponse
28     """
29 
30     # Force only the almighty dotKom to access this view
31     if not request.user.is_superuser:
32         return PermissionDenied
33 
34     context = get_base_context(request)
35 
36     # Fetch all clients sorted by name
37     context['apps'] = Client.objects.all().order_by('name')
38 
39     # Add all available scopes from settings dict (sorted)
40     context['available_scopes'] = sorted((k, v) for k, v in oauth2_settings.user_settings['SCOPES'].items())
41 
42     return render(request, 'sso/dashboard/index.html', context)
43 
44 
45 @login_required()
46 def new_app(request):
47     """
48     Viewcontroller for the creation of new apps that can access user information
49     :param request: Django request object
50     :return: An HttpResponse
51     """
52 
53     # Force only the almighty dotKom to access this view
54     if not request.user.is_superuser:
55         return PermissionDenied
56 
57     context = get_base_context(request)
58 
59     if request.method == 'POST':
60         # Bind the request data to the model form
61         client_form = NewClientForm(request.POST)
62 
63         if not client_form.is_valid():
64             messages.error(request, u'Noen av de påkrevde feltene inneholder feil.')
65         else:
66             # We save but not commit to get a Client instance
67             client = client_form.save(commit=False)
68 
69             # Add the user that performed the request as singlehandedly responsible for all shenanigans
70             # related to this application :)
71             client.user = request.user
72 
73             # We definetly want to keep this off as default for now. Can change it in the regular admin
74             # panel for later, as this will automatically approve the OAuth authorization request.
75             # It is intended for In-house applications that are pre-approved.
76             client.skip_authorization = False
77 
78             client.save()
79             messages.success(request, u'App-klienten ble opprettet')
80             return redirect(reverse('sso:app_details', kwargs={'app_pk': client.id}))
81 
82         context['form'] = client_form
83 
84     else:
85         context['form'] = NewClientForm()
86 
87     return render(request, 'sso/dashboard/new_app.html', context)
88 
89 
90 @login_required()
91 def app_details(request, app_pk):
92     """
93     Viewcontroller for detailed view of a specific registered app
94     :param request: Django request object
95     :return: An HttpResponse
96     """
97 
98     # Force only the almighty dotKom to access this view
99     if not request.user.is_superuser:
100         return PermissionDenied
101 
102     context = get_base_context(request)
103 
104     client = get_object_or_404(Client, pk=app_pk)
105     context['app'] = client
106 
107     # If we have some action to perform
108     if request.method == 'POST':
109         if 'action' in request.POST:
110             if request.POST['action'] == 'delete':
111                 context['app'].delete()
112                 messages.success(request, u'App-klienten ble slettet')
113                 return redirect(reverse('sso:index'))
114 
115     # Add the registered scopes for the client to the context as a list of scope:description tuples
116     scopes_available = oauth2_settings.user_settings['SCOPES']
117     scopes = [(s, scopes_available[s]) for s in client.get_scopes()]
118     context['scopes'] = scopes
119 
120     return render(request, 'sso/dashboard/app_details.html', context)
121
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/apps/sso/dashboard/views.py b/apps/sso/dashboard/views.py
--- a/apps/sso/dashboard/views.py
+++ b/apps/sso/dashboard/views.py
@@ -16,8 +16,6 @@
 from apps.sso.models import Client
 from apps.sso.dashboard.forms import NewClientForm
 
-log = logging.getLogger('SSO')
-
 
 @login_required()
 def index(request):
@@ -29,7 +27,7 @@
 
     # Force only the almighty dotKom to access this view
     if not request.user.is_superuser:
-        return PermissionDenied
+        raise PermissionDenied
 
     context = get_base_context(request)
 
@@ -50,9 +48,11 @@
     :return: An HttpResponse
     """
 
+    _log = logging.getLogger('%s.%s' % (__name__, new_app.__name__))
+
     # Force only the almighty dotKom to access this view
     if not request.user.is_superuser:
-        return PermissionDenied
+        raise PermissionDenied
 
     context = get_base_context(request)
 
@@ -76,6 +76,8 @@
             client.skip_authorization = False
 
             client.save()
+
+            _log.info(u'%s created external auth client %s (%d)' % (request.user, client.name, client.id))
             messages.success(request, u'App-klienten ble opprettet')
             return redirect(reverse('sso:app_details', kwargs={'app_pk': client.id}))
 
@@ -95,9 +97,11 @@
     :return: An HttpResponse
     """
 
+    _log = logging.getLogger('%s.%s' % (__name__, app_details.__name__))
+
     # Force only the almighty dotKom to access this view
     if not request.user.is_superuser:
-        return PermissionDenied
+        raise PermissionDenied
 
     context = get_base_context(request)
 
@@ -108,7 +112,10 @@
     if request.method == 'POST':
         if 'action' in request.POST:
             if request.POST['action'] == 'delete':
+                app_id = context['app'].id
+                app_name = context['app'].name
                 context['app'].delete()
+                _log.info(u'%s deleted external auth client %s (%d)' % (request.user, app_name, app_id))
                 messages.success(request, u'App-klienten ble slettet')
                 return redirect(reverse('sso:index'))
 
diff --git a/apps/sso/views.py b/apps/sso/views.py
--- a/apps/sso/views.py
+++ b/apps/sso/views.py
@@ -3,7 +3,7 @@
 import logging
 
 from django.contrib.auth.decorators import login_required
-from django.http import HttpResponse, JsonResponse
+from django.http import HttpResponse
 from django.shortcuts import render
 from django.views.decorators.debug import sensitive_post_parameters
 from django.views.generic import View, FormView
@@ -16,19 +16,16 @@
 
 from oauth2_provider.settings import oauth2_settings
 from oauth2_provider.backends import OAuth2Backend
-from oauth2_provider.decorators import protected_resource
 from oauth2_provider.oauth2_validators import OAuth2Validator
 from oauth2_provider.exceptions import OAuthToolkitError
 from oauth2_provider.forms import AllowForm
 from oauth2_provider.http import HttpResponseUriRedirect
 from oauth2_provider.models import get_application_model
 from oauth2_provider.views.mixins import OAuthLibMixin
-from oauth2_provider.models import AccessToken
 
-from apps.authentication.models import FIELD_OF_STUDY_CHOICES
 from apps.sso.models import Client
 
-log = logging.getLogger('SSO')
+_log = logging.getLogger('SSO')
 
 
 @login_required
@@ -122,7 +119,7 @@
             uri, headers, body, status = self.create_authorization_response(
                 request=self.request, scopes=scopes, credentials=credentials, allow=allow)
             self.success_url = uri
-            log.debug("Success url for the request: {0}".format(self.success_url))
+            _log.debug("Success url for the request: {0}".format(self.success_url))
             return HttpResponseUriRedirect(self.success_url)
 
         except OAuthToolkitError as error:

{"golden_diff": "diff --git a/apps/sso/dashboard/views.py b/apps/sso/dashboard/views.py\n--- a/apps/sso/dashboard/views.py\n+++ b/apps/sso/dashboard/views.py\n@@ -16,8 +16,6 @@\n from apps.sso.models import Client\n from apps.sso.dashboard.forms import NewClientForm\n \n-log = logging.getLogger('SSO')\n-\n \n @login_required()\n def index(request):\n@@ -29,7 +27,7 @@\n \n     # Force only the almighty dotKom to access this view\n     if not request.user.is_superuser:\n-        return PermissionDenied\n+        raise PermissionDenied\n \n     context = get_base_context(request)\n \n@@ -50,9 +48,11 @@\n     :return: An HttpResponse\n     \"\"\"\n \n+    _log = logging.getLogger('%s.%s' % (__name__, new_app.__name__))\n+\n     # Force only the almighty dotKom to access this view\n     if not request.user.is_superuser:\n-        return PermissionDenied\n+        raise PermissionDenied\n \n     context = get_base_context(request)\n \n@@ -76,6 +76,8 @@\n             client.skip_authorization = False\n \n             client.save()\n+\n+            _log.info(u'%s created external auth client %s (%d)' % (request.user, client.name, client.id))\n             messages.success(request, u'App-klienten ble opprettet')\n             return redirect(reverse('sso:app_details', kwargs={'app_pk': client.id}))\n \n@@ -95,9 +97,11 @@\n     :return: An HttpResponse\n     \"\"\"\n \n+    _log = logging.getLogger('%s.%s' % (__name__, app_details.__name__))\n+\n     # Force only the almighty dotKom to access this view\n     if not request.user.is_superuser:\n-        return PermissionDenied\n+        raise PermissionDenied\n \n     context = get_base_context(request)\n \n@@ -108,7 +112,10 @@\n     if request.method == 'POST':\n         if 'action' in request.POST:\n             if request.POST['action'] == 'delete':\n+                app_id = context['app'].id\n+                app_name = context['app'].name\n                 context['app'].delete()\n+                _log.info(u'%s deleted external auth client %s (%d)' % (request.user, app_name, app_id))\n                 messages.success(request, u'App-klienten ble slettet')\n                 return redirect(reverse('sso:index'))\n \ndiff --git a/apps/sso/views.py b/apps/sso/views.py\n--- a/apps/sso/views.py\n+++ b/apps/sso/views.py\n@@ -3,7 +3,7 @@\n import logging\n \n from django.contrib.auth.decorators import login_required\n-from django.http import HttpResponse, JsonResponse\n+from django.http import HttpResponse\n from django.shortcuts import render\n from django.views.decorators.debug import sensitive_post_parameters\n from django.views.generic import View, FormView\n@@ -16,19 +16,16 @@\n \n from oauth2_provider.settings import oauth2_settings\n from oauth2_provider.backends import OAuth2Backend\n-from oauth2_provider.decorators import protected_resource\n from oauth2_provider.oauth2_validators import OAuth2Validator\n from oauth2_provider.exceptions import OAuthToolkitError\n from oauth2_provider.forms import AllowForm\n from oauth2_provider.http import HttpResponseUriRedirect\n from oauth2_provider.models import get_application_model\n from oauth2_provider.views.mixins import OAuthLibMixin\n-from oauth2_provider.models import AccessToken\n \n-from apps.authentication.models import FIELD_OF_STUDY_CHOICES\n from apps.sso.models import Client\n \n-log = logging.getLogger('SSO')\n+_log = logging.getLogger('SSO')\n \n \n @login_required\n@@ -122,7 +119,7 @@\n             uri, headers, body, status = self.create_authorization_response(\n                 request=self.request, scopes=scopes, credentials=credentials, allow=allow)\n             self.success_url = uri\n-            log.debug(\"Success url for the request: {0}\".format(self.success_url))\n+            _log.debug(\"Success url for the request: {0}\".format(self.success_url))\n             return HttpResponseUriRedirect(self.success_url)\n \n         except OAuthToolkitError as error:\n", "issue": "External Auth dashboard view permission denied bug\n```\nInternal Server Error: /dashboard/auth/sso/\nTraceback (most recent call last):\n  File \"/srv/www/onlineweb4/env/local/lib/python2.7/site-packages/django/core/handlers/base.py\", line 204, in get_response\n    response = middleware_method(request, response)\n  File \"/srv/www/onlineweb4/env/local/lib/python2.7/site-packages/django/contrib/sessions/middleware.py\", line 30, in process_response\n    patch_vary_headers(response, ('Cookie',))\n  File \"/srv/www/onlineweb4/env/local/lib/python2.7/site-packages/django/utils/cache.py\", line 148, in patch_vary_headers\n    if response.has_header('Vary'):\nAttributeError: type object 'PermissionDenied' has no attribute 'has_header'\n```\n\n", "before_files": [{"content": "# -*- encoding: utf-8 -*-\n\nimport logging\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.http import HttpResponse, JsonResponse\nfrom django.shortcuts import render\nfrom django.views.decorators.debug import sensitive_post_parameters\nfrom django.views.generic import View, FormView\nfrom django.utils import timezone\nfrom django.utils.decorators import method_decorator\n\nfrom oauthlib.oauth2 import Server\n\nfrom braces.views import LoginRequiredMixin, CsrfExemptMixin\n\nfrom oauth2_provider.settings import oauth2_settings\nfrom oauth2_provider.backends import OAuth2Backend\nfrom oauth2_provider.decorators import protected_resource\nfrom oauth2_provider.oauth2_validators import OAuth2Validator\nfrom oauth2_provider.exceptions import OAuthToolkitError\nfrom oauth2_provider.forms import AllowForm\nfrom oauth2_provider.http import HttpResponseUriRedirect\nfrom oauth2_provider.models import get_application_model\nfrom oauth2_provider.views.mixins import OAuthLibMixin\nfrom oauth2_provider.models import AccessToken\n\nfrom apps.authentication.models import FIELD_OF_STUDY_CHOICES\nfrom apps.sso.models import Client\n\nlog = logging.getLogger('SSO')\n\n\n@login_required\ndef index(request):\n    \"\"\"\n    This is the main SSO view\n    \"\"\"\n\n    context = {}\n\n    return render(request, 'sso/index.html', context)\n\n\nclass BaseAuthorizationView(LoginRequiredMixin, OAuthLibMixin, View):\n    \"\"\"\n    Implements a generic endpoint to handle *Authorization Requests* as in :rfc:`4.1.1`. The view\n    does not implement any strategy to determine *authorize/do not authorize* logic.\n    The endpoint is used in the following flows:\n    * Authorization code\n    * Implicit grant\n    \"\"\"\n\n    def dispatch(self, request, *args, **kwargs):\n        self.oauth2_data = {}\n        return super(BaseAuthorizationView, self).dispatch(request, *args, **kwargs)\n\n    def error_response(self, error, **kwargs):\n        \"\"\"\n        Handle errors either by redirecting to redirect_uri with a json in the body containing\n        error details or providing an error response\n        \"\"\"\n        redirect, error_response = super(BaseAuthorizationView, self).error_response(error, **kwargs)\n\n        if redirect:\n            return HttpResponseUriRedirect(error_response['url'])\n\n        status = error_response['error'].status_code\n        return self.render_to_response(error_response, status=status)\n\n\nclass AuthorizationView(BaseAuthorizationView, FormView):\n    \"\"\"\n    Implements and endpoint to handle *Authorization Requests* as in :rfc:`4.1.1` and prompting the\n    user with a form to determine if she authorizes the client application to access her data.\n    This endpoint is reached two times during the authorization process:\n    * first receive a ``GET`` request from user asking authorization for a certain client\n    application, a form is served possibly showing some useful info and prompting for\n    *authorize/do not authorize*.\n    * then receive a ``POST`` request possibly after user authorized the access\n    Some informations contained in the ``GET`` request and needed to create a Grant token during\n    the ``POST`` request would be lost between the two steps above, so they are temporary stored in\n    hidden fields on the form.\n    A possible alternative could be keeping such informations in the session.\n    The endpoint is used in the followin flows:\n    * Authorization code\n    * Implicit grant\n    \"\"\"\n    template_name = 'sso/authorize.html'\n    form_class = AllowForm\n\n    server_class = Server\n    validator_class = OAuth2Validator\n    oauthlib_backend_class = OAuth2Backend\n\n    skip_authorization_completely = False\n\n    def get_initial(self):\n        scopes = self.oauth2_data.get('scope', self.oauth2_data.get('scopes', []))\n        initial_data = {\n            'redirect_uri': self.oauth2_data.get('redirect_uri', None),\n            'scope': ' '.join(scopes),\n            'client_id': self.oauth2_data.get('client_id', None),\n            'state': self.oauth2_data.get('state', None),\n            'response_type': self.oauth2_data.get('response_type', None),\n        }\n        return initial_data\n\n    def form_valid(self, form):\n        try:\n            credentials = {\n                'client_id': form.cleaned_data.get('client_id'),\n                'redirect_uri': form.cleaned_data.get('redirect_uri'),\n                'response_type': form.cleaned_data.get('response_type', None),\n                'state': form.cleaned_data.get('state', None),\n            }\n\n            scopes = Client.objects.get(client_id=credentials['client_id']).scopes\n            if not scopes:\n                scopes = 'null'\n            allow = form.cleaned_data.get('allow')\n            uri, headers, body, status = self.create_authorization_response(\n                request=self.request, scopes=scopes, credentials=credentials, allow=allow)\n            self.success_url = uri\n            log.debug(\"Success url for the request: {0}\".format(self.success_url))\n            return HttpResponseUriRedirect(self.success_url)\n\n        except OAuthToolkitError as error:\n            return self.error_response(error)\n\n    def get(self, request, *args, **kwargs):\n        try:\n            scopes, credentials = self.validate_authorization_request(request)\n            scopes = Client.objects.get(client_id=credentials['client_id']).get_scopes()\n            if not scopes:\n                scopes = ['null']\n            kwargs['scopes_descriptions'] = [oauth2_settings.SCOPES[scope] for scope in scopes]\n            kwargs['scopes'] = scopes\n            # at this point we know an Application instance with such client_id exists in the database\n            application = get_application_model().objects.get(client_id=credentials['client_id'])  # TODO: cache it!\n            kwargs['application'] = application\n            kwargs.update(credentials)\n            self.oauth2_data = kwargs\n            # following two loc are here only because of https://code.djangoproject.com/ticket/17795\n            form = self.get_form(self.get_form_class())\n            kwargs['form'] = form\n\n            # Check to see if the user has already granted access and return\n            # a successful response depending on 'approval_prompt' url parameter\n            require_approval = request.GET.get('approval_prompt', oauth2_settings.REQUEST_APPROVAL_PROMPT)\n\n            # If skip_authorization field is True, skip the authorization screen even\n            # if this is the first use of the application and there was no previous authorization.\n            # This is useful for in-house applications-> assume an in-house applications\n            # are already approved.\n            if application.skip_authorization:\n                uri, headers, body, status = self.create_authorization_response(\n                    request=self.request, scopes=\" \".join(scopes),\n                    credentials=credentials, allow=True)\n                return HttpResponseUriRedirect(uri)\n\n            elif require_approval == 'auto':\n                tokens = request.user.accesstoken_set.filter(application=kwargs['application'],\n                                                             expires__gt=timezone.now()).all()\n                # check past authorizations regarded the same scopes as the current one\n                for token in tokens:\n                    if token.allow_scopes(scopes):\n                        uri, headers, body, status = self.create_authorization_response(\n                            request=self.request, scopes=\" \".join(scopes),\n                            credentials=credentials, allow=True)\n                        return HttpResponseUriRedirect(uri)\n\n            return self.render_to_response(self.get_context_data(**kwargs))\n\n        except OAuthToolkitError as error:\n            return self.error_response(error)\n\n\nclass TokenView(CsrfExemptMixin, OAuthLibMixin, View):\n    \"\"\"\n    Implements an endpoint to provide access tokens\n    The endpoint is used in the following flows:\n    * Authorization code\n    * Password\n    * Client credentials\n    \"\"\"\n    server_class = Server\n    validator_class = OAuth2Validator\n    oauthlib_backend_class = OAuth2Backend\n\n    @method_decorator(sensitive_post_parameters('password'))\n    def post(self, request, *args, **kwargs):\n        url, headers, body, status = self.create_token_response(request)\n        response = HttpResponse(content=body, status=status)\n\n        for k, v in headers.items():\n            response[k] = v\n        return response\n\n\nclass RevokeTokenView(CsrfExemptMixin, OAuthLibMixin, View):\n    \"\"\"\n    Implements an endpoint to revoke access or refresh tokens\n    \"\"\"\n    server_class = Server\n    validator_class = OAuth2Validator\n    oauthlib_backend_class = OAuth2Backend\n\n    def post(self, request, *args, **kwargs):\n        url, headers, body, status = self.create_revocation_response(request)\n        response = HttpResponse(content=body or '', status=status)\n\n        for k, v in headers.items():\n            response[k] = v\n        return response\n", "path": "apps/sso/views.py"}, {"content": "# -*- coding: utf8 -*-\n#\n# Created by 'myth' on 6/25/15\n\nimport logging\n\nfrom django.core.urlresolvers import reverse\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.exceptions import PermissionDenied\nfrom django.shortcuts import render, get_object_or_404, redirect\n\nfrom oauth2_provider.settings import oauth2_settings\n\nfrom apps.dashboard.tools import get_base_context\nfrom apps.sso.models import Client\nfrom apps.sso.dashboard.forms import NewClientForm\n\nlog = logging.getLogger('SSO')\n\n\n@login_required()\ndef index(request):\n    \"\"\"\n    Main viewcontroller of the Dashboard SSO module\n    :param request: Django request object\n    :return: An HttpResponse\n    \"\"\"\n\n    # Force only the almighty dotKom to access this view\n    if not request.user.is_superuser:\n        return PermissionDenied\n\n    context = get_base_context(request)\n\n    # Fetch all clients sorted by name\n    context['apps'] = Client.objects.all().order_by('name')\n\n    # Add all available scopes from settings dict (sorted)\n    context['available_scopes'] = sorted((k, v) for k, v in oauth2_settings.user_settings['SCOPES'].items())\n\n    return render(request, 'sso/dashboard/index.html', context)\n\n\n@login_required()\ndef new_app(request):\n    \"\"\"\n    Viewcontroller for the creation of new apps that can access user information\n    :param request: Django request object\n    :return: An HttpResponse\n    \"\"\"\n\n    # Force only the almighty dotKom to access this view\n    if not request.user.is_superuser:\n        return PermissionDenied\n\n    context = get_base_context(request)\n\n    if request.method == 'POST':\n        # Bind the request data to the model form\n        client_form = NewClientForm(request.POST)\n\n        if not client_form.is_valid():\n            messages.error(request, u'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            # We save but not commit to get a Client instance\n            client = client_form.save(commit=False)\n\n            # Add the user that performed the request as singlehandedly responsible for all shenanigans\n            # related to this application :)\n            client.user = request.user\n\n            # We definetly want to keep this off as default for now. Can change it in the regular admin\n            # panel for later, as this will automatically approve the OAuth authorization request.\n            # It is intended for In-house applications that are pre-approved.\n            client.skip_authorization = False\n\n            client.save()\n            messages.success(request, u'App-klienten ble opprettet')\n            return redirect(reverse('sso:app_details', kwargs={'app_pk': client.id}))\n\n        context['form'] = client_form\n\n    else:\n        context['form'] = NewClientForm()\n\n    return render(request, 'sso/dashboard/new_app.html', context)\n\n\n@login_required()\ndef app_details(request, app_pk):\n    \"\"\"\n    Viewcontroller for detailed view of a specific registered app\n    :param request: Django request object\n    :return: An HttpResponse\n    \"\"\"\n\n    # Force only the almighty dotKom to access this view\n    if not request.user.is_superuser:\n        return PermissionDenied\n\n    context = get_base_context(request)\n\n    client = get_object_or_404(Client, pk=app_pk)\n    context['app'] = client\n\n    # If we have some action to perform\n    if request.method == 'POST':\n        if 'action' in request.POST:\n            if request.POST['action'] == 'delete':\n                context['app'].delete()\n                messages.success(request, u'App-klienten ble slettet')\n                return redirect(reverse('sso:index'))\n\n    # Add the registered scopes for the client to the context as a list of scope:description tuples\n    scopes_available = oauth2_settings.user_settings['SCOPES']\n    scopes = [(s, scopes_available[s]) for s in client.get_scopes()]\n    context['scopes'] = scopes\n\n    return render(request, 'sso/dashboard/app_details.html', context)\n", "path": "apps/sso/dashboard/views.py"}], "after_files": [{"content": "# -*- encoding: utf-8 -*-\n\nimport logging\n\nfrom django.contrib.auth.decorators import login_required\nfrom django.http import HttpResponse\nfrom django.shortcuts import render\nfrom django.views.decorators.debug import sensitive_post_parameters\nfrom django.views.generic import View, FormView\nfrom django.utils import timezone\nfrom django.utils.decorators import method_decorator\n\nfrom oauthlib.oauth2 import Server\n\nfrom braces.views import LoginRequiredMixin, CsrfExemptMixin\n\nfrom oauth2_provider.settings import oauth2_settings\nfrom oauth2_provider.backends import OAuth2Backend\nfrom oauth2_provider.oauth2_validators import OAuth2Validator\nfrom oauth2_provider.exceptions import OAuthToolkitError\nfrom oauth2_provider.forms import AllowForm\nfrom oauth2_provider.http import HttpResponseUriRedirect\nfrom oauth2_provider.models import get_application_model\nfrom oauth2_provider.views.mixins import OAuthLibMixin\n\nfrom apps.sso.models import Client\n\n_log = logging.getLogger('SSO')\n\n\n@login_required\ndef index(request):\n    \"\"\"\n    This is the main SSO view\n    \"\"\"\n\n    context = {}\n\n    return render(request, 'sso/index.html', context)\n\n\nclass BaseAuthorizationView(LoginRequiredMixin, OAuthLibMixin, View):\n    \"\"\"\n    Implements a generic endpoint to handle *Authorization Requests* as in :rfc:`4.1.1`. The view\n    does not implement any strategy to determine *authorize/do not authorize* logic.\n    The endpoint is used in the following flows:\n    * Authorization code\n    * Implicit grant\n    \"\"\"\n\n    def dispatch(self, request, *args, **kwargs):\n        self.oauth2_data = {}\n        return super(BaseAuthorizationView, self).dispatch(request, *args, **kwargs)\n\n    def error_response(self, error, **kwargs):\n        \"\"\"\n        Handle errors either by redirecting to redirect_uri with a json in the body containing\n        error details or providing an error response\n        \"\"\"\n        redirect, error_response = super(BaseAuthorizationView, self).error_response(error, **kwargs)\n\n        if redirect:\n            return HttpResponseUriRedirect(error_response['url'])\n\n        status = error_response['error'].status_code\n        return self.render_to_response(error_response, status=status)\n\n\nclass AuthorizationView(BaseAuthorizationView, FormView):\n    \"\"\"\n    Implements and endpoint to handle *Authorization Requests* as in :rfc:`4.1.1` and prompting the\n    user with a form to determine if she authorizes the client application to access her data.\n    This endpoint is reached two times during the authorization process:\n    * first receive a ``GET`` request from user asking authorization for a certain client\n    application, a form is served possibly showing some useful info and prompting for\n    *authorize/do not authorize*.\n    * then receive a ``POST`` request possibly after user authorized the access\n    Some informations contained in the ``GET`` request and needed to create a Grant token during\n    the ``POST`` request would be lost between the two steps above, so they are temporary stored in\n    hidden fields on the form.\n    A possible alternative could be keeping such informations in the session.\n    The endpoint is used in the followin flows:\n    * Authorization code\n    * Implicit grant\n    \"\"\"\n    template_name = 'sso/authorize.html'\n    form_class = AllowForm\n\n    server_class = Server\n    validator_class = OAuth2Validator\n    oauthlib_backend_class = OAuth2Backend\n\n    skip_authorization_completely = False\n\n    def get_initial(self):\n        scopes = self.oauth2_data.get('scope', self.oauth2_data.get('scopes', []))\n        initial_data = {\n            'redirect_uri': self.oauth2_data.get('redirect_uri', None),\n            'scope': ' '.join(scopes),\n            'client_id': self.oauth2_data.get('client_id', None),\n            'state': self.oauth2_data.get('state', None),\n            'response_type': self.oauth2_data.get('response_type', None),\n        }\n        return initial_data\n\n    def form_valid(self, form):\n        try:\n            credentials = {\n                'client_id': form.cleaned_data.get('client_id'),\n                'redirect_uri': form.cleaned_data.get('redirect_uri'),\n                'response_type': form.cleaned_data.get('response_type', None),\n                'state': form.cleaned_data.get('state', None),\n            }\n\n            scopes = Client.objects.get(client_id=credentials['client_id']).scopes\n            if not scopes:\n                scopes = 'null'\n            allow = form.cleaned_data.get('allow')\n            uri, headers, body, status = self.create_authorization_response(\n                request=self.request, scopes=scopes, credentials=credentials, allow=allow)\n            self.success_url = uri\n            _log.debug(\"Success url for the request: {0}\".format(self.success_url))\n            return HttpResponseUriRedirect(self.success_url)\n\n        except OAuthToolkitError as error:\n            return self.error_response(error)\n\n    def get(self, request, *args, **kwargs):\n        try:\n            scopes, credentials = self.validate_authorization_request(request)\n            scopes = Client.objects.get(client_id=credentials['client_id']).get_scopes()\n            if not scopes:\n                scopes = ['null']\n            kwargs['scopes_descriptions'] = [oauth2_settings.SCOPES[scope] for scope in scopes]\n            kwargs['scopes'] = scopes\n            # at this point we know an Application instance with such client_id exists in the database\n            application = get_application_model().objects.get(client_id=credentials['client_id'])  # TODO: cache it!\n            kwargs['application'] = application\n            kwargs.update(credentials)\n            self.oauth2_data = kwargs\n            # following two loc are here only because of https://code.djangoproject.com/ticket/17795\n            form = self.get_form(self.get_form_class())\n            kwargs['form'] = form\n\n            # Check to see if the user has already granted access and return\n            # a successful response depending on 'approval_prompt' url parameter\n            require_approval = request.GET.get('approval_prompt', oauth2_settings.REQUEST_APPROVAL_PROMPT)\n\n            # If skip_authorization field is True, skip the authorization screen even\n            # if this is the first use of the application and there was no previous authorization.\n            # This is useful for in-house applications-> assume an in-house applications\n            # are already approved.\n            if application.skip_authorization:\n                uri, headers, body, status = self.create_authorization_response(\n                    request=self.request, scopes=\" \".join(scopes),\n                    credentials=credentials, allow=True)\n                return HttpResponseUriRedirect(uri)\n\n            elif require_approval == 'auto':\n                tokens = request.user.accesstoken_set.filter(application=kwargs['application'],\n                                                             expires__gt=timezone.now()).all()\n                # check past authorizations regarded the same scopes as the current one\n                for token in tokens:\n                    if token.allow_scopes(scopes):\n                        uri, headers, body, status = self.create_authorization_response(\n                            request=self.request, scopes=\" \".join(scopes),\n                            credentials=credentials, allow=True)\n                        return HttpResponseUriRedirect(uri)\n\n            return self.render_to_response(self.get_context_data(**kwargs))\n\n        except OAuthToolkitError as error:\n            return self.error_response(error)\n\n\nclass TokenView(CsrfExemptMixin, OAuthLibMixin, View):\n    \"\"\"\n    Implements an endpoint to provide access tokens\n    The endpoint is used in the following flows:\n    * Authorization code\n    * Password\n    * Client credentials\n    \"\"\"\n    server_class = Server\n    validator_class = OAuth2Validator\n    oauthlib_backend_class = OAuth2Backend\n\n    @method_decorator(sensitive_post_parameters('password'))\n    def post(self, request, *args, **kwargs):\n        url, headers, body, status = self.create_token_response(request)\n        response = HttpResponse(content=body, status=status)\n\n        for k, v in headers.items():\n            response[k] = v\n        return response\n\n\nclass RevokeTokenView(CsrfExemptMixin, OAuthLibMixin, View):\n    \"\"\"\n    Implements an endpoint to revoke access or refresh tokens\n    \"\"\"\n    server_class = Server\n    validator_class = OAuth2Validator\n    oauthlib_backend_class = OAuth2Backend\n\n    def post(self, request, *args, **kwargs):\n        url, headers, body, status = self.create_revocation_response(request)\n        response = HttpResponse(content=body or '', status=status)\n\n        for k, v in headers.items():\n            response[k] = v\n        return response\n", "path": "apps/sso/views.py"}, {"content": "# -*- coding: utf8 -*-\n#\n# Created by 'myth' on 6/25/15\n\nimport logging\n\nfrom django.core.urlresolvers import reverse\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.core.exceptions import PermissionDenied\nfrom django.shortcuts import render, get_object_or_404, redirect\n\nfrom oauth2_provider.settings import oauth2_settings\n\nfrom apps.dashboard.tools import get_base_context\nfrom apps.sso.models import Client\nfrom apps.sso.dashboard.forms import NewClientForm\n\n\n@login_required()\ndef index(request):\n    \"\"\"\n    Main viewcontroller of the Dashboard SSO module\n    :param request: Django request object\n    :return: An HttpResponse\n    \"\"\"\n\n    # Force only the almighty dotKom to access this view\n    if not request.user.is_superuser:\n        raise PermissionDenied\n\n    context = get_base_context(request)\n\n    # Fetch all clients sorted by name\n    context['apps'] = Client.objects.all().order_by('name')\n\n    # Add all available scopes from settings dict (sorted)\n    context['available_scopes'] = sorted((k, v) for k, v in oauth2_settings.user_settings['SCOPES'].items())\n\n    return render(request, 'sso/dashboard/index.html', context)\n\n\n@login_required()\ndef new_app(request):\n    \"\"\"\n    Viewcontroller for the creation of new apps that can access user information\n    :param request: Django request object\n    :return: An HttpResponse\n    \"\"\"\n\n    _log = logging.getLogger('%s.%s' % (__name__, new_app.__name__))\n\n    # Force only the almighty dotKom to access this view\n    if not request.user.is_superuser:\n        raise PermissionDenied\n\n    context = get_base_context(request)\n\n    if request.method == 'POST':\n        # Bind the request data to the model form\n        client_form = NewClientForm(request.POST)\n\n        if not client_form.is_valid():\n            messages.error(request, u'Noen av de p\u00e5krevde feltene inneholder feil.')\n        else:\n            # We save but not commit to get a Client instance\n            client = client_form.save(commit=False)\n\n            # Add the user that performed the request as singlehandedly responsible for all shenanigans\n            # related to this application :)\n            client.user = request.user\n\n            # We definetly want to keep this off as default for now. Can change it in the regular admin\n            # panel for later, as this will automatically approve the OAuth authorization request.\n            # It is intended for In-house applications that are pre-approved.\n            client.skip_authorization = False\n\n            client.save()\n\n            _log.info(u'%s created external auth client %s (%d)' % (request.user, client.name, client.id))\n            messages.success(request, u'App-klienten ble opprettet')\n            return redirect(reverse('sso:app_details', kwargs={'app_pk': client.id}))\n\n        context['form'] = client_form\n\n    else:\n        context['form'] = NewClientForm()\n\n    return render(request, 'sso/dashboard/new_app.html', context)\n\n\n@login_required()\ndef app_details(request, app_pk):\n    \"\"\"\n    Viewcontroller for detailed view of a specific registered app\n    :param request: Django request object\n    :return: An HttpResponse\n    \"\"\"\n\n    _log = logging.getLogger('%s.%s' % (__name__, app_details.__name__))\n\n    # Force only the almighty dotKom to access this view\n    if not request.user.is_superuser:\n        raise PermissionDenied\n\n    context = get_base_context(request)\n\n    client = get_object_or_404(Client, pk=app_pk)\n    context['app'] = client\n\n    # If we have some action to perform\n    if request.method == 'POST':\n        if 'action' in request.POST:\n            if request.POST['action'] == 'delete':\n                app_id = context['app'].id\n                app_name = context['app'].name\n                context['app'].delete()\n                _log.info(u'%s deleted external auth client %s (%d)' % (request.user, app_name, app_id))\n                messages.success(request, u'App-klienten ble slettet')\n                return redirect(reverse('sso:index'))\n\n    # Add the registered scopes for the client to the context as a list of scope:description tuples\n    scopes_available = oauth2_settings.user_settings['SCOPES']\n    scopes = [(s, scopes_available[s]) for s in client.get_scopes()]\n    context['scopes'] = scopes\n\n    return render(request, 'sso/dashboard/app_details.html', context)\n", "path": "apps/sso/dashboard/views.py"}]}