Skip to content

Commit

Permalink
Defaults field value via settings (#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhindery authored Mar 2, 2021
1 parent c8d8a9d commit 0b43257
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 6 deletions.
7 changes: 6 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
==========================
Expand Down
7 changes: 7 additions & 0 deletions djangosaml2idp/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 3 additions & 2 deletions djangosaml2idp/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -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


Expand All @@ -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')),
Expand Down
18 changes: 16 additions & 2 deletions djangosaml2idp/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

User = get_user_model()

DEFAULT_PROCESSOR = 'djangosaml2idp.processors.BaseProcessor'

DEFAULT_ATTRIBUTE_MAPPING = {
# DJANGO: SAML
'email': 'email',
Expand All @@ -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)
Expand Down Expand Up @@ -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.')

Expand Down
7 changes: 6 additions & 1 deletion docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,16 @@ 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

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"}

0 comments on commit 0b43257

Please sign in to comment.