# -*- coding: utf-8 -*- """ Admin site configuration for third party authentication """ from config_models.admin import ConfigurationModelAdmin, KeyedConfigurationModelAdmin from django import forms from django.contrib import admin from third_party_auth.provider import Registry from .models import ( _PSA_OAUTH2_BACKENDS, _PSA_SAML_BACKENDS, LTIProviderConfig, OAuth2ProviderConfig, ProviderApiPermissions, SAMLConfiguration, SAMLProviderConfig, SAMLProviderData ) from .tasks import fetch_saml_metadata class OAuth2ProviderConfigForm(forms.ModelForm): """ Django Admin form class for OAuth2ProviderConfig """ backend_name = forms.ChoiceField(choices=((name, name) for name in _PSA_OAUTH2_BACKENDS)) class OAuth2ProviderConfigAdmin(KeyedConfigurationModelAdmin): """ Django Admin class for OAuth2ProviderConfig """ form = OAuth2ProviderConfigForm def get_list_display(self, request): """ Don't show every single field in the admin change list """ return ( 'name', 'enabled', 'provider_slug', 'site', 'backend_name', 'secondary', 'skip_registration_form', 'skip_email_verification', 'change_date', 'changed_by', 'edit_link', ) admin.site.register(OAuth2ProviderConfig, OAuth2ProviderConfigAdmin) class SAMLProviderConfigForm(forms.ModelForm): """ Django Admin form class for SAMLProviderConfig """ backend_name = forms.ChoiceField(choices=((name, name) for name in _PSA_SAML_BACKENDS)) class SAMLProviderConfigAdmin(KeyedConfigurationModelAdmin): """ Django Admin class for SAMLProviderConfig """ form = SAMLProviderConfigForm def get_list_display(self, request): """ Don't show every single field in the admin change list """ return ( 'name', 'enabled', 'site', 'backend_name', 'entity_id', 'metadata_source', 'has_data', 'mode', 'change_date', 'changed_by', 'edit_link', ) def has_data(self, inst): """ Do we have cached metadata for this SAML provider? """ if not inst.is_active: return None # N/A data = SAMLProviderData.current(inst.entity_id) return bool(data and data.is_valid()) has_data.short_description = u'Metadata Ready' has_data.boolean = True def mode(self, inst): """ Indicate if debug_mode is enabled or not""" if inst.debug_mode: return '<span style="color: red;">Debug</span>' return "Normal" mode.allow_tags = True def save_model(self, request, obj, form, change): """ Post save: Queue an asynchronous metadata fetch to update SAMLProviderData. We only want to do this for manual edits done using the admin interface. Note: This only works if the celery worker and the app worker are using the same 'configuration' cache. """ super(SAMLProviderConfigAdmin, self).save_model(request, obj, form, change) fetch_saml_metadata.apply_async((), countdown=2) admin.site.register(SAMLProviderConfig, SAMLProviderConfigAdmin) class SAMLConfigurationAdmin(KeyedConfigurationModelAdmin): """ Django Admin class for SAMLConfiguration """ def get_list_display(self, request): """ Shorten the public/private keys in the change view """ return ( 'site', 'change_date', 'changed_by', 'enabled', 'entity_id', 'org_info_str', 'key_summary', 'edit_link', ) def key_summary(self, inst): """ Short summary of the key pairs configured """ public_key = inst.get_setting('SP_PUBLIC_CERT') private_key = inst.get_setting('SP_PRIVATE_KEY') if not public_key or not private_key: return u'<em>Key pair incomplete/missing</em>' pub1, pub2 = public_key[0:10], public_key[-10:] priv1, priv2 = private_key[0:10], private_key[-10:] return u'Public: {}…{}<br>Private: {}…{}'.format(pub1, pub2, priv1, priv2) key_summary.allow_tags = True admin.site.register(SAMLConfiguration, SAMLConfigurationAdmin) class SAMLProviderDataAdmin(admin.ModelAdmin): """ Django Admin class for SAMLProviderData (Read Only) """ list_display = ('entity_id', 'is_valid', 'fetched_at', 'expires_at', 'sso_url') readonly_fields = ('is_valid', ) def get_readonly_fields(self, request, obj=None): if obj: # editing an existing object return self.model._meta.get_all_field_names() # pylint: disable=protected-access return self.readonly_fields admin.site.register(SAMLProviderData, SAMLProviderDataAdmin) class LTIProviderConfigAdmin(KeyedConfigurationModelAdmin): """ Django Admin class for LTIProviderConfig """ exclude = ( 'icon_class', 'icon_image', 'secondary', ) def get_list_display(self, request): """ Don't show every single field in the admin change list """ return ( 'name', 'enabled', 'site', 'lti_consumer_key', 'lti_max_timestamp_age', 'change_date', 'changed_by', 'edit_link', ) admin.site.register(LTIProviderConfig, LTIProviderConfigAdmin) class ApiPermissionsAdminForm(forms.ModelForm): """ Django admin form for ApiPermissions model """ class Meta(object): model = ProviderApiPermissions fields = ['client', 'provider_id'] provider_id = forms.ChoiceField(choices=[], required=True) def __init__(self, *args, **kwargs): super(ApiPermissionsAdminForm, self).__init__(*args, **kwargs) self.fields['provider_id'].choices = ( (provider.provider_id, "{} ({})".format(provider.name, provider.provider_id)) for provider in Registry.enabled() ) class ApiPermissionsAdmin(admin.ModelAdmin): """ Django Admin class for ApiPermissions """ list_display = ('client', 'provider_id') form = ApiPermissionsAdminForm admin.site.register(ProviderApiPermissions, ApiPermissionsAdmin)