From 6ebac95c0faf90a160b904e1cda1f7e77940b1ad Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Thu, 16 Jul 2020 17:31:03 +0200
Subject: [PATCH] oidc: revoke oidc claims authorization (#21966)

---
 src/authentic2/views.py          |  2 ++
 src/authentic2_idp_oidc/urls.py  |  3 +++
 src/authentic2_idp_oidc/views.py | 10 +++++++++-
 3 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/authentic2/views.py b/src/authentic2/views.py
index 78eb6760..2466cfb6 100644
--- a/src/authentic2/views.py
+++ b/src/authentic2/views.py
@@ -50,16 +50,17 @@ from django.contrib.auth import get_user_model
 from django.http import Http404
 from django.utils.http import urlsafe_base64_decode
 from django.views.generic.edit import CreateView
 from django.forms import CharField
 from django.http import HttpResponseBadRequest
 from django.template import loader
 
 from authentic2.compat.misc import default_token_generator
+from authentic2_idp_oidc.models import OIDCAuthorization
 from . import (utils, app_settings, decorators, constants,
                models, cbv, hooks, validators)
 from .utils import switch_user
 from .a2_rbac.utils import get_default_ou
 from .a2_rbac.models import OrganizationalUnit as OU
 from .forms import (
     passwords as passwords_forms,
     registration as registration_forms,
@@ -501,16 +502,17 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
         context.update({
             'frontends_block': blocks,
             'frontends_block_by_id': blocks_by_id,
             'profile': profile,
             'attributes': attributes,
             'allow_account_deletion': app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT,
             'allow_profile_edit': EditProfile.can_edit_profile(),
             'allow_email_change': app_settings.A2_PROFILE_CAN_CHANGE_EMAIL,
+            'oidc_authorizations': OIDCAuthorization.objects.filter(user=self.request.user),
             # TODO: deprecated should be removed when publik-base-theme is updated
             'allow_password_change': utils.user_can_change_password(request=request),
             'federation_management': federation_management,
         })
         hooks.call_hooks('modify_context_data', self, context)
         return context
 
 profile = login_required(ProfileView.as_view())
diff --git a/src/authentic2_idp_oidc/urls.py b/src/authentic2_idp_oidc/urls.py
index b5f0ffae..5dab28e5 100644
--- a/src/authentic2_idp_oidc/urls.py
+++ b/src/authentic2_idp_oidc/urls.py
@@ -24,16 +24,19 @@ urlpatterns = [
         views.openid_configuration,
         name='oidc-openid-configuration'),
     url(r'^idp/oidc/certs/$',
         views.certs,
         name='oidc-certs'),
     url(r'^idp/oidc/authorize/$',
         views.authorize,
         name='oidc-authorize'),
+    url(r'^idp/oidc/unconsent/(?P<authorization_id>[-\w]+)/$',
+        views.unconsent,
+        name='oidc-unconsent'),
     url(r'^idp/oidc/token/$',
         views.token,
         name='oidc-token'),
     url(r'^idp/oidc/user_info/$',
         views.user_info,
         name='oidc-user-info'),
     url(r'^idp/oidc/logout/$',
         views.logout,
diff --git a/src/authentic2_idp_oidc/views.py b/src/authentic2_idp_oidc/views.py
index e8b00322..4e7aaec4 100644
--- a/src/authentic2_idp_oidc/views.py
+++ b/src/authentic2_idp_oidc/views.py
@@ -15,17 +15,17 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import logging
 import math
 import datetime
 import base64
 import time
 
-from django.http import (HttpResponse, HttpResponseNotAllowed, JsonResponse)
+from django.http import (HttpResponse, HttpResponseNotAllowed, HttpResponseRedirect, JsonResponse)
 from django.urls import reverse
 from django.utils import six
 from django.utils.encoding import force_text
 from django.utils.timezone import now, utc
 from django.utils.http import urlencode
 from django.shortcuts import render
 from django.views.decorators.csrf import csrf_exempt
 from django.contrib import messages
@@ -361,16 +361,24 @@ def authorize(request, *args, **kwargs):
             })
         # query is transfered through the hashtag
         response = redirect(request, redirect_uri + '#%s' % urlencode(params), resolve=False)
     hooks.call_hooks('event', name='sso-success', idp='oidc', service=client, user=request.user)
     utils.add_oidc_session(request, client)
     return response
 
 
+def unconsent(request, authorization_id):
+    try:
+        models.OIDCAuthorization.objects.get(user=request.user, id=authorization_id).delete()
+    except models.DoesNotExist:
+        pass
+    return HttpResponseRedirect('/accounts/')
+
+
 def authenticate_client(request, client=None):
     '''Authenticate client on the token endpoint'''
 
     if 'HTTP_AUTHORIZATION' in request.META:
         authorization = request.META['HTTP_AUTHORIZATION'].split()
         if authorization[0] != 'Basic' or len(authorization) != 2:
             return None
         try:
-- 
2.27.0

