authentic/src/authentic2/saml/admin.py

218 lines
7.3 KiB
Python

# authentic2 - versatile identity manager
# Copyright (C) 2010-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from django.contrib import admin
from django.utils import six
from django.utils.translation import ugettext as _
from django.conf.urls import url
from django.conf import settings
from django.forms import ModelForm
from django import forms
from django.contrib import messages
from django.core.exceptions import ValidationError
try:
from django.contrib.contenttypes.admin import GenericTabularInline
except ImportError:
from django.contrib.contenttypes.generic import GenericTabularInline
from authentic2.saml.models import (LibertyProvider, LibertyServiceProvider,
SPOptionsIdPPolicy, LibertyFederation,
KeyValue, LibertySession, SAMLAttribute)
from authentic2.attributes_ng.engine import get_service_attributes
from . import admin_views
logger = logging.getLogger(__name__)
class LibertyServiceProviderInline(admin.StackedInline):
model = LibertyServiceProvider
class TextAndFileWidget(forms.widgets.MultiWidget):
def __init__(self, attrs=None):
widgets = (forms.widgets.Textarea(), forms.widgets.FileInput())
super(TextAndFileWidget, self).__init__(widgets, attrs)
def decompress(self, value):
return (value, None)
def value_from_datadict(self, data, files, name):
# If there is a file input use it
file = self.widgets[1].value_from_datadict(data, files, name + '_1')
if file:
file = file.read(file.size)
if file:
value = file
else:
value = self.widgets[0].value_from_datadict(data, files, name + '_0')
return value
def render(self, name, value, attrs=None):
if attrs is None:
attrs = {}
if isinstance(value, (str, six.text_type)):
attrs['rows'] = value.count('\n') + 5
attrs['cols'] = min(max((len(x) for x in value.split('\n'))), 150)
return super(TextAndFileWidget, self).render(name, value, attrs)
class LibertyProviderForm(ModelForm):
metadata = forms.CharField(required=True, widget=TextAndFileWidget, label=_('Metadata'))
class Meta:
model = LibertyProvider
fields = [
'name',
'slug',
'ou',
'entity_id',
'entity_id_sha1',
'federation_source',
'metadata_url',
'metadata',
]
def update_metadata(modeladmin, request, queryset):
qs = queryset.filter(metadata_url__startswith='https://')
total = qs.count()
count = 0
for provider in qs:
try:
provider.update_metadata()
except ValidationError as e:
params = {
'name': provider,
'error_msg': u', '.join(e.messages)
}
messages.error(request, _('Updating SAML provider %(name)s failed: ' '%(error_msg)s') % params)
else:
count += 1
messages.info(request, _('%(count)d on %(total)d SAML providers updated') % {'count': count, 'total': total})
class SAMLAttributeInlineForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
service = kwargs.pop('service', None)
super(SAMLAttributeInlineForm, self).__init__(*args, **kwargs)
choices = list(get_service_attributes(service))
choices += [('edupersontargetedid', 'eduPersonTargetedId')]
self.fields['attribute_name'].choices = choices
self.fields['attribute_name'].widget = forms.Select(choices=choices)
class Meta:
model = SAMLAttribute
fields = [
'name_format',
'name',
'friendly_name',
'attribute_name',
'enabled',
]
class SAMLAttributeInlineAdmin(GenericTabularInline):
model = SAMLAttribute
form = SAMLAttributeInlineForm
def get_formset(self, request, obj=None, **kwargs):
# add service argument to form constructor
class NewForm(self.form):
def __init__(self, *args, **kwargs):
kwargs['service'] = obj
super(NewForm, self).__init__(*args, **kwargs)
kwargs['form'] = NewForm
return super(SAMLAttributeInlineAdmin, self).get_formset(request, obj=obj, **kwargs)
class LibertyProviderAdmin(admin.ModelAdmin):
form = LibertyProviderForm
list_display = ('name', 'ou', 'slug', 'entity_id')
search_fields = ('name', 'entity_id')
readonly_fields = ('entity_id', 'protocol_conformance', 'entity_id_sha1', 'federation_source')
fieldsets = (
(None, {
'fields': ('name', 'slug', 'ou', 'entity_id', 'entity_id_sha1', 'federation_source')
}),
(_('Metadata files'), {
'fields': ('metadata_url', 'metadata')
}),
)
inlines = [
LibertyServiceProviderInline,
SAMLAttributeInlineAdmin,
]
actions = [update_metadata]
prepopulated_fields = {'slug': ('name',)}
list_filter = (
'service_provider__sp_options_policy',
'service_provider__enabled',
)
def get_urls(self):
urls = super(LibertyProviderAdmin, self).get_urls()
urls = [
url(r'^add-from-url/$',
self.admin_site.admin_view(admin_views.AddLibertyProviderFromUrlView.as_view(model_admin=self)),
name='saml_libertyprovider_add_from_url'),
] + urls
return urls
class LibertyFederationAdmin(admin.ModelAdmin):
search_fields = ('name_id_content', 'user__username')
list_display = ('user', 'creation', 'last_modification', 'name_id_content', 'format', 'sp')
list_filter = ('name_id_format', 'sp')
def format(self, obj):
name_id_format = obj.name_id_format
if name_id_format > 15:
name_id_format = u'\u2026' + name_id_format[-12:]
return name_id_format
class SPOptionsIdPPolicyAdmin(admin.ModelAdmin):
inlines = [SAMLAttributeInlineAdmin]
fields = (
'name',
'enabled',
'prefered_assertion_consumer_binding',
'encrypt_nameid',
'encrypt_assertion',
'authn_request_signed',
'idp_initiated_sso',
'default_name_id_format',
'accepted_name_id_format',
'ask_user_consent',
'accept_slo',
'forward_slo',
'needs_iframe_logout',
'iframe_logout_timeout',
'http_method_for_slo_request',
)
admin.site.register(SPOptionsIdPPolicy, SPOptionsIdPPolicyAdmin)
admin.site.register(LibertyProvider, LibertyProviderAdmin)
if settings.DEBUG:
admin.site.register(LibertyFederation, LibertyFederationAdmin)
admin.site.register(LibertySession)
admin.site.register(KeyValue)