218 lines
7.3 KiB
Python
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)
|