From 438dc8ef280f85dd1db962b43d9292de3a008328 Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Thu, 27 Oct 2022 09:12:50 +0200
Subject: [PATCH] auth_oidc: do not attempt to generate one's own client
 credentials (#70749)

    these credentials must be issued to authentic by the OIDC provider,
    see for instance https://datatracker.ietf.org/doc/html/rfc6749#section-2.2
---
 src/authentic2_auth_oidc/migrations/0001_initial.py | 6 ++----
 src/authentic2_auth_oidc/models.py                  | 5 ++---
 tests/test_auth_oidc.py                             | 4 ++++
 tests/test_manager_authenticators.py                | 9 +++++++--
 4 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/src/authentic2_auth_oidc/migrations/0001_initial.py b/src/authentic2_auth_oidc/migrations/0001_initial.py
index 03eadbd98..cf961e4a8 100644
--- a/src/authentic2_auth_oidc/migrations/0001_initial.py
+++ b/src/authentic2_auth_oidc/migrations/0001_initial.py
@@ -1,5 +1,3 @@
-import uuid
-
 import django.contrib.postgres.fields.jsonb
 from django.conf import settings
 from django.db import migrations, models
@@ -70,10 +68,10 @@ class Migration(migrations.Migration):
                     'issuer',
                     models.CharField(unique=True, max_length=256, verbose_name='issuer', db_index=True),
                 ),
-                ('client_id', models.CharField(default=uuid.uuid4, max_length=128, verbose_name='client id')),
+                ('client_id', models.CharField(max_length=128, verbose_name='client id')),
                 (
                     'client_secret',
-                    models.CharField(default=uuid.uuid4, max_length=128, verbose_name='client secret'),
+                    models.CharField(max_length=128, verbose_name='client secret'),
                 ),
                 (
                     'authorization_endpoint',
diff --git a/src/authentic2_auth_oidc/models.py b/src/authentic2_auth_oidc/models.py
index 37a23987d..bc15e2328 100644
--- a/src/authentic2_auth_oidc/models.py
+++ b/src/authentic2_auth_oidc/models.py
@@ -15,7 +15,6 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import json
-import uuid
 
 from django.conf import settings
 from django.contrib.postgres.fields import JSONField
@@ -81,8 +80,8 @@ class OIDCProvider(BaseAuthenticator):
     ]
 
     issuer = models.CharField(max_length=256, verbose_name=_('issuer'), db_index=True)
-    client_id = models.CharField(max_length=128, default=uuid.uuid4, verbose_name=_('client id'))
-    client_secret = models.CharField(max_length=128, default=uuid.uuid4, verbose_name=_('client secret'))
+    client_id = models.CharField(max_length=128, verbose_name=_('client id'))
+    client_secret = models.CharField(max_length=128, verbose_name=_('client secret'))
     # endpoints
     authorization_endpoint = models.URLField(max_length=128, verbose_name=_('authorization endpoint'))
     token_endpoint = models.URLField(max_length=128, verbose_name=_('token endpoint'))
diff --git a/tests/test_auth_oidc.py b/tests/test_auth_oidc.py
index d2b973c57..eb9a56676 100644
--- a/tests/test_auth_oidc.py
+++ b/tests/test_auth_oidc.py
@@ -161,6 +161,8 @@ def make_oidc_provider(
     idtoken_algo=OIDCProvider._meta.get_field('idtoken_algo').default,
     jwkset=None,
     claims_parameter_supported=False,
+    client_id='abc',
+    client_secret='def',
 ):
     slug = slug or name.lower()
     issuer = issuer or ('https://%s.example.com' % slug)
@@ -169,6 +171,8 @@ def make_oidc_provider(
         ou=get_default_ou(),
         name=name,
         slug=slug,
+        client_id=client_id,
+        client_secret=client_secret,
         enabled=True,
         issuer=issuer,
         authorization_endpoint='%s/authorize' % issuer,
diff --git a/tests/test_manager_authenticators.py b/tests/test_manager_authenticators.py
index 0c59e8da7..34feee3c0 100644
--- a/tests/test_manager_authenticators.py
+++ b/tests/test_manager_authenticators.py
@@ -166,6 +166,8 @@ def test_authenticators_oidc(app, superuser, ou1, ou2):
 
     resp = resp.click('Edit')
     assert 'enabled' not in resp.form.fields
+    assert resp.pyquery('input#id_client_id').val() == ''
+    assert resp.pyquery('input#id_client_secret').val() == ''
     resp.form['ou'] = ou1.pk
     resp.form['issuer'] = 'https://oidc.example.com'
     resp.form['scopes'] = 'profile email'
@@ -176,6 +178,8 @@ def test_authenticators_oidc(app, superuser, ou1, ou2):
     resp.form['idtoken_algo'] = 2
     resp.form['button_label'] = 'Test'
     resp.form['button_description'] = 'test'
+    resp.form['client_id'] = 'auie'
+    resp.form['client_secret'] = 'tsrn'
     resp = resp.form.submit().follow()
     assert_event('authenticator.edit', user=superuser, session=app.session)
 
@@ -195,8 +199,9 @@ def test_authenticators_oidc(app, superuser, ou1, ou2):
     resp = resp.click('Journal')
     assert 'enable' in resp.text
     assert (
-        'edit (ou, issuer, scopes, strategy, button_label, idtoken_algo, token_endpoint, '
-        'userinfo_endpoint, button_description, authorization_endpoint)' in resp.text
+        'edit (ou, issuer, scopes, strategy, client_id, button_label, idtoken_algo, '
+        'client_secret, token_endpoint, userinfo_endpoint, button_description, authorization_endpoint)'
+        in resp.text
     )
     assert 'creation' in resp.text
 
-- 
2.37.2

