diff --git a/MANIFEST.in b/MANIFEST.in index 7fcee19f9..90e28ab2f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -15,7 +15,6 @@ recursive-include authentic2/auth2_auth/auth2_ssl/templates *.html *.txt *.xml recursive-include authentic2/auth2_auth/templates *.html *.txt *.xml recursive-include authentic2/auth2_auth/auth2_oath/templates *.html *.txt *.xml recursive-include authentic2/auth2_auth/auth2_openid/templates *.html *.txt *.xml -recursive-include authentic2/authsaml2/templates *.html *.txt *.xml recursive-include authentic2/vendor/totp_js/js *.js recursive-include authentic2/saml/fixtures *.json @@ -27,7 +26,6 @@ recursive-include authentic2/auth2_auth/locale *.po *.mo recursive-include authentic2/auth2_auth/auth2_ssl/locale *.po *.mo recursive-include authentic2/auth2_auth/auth2_oath/locale *.po *.mo recursive-include authentic2/auth2_auth/auth2_openid/locale *.po *.mo -recursive-include authentic2/authsaml2/locale *.po *.mo recursive-include authentic2/attribute_aggregator/locale *.po *.mo recursive-include authentic2/disco_service/locale *.po *.mo recursive-include authentic2 README xrds.xml *.txt yadis.xrdf diff --git a/authentic2/authsaml2/README b/authentic2/authsaml2/README deleted file mode 100644 index 188796d14..000000000 --- a/authentic2/authsaml2/README +++ /dev/null @@ -1,110 +0,0 @@ -= Add to settings = - -SAML_SIGNATURE_PRIVATE_KEY = *your_key* -INSTALLED_APPS += ('*project*.authsaml2', '*project*.authsaml2.saml',) -AUTHENTICATION_BACKENDS = ( - 'django.contrib.auth.backends.ModelBackend', - '*project*.authsaml2.backends.SAML2AuthBackend', -) - -When login_required() with registration and you want to add on the login page the login with a federated account: -- the template is directly called: use a context processor to pass a variable -TEMPLATE_CONTEXT_PROCESSORS += ( - 'spsaml.views.idp_list', -) -spsaml.views.idp_list: -def idp_list(request): - return {'providers_list': authsaml2.saml.common.get_idp_list()} -- modify LOGIN_URL -LOGIN_URL = '/login/' -url(r'^login/', spsaml.views.login) -Pass {'providers_list': authsaml2.saml.common.get_idp_list()} to the template - -Then configure in the admin part your SP - -= Target URL = - -After logout, the parameter 'Back url' is used. If empty, authsaml2 returns to the root. - -After login, authsaml2 will redirect in a parameter you have to register, -authsaml2 returns to the root of the site. -To register a url, if a fonction is called with the next parameter in the url, -as it is the case usually with a login page, just call: - authsaml2.saml2_endpoints.register_next_target(request) -If there is no next parameter call this function giving the target url - authsaml2.saml2_endpoints.register_next_target(request, target_url) - -After defederation, by default the local session is not sesion is not ended -and the back url is the one of calling of the defederation function. - -= Call AuthSAML2 from your login page = - -* Views: -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.contrib.auth import views as auth_views -import authentic2.authsaml2.saml2_endpoints - -def login(request): - authsaml2.saml2_endpoints.register_next_target(request) - return auth_views.login(request) - -* Template: - -{% if providers_list %} -{% trans "Log in with a federated account?" %} - -{% endif %} - -= Call AuthSAML2 into the application for user account management = - -* Views: -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.contrib.auth import views as auth_views -import authentic2.authsaml2.saml2_endpoints -import authentic2.authsaml2.saml.common - -def inside(request): - authsaml2.saml2_endpoints.register_next_target(request, '/in') - return render_to_response('in.html', {'providers_list_federated': authsaml2.saml.common.get_idp_user_federated_list(request), - 'providers_list_not_federated': authsaml2.saml.common.get_idp_user_not_federated_list(request), - 'provider_active_session': authsaml2.saml.common.get_provider_of_active_session(request)}, - context_instance=RequestContext(request)) - -* Template: -{% if providers_list_not_federated %} -{% trans "Federate your identity" %} - -{% endif %} -{% if providers_list_federated %} -{% trans "Defederate your identity" %} - -{% endif %} -{% if provider_active_session %} -{% trans "Logout" %} - -{% else %} -{% trans "Log out" %} -{% endif %} - -Now in idp/__init__.py - - tpl_parameters['providers_list_federated'] = authentic.saml.common.get_idp_user_federated_list(request) - tpl_parameters['providers_list_not_federated'] = authentic.saml.common.get_idp_user_not_federated_list(request) - diff --git a/authentic2/authsaml2/__init__.py b/authentic2/authsaml2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/authentic2/authsaml2/backends.py b/authentic2/authsaml2/backends.py deleted file mode 100644 index 50f199a7b..000000000 --- a/authentic2/authsaml2/backends.py +++ /dev/null @@ -1,135 +0,0 @@ -import string -import random -import logging -import lasso - -from django.db import transaction -from django.core.urlresolvers import reverse -from django.utils.translation import ugettext as _ - -from authentic2.compat import get_user_model -from authentic2.saml.common import \ - lookup_federation_by_name_id_and_provider_id, add_federation, \ - get_idp_options_policy -from authentic2.saml.models import LIBERTY_SESSION_DUMP_KIND_SP, \ - LibertySessionDump, LibertyProvider -from authentic2.authsaml2.models import SAML2TransientUser - -logger = logging.getLogger('authentic2.authsaml2.backends') - - -class AuthenticationError(Exception): - pass - - -class AuthSAML2Backend: - def logout_list(self, request): - pid = None - q = LibertySessionDump. \ - objects.filter(django_session_key=request.session.session_key, - kind=LIBERTY_SESSION_DUMP_KIND_SP) - if not q: - logger.debug('logout_list: no LibertySessionDump found') - return [] - ''' - We deal with a single IdP session - ''' - try: - provider_id = lasso.Session(). \ - newFromDump(q[0].session_dump.encode('utf-8')). \ - get_assertions().keys()[0] - except: - return [] - if not provider_id: - return [] - logger.debug('logout_list: Found session for %s' % provider_id) - name = provider_id - provider = None - try: - provider = LibertyProvider.objects.get(entity_id=provider_id) - name = provider.name - except LibertyProvider.DoesNotExist: - logger.error('logout_list: session found for unknown provider %s' \ - % provider_id) - return [] - - policy = get_idp_options_policy(provider) - if not policy: - logger.error('logout_list: No policy found for %s' % provider_id) - return [] - elif not policy.forward_slo: - logger.info('logout_list: %s configured to not reveive slo' \ - % provider_id) - return [] - else: - import saml2_endpoints - code = '
' - code += _('Sending logout to %(pid)s....') % { 'pid': name or provider_id } - code += '''
''' \ - % (reverse(saml2_endpoints.sp_slo, - args=[provider_id]), provider_id) - return [ code ] - - -class AuthSAML2PersistentBackend: - supports_object_permissions = False - supports_anonymous_user = False - - def authenticate(self, name_id=None, provider_id=None): - '''Authenticate persistent NameID''' - if not name_id or not provider_id:# or not name_id.nameQualifier: - return None - #fed = lookup_federation_by_name_identifier(name_id=name_id) - fed = lookup_federation_by_name_id_and_provider_id(name_id, provider_id) - if fed is None: - return None - fed.user.backend = '%s.%s' % (__name__, self.__class__.__name__) - return fed.user - - def get_user(self, user_id): - User = get_user_model() - try: - return User.objects.get(id=user_id) - except User.DoesNotExist: - return None - - @transaction.commit_on_success - def create_user(self, username=None, name_id=None, provider_id=None): - '''Create a new user mapping to the given NameID''' - if not name_id or \ - name_id.format != \ - lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT or \ - not name_id.nameQualifier: - raise ValueError('Invalid NameID') - if not username: - # FIXME: maybe keep more information in the forged username - username = 'saml2-%s' % ''. \ - join([random.SystemRandom().choice(string.letters) for x in range(10)]) - User = get_user_model() - user = User() - user.username = username - if hasattr(User, 'set_unusable_password'): - user.set_unusable_password() - user.is_active = True - user.save() - add_federation(user, name_id=name_id, provider_id=provider_id) - return user - -class AuthSAML2TransientBackend: - supports_object_permissions = False - supports_anonymous_user = False - - def authenticate(self, name_id=None): - '''Create temporary user for transient NameID''' - if not name_id or \ - name_id.format != \ - lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT or \ - not name_id.content: - return None - user = SAML2TransientUser(id=name_id.content) - return user - - def get_user(self, user_id): - '''Create temporary user for transient NameID''' - return SAML2TransientUser(id=user_id) diff --git a/authentic2/authsaml2/frontend.py b/authentic2/authsaml2/frontend.py deleted file mode 100644 index 1c4190778..000000000 --- a/authentic2/authsaml2/frontend.py +++ /dev/null @@ -1,54 +0,0 @@ -import urllib -import functools -import django.forms as forms -import authentic2.saml.common as saml_common - -from django.utils.translation import gettext_noop -from django.http import HttpResponseRedirect -from django.contrib.auth import REDIRECT_FIELD_NAME -from django.utils.translation import ugettext as _ - -from . import saml2_endpoints - -class AuthSAML2Form(forms.Form): - def __init__(self, *args, **kwargs): - idp_list = kwargs.pop('idp_list') - super(AuthSAML2Form, self).__init__(*args, **kwargs) - self.fields['provider_id'].choices = \ - [(p['entity_id'], p['name']) for p in idp_list] - - provider_id = forms.ChoiceField(label=_('Choose your identity provider'), - choices=()) - -class AuthSAML2Frontend(object): - def __init__(self): - self.idp_list = saml_common.get_idp_list_sorted() - - def enabled(self): - return bool(self.idp_list) - - def id(self): - return 'saml2' - - def name(self): - return gettext_noop('SAML 2.0') - - def form(self): - return functools.partial(AuthSAML2Form, idp_list=self.idp_list) - - def post(self, request, form, nonce, next): - provider_id = form.cleaned_data['provider_id'] - return HttpResponseRedirect('/authsaml2/sso?entity_id=%s&%s=%s' % - (urllib.quote(provider_id), - REDIRECT_FIELD_NAME, - urllib.quote(next))) - - def get_context(self): - '''Specific context variable used by the specific template''' - return { 'idp_providers': self.idp_list } - - def template(self): - return 'auth/saml2/login_form.html' - - def profile(self, request): - return saml2_endpoints.profile(request) diff --git a/authentic2/authsaml2/locale/fr/LC_MESSAGES/django.po b/authentic2/authsaml2/locale/fr/LC_MESSAGES/django.po deleted file mode 100644 index 68b65dc77..000000000 --- a/authentic2/authsaml2/locale/fr/LC_MESSAGES/django.po +++ /dev/null @@ -1,410 +0,0 @@ -# French translation of Authentic -# Copyright (C) 2010, 2011 Entr'ouvert -# This file is distributed under the same license as the Authentic package. -# Frederic Peters , 2010. -# -msgid "" -msgstr "" -"Project-Id-Version: Authentic\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-07-23 16:39+0200\n" -"PO-Revision-Date: 2013-07-23 16:39+0200\n" -"Last-Translator: Mikaël Ates \n" -"Language-Team: None\n" -"Language: fr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n>1;\n" - -#: backends.py:67 -#, python-format -msgid "Sending logout to %(pid)s...." -msgstr "Envoi de la deconnesion a %(pid)s...." - -#: frontend.py:20 -msgid "Choose your identity provider" -msgstr "Choisissez votre fournisseur d'identité" - -#: frontend.py:34 -msgid "SAML 2.0" -msgstr "SAML 2.0" - -#: models.py:90 -msgid "Anonymous" -msgstr "Anonyme" - -#: saml2_endpoints.py:128 -msgid "redirect_to_disco: unable to build disco request" -msgstr "" - -#: saml2_endpoints.py:135 -#, python-format -msgid "disco_response: HTTP request not supported %s" -msgstr "" - -#: saml2_endpoints.py:176 saml2_endpoints.py:182 -msgid "sso: Service provider not configured" -msgstr "" - -#: saml2_endpoints.py:188 -msgid "sso: No SAML2 identity provider selected" -msgstr "" - -#: saml2_endpoints.py:196 -msgid "sso: The provider does not exist" -msgstr "" - -#: saml2_endpoints.py:201 -msgid "sso: Unable to create Login object" -msgstr "" - -#: saml2_endpoints.py:210 -#, python-format -msgid "sso: %s does not have any supported SingleSignOn endpoint" -msgstr "" - -#: saml2_endpoints.py:216 -#, python-format -msgid "sso: initAuthnRequest %s" -msgstr "" - -#: saml2_endpoints.py:222 -msgid "sso: No IdP policy defined" -msgstr "" - -#: saml2_endpoints.py:228 -#, python-format -msgid "SSO: buildAuthnRequestMsg %s" -msgstr "" - -#: saml2_endpoints.py:255 -msgid "singleSignOnArtifact: Service provider not configured" -msgstr "" - -#: saml2_endpoints.py:273 -msgid "singleSignOnArtifact: Unable to create Login object" -msgstr "" - -#: saml2_endpoints.py:279 -msgid "singleSignOnArtifact: No message given." -msgstr "" - -#: saml2_endpoints.py:300 -#, python-format -msgid "singleSignOnArtifact: provider %r unknown" -msgstr "" - -#: saml2_endpoints.py:309 -#, python-format -msgid "singleSignOnArtifact: initRequest %s" -msgstr "" - -#: saml2_endpoints.py:317 -#, python-format -msgid "singleSignOnArtifact: buildRequestMsg %s" -msgstr "" - -#: saml2_endpoints.py:329 -#, python-format -msgid "" -"singleSignOnArtifact: Failure to communicate with artifact " -"resolver %r" -msgstr "" - -#: saml2_endpoints.py:334 -#, python-format -msgid "" -"singleSignOnArtifact: Artifact resolver at %r returned an empty " -"response" -msgstr "" - -#: saml2_endpoints.py:350 -#, python-format -msgid "singleSignOnArtifact: processResponseMsg raised %s" -msgstr "" - -#: saml2_endpoints.py:365 -msgid "singleSignOnPost: Service provider not configured" -msgstr "" - -#: saml2_endpoints.py:371 -msgid "singleSignOnPost: Unable to create Login object" -msgstr "" - -#: saml2_endpoints.py:380 -msgid "singleSignOnPost: No message given." -msgstr "" - -#: saml2_endpoints.py:407 -#, python-format -msgid "singleSignOnPost: provider %r unknown" -msgstr "" - -#: saml2_endpoints.py:418 -#, python-format -msgid "singleSignOnPost: %s" -msgstr "" - -#: saml2_endpoints.py:441 -msgid "sso_after_response: error checking authn response" -msgstr "" - -#: saml2_endpoints.py:447 -#, python-format -msgid "sso_after_response: acceptSso raised %s" -msgstr "" - -#: saml2_endpoints.py:583 -msgid "sso_after_response: No IdP policy defined" -msgstr "" - -#: saml2_endpoints.py:632 -msgid "" -"sso_after_response: No backend for temporary federation " -"is configured" -msgstr "" - -#: saml2_endpoints.py:653 -msgid "" -"sso_after_response: Transient access policy: Configuration error" -msgstr "" - -#: saml2_endpoints.py:703 -msgid "" -"sso_after_response: You were not asked your consent for " -"account linking" -msgstr "" - -#: saml2_endpoints.py:720 -msgid "" -"sso_after_response: Persistent Account policy: Configuration " -"error" -msgstr "" - -#: saml2_endpoints.py:724 -msgid "" -"sso_after_response: Transient access policy: NameId format not " -"supported" -msgstr "" - -#: saml2_endpoints.py:747 -msgid "finish_federation: Service provider not configured" -msgstr "" - -#: saml2_endpoints.py:753 -msgid "finish_federation: Unable to create Login object" -msgstr "" - -#: saml2_endpoints.py:760 -msgid "finish_federation: Error loading session." -msgstr "" - -#: saml2_endpoints.py:777 -msgid "" -"SSO/finish_federation: Error adding new federation for " -"this user" -msgstr "" - -#: saml2_endpoints.py:816 -msgid "finish_federation: Unable to perform federation" -msgstr "" - -#: saml2_endpoints.py:958 -msgid "logout: not a logged in user" -msgstr "" - -#: saml2_endpoints.py:963 -msgid "logout: Service provider not configured" -msgstr "" - -#: saml2_endpoints.py:968 -msgid "logout: Unable to create Login object" -msgstr "" - -#: saml2_endpoints.py:976 -msgid "logout: No session for global logout." -msgstr "" - -#: saml2_endpoints.py:984 -msgid "logout: Session malformed." -msgstr "" - -#: saml2_endpoints.py:990 -msgid "logout: Error loading provider." -msgstr "" - -#: saml2_endpoints.py:1018 -msgid "logout: SOAP error - Only local logout performed." -msgstr "" - -#: saml2_endpoints.py:1066 -msgid "logout: Unknown HTTP method." -msgstr "" - -#: saml2_endpoints.py:1076 -#, python-format -msgid "" -"localLogout: SOAP error with %s - Only local logout performed." -msgstr "" - -#: saml2_endpoints.py:1080 -#, python-format -msgid "localLogout: %s - Only local logout performed." -msgstr "" - -#: saml2_endpoints.py:1092 -msgid "singleLogoutReturn: Service provider not configured" -msgstr "" - -#: saml2_endpoints.py:1098 -msgid "" -"singleLogoutReturn: Unable to handle Single Logout by Redirect " -"without request" -msgstr "" - -#: saml2_endpoints.py:1105 -msgid "singleLogoutReturn: Unable to create Login object" -msgstr "" - -#: saml2_endpoints.py:1391 -#, python-format -msgid "singleLogout: provider %r unknown" -msgstr "" - -#: saml2_endpoints.py:1469 -msgid "fedTerm/SP UI: No provider for defederation" -msgstr "" - -#: saml2_endpoints.py:1474 -msgid "fedTerm/SP UI: Unable to defederate a not logged user!" -msgstr "" - -#: saml2_endpoints.py:1480 -msgid "fedTerm/SP UI: Service provider not configured" -msgstr "" - -#: saml2_endpoints.py:1487 -msgid "fedTerm/SP UI: No such identity provider." -msgstr "" - -#: saml2_endpoints.py:1497 -msgid "fedTerm/SP UI: Not a valid federation" -msgstr "" - -#: saml2_endpoints.py:1513 -#, python-format -msgid "fedTerm/SP UI: %s" -msgstr "" - -#: saml2_endpoints.py:1521 saml2_endpoints.py:1552 -#, python-format -msgid "fedTerm/SP SOAP: %s" -msgstr "" - -#: saml2_endpoints.py:1530 -msgid "" -"fedTerm/SP SOAP: Unable to perform SOAP defederation " -"request" -msgstr "" - -#: saml2_endpoints.py:1539 saml2_endpoints.py:1573 -#, python-format -msgid "fedTerm/SP Redirect: %s" -msgstr "" - -#: saml2_endpoints.py:1561 -msgid "" -"fedTerm/SP SOAP: Unable to perform SOAP defederation request" -msgstr "" - -#: saml2_endpoints.py:1578 -msgid "Unknown HTTP method." -msgstr "" - -#: saml2_endpoints.py:1591 -msgid "fedTerm/SP Redirect: Service provider not configured" -msgstr "" - -#: saml2_endpoints.py:1599 -msgid "fedTerm/SP Redirect: Error managing manage dump" -msgstr "" - -#: saml2_endpoints.py:1614 -msgid "fedTerm/SP Redirect: Defederation failed" -msgstr "" - -#: saml2_endpoints.py:1640 -#, python-format -msgid "fedTerm/Return: provider %r unknown" -msgstr "" - -#: saml2_endpoints.py:1647 -#, python-format -msgid "fedTerm/manage_name_id_return: %s" -msgstr "" - -#: saml2_endpoints.py:1695 -#, python-format -msgid "fedTerm/SOAP: provider %r unknown" -msgstr "" - -#: saml2_endpoints.py:1888 -msgid "Successful federation deletion." -msgstr "" - -#: utils.py:42 -#, python-format -msgid "An error happened. Report this %s to the administrator." -msgstr "" - -#: templates/error_authsaml2.html:8 -msgid "Back" -msgstr "Retour" - -#: templates/profile.html:3 -msgid "SAML2 Federations" -msgstr "Fédérations SAML2" - -#: templates/profile.html:9 -msgid "Delete a federation?" -msgstr "Supprimer une fédération ?" - -#: templates/profile.html:15 -msgid "Delete" -msgstr "Supprimer" - -#: templates/profile.html:23 -msgid "Add a federation?" -msgstr "Ajouter une fédération ?" - -#: templates/profile.html:27 templates/auth/saml2/account_linking.html:32 -#: templates/auth/saml2/login_form.html:6 -msgid "Log in" -msgstr "S'identifier" - -#: templates/auth/saml2/account_linking.html:5 -msgid "Log in to link your account" -msgstr "Connectez-vous pour lier vos comptes" - -#: templates/auth/saml2/account_linking.html:9 -msgid "Log in to link with your existing account" -msgstr "Connectez-vous pour lier avec un compte existant" - -#: templates/auth/saml2/account_linking.html:17 -#: templates/auth/saml2/account_linking.html:24 -msgid "Username:" -msgstr "Nom d'utilisateur :" - -#: templates/auth/saml2/account_linking.html:20 -#: templates/auth/saml2/account_linking.html:28 -msgid "Password:" -msgstr "Mot de passe :" - -#: templates/auth/saml2/logout.html:5 -msgid "Logout" -msgstr "Déconnexion" - -#: templates/auth/saml2/logout.html:18 -msgid "Continue logout" -msgstr "Continuer la déconnexion" diff --git a/authentic2/authsaml2/migrations/0001_initial.py b/authentic2/authsaml2/migrations/0001_initial.py deleted file mode 100644 index 0fcad4fff..000000000 --- a/authentic2/authsaml2/migrations/0001_initial.py +++ /dev/null @@ -1,122 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding model 'AuthorizationAttributeMap' - db.create_table('authsaml2_authorizationattributemap', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=40)), - )) - db.send_create_signal('authsaml2', ['AuthorizationAttributeMap']) - - # Adding model 'AttributeMapping' - db.create_table('authsaml2_attributemapping', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('source_attribute_name', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('attribute_value_format', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('attribute_name', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('attribute_value', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('map', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['authsaml2.AuthorizationAttributeMap'])), - )) - db.send_create_signal('authsaml2', ['AttributeMapping']) - - # Adding model 'IdPOptionsPolicy' - db.create_table('authsaml2_idpoptionspolicy', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(unique=True, max_length=80)), - ('enabled', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('no_nameid_policy', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('requested_name_id_format', self.gf('django.db.models.fields.CharField')(default='none', max_length=20)), - ('transient_is_persistent', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('allow_create', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('enable_binding_for_sso_response', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('binding_for_sso_response', self.gf('django.db.models.fields.CharField')(default='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact', max_length=60)), - ('enable_http_method_for_slo_request', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('http_method_for_slo_request', self.gf('django.db.models.fields.IntegerField')(default=4, max_length=60)), - ('enable_http_method_for_defederation_request', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('http_method_for_defederation_request', self.gf('django.db.models.fields.IntegerField')(default=5, max_length=60)), - ('user_consent', self.gf('django.db.models.fields.CharField')(default='urn:oasis:names:tc:SAML:2.0:consent:current-implicit', max_length=60)), - ('want_force_authn_request', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('want_is_passive_authn_request', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('want_authn_request_signed', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('attribute_map', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='authorization_attributes', null=True, to=orm['authsaml2.AuthorizationAttributeMap'])), - )) - db.send_create_signal('authsaml2', ['IdPOptionsPolicy']) - - # Adding model 'MyServiceProvider' - db.create_table('authsaml2_myserviceprovider', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('handle_persistent', self.gf('django.db.models.fields.CharField')(max_length=80)), - ('handle_transient', self.gf('django.db.models.fields.CharField')(max_length=80)), - ('back_url', self.gf('django.db.models.fields.CharField')(max_length=80)), - )) - db.send_create_signal('authsaml2', ['MyServiceProvider']) - - - def backwards(self, orm): - - # Deleting model 'AuthorizationAttributeMap' - db.delete_table('authsaml2_authorizationattributemap') - - # Deleting model 'AttributeMapping' - db.delete_table('authsaml2_attributemapping') - - # Deleting model 'IdPOptionsPolicy' - db.delete_table('authsaml2_idpoptionspolicy') - - # Deleting model 'MyServiceProvider' - db.delete_table('authsaml2_myserviceprovider') - - - models = { - 'authsaml2.attributemapping': { - 'Meta': {'object_name': 'AttributeMapping'}, - 'attribute_name': ('django.db.models.fields.CharField', [], {'max_length': '40'}), - 'attribute_value': ('django.db.models.fields.CharField', [], {'max_length': '40'}), - 'attribute_value_format': ('django.db.models.fields.CharField', [], {'max_length': '40'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'map': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['authsaml2.AuthorizationAttributeMap']"}), - 'source_attribute_name': ('django.db.models.fields.CharField', [], {'max_length': '40'}) - }, - 'authsaml2.authorizationattributemap': { - 'Meta': {'object_name': 'AuthorizationAttributeMap'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}) - }, - 'authsaml2.idpoptionspolicy': { - 'Meta': {'object_name': 'IdPOptionsPolicy'}, - 'allow_create': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'attribute_map': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'authorization_attributes'", 'null': 'True', 'to': "orm['authsaml2.AuthorizationAttributeMap']"}), - 'binding_for_sso_response': ('django.db.models.fields.CharField', [], {'default': "'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact'", 'max_length': '60'}), - 'enable_binding_for_sso_response': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'enable_http_method_for_defederation_request': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'enable_http_method_for_slo_request': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'http_method_for_defederation_request': ('django.db.models.fields.IntegerField', [], {'default': '5', 'max_length': '60'}), - 'http_method_for_slo_request': ('django.db.models.fields.IntegerField', [], {'default': '4', 'max_length': '60'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'no_nameid_policy': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'requested_name_id_format': ('django.db.models.fields.CharField', [], {'default': "'none'", 'max_length': '20'}), - 'transient_is_persistent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'user_consent': ('django.db.models.fields.CharField', [], {'default': "'urn:oasis:names:tc:SAML:2.0:consent:current-implicit'", 'max_length': '60'}), - 'want_authn_request_signed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'want_force_authn_request': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'want_is_passive_authn_request': ('django.db.models.fields.BooleanField', [], {'default': 'False'}) - }, - 'authsaml2.myserviceprovider': { - 'Meta': {'object_name': 'MyServiceProvider'}, - 'back_url': ('django.db.models.fields.CharField', [], {'max_length': '80'}), - 'handle_persistent': ('django.db.models.fields.CharField', [], {'max_length': '80'}), - 'handle_transient': ('django.db.models.fields.CharField', [], {'max_length': '80'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - } - } - - complete_apps = ['authsaml2'] diff --git a/authentic2/authsaml2/migrations/0002_auto__del_authorizationattributemap__del_idpoptionspolicy__del_attribu.py b/authentic2/authsaml2/migrations/0002_auto__del_authorizationattributemap__del_idpoptionspolicy__del_attribu.py deleted file mode 100644 index 20c0e0dc2..000000000 --- a/authentic2/authsaml2/migrations/0002_auto__del_authorizationattributemap__del_idpoptionspolicy__del_attribu.py +++ /dev/null @@ -1,75 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Deleting model 'AuthorizationAttributeMap' - db.delete_table('authsaml2_authorizationattributemap') - - # Deleting model 'IdPOptionsPolicy' - db.delete_table('authsaml2_idpoptionspolicy') - - # Deleting model 'AttributeMapping' - db.delete_table('authsaml2_attributemapping') - - - def backwards(self, orm): - - # Adding model 'AuthorizationAttributeMap' - db.create_table('authsaml2_authorizationattributemap', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=40, unique=True)), - )) - db.send_create_signal('authsaml2', ['AuthorizationAttributeMap']) - - # Adding model 'IdPOptionsPolicy' - db.create_table('authsaml2_idpoptionspolicy', ( - ('enable_http_method_for_defederation_request', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=80, unique=True)), - ('http_method_for_defederation_request', self.gf('django.db.models.fields.IntegerField')(default=5, max_length=60)), - ('binding_for_sso_response', self.gf('django.db.models.fields.CharField')(default='urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact', max_length=60)), - ('enabled', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('allow_create', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('enable_http_method_for_slo_request', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('http_method_for_slo_request', self.gf('django.db.models.fields.IntegerField')(default=4, max_length=60)), - ('requested_name_id_format', self.gf('django.db.models.fields.CharField')(default='none', max_length=20)), - ('attribute_map', self.gf('django.db.models.fields.related.ForeignKey')(related_name='authorization_attributes', null=True, to=orm['authsaml2.AuthorizationAttributeMap'], blank=True)), - ('user_consent', self.gf('django.db.models.fields.CharField')(default='urn:oasis:names:tc:SAML:2.0:consent:current-implicit', max_length=60)), - ('no_nameid_policy', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('transient_is_persistent', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('want_authn_request_signed', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('want_is_passive_authn_request', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('enable_binding_for_sso_response', self.gf('django.db.models.fields.BooleanField')(default=False)), - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('want_force_authn_request', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('authsaml2', ['IdPOptionsPolicy']) - - # Adding model 'AttributeMapping' - db.create_table('authsaml2_attributemapping', ( - ('map', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['authsaml2.AuthorizationAttributeMap'])), - ('attribute_name', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('source_attribute_name', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('attribute_value_format', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('attribute_value', self.gf('django.db.models.fields.CharField')(max_length=40)), - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - )) - db.send_create_signal('authsaml2', ['AttributeMapping']) - - - models = { - 'authsaml2.myserviceprovider': { - 'Meta': {'object_name': 'MyServiceProvider'}, - 'back_url': ('django.db.models.fields.CharField', [], {'max_length': '80'}), - 'handle_persistent': ('django.db.models.fields.CharField', [], {'max_length': '80'}), - 'handle_transient': ('django.db.models.fields.CharField', [], {'max_length': '80'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - } - } - - complete_apps = ['authsaml2'] diff --git a/authentic2/authsaml2/migrations/0003_auto__del_myserviceprovider.py b/authentic2/authsaml2/migrations/0003_auto__del_myserviceprovider.py deleted file mode 100644 index 55425950f..000000000 --- a/authentic2/authsaml2/migrations/0003_auto__del_myserviceprovider.py +++ /dev/null @@ -1,31 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Deleting model 'MyServiceProvider' - db.delete_table('authsaml2_myserviceprovider') - - - def backwards(self, orm): - - # Adding model 'MyServiceProvider' - db.create_table('authsaml2_myserviceprovider', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('handle_persistent', self.gf('django.db.models.fields.CharField')(max_length=80)), - ('handle_transient', self.gf('django.db.models.fields.CharField')(max_length=80)), - ('back_url', self.gf('django.db.models.fields.CharField')(max_length=80)), - )) - db.send_create_signal('authsaml2', ['MyServiceProvider']) - - - models = { - - } - - complete_apps = ['authsaml2'] diff --git a/authentic2/authsaml2/migrations/__init__.py b/authentic2/authsaml2/migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/authentic2/authsaml2/models.py b/authentic2/authsaml2/models.py deleted file mode 100644 index 24672e9a4..000000000 --- a/authentic2/authsaml2/models.py +++ /dev/null @@ -1,92 +0,0 @@ -from django.db import models -from django.utils.translation import ugettext_lazy as _ -from django.db.models.manager import EmptyManager -from django.contrib.auth.models import _user_get_all_permissions, _user_has_perm, _user_has_module_perms - - -class FakePk: - name = 'pk' - -class FakeMeta: - pk = FakePk() - -class SAML2TransientUser(object): - '''Class compatible with django.contrib.auth.models.User - which represent an user authenticated using a Transient - federation''' - id = None - pk = None - is_staff = False - is_active = False - is_superuser = False - _groups = EmptyManager() - _user_permissions = EmptyManager() - _meta = FakeMeta() - - def __init__(self, id): - self.id = id - self.pk = id - - def __unicode__(self): - return 'AnonymousUser' - - def __str__(self): - return unicode(self).encode('utf-8') - - def __eq__(self, other): - return isinstance(other, self.__class__) - - def __ne__(self, other): - return not self.__eq__(other) - - def __hash__(self): - return 1 # instances always return the same hash value - - def save(self, **kwargs): - pass - - def delete(self): - raise NotImplementedError - - def set_password(self, raw_password): - raise NotImplementedError - - def check_password(self, raw_password): - raise NotImplementedError - - def _get_groups(self): - return self._groups - groups = property(_get_groups) - - def _get_user_permissions(self): - return self._user_permissions - user_permissions = property(_get_user_permissions) - - def get_group_permissions(self, obj=None): - return set() - - def get_all_permissions(self, obj=None): - return _user_get_all_permissions(self, obj=obj) - - def has_perm(self, perm, obj=None): - return _user_has_perm(self, perm, obj=obj) - - def has_perms(self, perm_list, obj=None): - for perm in perm_list: - if not self.has_perm(perm, obj): - return False - return True - - def has_module_perms(self, module): - return _user_has_module_perms(self, module) - - def is_anonymous(self): - #XXX: Should return True - return False - - def is_authenticated(self): - return True - - def get_username(self): - return _('Anonymous') - username = property(get_username) diff --git a/authentic2/authsaml2/saml2_endpoints.py b/authentic2/authsaml2/saml2_endpoints.py deleted file mode 100644 index 5abbc3d29..000000000 --- a/authentic2/authsaml2/saml2_endpoints.py +++ /dev/null @@ -1,1745 +0,0 @@ -"""SAML2.0 SP implementation""" - -import logging -import urlparse -import urllib - -import lasso - -import authentic2.idp.views as idp_views - -from django.conf import settings -from django.core.urlresolvers import reverse -from django.shortcuts import render_to_response -from django.http import HttpResponse, HttpResponseRedirect, \ - HttpResponseBadRequest, HttpResponseForbidden -from django.views.decorators.csrf import csrf_exempt -from django.template import RequestContext -from django.template.loader import render_to_string -from django.contrib.auth import login as auth_login, authenticate -from django.contrib.auth import logout as auth_logout -from django.contrib.auth import REDIRECT_FIELD_NAME -from django.contrib.auth.forms import AuthenticationForm -from django.contrib.auth.decorators import login_required -from django.contrib import messages -from django.utils.translation import ugettext as _ -from django.utils.http import urlquote - -from authentic2.saml.common import get_idp_list, load_provider, \ - return_saml2_request, get_saml2_request_message, get_saml2_query_request, \ - get_saml2_post_response, soap_call, \ - lookup_federation_by_name_identifier, get_authorization_policy, \ - get_idp_options_policy, save_session, \ - add_federation, load_session, send_soap_request, \ - redirect_next, delete_session, SOAPException, \ - remove_liberty_session_sp, get_session_index, get_soap_message, \ - load_federation, save_manage, lookup_federation_by_user, \ - get_manage_dump, get_saml2_metadata, create_saml2_server, \ - maintain_liberty_session_on_service_provider, \ - get_session_not_on_or_after, \ - AUTHENTIC_STATUS_CODE_UNKNOWN_PROVIDER, \ - AUTHENTIC_STATUS_CODE_INTERNAL_SERVER_ERROR, \ - AUTHENTIC_STATUS_CODE_UNAUTHORIZED, \ - get_sp_options_policy, get_entity_id -from authentic2.saml.models import LibertyProvider, LibertyFederation, \ - LibertySessionSP, LibertySessionDump, LIBERTY_SESSION_DUMP_KIND_SP, \ - save_key_values, NAME_ID_FORMATS, LibertySession, \ - get_and_delete_key_values -from authentic2.saml.saml2utils import authnresponse_checking, \ - get_attributes_from_assertion -from authentic2.idp.saml.saml2_endpoints import return_logout_error -from authentic2.authsaml2.utils import error_page, register_next_target, \ - register_request_id, get_registered_url, save_federation_temp, \ - load_federation_temp -from authentic2.authsaml2 import signals -from authentic2.authsaml2.backends import AuthSAML2PersistentBackend -from authentic2.utils import cache_and_validate, flush_django_session - -__logout_redirection_timeout = getattr(settings, 'IDP_LOGOUT_TIMEOUT', 600) - -logger = logging.getLogger(__name__) - -metadata_map = ( - ('AssertionConsumerService', - lasso.SAML2_METADATA_BINDING_ARTIFACT, - '/singleSignOnArtifact'), - ('AssertionConsumerService', - lasso.SAML2_METADATA_BINDING_POST, - '/singleSignOnPost'), - ('SingleLogoutService', - lasso.SAML2_METADATA_BINDING_REDIRECT, - '/singleLogout', '/singleLogoutReturn'), - ('SingleLogoutService', - lasso.SAML2_METADATA_BINDING_SOAP, - '/singleLogoutSOAP'), - ('ManageNameIDService', - lasso.SAML2_METADATA_BINDING_SOAP, - '/manageNameIdSOAP'), - ('ManageNameIDService', - lasso.SAML2_METADATA_BINDING_REDIRECT, - '/manageNameId', '/manageNameIdReturn'), -) -metadata_options = {'key': settings.SAML_SIGNATURE_PUBLIC_KEY} -try: - if settings.SHOW_DISCO_IN_MD: - metadata_options['disco'] = ('/discoveryReturn', ) -except: - pass - -@cache_and_validate(settings.LOCAL_METADATA_CACHE_TIMEOUT) -def metadata(request): - '''Endpoint to retrieve the metadata file''' - logger.info('metadata: return metadata') - return HttpResponse(get_metadata(request, request.path), - mimetype='text/xml') - - -############################################################## -# -# Discovery service Requester -# See Identity Provider Discovery Service Protocol and Profile -# OASIS Committee Specification 01 -# 27 March 2008 -# -############################################################## -def build_discovery_url(request): - target = None - returnIDParam = None - try: - target = settings.DISCO_SERVICE_NAME - returnIDParam = settings.DISCO_RETURN_ID_PARAM - except: - logger.error('build_discovery_url: missing parameter in settings') - return None - _return = urlquote(request.build_absolute_uri(reverse(disco_response))) - query = 'entityID=%s&return=%s&returnIDParam=%s' \ - % (urlquote(request.build_absolute_uri(reverse(metadata))), - _return, returnIDParam) - try: - scheme, netloc, path, params, query, fragment = urlparse.urlparse(target) - return urlparse.urlunparse((scheme, netloc, path, params, query, - fragment)) - except Exception, e: - logger.error('build_discovery_url: Exception %s' % str(e)) - return None - - -def redirect_to_disco(request): - register_next_target(request) - url = build_discovery_url(request) - if not url: - return error_page(request, - _('redirect_to_disco: unable to build disco request'), - logger=logger) - return HttpResponseRedirect(url) - - -def disco_response(request): - if not request.method == "GET": - message = _('disco_response: HTTP request not supported %s' \ - % request.method) - return error_page(request, message, logger=logger) - provider = request.GET.get(settings.DISCO_RETURN_ID_PARAM, '') - if provider: - request.session['prefered_idp'] = provider - logger.info('disco_response: discovered %s' % provider) - else: - logger.warn('disco_response: No provider discovered') - return HttpResponseRedirect(get_registered_url(request)) - - -### - # sso - # @request - # @entity_id: Provider ID to request - # - # Single SignOn request initiated from SP UI - # Binding supported: Redirect - ### -def sso(request, is_passive=None, force_authn=None, http_method=None): - '''Django view initiating an AuthnRequesst toward an identity provider. - - Keyword arguments: - entity_id -- the SAMLv2 entity id identifier targeted by the - AuthnRequest, it should be resolvable to a metadata document. - is_passive -- whether to let the identity provider passively, i.e. - without user interaction, authenticate the user. - force_authn -- whether to ask the identity provider to authenticate the - user even if it is already authenticated. - ''' - entity_id = request.REQUEST.get('entity_id') - # 1. Save the target page - logger.info('sso: save next url in session %s' \ - % request.session.session_key) - register_next_target(request) - - # 2. Init the server object - server = build_service_provider(request) - if not server: - return error_page(request, - _('sso: Service provider not configured'), logger=logger) - # 3. Define the provider or ask the user - if not entity_id: - providers_list = get_idp_list() - if not providers_list: - return error_page(request, - _('sso: Service provider not configured'), logger=logger) - if providers_list.count() == 1: - p = providers_list[0] - else: - logger.error('sso: No SAML2 identity provider selected') - return error_page(request, - _('sso: No SAML2 identity provider selected'), - logger=logger) - else: - logger.info('sso: sso with provider %s' % entity_id) - p = load_provider(request, entity_id, server=server, sp_or_idp='idp', - autoload=True) - if not p: - return error_page(request, - _('sso: The provider does not exist'), logger=logger) - # 4. Build authn request - login = lasso.Login(server) - if not login: - return error_page(request, - _('sso: Unable to create Login object'), logger=logger) - # Only redirect is necessary for the authnrequest - if not http_method: - http_method = server.getFirstHttpMethod(server.providers[p.entity_id], - lasso.MD_PROTOCOL_TYPE_SINGLE_SIGN_ON) - logger.debug('sso: \ - No http method given. Method infered: %s' % http_method) - if http_method == lasso.HTTP_METHOD_NONE: - return error_page(request, - _('sso: %s does not have any supported SingleSignOn endpoint') \ - % entity_id, logger=logger) - try: - login.initAuthnRequest(p.entity_id, http_method) - except lasso.Error, error: - return error_page(request, - _('sso: initAuthnRequest %s') % lasso.strError(error[0]), - logger=logger) - - # 5. Request setting - if not setAuthnrequestOptions(p, login, force_authn, is_passive): - logger.error('sso: No policy defined') - return error_page(request, _('sso: No IdP policy defined'), - logger=logger) - try: - login.buildAuthnRequestMsg() - except lasso.Error, error: - return error_page(request, - _('SSO: buildAuthnRequestMsg %s') % lasso.strError(error[0]), - logger=logger) - - # 6. Save the request ID (association with the target page) - logger.debug('sso: Authnrequest ID: %s' % login.request.iD) - logger.debug('sso: Save request id in the session %s' \ - % request.session.session_key) - register_request_id(request, login.request.iD) - - # 7. Redirect the user - logger.debug('sso: user redirection') - return return_saml2_request(request, login, - title=('AuthnRequest for %s' % entity_id)) - - -### - # singleSignOnArtifact, singleSignOnPostOrRedirect - # @request - # - # Single SignOn Response - # Binding supported: Artifact, POST - ### -def singleSignOnArtifact(request): - logger.info('singleSignOnArtifact: Binding Artifact processing begins...') - server = build_service_provider(request) - if not server: - return error_page(request, - _('singleSignOnArtifact: Service provider not configured'), - logger=logger) - - # Load the provider metadata using the artifact - if request.method == 'GET': - logger.debug('singleSignOnArtifact: GET') - artifact = request.REQUEST.get('SAMLart') - else: - logger.debug('singleSignOnArtifact: POST') - artifact = request.POST.get('SAMLart') - logger.debug('singleSignOnArtifact: artifact %s' % artifact) - p = LibertyProvider.get_provider_by_samlv2_artifact(artifact) - p = load_provider(request, p.entity_id, server=server, sp_or_idp='idp') - logger.info('singleSignOnArtifact: provider %s loaded' % p.entity_id) - - login = lasso.Login(server) - if not login: - return error_page(request, - _('singleSignOnArtifact: Unable to create Login object'), - logger=logger) - - message = get_saml2_request_message(request) - if not message: - return error_page(request, - _('singleSignOnArtifact: No message given.'), logger=logger) - #logger.debug('singleSignOnArtifact: message %s' % message) - - while True: - logger.debug('singleSignOnArtifact: Authnresponse processing') - try: - if request.method == 'GET': - login.initRequest(get_saml2_query_request(request), - lasso.HTTP_METHOD_ARTIFACT_GET) - else: - login.initRequest(artifact, lasso.HTTP_METHOD_ARTIFACT_POST) - break - except (lasso.ServerProviderNotFoundError, - lasso.ProfileUnknownProviderError): - logger.debug('singleSignOnArtifact: Unable to process \ - Authnresponse -load another provider') - provider_id = login.remoteProviderId - provider_loaded = load_provider(request, provider_id, - server=server, sp_or_idp='idp') - - if not provider_loaded: - message = _('singleSignOnArtifact: provider %r unknown') \ - % provider_id - return error_page(request, message, logger=logger) - else: - logger.info('singleSignOnArtifact: \ - provider %s loaded' % provider_id) - continue - except lasso.Error, error: - return error_page(request, - _('singleSignOnArtifact: initRequest %s') \ - % lasso.strError(error[0]), - logger=logger) - - try: - login.buildRequestMsg() - except lasso.Error, error: - return error_page(request, - _('singleSignOnArtifact: buildRequestMsg %s') \ - % lasso.strError(error[0]), logger=logger) - - # TODO: Client certificate - client_cert = None - try: - logger.info('singleSignOnArtifact: soap call to %s' % login.msgUrl) - logger.debug('singleSignOnArtifact: soap message %s' % login.msgBody) - soap_answer = soap_call(login.msgUrl, - login.msgBody, client_cert=client_cert) - except Exception: - return error_page(request, - _('singleSignOnArtifact: Failure to communicate \ - with artifact resolver %r') % login.msgUrl, - logger=logger) - if not soap_answer: - return error_page(request, - _('singleSignOnArtifact: Artifact resolver at %r returned \ - an empty response') % login.msgUrl, - logger=logger) - - logger.debug('singleSignOnArtifact: soap answer %s' % soap_answer) - - # If connexion over HTTPS, do not check signature?! - if login.msgUrl.startswith('https'): - logger.debug('singleSignOnArtifact: \ - artifact solved over HTTPS - Signature Hint forbidden') - login.setSignatureVerifyHint(lasso.PROFILE_SIGNATURE_HINT_FORBID) - - try: - login.processResponseMsg(soap_answer) - except lasso.Error, error: - return error_page(request, - _('singleSignOnArtifact: processResponseMsg raised %s') \ - % lasso.strError(error[0]), logger=logger) - - # TODO: Relay State - - logger.info('singleSignOnArtifact: Binding artifact treatment terminated') - return sso_after_response(request, login, provider=p) - - -@csrf_exempt -def singleSignOnPost(request): - logger.info('singleSignOnPost: Binding POST processing begins...') - server = build_service_provider(request) - if not server: - return error_page(request, - _('singleSignOnPost: Service provider not configured'), - logger=logger) - - login = lasso.Login(server) - if not login: - return error_page(request, - _('singleSignOnPost: Unable to create Login object'), - logger=logger) - - # TODO: check messages = get_saml2_request_message(request) - - # Binding POST - message = get_saml2_post_response(request) - if not message: - return error_page(request, - _('singleSignOnPost: No message given.'), logger=logger) - logger.debug('singleSignOnPost: message %s' % message) - - ''' Binding REDIRECT - - According to: saml-profiles-2.0-os - The HTTP Redirect binding MUST NOT be used, - as the response will typically exceed the - URL length permitted by most user agents. - ''' - # if not message: - # message = request.META.get('QUERY_STRING', '') - - while True: - logger.debug('singleSignOnPost: Authnresponse processing') - try: - login.processAuthnResponseMsg(message) - break - except (lasso.ServerProviderNotFoundError, - lasso.ProfileUnknownProviderError): - logger.debug('singleSignOnPost: \ - Unable to process Authnresponse - load another provider') - provider_id = login.remoteProviderId - provider_loaded = load_provider(request, provider_id, - server=server, sp_or_idp='idp') - - if not provider_loaded: - message = _('singleSignOnPost: provider %r unknown' \ - % provider_id) - return error_page(request, message, logger=logger) - else: - logger.info('singleSignOnPost: \ - provider %s loaded' % provider_id) - continue - except lasso.Error, error: - logger.debug('singleSignOnPost: lasso error, login dump is %s' \ - % login.dump()) - return error_page(request, - _('singleSignOnPost: %s') % lasso.strError(error[0]), - logger=logger) - - logger.info('singleSignOnPost: Binding POST treatment terminated') - return sso_after_response(request, login, provider=provider_loaded) - - -### - # sso_after_response - # @request - # @login - # @relay_state - # - # Post-authnrequest processing - ### -def sso_after_response(request, login, relay_state=None, provider=None): - logger.info('sso_after_response: Authnresponse processing begins...') - - subject_confirmation = request.build_absolute_uri().partition('?')[0] - saml_request_id = request.session.get('saml_request_id') - check = authnresponse_checking(login, subject_confirmation, logger, saml_request_id=saml_request_id) - if not check: - return error_page(request, - _('sso_after_response: error checking authn response'), logger=logger) - - try: - login.acceptSso() - except lasso.Error, error: - return error_page(request, - _('sso_after_response: acceptSso raised %s') \ - % lasso.strError(error[0]), logger=logger) - - logger.info('sso_after_response: \ - Assertion processing terminated with success') - - attributes = get_attributes_from_assertion(login.assertion, logger) - # Register attributes in session for other applications - request.session['attributes'] = attributes - - attrs = {} - - for att_statement in login.assertion.attributeStatement: - for attribute in att_statement.attribute: - name = None - format = lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC - nickname = None - try: - name = attribute.name.decode('ascii') - except: - logger.warning('sso_after_response: error decoding name of \ - attribute %s' % attribute.dump()) - else: - try: - if attribute.nameFormat: - format = attribute.nameFormat.decode('ascii') - if attribute.friendlyName: - nickname = attribute.friendlyName - except Exception, e: - message = 'sso_after_response: name or format of an \ - attribute failed to decode as ascii: %s due to %s' - logger.warning(message % (attribute.dump(), str(e))) - try: - if name: - if format: - if nickname: - key = (name, format, nickname) - else: - key = (name, format) - else: - key = (name) - attrs[key] = list() - for value in attribute.attributeValue: - content = [any.exportToXml() for any in value.any] - content = ''.join(content) - attrs[key].append(content.decode('utf8')) - except Exception, e: - message = 'sso_after_response: value of an \ - attribute failed to decode as ascii: %s due to %s' - logger.warning(message % (attribute.dump(), str(e))) - - if not 'multisource_attributes' in request.session: - request.session['multisource_attributes'] = dict() - request.\ - session['multisource_attributes'][login.assertion.issuer.content] = \ - list() - a8n = dict() - a8n['certificate_type'] = 'SAML2_assertion' - try: - a8n['nameid'] = \ - login.assertion.subject.nameID.content - except: - pass - try: - a8n['subject_confirmation_method'] = \ - login.assertion.subject.subjectConfirmation.method - except: - pass - try: - a8n['not_before'] = \ - login.assertion.subject. \ - subjectConfirmation.subjectConfirmationData.notBefore - except: - pass - try: - a8n['not_on_or_after'] = \ - login.assertion.subject.subjectConfirmation. \ - subjectConfirmationData.notOnOrAfter - except: - pass - try: - a8n['authn_context'] = \ - login.assertion.authnStatement[0]. \ - authnContext.authnContextClassRef - except: - pass - try: - a8n['authn_instant'] = \ - login.assertion.authnStatement[0].authnInstant - except: - pass - a8n['attributes'] = attrs - request.\ - session['multisource_attributes'][login.assertion.issuer.content].\ - append(a8n) - logger.debug('sso_after_response: \ - attributes in assertion %s from %s' \ - % (str(attrs), login.assertion.issuer.content)) - #authncontext - - #Access control processing - decisions = signals.authz_decision.send(sender=None, - request=request, attributes=attributes, provider=provider) - if not decisions: - logger.debug('sso_after_response: No authorization function \ - connected') - - access_granted = True - one_message = False - for decision in decisions: - logger.debug('sso_after_response: authorization function %s' \ - % decision[0].__name__) - dic = decision[1] - logger.debug('sso_after_response: decision is %s' % dic['authz']) - if 'message' in dic: - logger.debug('sso_after_response: with message %s' \ - % dic['message']) - if not dic['authz']: - access_granted = False - if 'message' in dic: - one_message = True - messages.add_message(request, messages.ERROR, dic['message']) - - if not access_granted: - if not one_message: - p = get_authorization_policy(provider) - messages.add_message(request, messages.ERROR, - p.default_denial_message) - return error_page(request, - logger=logger, default_message=False, timer=True) - - #Access granted, now we deal with session management - policy = get_idp_options_policy(provider) - if not policy: - logger.error('sso_after_response: No policy defined') - return error_page(request, - _('sso_after_response: No IdP policy defined'), logger=logger) - - user = request.user - - url = get_registered_url(request) - if not 'saml_request_id' in request.session: - #IdP initiated - url = policy.back_url - if login.nameIdentifier.format == \ - lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT \ - and (policy is None \ - or not policy.transient_is_persistent): - logger.info('sso_after_response: Transient nameID') - if policy.handle_transient == 'AUTHSAML2_UNAUTH_TRANSIENT_ASK_AUTH': - if not request.user.is_authenticated(): - #XXX: To test! - logger.info('sso_after_response: Account linking required') - save_session(request, login, - kind=LIBERTY_SESSION_DUMP_KIND_SP) - logger.debug('sso_after_response: \ - Register identity dump in session') - save_federation_temp(request, login, attributes=attributes) - maintain_liberty_session_on_service_provider(request, login) - return render_to_response('auth/saml2/account_linking.html', - context_instance=RequestContext(request)) - logger.debug('sso_after_response: django session opened') - session_not_on_or_after = \ - get_session_not_on_or_after(login.assertion) - if session_not_on_or_after: - request.session.set_expiry(session_not_on_or_after) - logger.debug('sso_after_response: session set to expire on \ - %s by SessionNotOnOrAfter attribute', - session_not_on_or_after) - if request.session.test_cookie_worked(): - request.session.delete_test_cookie() - save_session(request, login, kind=LIBERTY_SESSION_DUMP_KIND_SP) - logger.info('sso_after_response: \ - login processing ended with success - redirect to target') - return HttpResponseRedirect(url) - - if policy.handle_transient == \ - 'AUTHSAML2_UNAUTH_TRANSIENT_OPEN_SESSION': - logger.info('sso_after_response: \ - Opening session for transient with nameID') - logger.debug('sso_after_response: nameID %s' \ - % login.nameIdentifier.dump()) - user = authenticate(name_id=login.nameIdentifier) - if not user: - return error_page(request, - _('sso_after_response: \ - No backend for temporary federation is configured'), - logger=logger) - auth_login(request, user) - logger.debug('sso_after_response: django session opened') - session_not_on_or_after = \ - get_session_not_on_or_after(login.assertion) - if session_not_on_or_after: - request.session.set_expiry(session_not_on_or_after) - logger.debug('sso_after_response: session set to expire on \ - %s by SessionNotOnOrAfter attribute', - session_not_on_or_after) - signals.auth_login.send(sender=None, - request=request, attributes=attributes) - logger.debug('sso_after_response: successful login signal sent') - if request.session.test_cookie_worked(): - request.session.delete_test_cookie() - save_session(request, login, kind=LIBERTY_SESSION_DUMP_KIND_SP) - logger.info('sso_after_response: \ - login processing ended with success - redirect to target') - return HttpResponseRedirect(url) - return error_page(request, _('sso_after_response: \ - Transient access policy: Configuration error'), - logger=logger) - - elif login.nameIdentifier.format != \ - lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT \ - or (policy is not None and policy.transient_is_persistent): - #Consider that all kinds of nameId not transient are persistent. - logger.info('sso_after_response: persistent federation processing') - if policy is not None and policy.transient_is_persistent and \ - login.nameIdentifier.format == \ - lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT: - logger.info('sso_after_response: \ - the nameId %s is transient the but option persistent ' - 'federation processing is selected' \ - % login.nameIdentifier.dump()) - if policy.persistent_identifier_attribute: - logger.info('sso_after_response: ' - '%s is used as persistent identifier for federation' % \ - policy.persistent_identifier_attribute) - identifier = None - for key in attributes: - if policy.persistent_identifier_attribute in key \ - and attributes[key]: - identifier = attributes[key][0] - break - if identifier: - logger.info('sso_after_response: ' - '%s value is %s' % \ - (policy.persistent_identifier_attribute, identifier)) - login.nameIdentifier.content = identifier - else: - logger.warn('sso_after_response: ' - '%s not provided by the identity provider, ' - 'we continue with the nameID.' % \ - policy.persistent_identifier_attribute) - else: - logger.info('sso_after_response: ' - 'No attribute declared as persistent identifier ' - 'NameID is used.') - login.nameIdentifier.format = \ - lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT - login.nameIdentifier.nameQualifier = provider.entity_id - - user = AuthSAML2PersistentBackend(). \ - authenticate(name_id=login.nameIdentifier, - provider_id=login.remoteProviderId) - if not user and \ - policy.handle_persistent == \ - 'AUTHSAML2_UNAUTH_PERSISTENT_CREATE_USER_PSEUDONYMOUS': - # Auto-create an user then do the authentication again - logger.info('sso_after_response: Account creation') - AuthSAML2PersistentBackend(). \ - create_user(name_id=login.nameIdentifier, - provider_id=provider.entity_id) - user = AuthSAML2PersistentBackend(). \ - authenticate(name_id=login.nameIdentifier, - provider_id=login.remoteProviderId) - if user: - auth_login(request, user) - logger.debug('sso_after_response: session opened') - signals.auth_login.send(sender=None, - request=request, attributes=attributes) - logger.debug('sso_after_response: \ - signal sent that the session is opened') - if request.session.test_cookie_worked(): - request.session.delete_test_cookie() - save_session(request, login, kind=LIBERTY_SESSION_DUMP_KIND_SP) - maintain_liberty_session_on_service_provider(request, login) - logger.info('sso_after_response: \ - Login processing ended with success - redirect to target') - return HttpResponseRedirect(url) - elif policy.handle_persistent == \ - 'AUTHSAML2_UNAUTH_PERSISTENT_ACCOUNT_LINKING_BY_AUTH': - '''Check if the user consent for federation has been given''' - if policy.force_user_consent \ - and not login.response.consent in \ - ('urn:oasis:names:tc:SAML:2.0:consent:obtained', - 'urn:oasis:names:tc:SAML:2.0:consent:prior', - 'urn:oasis:names:tc:SAML:2.0:consent:current-explicit', - 'urn:oasis:names:tc:SAML:2.0:consent:current-implicit'): - return error_page(request, _('sso_after_response: You were \ - not asked your consent for account linking'), - logger=logger) - if request.user.is_authenticated(): - logger.info('sso_after_response: Add federation') - add_federation(request.user, name_id=login.nameIdentifier, - provider_id=login.remoteProviderId) - return HttpResponseRedirect(url) - logger.info('sso_after_response: Account linking required') - save_session(request, login, kind=LIBERTY_SESSION_DUMP_KIND_SP) - logger.debug('sso_after_response: \ - Register identity dump in session') - save_federation_temp(request, login, attributes=attributes) - maintain_liberty_session_on_service_provider(request, login) - return render_to_response('auth/saml2/account_linking.html', - context_instance=RequestContext(request)) - return error_page(request, - _('sso_after_response: \ - Persistent Account policy: Configuration error'), logger=logger) - - return error_page(request, - _('sso_after_response: \ - Transient access policy: NameId format not supported'), logger=logger) - #TODO: Relay state - - -### - # finish_federation - # @request - # - # Called after an account linking. - # TODO: add checkbox, create new account (settings option, user can choose) - # Create pseudonymous or user choose or only account linking - ### -@csrf_exempt -def finish_federation(request): - logger.info('finish_federation: Return after account linking form filled') - if request.method == "POST": - form = AuthenticationForm(data=request.POST) - if form.is_valid(): - logger.info('finish_federation: form valid') - server = build_service_provider(request) - if not server: - return error_page(request, - _('finish_federation: \ - Service provider not configured'), logger=logger) - - login = lasso.Login(server) - if not login: - return error_page(request, - _('finish_federation: \ - Unable to create Login object'), logger=logger) - - s = load_session(request, login, kind=LIBERTY_SESSION_DUMP_KIND_SP) - load_federation_temp(request, login) - if not login.session: - return error_page(request, - _('finish_federation: Error loading session.'), - logger=logger) - - login.nameIdentifier = request.session['nameId'] - - logger.debug('finish_federation: nameID %s' % \ - login.nameIdentifier.dump()) - - provider_id = None - if 'remoteProviderId' in request.session: - provider_id = request.session['remoteProviderId'] - fed = add_federation(form.get_user(), - name_id=login.nameIdentifier, - provider_id=provider_id) - if not fed: - return error_page(request, - _('SSO/finish_federation: \ - Error adding new federation for this user'), - logger=logger) - - logger.info('finish_federation: federation added') - - url = get_registered_url(request) - auth_login(request, form.get_user()) - if request.session.test_cookie_worked(): - request.session.delete_test_cookie() - logger.debug('finish_federation: session opened') - - attributes = [] - if 'attributes' in request.session: - attributes = request.session['attributes'] - signals.auth_login.send(sender=None, - request=request, attributes=attributes) - logger.debug('finish_federation: \ - signal sent that the session is opened') - - if s: - s.delete() - if login.session: - login.session.isDirty = True - if login.identity: - login.identity.isDirty = True - save_session(request, login, kind=LIBERTY_SESSION_DUMP_KIND_SP) - maintain_liberty_session_on_service_provider(request, login) - logger.info('finish_federation: \ - Login processing ended with success - redirect to target') - return HttpResponseRedirect(url) - else: - # TODO: Error: login failed: message and count 3 attemps - logger.warning('finish_federation: \ - form not valid - Try again! (Brute force?)') - return render_to_response('auth/saml2/account_linking.html', - context_instance=RequestContext(request)) - else: - return error_page(request, - _('finish_federation: Unable to perform federation'), - logger=logger) - - -''' - Single Logout (SLO) - - Initiated by SP or by IdP with SOAP or with Redirect -''' - - -def ko_icon(request): - return HttpResponseRedirect('%s/authentic2/images/ko.png' \ - % settings.STATIC_URL) - - -def ok_icon(request): - return HttpResponseRedirect('%s/authentic2/images/ok.png' \ - % settings.STATIC_URL) - - -def sp_slo(request, provider_id=None): - ''' - To make another module call the SLO function. - Does not deal with the local django session. - ''' - next = request.REQUEST.get('next') - - logger.debug('sp_slo: provider_id in parameter %s' % str(provider_id)) - - if request.method == 'GET' and 'provider_id' in request.GET: - provider_id = request.GET.get('provider_id') - logger.debug('sp_slo: provider_id from GET %s' % str(provider_id)) - if request.method == 'POST' and 'provider_id' in request.POST: - provider_id = request.POST.get('provider_id') - logger.debug('sp_slo: provider_id from POST %s' % str(provider_id)) - if not provider_id: - logger.info('sp_slo: to initiate a slo we need a provider_id') - return redirect_next(request, next) or ko_icon(request) - logger.info('sp_slo: slo initiated with %(provider_id)s' \ - % {'provider_id': provider_id}) - - server = create_server(request) - logout = lasso.Logout(server) - logger.info('sp_slo: sp_slo for %s' % provider_id) - load_session(request, logout, kind=LIBERTY_SESSION_DUMP_KIND_SP) - provider = load_provider(request, provider_id, - server=server, sp_or_idp='idp') - if not provider: - logger.error('sp_slo: sp_slo failed to load provider') - return redirect_next(request, next) or ko_icon(request) - policy = get_idp_options_policy(provider) - if not policy: - logger.error('sp_slo: No policy found for %s'\ - % provider_id) - return redirect_next(request, next) or ko_icon(request) - if not policy.forward_slo: - logger.warn('sp_slo: slo asked for %s configured to not receive slo' \ - % provider_id) - return redirect_next(request, next) or ko_icon(request) - if policy.enable_http_method_for_slo_request \ - and policy.http_method_for_slo_request: - if policy.http_method_for_slo_request == lasso.HTTP_METHOD_SOAP: - logger.info('sp_slo: sp_slo by SOAP') - try: - logout.initRequest(None, lasso.HTTP_METHOD_SOAP) - except: - logger.exception('sp_slo: sp_slo init error') - return redirect_next(request, next) or ko_icon(request) - try: - logout.buildRequestMsg() - except: - logger.exception('sp_slo: sp_slo build error') - return redirect_next(request, next) or ko_icon(request) - try: - soap_response = send_soap_request(request, logout) - except: - logger.exception('sp_slo: sp_slo SOAP failure') - return redirect_next(request, next) or ko_icon(request) - logger.info('sp_slo: successful soap call') - return process_logout_response(request, - logout, soap_response, next) - else: - try: - logout.initRequest(None, lasso.HTTP_METHOD_REDIRECT) - except: - logger.exception('sp_slo: sp_slo init error') - return redirect_next(request, next) or ko_icon(request) - logout.msgRelayState = logout.request.id - try: - logout.buildRequestMsg() - except: - logger.exception('sp_slo: sp_slo build error') - return redirect_next(request, next) or ko_icon(request) - logger.info('sp_slo: sp_slo by redirect') - save_key_values(logout.request.id, - logout.dump(), provider_id, next) - return HttpResponseRedirect(logout.msgUrl) - try: - logout.initRequest(provider_id) - except lasso.ProfileMissingAssertionError: - logger.error('sp_slo: \ - sp_slo failed because no sessions exists for %r' % provider_id) - return redirect_next(request, next) or ko_icon(request) - logout.msgRelayState = logout.request.id - try: - logout.buildRequestMsg() - except: - logger.exception('sp_slo: sp_slo misc error') - return redirect_next(request, next) or ko_icon(request) - # SOAP case - if logout.msgBody: - logger.info('sp_slo: sp_slo by SOAP') - try: - soap_response = send_soap_request(request, logout) - except: - logger.exception('sp_slo: sp_slo SOAP failure') - return redirect_next(request, next) or ko_icon(request) - return process_logout_response(request, logout, soap_response, next) - else: - logger.info('sp_slo: sp_slo by redirect') - save_key_values(logout.request.id, logout.dump(), provider_id, next) - return HttpResponseRedirect(logout.msgUrl) - - -def process_logout_response(request, logout, soap_response, next): - try: - logout.processResponseMsg(soap_response) - except: - logger.exception('process_logout_response: \ - processResponseMsg raised an exception') - return redirect_next(request, next) or ko_icon(request) - else: - delete_session(request) - return redirect_next(request, next) or ok_icon(request) - - -def singleLogoutReturn(request): - ''' - IdP response to a SLO SP initiated by redirect - ''' - server = build_service_provider(request) - if not server: - logger.warn('singleLogoutReturn: Service provider not configured') - return ko_icon(request) - query = get_saml2_query_request(request) - if not query: - logger.warn('singleLogoutReturn: \ - Unable to handle SLO by Redirect return without LogoutResponse') - return ko_icon(request) - logout = lasso.Logout(server) - if not logout: - logger.warn('singleLogoutReturn: Unable to create Login object') - return ko_icon(request) - load_session(request, logout, kind=LIBERTY_SESSION_DUMP_KIND_SP) - id = request.REQUEST.get('RelayState', None) - if not id: - logger.error('singleLogoutReturn: missing id argument') - return ko_icon(request) - logout_dump, provider_id_saved, next = get_and_delete_key_values(id) - provider_loaded = None - provider_id = None - while True: - try: - logout.processResponseMsg(query) - break - except (lasso.ServerProviderNotFoundError, - lasso.ProfileUnknownProviderError): - provider_id = logout.remoteProviderId - provider_loaded = load_provider(request, provider_id, - server=server, sp_or_idp='idp') - if not provider_loaded: - logger.warn('singleLogoutReturn: provider %r unknown' \ - % provider_id) - return redirect_next(request, next) or ko_icon(request) - else: - continue - except lasso.Error, error: - return redirect_next(request, next) or ko_icon(request) - if provider_id != provider_id_saved: - logger.warn('singleLogoutReturn: provider mistmatch between %s and %s' \ - % (provider_id, provider_id_saved)) - return redirect_next(request, next) or ko_icon(request) - if logout.isSessionDirty: - if logout.session: - save_session(request, logout, kind=LIBERTY_SESSION_DUMP_KIND_SP) - else: - delete_session(request) - remove_liberty_session_sp(request) - return redirect_next(request, next) or ok_icon(request) - - -def slo_soap_as_idp(request, logout, session=None): - logger.debug('slo_soap_as_idp: start slo proxying to sp processing') - from authentic2.idp.saml import saml2_endpoints - error = saml2_endpoints. \ - validate_logout_request(request, logout, idp=False) - if error: - return error - if not session: - key = request.session.session_key - else: - key = session.django_session_key - lib_sessions = LibertySession.objects.filter( - django_session_key=key) - if not lib_sessions: - logger.debug('slo_soap_as_idp: no sp session') - else: - server = saml2_endpoints.create_server(request) - logout2 = lasso.Logout(server) - for lib_session in lib_sessions: - logger.info('slo_soap_as_idp: logout to provider %s' \ - % lib_session.provider_id) - p = load_provider(request, lib_session.provider_id, - server=server) - if p: - policy = get_sp_options_policy(p) - if not policy: - logger.error('slo_soap_as_idp: No policy found for %s' \ - % lib_session.provider_id) - elif not policy.forward_slo: - logger.info('slo_soap_as_idp: %s configured to not \ - reveive slo' % lib_session.provider_id) - else: - try: - session_dump = saml2_endpoints.build_session_dump([lib_session]) - logout2.setSessionFromDump(session_dump.encode('utf8')) - logout2.initRequest(None, lasso.HTTP_METHOD_SOAP) - logout2.buildRequestMsg() - soap_response = send_soap_request(request, logout2) - except Exception, e: - logger.error('slo_soap_as_idp: error building \ - request to provider %s due to %s' \ - % (lib_session.provider_id, str(e))) - else: - try: - logout2.processResponseMsg(soap_response) - except Exception, e: - logger.error('slo_soap_as_idp: error received \ - from provider %s due to %s' \ - % (lib_session.provider_id, str(e))) - else: - logger.error('slo_soap_as_idp: unable to load provider %s' \ - % lib_session.provider_id) - logger.debug('slo_soap_as_idp: end slo proxying to sp processing') - - -def common_processing_slo_idp_init_bindings(request, message): - server = build_service_provider(request) - if not server: - return http_response_forbidden_request('common_processing: ' - 'Service provider not configured'), None, None - - logout = lasso.Logout(server) - if not logout: - return http_response_forbidden_request('common_processing: ' - 'Unable to create Logout object'), None, None - - provider_loaded = None - while True: - try: - logout.processRequestMsg(message) - break - except (lasso.ServerProviderNotFoundError, - lasso.ProfileUnknownProviderError): - provider_id = logout.remoteProviderId - provider_loaded = load_provider(request, provider_id, - server=server, sp_or_idp='idp') - - if not provider_loaded: - logger.warn('common_processing: provider %r unknown' \ - % provider_id) - return return_logout_error(request, logout, - AUTHENTIC_STATUS_CODE_UNKNOWN_PROVIDER), None, None - else: - continue - except lasso.Error, error: - return return_logout_error(request, logout, - AUTHENTIC_STATUS_CODE_INTERNAL_SERVER_ERROR), None, None - - policy = get_idp_options_policy(provider_loaded) - if not policy: - logger.error('common_processing: No policy found for %s'\ - % logout.remoteProviderId) - return return_logout_error(request, logout, - AUTHENTIC_STATUS_CODE_UNAUTHORIZED), None, None - if not policy.accept_slo: - logger.warn('common_processing: received slo from %s not authorized'\ - % logout.remoteProviderId) - return return_logout_error(request, logout, - AUTHENTIC_STATUS_CODE_UNAUTHORIZED), None, None - - # Look for a session index - try: - session_index = logout.request.sessionIndex - except: - pass - - fed = lookup_federation_by_name_identifier(profile=logout) - if not fed: - logger.warning('common_processing: unknown user for %s' \ - % logout.request.dump()) - return return_logout_error(request, logout, - lasso.SAML2_STATUS_CODE_UNKNOWN_PRINCIPAL), None, None - - session = None - try: - session = LibertySessionSP. \ - objects.get(federation=fed, session_index=session_index) - except LibertySessionSP.DoesNotExist: - logger.warning('common_processing: No Liberty session found') - return return_logout_error(request, logout, - lasso.SAML2_STATUS_CODE_UNKNOWN_PRINCIPAL), None, None - - q = LibertySessionDump. \ - objects.filter(django_session_key=session.django_session_key) - if not q: - logger.warning('common_processing: \ - No session dump for this session') - return return_logout_error(request, logout, - lasso.SAML2_STATUS_CODE_UNKNOWN_PRINCIPAL), None, None - logger.info('common_processing: from %s, \ - for session index %s and session %s' % \ - (logout.remoteProviderId, session_index, session.id)) - logout.setSessionFromDump(q[0].session_dump.encode('utf8')) - q.delete() - - try: - logout.validateRequest() - except lasso.Error, error: - msg = 'common_processing: error validateRequest: %s' \ - % lasso.strError(error[0]) - logger.info(msg) - # We continue the process - return None, session, logout - - -@csrf_exempt -def singleLogoutSOAP(request): - ''' - Single Logout IdP initiated by SOAP - ''' - message = None - try: - message = get_soap_message(request) - except: - return http_response_bad_request('singleLogoutSOAP: Bad SOAP message') - - if not message: - return http_response_bad_request('singleLogoutSOAP: Bad SOAP message') - - request_type = lasso.getRequestTypeFromSoapMsg(message) - if request_type != lasso.REQUEST_TYPE_LOGOUT: - return http_response_bad_request('singleLogoutSOAP: \ - SOAP message is not a slo message') - - error, session, logout = \ - common_processing_slo_idp_init_bindings(request, message) - if error: - return error - - ''' - Play the role of IdP sending a SLO to all SP - ''' - slo_soap_as_idp(request, logout, session) - - '''Break local session and respond to the IdP initiating the SLO''' - try: - flush_django_session(session.django_session_key) - session.delete() - except Exception, e: - logger.error('singleLogoutSOAP: Error at session deletion due to %s' \ - % str(e)) - return finishSingleLogoutSOAP(logout) - return finishSingleLogoutSOAP(logout) - - -def finishSingleLogoutSOAP(logout): - try: - logout.buildResponseMsg() - except lasso.Error, error: - message = 'singleLogoutSOAP \ - buildResponseMsg: %s' % lasso.strError(error[0]) - return http_response_forbidden_request(message) - django_response = HttpResponse() - django_response.status_code = 200 - django_response.content_type = 'text/xml' - django_response.content = logout.msgBody - return django_response - - -def finish_slo(request): - id = request.REQUEST.get('id') - if not id: - logger.error('finish_slo: missing id argument') - return HttpResponseBadRequest('finish_slo: missing id argument') - logout_dump, session_key, provider_id = get_and_delete_key_values(id) - server = create_server(request) - logout = lasso.Logout.newFromDump(server, logout_dump) - load_provider(request, provider_id, server=logout.server, - sp_or_idp='idp') - #Break local session and respond to the IdP initiating the SLO - if logout.isSessionDirty: - if logout.session: - save_session(request, logout, session_key=session_key, - kind=LIBERTY_SESSION_DUMP_KIND_SP) - else: - delete_session(request, session_key=session_key) - remove_liberty_session_sp(request, session_key=session_key) - return slo_return_response(logout) - - -def singleLogout(request): - ''' - Single Logout IdP initiated by Redirect - ''' - message = get_saml2_query_request(request) - if not message: - return http_response_forbidden_request('singleLogout: \ - Unable to handle Single Logout by Redirect without request') - - error, session, logout = \ - common_processing_slo_idp_init_bindings(request, message) - if error: - return error - - if settings.IDP_SAML2: - save_key_values(logout.request.id, logout.dump(), - request.session.session_key, logout.remoteProviderId) - return idp_views.redirect_to_logout(request, next_page='%s?id=%s' % - (reverse(finish_slo), urllib.quote(logout.request.id))) - - try: - flush_django_session(request.session.session_key) - session.delete() - except Exception, e: - logger.error('singleLogout: Error at session deletion due to %s' \ - % str(e)) - return slo_return_response(logout) - return slo_return_response(logout) - - -def slo_return_response(logout): - try: - logout.buildResponseMsg() - except lasso.Error, error: - return http_response_forbidden_request('slo_return_response: %s' \ - % lasso.strError(error[0])) - else: - logger.info('slo_return_response: redirect to %s' % logout.msgUrl) - return HttpResponseRedirect(logout.msgUrl) - - -### - # federationTermination - # @request - # @method - # @entity_id - # - # Name Identifier Management - # Federation termination: request from user interface - # Profile supported: Redirect, SOAP - # For response, if the requester uses a (a)synchronous binding, - # the responder uses the same. - # Else, the grabs the preferred method from the metadata. - # By default we do not break the session. - # TODO: Define in admin a parameter to indicate if the - # federation termination implies a local logout (IDP and SP initiated) - # -> Should not logout. - # TODO: Clean tables of all dumps about this user - ### -def federationTermination(request): - entity_id = request.REQUEST.get('entity_id') - if not entity_id: - return error_page(request, - _('fedTerm/SP UI: No provider for defederation'), - logger=logger) - - if request.user.is_anonymous(): - return error_page(request, - _('fedTerm/SP UI: Unable to defederate a not logged user!'), - logger=logger) - - server = build_service_provider(request) - if not server: - error_page(request, - _('fedTerm/SP UI: Service provider not configured'), - logger=logger) - - # Lookup for the Identity provider - p = load_provider(request, entity_id, server=server, sp_or_idp='idp') - if not p: - return error_page(request, - _('fedTerm/SP UI: No such identity provider.'), - logger=logger) - - manage = lasso.NameIdManagement(server) - - load_session(request, manage, kind=LIBERTY_SESSION_DUMP_KIND_SP) - load_federation(request, get_entity_id(request, reverse(metadata)), manage) - fed = lookup_federation_by_user(request.user, p.entity_id) - if not fed: - return error_page(request, - _('fedTerm/SP UI: Not a valid federation'), - logger=logger) - - # The user asks a defederation, - # we perform without knowing if the IdP can handle - fed.delete() - - # TODO: Deal with identity provider configuration in policies - - # If not defined in the metadata, - # put ANY to let lasso do its job from metadata - if not p.identity_provider.enable_http_method_for_defederation_request: - try: - manage.initRequest(entity_id, None, lasso.HTTP_METHOD_ANY) - except lasso.Error, error: - return error_page(request, - _('fedTerm/SP UI: %s') % lasso.strError(error[0]), - logger=logger) - - if manage.msgBody: - try: - manage.buildRequestMsg() - except lasso.Error, error: - return error_page(request, - _('fedTerm/SP SOAP: %s') % lasso.strError(error[0]), - logger=logger) - # TODO: Client cert - client_cert = None - try: - soap_answer = soap_call(manage.msgUrl, - manage.msgBody, client_cert=client_cert) - except SOAPException: - return error_page(request, - _('fedTerm/SP SOAP: \ - Unable to perform SOAP defederation request'), - logger=logger) - return manage_name_id_return(request, manage, soap_answer) - else: - try: - manage.buildRequestMsg() - except lasso.Error, error: - return error_page(request, - _('fedTerm/SP Redirect: %s') % \ - lasso.strError(error[0]), logger=logger) - save_manage(request, manage) - return HttpResponseRedirect(manage.msgUrl) - - # Else, taken from config - if p.identity_provider.http_method_for_defederation_request == \ - lasso.HTTP_METHOD_SOAP: - try: - manage.initRequest(entity_id, None, lasso.HTTP_METHOD_SOAP) - manage.buildRequestMsg() - except lasso.Error, error: - return error_page(request, - _('fedTerm/SP SOAP: %s') % lasso.strError(error[0]), - logger=logger) - # TODO: Client cert - client_cert = None - try: - soap_answer = soap_call(manage.msgUrl, - manage.msgBody, client_cert=client_cert) - except SOAPException: - return error_page(request, - _('fedTerm/SP SOAP: \ - Unable to perform SOAP defederation request'), - logger=logger) - return manage_name_id_return(request, manage, soap_answer) - - if p.identity_provider.http_method_for_defederation_request == \ - lasso.HTTP_METHOD_REDIRECT: - try: - manage.initRequest(entity_id, None, lasso.HTTP_METHOD_REDIRECT) - manage.buildRequestMsg() - except lasso.Error, error: - return error_page(request, - _('fedTerm/SP Redirect: %s') % lasso.strError(error[0]), - logger=logger) - save_manage(request, manage) - return HttpResponseRedirect(manage.msgUrl) - - return error_page(request, _('Unknown HTTP method.'), logger=logger) - - -### - # manageNameIdReturn - # @request - # - # Federation termination: response from Redirect SP initiated - ### -def manageNameIdReturn(request): - server = build_service_provider(request) - if not server: - return error_page(request, - _('fedTerm/SP Redirect: Service provider not configured'),\ - logger=logger) - - manage_dump = get_manage_dump(request) - manage = None - if manage_dump.exists() and manage_dump.count() > 1: - manage_dump.delete() - return error_page(request, - _('fedTerm/SP Redirect: Error managing manage dump'), - logger=logger) - elif manage_dump.exists(): - try: - manage = \ - lasso.NameIdManagement.newFromDump(server, - manage_dump[0].manage_dump) - except: - pass - manage_dump.delete() - else: - manage = lasso.NameIdManagement(server) - - if not manage: - return error_page(request, - _('fedTerm/SP Redirect: Defederation failed'), logger=logger) - - load_federation(request, get_entity_id(request, reverse(metadata)), manage) - message = get_saml2_request_message(request) - return manage_name_id_return(request, manage, message) - - -### - # manage_name_id_return - # @request - # @logout - # @message - # - # Post-response processing - ### -def manage_name_id_return(request, manage, message): - while True: - try: - manage.processResponseMsg(message) - except (lasso.ServerProviderNotFoundError, - lasso.ProfileUnknownProviderError): - provider_id = manage.remoteProviderId - provider_loaded = load_provider(request, provider_id, - server=manage.server, sp_or_idp='idp') - - if not provider_loaded: - message = _('fedTerm/Return: \ - provider %r unknown') % provider_id - return error_page(request, message, logger=logger) - else: - continue - except lasso.Error, error: - return error_page(request, - _('fedTerm/manage_name_id_return: %s') % \ - lasso.strError(error[0]), - logger=logger) - return HttpResponseRedirect(get_registered_url(request)) - - -### - # manageNameIdSOAP - # @request - # - # Federation termination: request from SOAP IdP initiated - # TODO: Manage valid soap responses on error (else error 500) - ### -@csrf_exempt -def manageNameIdSOAP(request): - try: - soap_message = get_soap_message(request) - except: - return http_response_bad_request('fedTerm/IdP SOAP: Bad SOAP message') - if not soap_message: - return http_response_bad_request('fedTerm/IdP SOAP: Bad SOAP message') - - request_type = lasso.getRequestTypeFromSoapMsg(soap_message) - if request_type != lasso.REQUEST_TYPE_NAME_ID_MANAGEMENT: - return http_response_bad_request('fedTerm/IdP SOAP: \ - SOAP message is not a slo message') - - server = build_service_provider(request) - if not server: - return http_response_forbidden_request('fedTerm/IdP SOAP: \ - Service provider not configured') - - manage = lasso.NameIdManagement(server) - if not manage: - return http_response_forbidden_request('fedTerm/IdP SOAP: \ - Unable to create Login object') - - while True: - try: - manage.processRequestMsg(soap_message) - break - except (lasso.ServerProviderNotFoundError, - lasso.ProfileUnknownProviderError): - provider_id = manage.remoteProviderId - provider_loaded = load_provider(request, provider_id, - server=server, sp_or_idp='idp') - - if not provider_loaded: - message = _('fedTerm/SOAP: provider %r unknown') % provider_id - return error_page(request, message, logger=logger) - else: - continue - except lasso.Error, error: - message = 'fedTerm/IdP SOAP: %s' % lasso.strError(error[0]) - return http_response_forbidden_request(message) - - fed = lookup_federation_by_name_identifier(profile=manage) - load_federation(request, get_entity_id(request, reverse(metadata)), manage, fed.user) - try: - manage.validateRequest() - except lasso.Error, error: - message = 'fedTerm/IdP SOAP: %s' % lasso.strError(error[0]) - return http_response_forbidden_request(message) - - fed.delete() - - try: - manage.buildResponseMsg() - except: - message = 'fedTerm/IdP SOAP: %s' % lasso.strError(error[0]) - return http_response_forbidden_request(message) - - django_response = HttpResponse() - django_response.status_code = 200 - django_response.content_type = 'text/xml' - django_response.content = manage.msgBody - return django_response - - -### - # manageNameId - # @request - # - # Federation termination: request from Redirect IdP initiated - ### -def manageNameId(request): - query = get_saml2_query_request(request) - if not query: - return http_response_forbidden_request('fedTerm/IdP Redirect: \ - Unable to handle Single Logout by Redirect without request') - - server = build_service_provider(request) - if not server: - return http_response_forbidden_request('fedTerm/IdP Redirect: \ - Service provider not configured') - - manage = lasso.NameIdManagement(server) - if not manage: - return http_response_forbidden_request('fedTerm/IdP Redirect: \ - Unable to create Login object') - - try: - manage.processRequestMsg(query) - except lasso.Error, error: - message = 'fedTerm/IdP Redirect: %s' % lasso.strError(error[0]) - return http_response_forbidden_request(message) - - fed = lookup_federation_by_name_identifier(profile=manage) - load_federation(request, get_entity_id(request, reverse(metadata)), manage, fed.user) - try: - manage.validateRequest() - except lasso.Error, error: - logger.warning('fedTerm/IdP Redirect: Unable to validate request') - return - - fed.delete() - - try: - manage.buildResponseMsg() - except: - message = 'fedTerm/IdP Redirect: %s' % lasso.strError(error[0]) - return http_response_forbidden_request(message) - - return HttpResponseRedirect(manage.msgUrl) - - -############################################# -# Helper functions -############################################# - -def get_provider_id_and_options(provider_id): - if not provider_id: - provider_id = reverse(metadata) - options = metadata_options - if getattr(settings, 'AUTHSAML2_METADATA_OPTIONS', None): - options.update(settings.AUTHSAML2_METADATA_OPTIONS) - return provider_id, options - - -def get_metadata(request, provider_id=None): - provider_id, options = get_provider_id_and_options(provider_id) - return get_saml2_metadata(request, provider_id, sp_map=metadata_map, - options=options) - - -def create_server(request, provider_id=None): - provider_id, options = get_provider_id_and_options(provider_id) - return create_saml2_server(request, provider_id, sp_map=metadata_map, - options=options) - - -def http_response_bad_request(message): - logger.error(message) - return HttpResponseBadRequest(_(message)) - - -def http_response_forbidden_request(message): - logger.error(message) - return HttpResponseForbidden(_(message)) - - -def build_service_provider(request): - return create_server(request, reverse(metadata)) - - -def setAuthnrequestOptions(provider, login, force_authn, is_passive): - if not provider or not login: - return None - - p = get_idp_options_policy(provider) - if not p: - return None - - if p.no_nameid_policy: - login.request.nameIDPolicy = None - else: - login.request.nameIDPolicy.format = \ - NAME_ID_FORMATS[p.requested_name_id_format]['samlv2'] - login.request.nameIDPolicy.allowCreate = p.allow_create - login.request.nameIDPolicy.spNameQualifier = None - - if p.enable_binding_for_sso_response: - login.request.protocolBinding = p.binding_for_sso_response - - if force_authn is None: - force_authn = p.want_force_authn_request - login.request.forceAuthn = force_authn - - if is_passive is None: - is_passive = p.want_is_passive_authn_request - login.request.isPassive = is_passive - - return p - - -def profile(request, template_name='profile.html'): - if 'next' in request.session: - next = request.session['next'] - else: - next = next - if request.user is None \ - or not request.user.is_authenticated() \ - or not hasattr(request.user, '_meta'): - return HttpResponseRedirect(next) - logger.info('view_profile: View profile of user %s' % str(request.user)) - - #Add creation date - federations = LibertyProvider.objects \ - .filter(identity_provider__libertyfederation__user=request.user) \ - .values_list('name', flat=True) - - from frontend import AuthSAML2Frontend - form = AuthSAML2Frontend().form()() - if not form.fields['provider_id'].choices: - form = None - context = {'submit_name': 'submit-%s' % AuthSAML2Frontend().id(), - REDIRECT_FIELD_NAME: '/profile', - 'form': form} - - return render_to_string(template_name, - {'next': next, - 'federations': federations, - 'base': '/authsaml2'}, - RequestContext(request, context)) - - -@login_required -@csrf_exempt -def delete_federation(request, next_url='/'): - next = request.REQUEST.get('next', next_url) - logger.info('delete_federation: federation deletion requested') - if request.method == "POST": - provider_name = request.POST.get('fed') - if provider_name: - LibertyFederation.objects.filter( - user=request.user, - idp__liberty_provider__name=provider_name).update(user=None) - logger.info('delete_federation: federation %s deleted', - provider_name) - messages.add_message(request, messages.INFO, - _('Successful federation deletion.')) - return HttpResponseRedirect(next) - return HttpResponseRedirect(next) diff --git a/authentic2/authsaml2/signals.py b/authentic2/authsaml2/signals.py deleted file mode 100644 index 59e8f17f0..000000000 --- a/authentic2/authsaml2/signals.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.dispatch import Signal - -#authz_decision -authz_decision = Signal(providing_args = ["request","attributes","provider"]) - -#user login -auth_login = Signal(providing_args = ["request","attributes"]) - -#user logout -auth_logout = Signal(providing_args = ["user"]) diff --git a/authentic2/authsaml2/templates/auth/saml2/account_linking.html b/authentic2/authsaml2/templates/auth/saml2/account_linking.html deleted file mode 100644 index 91e46a081..000000000 --- a/authentic2/authsaml2/templates/auth/saml2/account_linking.html +++ /dev/null @@ -1,39 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %} -{% trans "Log in to link your account" %} -{% endblock %} - -{% block content %} -

* {% trans "Log in to link with your existing account" %}

-
-
-
    - {% for error in form.non_field_errors %} -
  • {{ error|escape }}
  • - {% endfor %} - {% for error in form.username.errors %} -
  • {% trans "Username:" %} {{ error|escape }}
  • - {% endfor %} - {% for error in form.password.errors %} -
  • {% trans "Password:" %} {{ error|escape }}
  • - {% endfor %} -
-

- - -

-

- - -

- - - -
-
- -{% endblock %} diff --git a/authentic2/authsaml2/templates/auth/saml2/login_form.html b/authentic2/authsaml2/templates/auth/saml2/login_form.html deleted file mode 100644 index 21c583170..000000000 --- a/authentic2/authsaml2/templates/auth/saml2/login_form.html +++ /dev/null @@ -1,8 +0,0 @@ -{% load i18n %} -
-
-{% csrf_token %} -{{ form.as_p }} - -
-
diff --git a/authentic2/authsaml2/templates/auth/saml2/logout.html b/authentic2/authsaml2/templates/auth/saml2/logout.html deleted file mode 100644 index bdc831297..000000000 --- a/authentic2/authsaml2/templates/auth/saml2/logout.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %} -{% trans "Logout" %} -{% endblock %} -{% block bodyargs %}onload="setTimeout(function () { window.location='{{ next_page }}' }, {{ redir_timeout }})"{% endblock %} - -{% block content %} - -

{% trans message %}

- - - - -{% endblock %} diff --git a/authentic2/authsaml2/templates/error_authsaml2.html b/authentic2/authsaml2/templates/error_authsaml2.html deleted file mode 100644 index 89f7aa018..000000000 --- a/authentic2/authsaml2/templates/error_authsaml2.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} -{% block bodyargs %}onload="setTimeout(function () { window.location='{{ next_page }}' }, {{ redir_timeout }})"{% endblock %} - -{% block content %} -

{{ title }}

- -

{% trans "Back" %}

-{% endblock %} diff --git a/authentic2/authsaml2/templates/profile.html b/authentic2/authsaml2/templates/profile.html deleted file mode 100644 index 686b3c6ff..000000000 --- a/authentic2/authsaml2/templates/profile.html +++ /dev/null @@ -1,32 +0,0 @@ -{% load i18n %} -{% if form or federations %} -

{% trans "SAML2 Federations" %}

- -
- -{% if federations %} -

-

{% trans "Delete a federation?" %}
-{% for f in federations %} -
- - - - -
-{% endfor %} -

-{% endif %} - -{% if form %} -

-

{% trans "Add a federation?" %}
-
-{% csrf_token %} -{{ form.as_p }} - -
-

-{% endif %} -
-{% endif %} diff --git a/authentic2/authsaml2/urls.py b/authentic2/authsaml2/urls.py deleted file mode 100644 index 2816f92e5..000000000 --- a/authentic2/authsaml2/urls.py +++ /dev/null @@ -1,50 +0,0 @@ -from django.conf import settings - -from django.conf.urls import patterns, url - -from authentic2.authsaml2.saml2_endpoints import metadata, sso, finish_federation, \ - singleSignOnArtifact, singleSignOnPost, sp_slo, singleLogoutReturn, \ - singleLogoutSOAP, singleLogout, federationTermination, manageNameIdReturn, \ - manageNameIdSOAP, manageNameId, delete_federation, redirect_to_disco, \ - disco_response, finish_slo - -urlpatterns = patterns('', - (r'^metadata$', metadata), - # Receive request from user interface - (r'^sso$', sso), - (r'^finish_federation$', finish_federation), - (r'^singleSignOnArtifact$', singleSignOnArtifact), - (r'^singleSignOnPost$', singleSignOnPost), - # Receive request from functions - (r'^sp_slo/(.*)$', sp_slo), - # Receive response from Redirect SP initiated - (r'^singleLogoutReturn$', singleLogoutReturn), - # Receive request from SOAP IdP initiated - (r'^singleLogoutSOAP$', singleLogoutSOAP), - # Receive request from Redirect IdP initiated - (r'^singleLogout$', singleLogout), - # Back of SLO treatment by the IdP Side - (r'^finish_slo$', finish_slo), - # Receive request from user interface - (r'^federationTermination$', federationTermination), - # Receive response from Redirect SP initiated - (r'^manageNameIdReturn$', manageNameIdReturn), - # Receive request from SOAP IdP initiated - (r'^manageNameIdSOAP$', manageNameIdSOAP), - # Receive request from Redirect IdP initiated - (r'^manageNameId$', manageNameId), - # Receive request from Redirect IdP initiated - url(r'^delete_federation/$', delete_federation, - name='authsaml2-delete-federation'), -) - -try: - if settings.USE_DISCO_SERVICE: - urlpatterns += patterns('', - #Send idp discovery request - (r'^redirect_to_disco$', redirect_to_disco), - #receive idp discovery response - (r'^discoveryReturn$', disco_response), - ) -except: - pass diff --git a/authentic2/authsaml2/utils.py b/authentic2/authsaml2/utils.py deleted file mode 100644 index bca3ab3b1..000000000 --- a/authentic2/authsaml2/utils.py +++ /dev/null @@ -1,78 +0,0 @@ -import re -import time -import logging - -from django.template import RequestContext -from django.contrib.auth import REDIRECT_FIELD_NAME -from django.utils.translation import ugettext as _ -from django.shortcuts import render_to_response -from django.contrib import messages -from django.conf import settings - -__redirection_timeout = 1600 - -__root_refererer_re = re.compile('^(https?://[^/]*/?)') -def error_page(request, message=None, back=None, logger=None, - default_message=True, timer=False): - '''View that show a simple error page to the user with a back link. - - back - url for the back link, if None, return to root of the referer - or the local root. - ''' - if logger: - logger.error('Showing message %r on an error page' % message) - else: - logging.error('Showing message %r on an error page' % message) - if back is None: - referer = request.META.get('HTTP_REFERER') - if referer: - root_referer = __root_refererer_re.match(referer) - if root_referer: - back = root_referer.group(1) - if back is None: - back = '/' - global __redirection_timeout - context = RequestContext(request) - if timer: - context['redir_timeout'] = __redirection_timeout - context['next_page'] = back - display_message = getattr(settings, 'DISPLAY_MESSAGE_ERROR_PAGE', ()) - if default_message and not display_message: - messages.add_message(request, messages.ERROR, - _('An error happened. Report this %s to the administrator.') % \ - time.strftime("[%Y-%m-%d %a %H:%M:%S]", time.localtime())) - elif message: - messages.add_message(request, messages.ERROR, message) - return render_to_response('error_authsaml2.html', {'back': back}, - context_instance=context) - -# Used to register requested url during SAML redirections -def register_next_target(request, url=None): - if url: - next = url - else: - next = request.GET.get(REDIRECT_FIELD_NAME) - if not next: - next = '/' - request.session['next'] = next - -def get_registered_url(request): - if 'next' in request.session: - return request.session['next'] - return None - -def register_request_id(request, request_id): - request.session['saml_request_id'] = request_id - -# Used for account linking -def save_federation_temp(request, login, attributes=None): - if login and login.identity: - request.session['identity_dump'] = login.identity.dump() - request.session['remoteProviderId'] = login.remoteProviderId - request.session['nameId'] = login.nameIdentifier - if attributes: - request.session['attributes'] = attributes - -def load_federation_temp(request, login): - if 'identity_dump' in request.session: - login.setIdentityFromDump(request.session['identity_dump']) diff --git a/authentic2/decorators.py b/authentic2/decorators.py index 8803d76dc..bf69d0913 100644 --- a/authentic2/decorators.py +++ b/authentic2/decorators.py @@ -2,12 +2,10 @@ from django.contrib.auth.decorators import login_required from django.http import HttpResponseRedirect from functools import wraps -from authentic2.authsaml2.models import SAML2TransientUser - -TRANSIENT_USER_TYPES = (SAML2TransientUser, ) +TRANSIENT_USER_TYPES = [] def is_transient_user(user): - return isinstance(user, TRANSIENT_USER_TYPES) + return isinstance(user, tuple(TRANSIENT_USER_TYPES)) def prevent_access_to_transient_users(view_func): def _wrapped_view(request, *args, **kwargs): diff --git a/authentic2/idp/saml/saml2_endpoints.py b/authentic2/idp/saml/saml2_endpoints.py index 9eabf3a40..131878bf1 100644 --- a/authentic2/idp/saml/saml2_endpoints.py +++ b/authentic2/idp/saml/saml2_endpoints.py @@ -72,9 +72,9 @@ from authentic2.constants import NONCE_FIELD_NAME from authentic2.idp import signals as idp_signals # from authentic2.idp.models import * -from authentic2.authsaml2.models import SAML2TransientUser from authentic2.utils import (cache_and_validate, get_backends as get_idp_backends, get_username) +from authentic2.decorators import is_transient_user logger = logging.getLogger('authentic2.idp.saml') @@ -252,13 +252,6 @@ def build_assertion(request, login, nid_format='transient', attributes=None): authn_context = lasso.SAML2_AUTHN_CONTEXT_PASSWORD elif backend == 'authentic2.auth2_auth.auth2_ssl.backend.SSLBackend': authn_context = lasso.SAML2_AUTHN_CONTEXT_X509 - # XXX: grab context from the assertion received - elif backend == \ - 'authentic2.authsaml2.backends.AuthSAML2PersistentBackend': - authn_context = lasso.SAML2_AUTHN_CONTEXT_UNSPECIFIED - elif backend == \ - 'authentic2.authsaml2.backends.AuthSAML2TransientBackend': - authn_context = lasso.SAML2_AUTHN_CONTEXT_UNSPECIFIED else: backend = load_backend(backend) if hasattr(backend, 'get_saml2_authn_context'): @@ -581,8 +574,7 @@ def sso_after_process_request(request, login, consent_obtained=False, #Deal with transient users transient_user = False # XXX: Deal with all kind of transient users - type(SAML2TransientUser) - if isinstance(request.user, SAML2TransientUser): + if is_transient_user(request.user): logger.debug('the user is transient') transient_user = True if transient_user and login.request.nameIdPolicy.format == \ @@ -1285,52 +1277,6 @@ def slo_soap(request): logger.exception('slo, relaying to %s failed ' % lib_session.provider_id) - #Send SLO to IdP - pid = None - q = LibertySessionDump. \ - objects.filter(django_session_key__in=django_session_keys, - kind=LIBERTY_SESSION_DUMP_KIND_SP) - if not q: - logger.info('No session found for a third IdP') - else: - from authentic2.authsaml2 import saml2_endpoints - server = saml2_endpoints.create_server(request) - logout2 = lasso.Logout(server) - for s in q: - logger.debug('IdP session found %s' % s.session_dump) - try: - lib_session = lasso.Session().newFromDump(s.session_dump.encode('utf-8')) - except lasso.Error: - logger.debug('Unable to load session %s' % s.session_dump) - else: - try: - pid = lib_session.get_assertions().keys()[0] - logger.debug('SLO to %s' % pid) - logout2.setSessionFromDump(s.session_dump.encode('utf8')) - provider = load_provider(request, pid, - server=server, sp_or_idp='idp') - policy = get_idp_options_policy(provider) - if not policy: - logger.error('No policy found for %s'\ - % provider) - elif not policy.forward_slo: - logger.info('%s configured to not receive \ - slo' % provider) - else: - ''' - As we are in a synchronous binding, - we need SOAP support - ''' - logout2.initRequest(None, lasso.HTTP_METHOD_SOAP) - logout2.buildRequestMsg() - soap_response = send_soap_request(request, logout2) - logout2.processResponseMsg(soap_response) - logger.info('successful SLO with %s' \ - % pid) - except Exception, e: - logger.error('error treating SLO with IdP %s' \ - % str(e)) - ''' Respond to the SP initiating SLO ''' diff --git a/authentic2/saml/common.py b/authentic2/saml/common.py index 387076787..f56aac19f 100644 --- a/authentic2/saml/common.py +++ b/authentic2/saml/common.py @@ -26,7 +26,6 @@ from authentic2.saml.models import LibertyFederation, LibertyProvider, \ from authentic2.saml import models from authentic2.saml import saml2utils -from authentic2.authsaml2 import signals from authentic2.http_utils import get_url from .. import nonce @@ -438,31 +437,6 @@ def lookup_federation_by_user(user, qualifier): return None return fed[0] -# List Idp providers - Use from display in templates -# WARNING: No way for multiple federation by user with a single IdP (is it a problem??) -def get_idp_list(): - return LibertyProvider.objects.exclude(identity_provider=None) \ - .values('entity_id','name') - -def get_idp_list_sorted(): - return LibertyProvider.objects.exclude(identity_provider=None) \ - .order_by('name').values('entity_id','name') - -def get_idp_user_federated_list(request): - user = request.user - if request.user.is_anonymous(): - return None - return [p for p in get_idp_list() \ - if lookup_federation_by_user(user, p.entity_id)] - -def get_idp_user_not_federated_list(request): - user = request.user - if request.user.is_anonymous(): - return None - return [p for p in get_idp_list() \ - if not lookup_federation_by_user(user, p.entity_id)] - - # The session_index is the "session on the IdP" identifiers # One identifier is dedicated for each sp for each user session # to not be a factor of linkability between sp @@ -724,9 +698,6 @@ def authz_decision_cb(sender, request=None, attributes={}, _('Your access is denied. At least one attribute does not match.') return dic -signals.authz_decision.connect(authz_decision_cb, - dispatch_uid='authz_decision_on_attributes') - def get_session_not_on_or_after(assertion): '''Extract the minimal value for the SessionNotOnOrAfter found in the given assertion AuthenticationStatement(s). diff --git a/authentic2/settings.py b/authentic2/settings.py index 19accd07e..5fe7a2a0d 100644 --- a/authentic2/settings.py +++ b/authentic2/settings.py @@ -213,7 +213,6 @@ DISCO_USE_OF_METADATA = 'DISCO_USE_OF_METADATA' in os.environ DISCO_SERVICE_NAME = os.environ.get('DISCO_SERVICE_NAME', "http://www.identity-hub.com/disco_service/disco") DISCO_RETURN_ID_PARAM = "entityID" SHOW_DISCO_IN_MD = 'SHOW_DISCO_IN_MD' in os.environ -USE_DISCO_SERVICE = 'USE_DISCO_SERVICE' in os.environ ########################### # Authentication settings @@ -339,7 +338,6 @@ ADMIN_TOOLS_INDEX_DASHBOARD = 'authentic2.dashboard.CustomIndexDashboard' ADMIN_TOOLS_APP_INDEX_DASHBOARD = 'authentic2.dashboard.CustomAppIndexDashboard' ADMIN_TOOLS_MENU = 'authentic2.menu.CustomMenu' -AUTH_SAML2 = 'AUTH_SAML2' in os.environ AUTH_OPENID = 'AUTH_OPENID' in os.environ AUTH_SSL = 'AUTH_SSL' in os.environ IDP_SAML2 = 'IDP_SAML2' in os.environ @@ -435,15 +433,6 @@ if USE_DEBUG_TOOLBAR: except ImportError: print "Debug toolbar missing, not loaded" -if AUTH_SAML2: - INSTALLED_APPS += ('authentic2.authsaml2',) - AUTHENTICATION_BACKENDS += ( - 'authentic2.authsaml2.backends.AuthSAML2PersistentBackend', - 'authentic2.authsaml2.backends.AuthSAML2TransientBackend') - AUTH_FRONTENDS += ('authentic2.authsaml2.frontend.AuthSAML2Frontend',) - IDP_BACKENDS += ('authentic2.authsaml2.backends.AuthSAML2Backend',) - DISPLAY_MESSAGE_ERROR_PAGE = True - if AUTH_OPENID: INSTALLED_APPS += ('authentic2.auth2_auth.auth2_openid', 'django_authopenid',) AUTH_FRONTENDS += ('authentic2.auth2_auth.auth2_openid.backend.OpenIDFrontend',) diff --git a/authentic2/templates/registration/login.html b/authentic2/templates/registration/login.html deleted file mode 100644 index d6e05f715..000000000 --- a/authentic2/templates/registration/login.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "base.html" %} -{% load i18n %} - -{% block title %} -{% trans "Log in" %} -{% endblock %} - -{% block content %} -
- {% csrf_token %} - {{ form.as_p }} - - - -
- -
- -
-{% for method in alt_methods %} -

{% trans method.caption %}

-{% endfor %} -
- -{% if providers_list %} -
-{% trans "Log in with a federated account?" %} -
-
-
- {% csrf_token %} - -
-
-{% endif %} - - - -{% endblock %} - -{% block extra_scripts %} - - -{% endblock %} diff --git a/authentic2/urls.py b/authentic2/urls.py index d17bc0f81..0d8382f83 100644 --- a/authentic2/urls.py +++ b/authentic2/urls.py @@ -37,10 +37,6 @@ if settings.AUTH_SSL: urlpatterns += not_homepage_patterns -urlpatterns += patterns('', - (r'^authsaml2/', include('authentic2.authsaml2.urls')), -) - try: if settings.DISCO_SERVICE: urlpatterns += patterns('', diff --git a/authentic2/views.py b/authentic2/views.py index db9b97f4e..fd01895a2 100644 --- a/authentic2/views.py +++ b/authentic2/views.py @@ -310,9 +310,7 @@ def homepage(request): def _homepage(request): '''Homepage of the IdP''' tpl_parameters = {} - # FIXME: we should not refer to a specific authentication module here - from authentic2.authsaml2.models import SAML2TransientUser - if not isinstance(request.user, SAML2TransientUser): + if not decorators.is_transient_user(request.user): tpl_parameters['account_management'] = 'account_management' tpl_parameters['authorized_services'] = service_list(request) return render_to_response('idp/homepage.html', diff --git a/doc/settings.rst b/doc/settings.rst index 39665d312..ecc47ffa8 100644 --- a/doc/settings.rst +++ b/doc/settings.rst @@ -61,16 +61,6 @@ Values: * False: deactivate SSL authentication * True: activate SSL authentication -Activate or deactivate SAML2 authentication, Authentic 2 is a SAML2 service provider -==================================================================================== - -Variable: AUTH_SAML2 - -Values: - -* False: deactivate SAML2 authentication -* True: activate SAML2 authentication - Activate or deactivate OpenID authentication, Authentic 2 is an OpenID relying party ====================================================================================