idp_oidc: enforce name uniqueness on claims in UI (#74920)
gitea/authentic/pipeline/head This commit looks good Details

This commit is contained in:
Paul Marillonnet 2023-02-28 14:00:59 +01:00
parent e59226cb5b
commit 324c368a20
2 changed files with 74 additions and 0 deletions

View File

@ -16,11 +16,13 @@
from django import forms
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from authentic2.attributes_ng.engine import get_service_attributes
from authentic2.forms.mixins import SlugMixin
from authentic2.forms.widgets import DatalistTextInput
from authentic2.middleware import StoreRequestMiddleware
from authentic2_idp_oidc.models import OIDCClaim, OIDCClient
@ -86,9 +88,27 @@ class OIDCClaimForm(forms.ModelForm):
'value': DatalistTextInput,
}
def clean_name(self):
name = self.cleaned_data['name'] # name is now a mandatory field
request = StoreRequestMiddleware.get_request()
client = OIDCClient.objects.get(pk=request.resolver_match.kwargs['service_pk'])
errmsg = _('This claim name is already defined for this client. Pick another claim name')
try:
claim = OIDCClaim.objects.get(client=client, name=name)
except OIDCClaim.DoesNotExist:
pass
except OIDCClaim.MultipleObjectsReturned:
raise ValidationError(errmsg)
else:
if self.instance != claim:
raise ValidationError(errmsg)
return name
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
data = dict(get_service_attributes(getattr(self.instance, 'client', None))).keys()
for field in ('name', 'value', 'scopes'):
self.fields[field].required = True
widget = self.fields['value'].widget
widget.data = data
widget.name = 'list__oidcclaim-inline'

View File

@ -126,6 +126,60 @@ class TestEdit:
client=oidc_client, name='claim', value='value', scopes='profile'
).exists()
def test_add_claim_mandatory_field_name(self, app, oidc_client):
resp = app.get(f'/manage/services/{oidc_client.pk}/settings/')
resp = resp.click('Add claim')
form = resp.form
form['value'] = 'value'
form['scopes'] = 'profile'
resp = form.submit()
assert len(resp.pyquery('.error')) == 1
assert 'This field is required.' in resp.pyquery('.error')[0].text
assert not OIDCClaim.objects.filter(client=oidc_client, name='claim', value='value', scopes='profile')
def test_add_claim_mandatory_field_value(self, app, oidc_client):
resp = app.get(f'/manage/services/{oidc_client.pk}/settings/')
resp = resp.click('Add claim')
form = resp.form
form['name'] = 'claim'
form['scopes'] = 'profile'
resp = form.submit()
assert len(resp.pyquery('.error')) == 1
assert 'This field is required.' in resp.pyquery('.error')[0].text
assert not OIDCClaim.objects.filter(client=oidc_client, name='claim', value='value', scopes='profile')
def test_add_claim_mandatory_field_scope(self, app, oidc_client):
resp = app.get(f'/manage/services/{oidc_client.pk}/settings/')
resp = resp.click('Add claim')
form = resp.form
form['name'] = 'claim'
form['value'] = 'value'
resp = form.submit()
assert len(resp.pyquery('.error')) == 1
assert 'This field is required.' in resp.pyquery('.error')[0].text
assert not OIDCClaim.objects.filter(client=oidc_client, name='claim', value='value', scopes='profile')
def test_add_claim_redundancy_error(self, app, oidc_client):
resp = app.get(f'/manage/services/{oidc_client.pk}/settings/')
OIDCClaim.objects.create(
client=oidc_client, name='yet_another_claim', value='value', scopes='profile'
)
resp = resp.click('Add claim')
form = resp.form
form['name'] = 'yet_another_claim'
form['value'] = 'value'
form['scopes'] = 'profile'
resp = form.submit()
assert len(resp.pyquery('.error')) == 1
assert 'claim name is already defined for this client' in resp.pyquery('.error')[0].text
assert (
OIDCClaim.objects.filter(
client=oidc_client, name='yet_another_claim', value='value', scopes='profile'
).count()
== 1
)
class TestEditClaim:
@pytest.fixture(autouse=True)
def claim(self, oidc_client):