diff --git a/README.rst b/README.rst index 83470b8..819b775 100644 --- a/README.rst +++ b/README.rst @@ -144,7 +144,7 @@ Use this metadata xml to configure your SP. Place the metadata xml from that SP Without custom setting, users will be identified by the ``USERNAME_FIELD`` property on the user Model you use. By Django defaults this will be the username. You can customize which field is used for the identifier by adding ``SAML_IDP_DJANGO_USERNAME_FIELD`` to your settings with as value the attribute to use on your user instance. -Other settings you can set as defaults to be used if not overriden by an SP are `SAML_AUTHN_SIGN_ALG`, `SAML_AUTHN_DIGEST_ALG`, and `SAML_ENCRYPT_AUTHN_RESPONSE`. They can be set if desired in the django settings, in which case they will be used for all ServiceProviders configuration on this instance if they don't override it. E.g.: +Other settings you can set as defaults to be used if not overriden by an SP are `SAML_AUTHN_SIGN_ALG`, `SAML_AUTHN_DIGEST_ALG`, and `SAML_ENCRYPT_AUTHN_RESPONSE`. They can be set if desired in the django settings, in which case they will be used for all ServiceProviders configuration on this instance if they don't override it. E.g.:: SAML_AUTHN_SIGN_ALG = saml2.xmldsig.SIG_RSA_SHA256 SAML_AUTHN_DIGEST_ALG = saml2.xmldsig.DIGEST_SHA256 @@ -153,6 +153,11 @@ In case your SP does not properly expose validuntil in metadata, you can provide SAML_IDP_FALLBACK_EXPIRATION_DAYS = 30 +The default value for the fields ``processor`` and ``attribute_mapping`` in the ``ServiceProvider`` can be set via the settings (the values displayed here are the defaults):: + + SAML_IDP_SP_FIELD_DEFAULT_PROCESSOR = 'djangosaml2idp.processors.BaseProcessor' + SAML_IDP_SP_FIELD_DEFAULT_ATTRIBUTE_MAPPING = {"email": "email", "first_name": "first_name", "last_name": "last_name", "is_staff": "is_staff", "is_superuser": "is_superuser"} + Customizing error handling ========================== diff --git a/djangosaml2idp/forms.py b/djangosaml2idp/forms.py index 2ac4489..5083f0a 100644 --- a/djangosaml2idp/forms.py +++ b/djangosaml2idp/forms.py @@ -10,6 +10,13 @@ boolean_form_select_choices = ((None, _('--------')), (True, _('Yes')), (False, _('No'))) +def get_initial_value(instance: ServiceProvider, field_name: str) -> str: + for field in instance._meta.fields: + if field.name == field_name: + return field.default + return '' + + class ServiceProviderAdminForm(forms.ModelForm): class Meta: diff --git a/djangosaml2idp/migrations/0001_initial.py b/djangosaml2idp/migrations/0001_initial.py index 3d005fd..7699338 100644 --- a/djangosaml2idp/migrations/0001_initial.py +++ b/djangosaml2idp/migrations/0001_initial.py @@ -1,5 +1,6 @@ # Generated by Django 2.2.9 on 2020-02-05 21:13 +import djangosaml2idp.models from django.db import migrations, models @@ -24,8 +25,8 @@ class Migration(migrations.Migration): ('remote_metadata_url', models.CharField(blank=True, help_text='If set, metadata will be fetched upon saving into the local metadata xml field, and automatically be refreshed after the expiration timestamp.', max_length=512, verbose_name='Remote metadata URL')), ('local_metadata', models.TextField(blank=True, help_text='XML containing the metadata', verbose_name='Local Metadata XML')), ('active', models.BooleanField(default=True, verbose_name='Active')), - ('_processor', models.CharField(default='djangosaml2idp.processors.BaseProcessor', help_text='Import string for the (access) Processor to use.', max_length=256, verbose_name='Processor')), - ('_attribute_mapping', models.TextField(default='{"email": "email", "first_name": "first_name", "last_name": "last_name", "is_staff": "is_staff", "is_superuser": "is_superuser"}', help_text='dict with the mapping from django attributes to saml attributes in the identity.', verbose_name='Attribute mapping')), + ('_processor', models.CharField(default=djangosaml2idp.models.get_default_processor, help_text='Import string for the (access) Processor to use.', max_length=256, verbose_name='Processor')), + ('_attribute_mapping', models.TextField(default=djangosaml2idp.models.get_default_attribute_mapping, help_text='dict with the mapping from django attributes to saml attributes in the identity.', verbose_name='Attribute mapping')), ('_nameid_field', models.CharField(blank=True, help_text='Attribute on the user to use as identifier during the NameID construction. Can be a callable. If not set, this will default to settings.SAML_IDP_DJANGO_USERNAME_FIELD; if that is not set, it will use the `USERNAME_FIELD` attribute on the active user model.', max_length=64, verbose_name='NameID Field')), ('_sign_response', models.BooleanField(blank=True, help_text='If not set, default to the "sign_response" setting of the IDP. If that one is not set, default to False.', null=True, verbose_name='Sign response')), ('_sign_assertion', models.BooleanField(blank=True, help_text='If not set, default to the "sign_assertion" setting of the IDP. If that one is not set, default to False.', null=True, verbose_name='Sign assertion')), diff --git a/djangosaml2idp/models.py b/djangosaml2idp/models.py index 4ca3049..449fa31 100644 --- a/djangosaml2idp/models.py +++ b/djangosaml2idp/models.py @@ -27,6 +27,8 @@ User = get_user_model() +DEFAULT_PROCESSOR = 'djangosaml2idp.processors.BaseProcessor' + DEFAULT_ATTRIBUTE_MAPPING = { # DJANGO: SAML 'email': 'email', @@ -37,6 +39,18 @@ } +def get_default_processor() -> str: + if hasattr(settings, 'SAML_IDP_SP_FIELD_DEFAULT_PROCESSOR'): + return getattr(settings, 'SAML_IDP_SP_FIELD_DEFAULT_PROCESSOR') + return DEFAULT_PROCESSOR + + +def get_default_attribute_mapping() -> str: + if hasattr(settings, 'SAML_IDP_SP_FIELD_DEFAULT_ATTRIBUTE_MAPPING'): + return json.dumps(getattr(settings, 'SAML_IDP_SP_FIELD_DEFAULT_ATTRIBUTE_MAPPING')) + return json.dumps(DEFAULT_ATTRIBUTE_MAPPING) + + class ServiceProvider(models.Model): # Bookkeeping dt_created = models.DateTimeField(verbose_name='Created at', auto_now_add=True) @@ -130,8 +144,8 @@ def refresh_metadata(self, force_refresh: bool = False) -> bool: # Configuration active = models.BooleanField(verbose_name='Active', default=True) - _processor = models.CharField(verbose_name='Processor', max_length=256, help_text='Import string for the (access) Processor to use.', default='djangosaml2idp.processors.BaseProcessor') - _attribute_mapping = models.TextField(verbose_name='Attribute mapping', default=json.dumps(DEFAULT_ATTRIBUTE_MAPPING), help_text='dict with the mapping from django attributes to saml attributes in the identity.') + _processor = models.CharField(verbose_name='Processor', max_length=256, help_text='Import string for the (access) Processor to use.', default=get_default_processor) + _attribute_mapping = models.TextField(verbose_name='Attribute mapping', default=get_default_attribute_mapping, help_text='dict with the mapping from django attributes to saml attributes in the identity.') _nameid_field = models.CharField(verbose_name='NameID Field', blank=True, max_length=64, help_text='Attribute on the user to use as identifier during the NameID construction. Can be a callable. If not set, this will default to settings.SAML_IDP_DJANGO_USERNAME_FIELD; if that is not set, it will use the `USERNAME_FIELD` attribute on the active user model.') diff --git a/docs/configuration.rst b/docs/configuration.rst index 697f579..8702c23 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -92,7 +92,7 @@ Use this metadata xml to configure your SP. Place the metadata xml from that SP Without custom setting, users will be identified by the ``USERNAME_FIELD`` property on the user Model you use. By Django defaults this will be the username. You can customize which field is used for the identifier by adding ``SAML_IDP_DJANGO_USERNAME_FIELD`` to your settings with as value the attribute to use on your user instance. -Other settings you can set as defaults to be used if not overriden by an SP are `SAML_AUTHN_SIGN_ALG`, `SAML_AUTHN_DIGEST_ALG`, and `SAML_ENCRYPT_AUTHN_RESPONSE`. They can be set if desired in the django settings, in which case they will be used for all ServiceProviders configuration on this instance if they don't override it. E.g.: +Other settings you can set as defaults to be used if not overriden by an SP are `SAML_AUTHN_SIGN_ALG`, `SAML_AUTHN_DIGEST_ALG`, and `SAML_ENCRYPT_AUTHN_RESPONSE`. They can be set if desired in the django settings, in which case they will be used for all ServiceProviders configuration on this instance if they don't override it. E.g.:: SAML_AUTHN_SIGN_ALG = saml2.xmldsig.SIG_RSA_SHA256 SAML_AUTHN_DIGEST_ALG = saml2.xmldsig.DIGEST_SHA256 @@ -100,3 +100,8 @@ Other settings you can set as defaults to be used if not overriden by an SP are In case your SP does not properly expose validuntil in metadata, you can provide fallback setting for it using:: SAML_IDP_FALLBACK_EXPIRATION_DAYS = 30 + +The default value for the fields ``processor`` and ``attribute_mapping`` can be set via the settings (the values displayed here are the defaults):: + + SAML_IDP_SP_FIELD_DEFAULT_PROCESSOR = 'djangosaml2idp.processors.BaseProcessor' + SAML_IDP_SP_FIELD_DEFAULT_ATTRIBUTE_MAPPING = {"email": "email", "first_name": "first_name", "last_name": "last_name", "is_staff": "is_staff", "is_superuser": "is_superuser"}