From c5b67aaae1be3642d0e53069862b36aa5e4010fe Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Fri, 16 Dec 2022 10:12:06 +0100
Subject: [PATCH] idp_oidc: get user profile selection or consent even when
 prompt=none (#72507)

---
 src/authentic2_idp_oidc/views.py |  7 ---
 tests/idp_oidc/test_misc.py      | 74 ++++++++++++++++++++++++++++++--
 2 files changed, 70 insertions(+), 11 deletions(-)

diff --git a/src/authentic2_idp_oidc/views.py b/src/authentic2_idp_oidc/views.py
index 71dd283f8..ff52d7109 100644
--- a/src/authentic2_idp_oidc/views.py
+++ b/src/authentic2_idp_oidc/views.py
@@ -164,11 +164,6 @@ class InteractionRequired(OIDCException):
     show_message = False
 
 
-class ConsentRequired(OIDCException):
-    error_code = 'consent_required'
-    show_message = False
-
-
 class AccessDenied(OIDCException):
     error_code = 'access_denied'
     show_message = False
@@ -402,8 +397,6 @@ def authorize_for_client(request, client, redirect_uri):
         if (authorized_scopes & scopes) < scopes:
             needs_scope_validation = True
         if needs_scope_validation or (user_has_selectable_profiles and client.activate_user_profiles):
-            if 'none' in prompt:
-                raise ConsentRequired(_('Consent is required but prompt parameter is "none"'))
             if request.method == 'POST':
                 if request.POST.get('profile-validation', ''):
                     try:
diff --git a/tests/idp_oidc/test_misc.py b/tests/idp_oidc/test_misc.py
index bc5f42b3f..fe2bfbe33 100644
--- a/tests/idp_oidc/test_misc.py
+++ b/tests/idp_oidc/test_misc.py
@@ -37,6 +37,7 @@ from jwcrypto.jwt import JWT
 
 from authentic2.a2_rbac.models import OrganizationalUnit, Role
 from authentic2.a2_rbac.utils import get_default_ou
+from authentic2.custom_user.models import Profile, ProfileType
 from authentic2.models import Attribute, AuthorizedRole
 from authentic2.utils.misc import good_next_url, make_url
 from authentic2_auth_oidc.utils import parse_timestamp
@@ -734,7 +735,37 @@ def test_invalid_request(oidc_client, caplog, oidc_settings, simple_user, app, m
     assert urllib.parse.urlparse(response['Location']).path == reverse('auth_login')
 
     if oidc_client.authorization_mode != oidc_client.AUTHORIZATION_MODE_NONE:
-        # prompt is none, but consent is required
+
+        # prompt is none, but account selection is required, out-of-spec corner case without error
+        oidc_client.activate_user_profiles = True
+        oidc_client.save()
+        profile_type_manager = ProfileType.objects.create(
+            name='One Manager Type',
+            slug='one-manager-type',
+        )
+        profile_type_delegate = ProfileType.objects.create(
+            name='One Delegate Type',
+            slug='one-delegate-type',
+        )
+        profile_manager = Profile.objects.create(
+            user=simple_user,
+            profile_type=profile_type_manager,
+            identifier='Entity 789',
+            email='manager@example789.org',
+        )
+        profile_delegate = Profile.objects.create(
+            user=simple_user,
+            profile_type=profile_type_delegate,
+            identifier='Entity 1011',
+            email='delegate@example1011.org',
+        )
+        # authorization exists
+        authorize = OIDCAuthorization.objects.create(
+            client=oidc_client,
+            user=simple_user,
+            scopes='openid profile email',
+            expired=now() + datetime.timedelta(days=2),
+        )
         response = app.get(
             make_url(
                 'oidc-authorize',
@@ -742,14 +773,49 @@ def test_invalid_request(oidc_client, caplog, oidc_settings, simple_user, app, m
                     'client_id': oidc_client.client_id,
                     'redirect_uri': redirect_uri,
                     'response_type': response_type,
-                    'scope': 'openid email profile',
+                    'scope': 'openid',
                     'prompt': 'none',
                 },
             )
         )
-        assert_authorize_error(
-            response, 'consent_required', 'Consent is required but prompt parameter is "none"', message=False
+
+        response.form['profile-validation'] = str(profile_manager.id)
+        response = response.form.submit('accept')
+
+        if oidc_client.authorization_flow == OIDCClient.FLOW_IMPLICIT:
+            assert 'access_token' in response.location
+            assert 'id_token' in response.location
+            assert 'expires_in' in response.location
+            assert 'token_type' in response.location
+        elif oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
+            assert 'code' in response.location
+
+        profile_manager.delete()
+        profile_delegate.delete()
+        authorize.delete()
+
+        # prompt is none, consent is required, out-of-spec corner case without error
+        response = app.get(
+            make_url(
+                'oidc-authorize',
+                params={
+                    'client_id': oidc_client.client_id,
+                    'redirect_uri': redirect_uri,
+                    'response_type': response_type,
+                    'scope': 'openid',
+                    'prompt': 'none',
+                },
+            )
         )
+        response = response.form.submit('accept')
+
+        if oidc_client.authorization_flow == OIDCClient.FLOW_IMPLICIT:
+            assert 'access_token' in response.location
+            assert 'id_token' in response.location
+            assert 'expires_in' in response.location
+            assert 'token_type' in response.location
+        elif oidc_client.authorization_flow == oidc_client.FLOW_AUTHORIZATION_CODE:
+            assert 'code' in response.location
 
         # user do not consent
         response = app.get(
-- 
2.38.1

