Projet

Général

Profil

0001-remove-authentic2_idp_openid-fixes-23515.patch

Benjamin Dauvergne, 02 mai 2018 19:45

Télécharger (58 ko)

Voir les différences:

Subject: [PATCH] remove authentic2_idp_openid (fixes #23515)

Code is no more used nor maintained.
 MANIFEST.in                                   |   2 -
 debian-jessie/conf/authentic.conf             |   1 -
 debian-jessie/debian_config.py                |   2 -
 debian-jessie/multitenant/config.py           |   2 -
 debian-wheezy/conf/authentic.conf             |   1 -
 debian-wheezy/debian_config.py                |   2 -
 debian-wheezy/multitenant/config.py           |   2 -
 .../patches/01-hide-oidc-plugins.diff         |   3 +-
 doc/settings_listing.rst                      |  10 -
 local_settings.py.example                     |   3 -
 setup.py                                      |   4 -
 src/authentic2/dashboard.py                   |   1 -
 src/authentic2_idp_openid/__init__.py         |  44 ---
 src/authentic2_idp_openid/admin.py            |   8 -
 src/authentic2_idp_openid/app_settings.py     |  34 --
 src/authentic2_idp_openid/backend.py          |  30 --
 src/authentic2_idp_openid/conf.py             |  11 -
 src/authentic2_idp_openid/decorators.py       |   7 -
 .../locale/fr/LC_MESSAGES/django.po           |  83 -----
 src/authentic2_idp_openid/middleware.py       |  13 -
 src/authentic2_idp_openid/migration_utils.py  |  17 -
 .../migrations/0001_initial.py                |  71 ----
 .../migrations/__init__.py                    |   0
 src/authentic2_idp_openid/models.py           | 149 ---------
 src/authentic2_idp_openid/openid_store.py     |  38 ---
 .../django_openid_provider/manage_id.html     |  64 ----
 .../manage_id_confirm.html                    |  19 --
 .../manage_trustroot.html                     |  37 ---
 .../django_openid_provider/server.html        |  36 ---
 .../templates/idp/openid/base.html            |   1 -
 .../templates/idp/openid/decide.html          |  57 ----
 .../templates/idp/openid/discovery.html       |   8 -
 .../templates/idp/openid/error.html           |   6 -
 .../openid/trustedroot_confirm_delete.html    |  11 -
 .../templates/idp/openid/xrds.xml             |  12 -
 src/authentic2_idp_openid/urls.py             |  26 --
 src/authentic2_idp_openid/utils.py            |  36 ---
 src/authentic2_idp_openid/views.py            | 303 ------------------
 38 files changed, 1 insertion(+), 1153 deletions(-)
 delete mode 100644 src/authentic2_idp_openid/__init__.py
 delete mode 100644 src/authentic2_idp_openid/admin.py
 delete mode 100644 src/authentic2_idp_openid/app_settings.py
 delete mode 100644 src/authentic2_idp_openid/backend.py
 delete mode 100644 src/authentic2_idp_openid/conf.py
 delete mode 100644 src/authentic2_idp_openid/decorators.py
 delete mode 100644 src/authentic2_idp_openid/locale/fr/LC_MESSAGES/django.po
 delete mode 100644 src/authentic2_idp_openid/middleware.py
 delete mode 100644 src/authentic2_idp_openid/migration_utils.py
 delete mode 100644 src/authentic2_idp_openid/migrations/0001_initial.py
 delete mode 100644 src/authentic2_idp_openid/migrations/__init__.py
 delete mode 100644 src/authentic2_idp_openid/models.py
 delete mode 100644 src/authentic2_idp_openid/openid_store.py
 delete mode 100644 src/authentic2_idp_openid/templates/django_openid_provider/manage_id.html
 delete mode 100644 src/authentic2_idp_openid/templates/django_openid_provider/manage_id_confirm.html
 delete mode 100644 src/authentic2_idp_openid/templates/django_openid_provider/manage_trustroot.html
 delete mode 100644 src/authentic2_idp_openid/templates/django_openid_provider/server.html
 delete mode 100644 src/authentic2_idp_openid/templates/idp/openid/base.html
 delete mode 100644 src/authentic2_idp_openid/templates/idp/openid/decide.html
 delete mode 100644 src/authentic2_idp_openid/templates/idp/openid/discovery.html
 delete mode 100644 src/authentic2_idp_openid/templates/idp/openid/error.html
 delete mode 100644 src/authentic2_idp_openid/templates/idp/openid/trustedroot_confirm_delete.html
 delete mode 100644 src/authentic2_idp_openid/templates/idp/openid/xrds.xml
 delete mode 100644 src/authentic2_idp_openid/urls.py
 delete mode 100644 src/authentic2_idp_openid/utils.py
 delete mode 100644 src/authentic2_idp_openid/views.py
MANIFEST.in
13 13
recursive-include src/authentic2/saml/templates *.html *.txt *.xml
14 14
recursive-include src/authentic2/templates *.html *.txt *.xml
15 15
recursive-include src/authentic2/idp/templates *.html *.txt *.xml
16
recursive-include src/authentic2_idp_openid/templates *.html *.txt *.xml
17 16
recursive-include src/authentic2_idp_cas/templates *.html *.txt *.xml
18 17
recursive-include src/authentic2/idp/saml/templates *.html *.txt *.xml
19 18
recursive-include src/authentic2/auth2_auth/auth2_ssl/templates *.html *.txt *.xml
......
30 29
recursive-include src/authentic2/saml/locale *.po *.mo
31 30
recursive-include src/authentic2/idp/locale *.po *.mo
32 31
recursive-include src/authentic2/idp/saml/locale *.po *.mo
33
recursive-include src/authentic2_idp_openid/locale *.po *.mo
34 32
recursive-include src/authentic2_idp_cas/locale *.po *.mo
35 33
recursive-include src/authentic2/auth2_auth/locale *.po *.mo
36 34
recursive-include src/authentic2/auth2_auth/auth2_ssl/locale *.po *.mo
debian-jessie/conf/authentic.conf
29 29

  
30 30
# Enables some features
31 31
#export IDP_SAML2='yes'
32
#export IDP_OPENID='yes' # require package python-openid
33 32
#export IDP_CAS='yes'
34 33
#export AUTH_SAML2='yes'
35 34
#export AUTH_OPENID='yes' # require package python-openid
debian-jessie/debian_config.py
137 137
           'A2_AUTH_PASSWORD_ENABLE',
138 138
           'SSLAUTH_ENABLE',
139 139
           'A2_IDP_SAML2_ENABLE',
140
           'IDP_OPENID',
141

  
142 140
    )
143 141

  
144 142
    def to_boolean(name, default=True):
debian-jessie/multitenant/config.py
64 64
#A2_IDP_SAML2_ENABLE = False
65 65
# CAS 1.0 / 2.0 IDP
66 66
#A2_IDP_CAS_ENABLE = False
67
# OpenID 1.0 / 2.0 IDP
68
#A2_IDP_OPENID_ENABLE = False
69 67

  
70 68
# Authentifications
71 69
#A2_AUTH_PASSWORD_ENABLE = True
debian-wheezy/conf/authentic.conf
29 29

  
30 30
# Enables some features
31 31
#export IDP_SAML2='yes'
32
#export IDP_OPENID='yes' # require package python-openid
33 32
#export IDP_CAS='yes'
34 33
#export AUTH_SAML2='yes'
35 34
#export AUTH_OPENID='yes' # require package python-openid
debian-wheezy/debian_config.py
140 140
           'A2_AUTH_PASSWORD_ENABLE',
141 141
           'SSLAUTH_ENABLE',
142 142
           'A2_IDP_SAML2_ENABLE',
143
           'IDP_OPENID',
144

  
145 143
    )
146 144

  
147 145
    def to_boolean(name, default=True):
debian-wheezy/multitenant/config.py
64 64
#A2_IDP_SAML2_ENABLE = False
65 65
# CAS 1.0 / 2.0 IDP
66 66
#A2_IDP_CAS_ENABLE = False
67
# OpenID 1.0 / 2.0 IDP
68
#A2_IDP_OPENID_ENABLE = False
69 67

  
70 68
# Authentifications
71 69
#A2_AUTH_PASSWORD_ENABLE = True
debian-wheezy/patches/01-hide-oidc-plugins.diff
11 11
           'XStatic-jQuery',
12 12
           'XStatic-jquery-ui',
13 13
           'xstatic-select2',
14
@@ -163,11 +161,9 @@ setup(name="authentic2",
14
@@ -163,10 +161,8 @@ setup(name="authentic2",
15 15
           'authentic2.plugin': [
16 16
               'authentic2-auth-ssl = authentic2.auth2_auth.auth2_ssl:Plugin',
17 17
               'authentic2-auth-saml = authentic2_auth_saml:Plugin',
18 18
-              'authentic2-auth-oidc = authentic2_auth_oidc:Plugin',
19 19
               'authentic2-idp-saml2 = authentic2.idp.saml:Plugin',
20
               'authentic2-idp-openid = authentic2_idp_openid:Plugin',
21 20
               'authentic2-idp-cas = authentic2_idp_cas:Plugin',
22 21
-              'authentic2-idp-oidc = authentic2_idp_oidc:Plugin',
23 22
               'authentic2-provisionning-ldap = authentic2_provisionning_ldap:Plugin',
doc/settings_listing.rst
86 86
the signature keys are used for encryption.
87 87

  
88 88

  
89
Activate or deactivate Authentic 2 as an OpenID provider
90
========================================================
91

  
92
Variable: IDP_OPENID
93

  
94
Values:
95

  
96
* False: deactivate OpenID provider
97
* True: activate OpenID provider
98

  
99 89
Activate or deactivate Authentic 2 as a CAS server
100 90
==================================================
101 91

  
local_settings.py.example
5 5
# Activate SAML 2 idp
6 6
A2_IDP_SAML2_ENABLE = True
7 7

  
8
# Activate OpenID idp
9
A2_IDP_OPENID_ENABLE = True
10

  
11 8
# Debugging helper
12 9
try:
13 10
	import debug_toolbar
setup.py
133 133
          'XStatic-jquery-ui<1.12',
134 134
          'xstatic-select2',
135 135
      ],
136
      extras_require = {
137
          'idp-openid': ['python-openid'],
138
      },
139 136
      zip_safe=False,
140 137
      classifiers=[
141 138
          "Development Status :: 5 - Production/Stable",
......
165 162
              'authentic2-auth-saml = authentic2_auth_saml:Plugin',
166 163
              'authentic2-auth-oidc = authentic2_auth_oidc:Plugin',
167 164
              'authentic2-idp-saml2 = authentic2.idp.saml:Plugin',
168
              'authentic2-idp-openid = authentic2_idp_openid:Plugin',
169 165
              'authentic2-idp-cas = authentic2_idp_cas:Plugin',
170 166
              'authentic2-idp-oidc = authentic2_idp_oidc:Plugin',
171 167
              'authentic2-provisionning-ldap = authentic2_provisionning_ldap:Plugin',
src/authentic2/dashboard.py
67 67
                'authentic2.models.AuthenticationEvent',
68 68
                'authentic2.models.UserExternalId',
69 69
                'authentic2.models.DeletedUser',
70
                'authentic2.idp.idp_openid.models.*',
71 70
                'django.contrib.sessions.*',
72 71
            ),
73 72
        ))
src/authentic2_idp_openid/__init__.py
1
from django.utils.translation import ugettext_lazy as _
2
from django.core.exceptions import ImproperlyConfigured
3

  
4
try:
5
    import openid
6
except ImportError:
7
    from . import app_settings
8
    if app_settings.ENABLE:
9
        raise ImproperlyConfigured('OpenID idp is enabled by python-openid is not installed')
10
    class Plugin(object):
11
        pass
12
else:
13
    class Plugin(object):
14
        def get_before_urls(self):
15
            from . import app_settings
16
            from django.conf.urls import patterns, include
17
            from authentic2.decorators import (setting_enabled, required,
18
                    lasso_required)
19

  
20
            return required(
21
                    (
22
                        setting_enabled('ENABLE', settings=app_settings),
23
                        lasso_required()
24
                    ),
25
                    patterns('',
26
                        (r'^idp/openid/', include(__name__ + '.urls'))))
27

  
28
        def get_apps(self):
29
            return [__name__]
30

  
31
        def get_admin_modules(self):
32
            from admin_tools.dashboard import modules
33
            return [modules.ModelList(
34
                _('OpenID'),
35
                models=(
36
                    '%s.models.*' % __name__,
37
                ),
38
            )]
39

  
40
        def get_idp_backends(self):
41
            return ['%s.backend.OpenIDBackend' % __name__]
42

  
43
        def get_before_middleware(self):
44
            return ['%s.middleware.OpenIDMiddleware' % __name__]
src/authentic2_idp_openid/admin.py
1
# -*- coding: utf-8 -*-
2

  
3
from django.contrib import admin
4
from models import TrustedRoot, Association, Nonce
5

  
6
admin.site.register(TrustedRoot)
7
admin.site.register(Association)
8
admin.site.register(Nonce)
src/authentic2_idp_openid/app_settings.py
1
class AppSettings(object):
2
    __DEFAULTS = dict(
3
            ENABLE=False,
4
            OPENID_ACTIONS={},
5
    )
6

  
7
    def __init__(self, prefix):
8
        self.prefix = prefix
9

  
10
    def _setting(self, name, dflt):
11
        from django.conf import settings
12
        return getattr(settings, name, dflt)
13

  
14
    def _setting_with_prefix(self, name, dflt):
15
        return self._setting(self.prefix + name, dflt)
16

  
17
    @property
18
    def ENABLE(self):
19
        return self._setting_with_prefix('ENABLE',
20
                self._settings('IDP_OPENID',
21
                    self.__DEFAULTS['ENABLE']))
22

  
23
    def __getattr__(self, name):
24
        if name not in self.__DEFAULTS:
25
            raise AttributeError(name)
26
        return self._setting_with_prefix(name, self.__DEFAULTS[name])
27

  
28

  
29
# Ugly? Guido recommends this himself ...
30
# http://mail.python.org/pipermail/python-ideas/2012-May/014969.html
31
import sys
32
app_settings = AppSettings('A2_IDP_OPENID_')
33
app_settings.__name__ = __name__
34
sys.modules[__name__] = app_settings
src/authentic2_idp_openid/backend.py
1
import logging
2

  
3
from django.core.urlresolvers import reverse
4

  
5
from authentic2.utils import Service
6

  
7
from . import models, app_settings
8

  
9

  
10
logger = logging.getLogger(__name__)
11

  
12

  
13
class OpenIDBackend(object):
14
    def service_list(self, request):
15
        if not request.user.is_authenticated():
16
            return ()
17
        q = models.TrustedRoot.objects.filter(user=request.user.id)
18
        ls = []
19
        for service_provider in q:
20
            actions = []
21
            actions.append(('go', 'GET', service_provider.trust_root, None))
22
            if app_settings.OPENID_ACTIONS:
23
                tpl = app_settings.OPENID_ACTIONS.get(service_provider.trust_root, None)
24
                if tpl:
25
                    actions.append(('template', tpl))
26
            actions.append(('unlink', 'GET', reverse('trustedroot_delete',
27
                kwargs={'pk': service_provider.id}), None))
28
            ls.append(Service(url=None, name=service_provider.trust_root,
29
                actions=actions))
30
        return ls
src/authentic2_idp_openid/conf.py
1
import os
2
import tempfile
3
from django.conf import settings
4

  
5
tempdir = tempfile.gettempdir()
6

  
7
STORE = getattr(settings, 'OPENID_PROVIDER_STORE',
8
                'authentic2.idp.idp_openid.openid_store.DjangoOpenIDStore')
9

  
10
FILESTORE_PATH = getattr(settings, 'OPENID_PROVIDER_FILESTORE_PATH',
11
                         os.path.join(tempdir, 'openid-filestore'))
src/authentic2_idp_openid/decorators.py
1
from authentic2.decorators import setting_enabled
2

  
3
from . import app_settings
4

  
5
def openid_enabled(func):
6
    return setting_enabled('ENABLE', app_settings)(func)
7

  
src/authentic2_idp_openid/locale/fr/LC_MESSAGES/django.po
1
# authentic2 idp openid french l10n
2
# Copyright (C) 2015 Entr'ouvert
3
# This file is distributed under the same license as the Authentic package.
4
# Frederic Peters <fpeters@entrouvert.com>, 2010.
5
#
6
msgid ""
7
msgstr ""
8
"Project-Id-Version: Authentic\n"
9
"Report-Msgid-Bugs-To: \n"
10
"POT-Creation-Date: 2018-01-24 12:02+0100\n"
11
"PO-Revision-Date: 2018-01-24 12:12+0100\n"
12
"Last-Translator: Mikaël Ates <mates@entrouvert.com>\n"
13
"Language-Team: None\n"
14
"Language: fr\n"
15
"MIME-Version: 1.0\n"
16
"Content-Type: text/plain; charset=UTF-8\n"
17
"Content-Transfer-Encoding: 8bit\n"
18
"Plural-Forms: nplurals=2; plural=n>1;\n"
19

  
20
#: src/authentic2_idp_openid/__init__.py:34
21
msgid "OpenID"
22
msgstr "Gérer la connexion OpenID"
23

  
24
#: src/authentic2_idp_openid/models.py:35
25
msgid "trusted root"
26
msgstr "Site de confiance"
27

  
28
#: src/authentic2_idp_openid/models.py:36
29
msgid "trusted roots"
30
msgstr "Sites de confiance"
31

  
32
#: src/authentic2_idp_openid/models.py:57
33
msgid "association"
34
msgstr "association"
35

  
36
#: src/authentic2_idp_openid/models.py:58
37
msgid "associations"
38
msgstr "associations"
39

  
40
#: src/authentic2_idp_openid/models.py:125
41
msgid "nonce"
42
msgstr "nonce"
43

  
44
#: src/authentic2_idp_openid/models.py:126
45
msgid "nonces"
46
msgstr "nonces"
47

  
48
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_id.html:5
49
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_id_confirm.html:5
50
msgid "Manage OpenID"
51
msgstr "Gérer la connexion OpenID"
52

  
53
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_id.html:23
54
msgid "Your current OpenID"
55
msgstr "Vos identifiants OpenID actuels"
56

  
57
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_id.html:52
58
msgid "Add a new OpenID identity"
59
msgstr "Ajouter une nouvelle identité OpenID"
60

  
61
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_trustroot.html:5
62
msgid "Manage trusted site"
63
msgstr "Gérer vos sites de confiance"
64

  
65
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_trustroot.html:17
66
msgid "Your trusted site"
67
msgstr "Vos sites de confiance"
68

  
69
#: src/authentic2_idp_openid/templates/idp/openid/trustedroot_confirm_delete.html:5
70
msgid "Remove Link ?"
71
msgstr "Supprimer le lien ?"
72

  
73
#: src/authentic2_idp_openid/templates/idp/openid/trustedroot_confirm_delete.html:7
74
msgid "Are you sure you want to delete link with"
75
msgstr "Êtes-vous sûr de vouloir supprimer le lien avec"
76

  
77
#: src/authentic2_idp_openid/templates/idp/openid/trustedroot_confirm_delete.html:10
78
msgid "Back"
79
msgstr "Retour"
80

  
81
#: src/authentic2_idp_openid/views.py:278
82
msgid "Trust this site?"
83
msgstr "Faire confiance à ce site ?"
src/authentic2_idp_openid/middleware.py
1
from django.core.urlresolvers import reverse
2

  
3
from . import views
4

  
5
class OpenIDMiddleware(object):
6
    '''Add OpenID discovery header to all responses,
7
       if Accept header is 'application/xrds+xml' also return an XRDS document.
8
    '''
9
    def process_response(self, request, response):
10
        response['X-XRDS-Location'] = request.build_absolute_uri(reverse('a2-idp-openid-xrds'))
11
        if request.META.get('HTTP_ACCEPT') == 'application/xrds+xml':
12
            return views.openid_xrds(request)
13
        return response
src/authentic2_idp_openid/migration_utils.py
1
"""utils to help rename apps and South migrations"""
2
import os
3
from south.models import MigrationHistory
4

  
5
def was_applied(migration_file_path, app_name):
6
    """true if migration with a given file name ``migration_file``
7
    was applied to app with name ``app_name``"""
8
    try:
9
        migration_file = os.path.basename(migration_file_path)
10
        migration_name = migration_file.split('.')[0]
11
        MigrationHistory.objects.get(
12
            app_name = app_name,
13
            migration = migration_name
14
        )
15
        return True
16
    except MigrationHistory.DoesNotExist:
17
        return False
src/authentic2_idp_openid/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import models, migrations
5
import authentic2.saml.fields
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    dependencies = [
11
    ]
12

  
13
    operations = [
14
        migrations.CreateModel(
15
            name='Association',
16
            fields=[
17
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
18
                ('server_url', models.CharField(max_length=768)),
19
                ('handle', models.CharField(max_length=255)),
20
                ('secret', authentic2.saml.fields.PickledObjectField(editable=False)),
21
                ('issued', models.DateTimeField(verbose_name=b'Issue time for this association, as seconds since EPOCH', editable=False)),
22
                ('lifetime', models.IntegerField(verbose_name=b'Lifetime of this association as seconds since the issued time')),
23
                ('expire', models.DateTimeField(verbose_name=b'After this time, the association will be expired')),
24
                ('assoc_type', models.CharField(max_length=64)),
25
            ],
26
            options={
27
                'db_table': 'idp_openid_association',
28
                'verbose_name': 'association',
29
                'verbose_name_plural': 'associations',
30
            },
31
            bases=(models.Model,),
32
        ),
33
        migrations.CreateModel(
34
            name='Nonce',
35
            fields=[
36
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
37
                ('salt', models.CharField(max_length=40)),
38
                ('server_url', models.CharField(max_length=768)),
39
                ('timestamp', models.IntegerField()),
40
            ],
41
            options={
42
                'db_table': 'idp_openid_nonce',
43
                'verbose_name': 'nonce',
44
                'verbose_name_plural': 'nonces',
45
            },
46
            bases=(models.Model,),
47
        ),
48
        migrations.CreateModel(
49
            name='TrustedRoot',
50
            fields=[
51
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
52
                ('user', models.CharField(max_length=255)),
53
                ('trust_root', models.CharField(max_length=200)),
54
                ('choices', authentic2.saml.fields.PickledObjectField()),
55
            ],
56
            options={
57
                'db_table': 'idp_openid_trustedroot',
58
                'verbose_name': 'trusted root',
59
                'verbose_name_plural': 'trusted roots',
60
            },
61
            bases=(models.Model,),
62
        ),
63
        migrations.AlterUniqueTogether(
64
            name='nonce',
65
            unique_together=set([('server_url', 'salt')]),
66
        ),
67
        migrations.AlterUniqueTogether(
68
            name='association',
69
            unique_together=set([('server_url', 'handle')]),
70
        ),
71
    ]
src/authentic2_idp_openid/models.py
1
# -*- coding: utf-8 -*-
2
# vim: set ts=4 sw=4 : */
3

  
4
import datetime
5
import time
6
import calendar
7

  
8
import openid.association
9
import openid.store.nonce
10
from django.db import models
11
from django.utils.timezone import now, utc
12
from django.conf import settings
13
from django.utils.translation import ugettext_lazy as _
14

  
15
from authentic2.saml.fields import PickledObjectField
16

  
17

  
18
def utctimestamp_to_aware_datetime(tst):
19
    if settings.USE_TZ:
20
        return datetime.datetime.utcfromtimestamp(tst) \
21
                .replace(tz_info=utc)
22
    else:
23
        return datetime.datetime.utcfromtimestamp(tst)
24

  
25

  
26
class TrustedRoot(models.Model):
27
    user = models.CharField(max_length=255)
28
    trust_root = models.CharField(max_length=200)
29
    choices = PickledObjectField()
30

  
31
    def __unicode__(self):
32
        return unicode(self.trust_root)
33

  
34
    class Meta:
35
        verbose_name = _('trusted root')
36
        verbose_name_plural = _('trusted roots')
37
        db_table = 'idp_openid_trustedroot' # app was named idp_openid before
38

  
39

  
40

  
41
class Association(models.Model):
42
    server_url = models.CharField(max_length=768, blank=False)
43
    handle = models.CharField(max_length=255, blank=False)
44
    secret = PickledObjectField(editable=False)
45
    issued = models.DateTimeField(editable=False,
46
            verbose_name="Issue time for this association, as seconds \
47
since EPOCH")
48
    lifetime = models.IntegerField(
49
            verbose_name="Lifetime of this association as seconds since \
50
the issued time")
51
    expire = models.DateTimeField("After this time, the association will \
52
be expired")
53
    assoc_type = models.CharField(max_length=64, blank=False)
54

  
55
    class Meta:
56
        unique_together = ('server_url', 'handle')
57
        verbose_name = _('association')
58
        verbose_name_plural = _('associations')
59
        db_table = 'idp_openid_association' # app was named idp_openid before
60

  
61
    def save(self, *args, **kwargs):
62
        '''Overload default save() method to compute the expire field'''
63
        self.issued = now()
64
        self.expire = self.issued + datetime.timedelta(seconds=self.lifetime)
65
        super(Association, self).save(*args, **kwargs)
66

  
67
    def to_association(self):
68
        '''Convert a model instance to an Association object of the openid
69
           library.
70
        '''
71
        return openid.association.Association(handle=self.handle,
72
                secret=self.secret,
73
                issued=calendar.timegm(self.issued.utctimetuple()),
74
                lifetime=self.lifetime,
75
                assoc_type=self.assoc_type)
76

  
77
    @classmethod
78
    def get_association(cls, server_url, handle=None):
79
        try:
80
            filter = cls.objects.filter(server_url=server_url,
81
                expire__gt=now())
82
            if handle is not None:
83
                filter = filter.filter(handle=handle)
84
            return filter.latest('issued').to_association()
85
        except cls.DoesNotExist:
86
            return None
87

  
88
    @classmethod
89
    def cleanup_associations(cls):
90
        filter = cls.objects.filter(expire__lt=now())
91
        count = filter.count()
92
        filter.delete()
93
        return count
94

  
95
    @classmethod
96
    def remove_association(cls, server_url, handle=None):
97
        filter = cls.objects.filter(server_url=server_url)
98
        if handle is not None:
99
            filter = filter.filter(handle=handle)
100
        filter.delete()
101

  
102
    @classmethod
103
    def store_association(cls, server_url, association):
104
        Association(server_url=server_url,
105
                handle=association.handle,
106
                secret=association.secret,
107
                issued=utctimestamp_to_aware_datetime(association.issued),
108
                lifetime=association.lifetime,
109
                assoc_type=association.assoc_type).save()
110

  
111
class NonceManager(models.Manager):
112
    def cleanup(self):
113
        expire = openid.store.nonce.SKEW
114
        timestamp = calendar.timegm(now().utctimetuple())
115
        self.filter(timestamp__lt=timestamp-expire).delete()
116

  
117
class Nonce(models.Model):
118
    salt = models.CharField(max_length=40)
119
    server_url = models.CharField(max_length=768)
120
    timestamp = models.IntegerField()
121

  
122
    objects = NonceManager()
123

  
124
    class Meta:
125
        verbose_name = _('nonce')
126
        verbose_name_plural = _('nonces')
127
        unique_together = ('server_url', 'salt')
128
        db_table = 'idp_openid_nonce' # app was named idp_openid before
129

  
130
    @classmethod
131
    def use_nonce(cls, server_url, timestamp, salt):
132
        now = time.time()
133
        if timestamp > now or timestamp + openid.store.nonce.SKEW < now:
134
            return False
135

  
136
        n, created = cls.objects.get_or_create(server_url=server_url,
137
                salt=salt)
138
        if created:
139
            n.timestamp = timestamp
140
            n.save()
141
        return created
142

  
143
    @classmethod
144
    def cleanup_nonces(cls):
145
        filter = cls.objects.filter(
146
                timestamp_lt=time.time()-openid.store.nonce.SKEW)
147
        count = filter.count()
148
        filter.delete()
149
        return count
src/authentic2_idp_openid/openid_store.py
1
# -*- coding: utf-8 -*-
2
# vim: set ts=4 sw=4 : */
3

  
4
import time
5

  
6
import openid.store.interface
7
from django.conf import settings
8

  
9
import models
10
from authentic2 import nonce
11

  
12

  
13
NONCE_TIMEOUT = getattr(settings, 'OPENID_NONCE_TIMEOUT',
14
        getattr(settings, 'NONCE_TIMEOUT', openid.store.nonce.SKEW))
15

  
16
class DjangoOpenIDStore(openid.store.interface.OpenIDStore):
17
    def cleanupAssociations(self):
18
        return models.Association.cleanup_associations()
19

  
20
    def cleanupNonces(self):
21
        nonce.cleanup_nonces()
22

  
23
    def storeAssociation(self, server_url, association):
24
        return models.Association.store_association(server_url, association)
25

  
26
    def getAssociation(self, server_url, handle=None):
27
        return models.Association.get_association(server_url, handle)
28

  
29
    def removeAssociation(self, server_url, handle):
30
        return models.Association.remove_association(server_url, handle)
31

  
32
    def useNonce(self, server_url, timestamp, salt):
33
        now = time.time()
34
        if not (timestamp < now < (timestamp + NONCE_TIMEOUT)):
35
            return False
36
        value = '%s_%s_%s' % (server_url, timestamp, salt)
37

  
38
        return nonce.accept_nonce(value, 'OpenID', NONCE_TIMEOUT)
src/authentic2_idp_openid/templates/django_openid_provider/manage_id.html
1
{% extends "authentic2/base-page.html" %}
2
{% load i18n %}
3

  
4
{% block title %}
5
{% trans "Manage OpenID" %}
6
{% endblock %}
7

  
8
{% load breadcrumbs %}
9
{% block breadcrumbs %}
10
{{ block.super }}
11
{% breadcrumb_url 'Manage OpenID' 'manage_id' %}
12
{% endblock %}
13

  
14
{% block content %}
15
{% if message %}
16
<ul class="errorlist">{{ message }}</ul>
17
{% endif %}
18
<p>
19
{% if nb_openids > 0 %}
20
<a href="/openid/manage/">Manage your trusted site</a>
21
</p>
22
<fieldset>
23
<legend>{% trans "Your current OpenID" %}</legend>
24
<p> Choose your identities to remove, be careful this will remove all the trusted site for these identities.
25
You can change your default OpenID by clicking on "Make Default"
26
</p>
27
<form action="." id="form1" method="post">
28
{% csrf_token %}
29
{% for key,value in openids.items %}
30
<p>  <h4> {{ uri }}{{ oipath }}/{{ value.caption }}/
31
    {% if value.Default %}
32
        (Default)
33
    {% endif %}
34
    </h4>
35
    {% for key2, value2 in value.trustroot.items %}
36
        <li class="indented"> {{ value2 }} </li>
37
    {% empty %}
38
    There is no trusted site for this identity.
39
    {% endfor %}
40
    {% if not value.Default %}
41
        <input type = "submit" name= {{ value.caption }} value = "Make default" />
42
    {% endif %}
43
    <input type = "submit" name = {{ value.caption }} value = "Remove"/>
44
</p>
45
{% endfor %}
46
</form>
47
</fieldset>
48
{% else %}
49
<p> You have no OpenID account for the moment</p>
50
{% endif %}
51
<fieldset>
52
<legend>{% trans "Add a new OpenID identity" %} </legend>
53
<p>
54
<form action = "/openid/addopenid/" id = "form2" method = "post">
55
    {% csrf_token %}
56
    <p> Leave blank to create an anonymous OpenID</p>
57
    {{ uri }}{{ oipath }}/{{ form.openid }}/
58
    {{ form.Default }}
59
    Check if you want this OpenID account become your default OpenID account.
60
    <input type = "submit" value = "Add" />
61
    </p>
62
</form>
63
</fieldset>
64
{% endblock %}
src/authentic2_idp_openid/templates/django_openid_provider/manage_id_confirm.html
1
{% extends "authentic2/base-page.html" %}
2
{% load i18n %}
3

  
4
{% block title %}
5
{% trans "Manage OpenID" %}
6
{% endblock %}
7

  
8
{% block content %}
9
    <form action = "/openid/manageid_confirm/" id = "form" method = "post">
10
    {% csrf_token %}
11
            <p>Are you sure, you want to delete <strong> {{ id }} </strong> and these trusted site:</p>
12
        {% for i in trust %}
13
            {{ i }}
14
        {% endfor %}
15
    <input type = "hidden" name = "idremove" value = {{ id }}>
16
    <input type = "submit" value = "Yes" name = "Answer" />
17
    <input type = "submit" value = "No" name = "Answer" />
18
    </form>
19
{% endblock %}
src/authentic2_idp_openid/templates/django_openid_provider/manage_trustroot.html
1
{% extends "authentic2/base-page.html" %}
2
{% load i18n %}
3

  
4
{% block title %}
5
{% trans "Manage trusted site" %}
6
{% endblock %}
7

  
8
{% load breadcrumbs %}
9
{% block breadcrumbs %}
10
{{ block.super }}
11
{% breadcrumb_url 'Manage OpenID' 'manage_id' %}
12
{% breadcrumb_url 'Manage trusted site' 'manage_trustroot' %}
13
{% endblock %}
14

  
15
{% block content %}
16
<fieldset>
17
<legend>{% trans "Your trusted site" %} </legend>
18
<p>Check the trusted site that you want to remove and click on remove to remove these trusted site from these </p>
19
 <form action="." id="form" method="post">
20
 {% csrf_token %}
21
 {% for key, value in openids.items %}
22
    <p> <h4> {{ uri }}{{ oipath }}/{{ value.caption }}/ </h4>
23
    <ul class="NoBullet">
24
    {% for key2, value2 in value.trustroot.items %}
25
        <li class="indented"> <input type="checkbox" name = "trustremove" value = {{ key2 }} /> {{ value2 }} </li>
26
    {% empty %}
27
        You have no trusted site for this openid
28
    {% endfor %}
29
    </ul>
30
    </p>
31
 {% endfor %}
32
 {% if trust_sum != 0 %}
33
    <input type="submit" value="Remove" />
34
 {% endif %}
35
 </form>
36
 </fieldset>
37
{% endblock %}
src/authentic2_idp_openid/templates/django_openid_provider/server.html
1
{% extends "authentic2/base-page.html" %}
2

  
3
{% block extrahead %}{{ block.super }}
4
<meta http-equiv="x-xrds-location" content="{{ host }}{% url 'openid-provider-xrds' %}">
5
{% endblock %}
6

  
7
{% block title %}
8
 OpenID endpoint
9
{% endblock %}
10

  
11
{% load breadcrumbs %}
12
{% block breadcrumbs %}
13
{{ block.super }}
14
{% breadcrumb_url 'OpenID' 'openid-provider-root' %}
15
{% endblock %}
16

  
17
{% block content %}
18

  
19
{% if nb_openid > 0 %}
20
 <p>To manage your OpenID accounts go on <a href='/openid/manageid/'> manage your OpenID account</a></p>
21
<h3>Your OpenID account are: </h3>
22
 {% for key, value in openids.items %}
23
    <p> <h4> {{ uri }}{{ oipath }}/{{ value.caption }}/ </h4>
24
    {% for key2, value2 in value.trustroot.items %}
25
        <li> {{ value2 }}  </li>
26
    {% empty %}
27
        You have no trusted site for this openid.
28
    {% endfor %}
29
    </p>
30
 {% endfor %}
31
{% else %}
32
    <p>You currently have no OpenID account.
33
    To create an OpenID account go on <a href='/openid/manageid/'> create an OpenID account</a></p>
34
{% endif %}
35

  
36
{% endblock %}
src/authentic2_idp_openid/templates/idp/openid/base.html
1
{% extends "base.html" %}
src/authentic2_idp_openid/templates/idp/openid/decide.html
1
{% extends "authentic2/base-page.html" %}
2

  
3
{% block content %}
4
{% ifequal trust_root_valid "Valid" %}
5
  <!-- Trust root has been validated by OpenID 2 mechanism. -->
6
  <p>The site <tt>{{ trust_root|escape }}</tt> has requested verification
7
  of your OpenID.</p>
8
{% endifequal %}
9
{% ifequal trust_root_valid "Invalid" %}
10
<div class="error">
11
  <p>This request claims to be from {{ trust_root|escape }} but I have
12
  determined that <em>it is a pack of lies</em>.  Beware, if you release
13
  information to them, they are likely to do unconscionable things with it,
14
  being the lying liars that they are.</p>
15
  <p>Please tell the <em>real</em> {{ trust_root|escape }} that someone is
16
  trying to abuse your trust in their good name.</p>
17
</div>
18
{% endifequal %}
19
{% ifequal trust_root_valid "Unreachable" %}
20
  <p>The site <tt>{{ trust_root|escape }}</tt> has requested verification
21
  of your OpenID.  I have failed to reach it and thus cannot vouch for its
22
  authenticity.  Perhaps it is on your local network.</p>
23
{% endifequal %}
24
{% ifequal trust_root_valid "DISCOVERY_FAILED" %}
25
  <p>The site <tt>{{ trust_root|escape }}</tt> has requested verification
26
  of your OpenID.  However, <tt>{{ trust_root|escape }}</tt> does not
27
  implement OpenID 2.0's relying party verification mechanism.  Please use
28
  extra caution in deciding whether to release information to this party,
29
  and ask <tt>{{ trust_root|escape }}</tt> to implement relying party
30
  verification for your future transactions.</p>
31
{% endifequal %}
32

  
33
<!-- trust_root_valid is {{ trust_root_valid }} -->
34

  
35
<form method="post" action="{% url 'openid-provider-decide' %}">
36
{% csrf_token %}
37
{% if required %}
38
<p>
39
It requires the following attributes:
40
<ul>
41
{% for att in required %}
42
<li>{{ att }}</li>
43
{% endfor %}
44
</ul>
45
{% endif %}
46
{% if optional %}
47
The following attributes are optional:
48
<ul>
49
{{ form.as_ul }}
50
</ul>
51
</p>
52
{% endif %}
53
<p>Allow Identity-Hub to verify your identity ?</p>
54
<input type="submit" value="Yes (Allow)" name="allow" />
55
<input type="submit" value="No (Cancel)" name="cancel" />
56
</form>
57
{% endblock %}
src/authentic2_idp_openid/templates/idp/openid/discovery.html
1
<html> 
2
<head> 
3
<link rel="openid.server" href="{{ openid_server }}" /> 
4
<meta http-equiv="refresh" content="1;url=/"> 
5
</head> 
6
<body> 
7
</body> 
8
</html> 
src/authentic2_idp_openid/templates/idp/openid/error.html
1
{% extends "authentic2/base-page.html" %}
2

  
3
{% block content %}
4
<h2>{{ title }}</h2>
5
{{ msg }}
6
{% endblock %}
src/authentic2_idp_openid/templates/idp/openid/trustedroot_confirm_delete.html
1
{% extends "authentic2/base-page.html" %}
2
{% load i18n %}
3

  
4
{% block content %}
5
<h2>{% trans "Remove Link ?" %}</h2>
6
<form action="" method="post">{% csrf_token %}
7
 <p>{% trans "Are you sure you want to delete link with" %} {{ trustedroot }} ?</p>
8
 <input type="submit" value="Yes" />
9
</form>
10
<p><a href="/">{% trans "Back" %}</a></p>
11
{% endblock %}
src/authentic2_idp_openid/templates/idp/openid/xrds.xml
1
<?xml version="1.0" encoding="UTF-8"?>
2
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
3
	<XRD>
4
		<Service priority="0">{% for uri in types %}
5
			<Type>{{ uri|escape }}</Type>
6
		{% endfor %}{% for endpoint in endpoints %}
7
			<URI>{{ endpoint }}</URI>
8
		{% endfor %}{% for local_id in local_ids %}
9
			<LocalID>{{ local_id }}</LocalID>
10
		{% endfor %}</Service>
11
	</XRD>
12
</xrds:XRDS>
src/authentic2_idp_openid/urls.py
1
# vim: set ts=4 sw=4 : */
2

  
3
from django.conf.urls import patterns, url
4
from . import views
5

  
6
urlpatterns = patterns('authentic2.idp.idp_openid.views',
7
    url(r'^$',
8
        views.openid_server,
9
        name='a2-idp-openid-root'),
10
    url(r'^trustedroot/(?P<pk>\d+)/delete/$',
11
        views.openid_trustedroot_delete,
12
        name='trustedroot_delete'),
13
    url(r'^decide/$',
14
        views.openid_decide,
15
        name='a2-idp-openid-decide'),
16
    url(r'^xrds/$',
17
        views.openid_xrds,
18
        name='a2-idp-openid-xrds'),
19
    url(r'^(?P<id>.+)/xrds/$',
20
        views.openid_xrds,
21
        {'identity': True},
22
        name='a2-idp-openid-identity-xrds'),
23
    url(r'^(?P<id>.+)/$',
24
        views.openid_discovery,
25
        name='a2-idp-openid-identity'),
26
)
src/authentic2_idp_openid/utils.py
1
# -*- coding: utf-8 -*-
2
# vim: set ts=4 sw=4 fdm=indent : */
3
# some code from http://www.djangosnippets.org/snippets/310/ by simon
4
# and from examples/djopenid from python-openid-2.2.4
5

  
6
import openid.server
7
from django.core.exceptions import ImproperlyConfigured
8
from django.utils.importlib import import_module
9
from django.http import HttpResponse, HttpResponseRedirect
10

  
11
import conf
12

  
13
def oresponse_to_response(server, oresponse):
14
    try:
15
        webresponse = server.encodeResponse(oresponse)
16
    except openid.server.EncodingError:
17
        return HttpResponseRedirect('/')
18
    response = HttpResponse(webresponse.body)
19
    response.status_code = webresponse.code
20
    for key, value in webresponse.headers.items():
21
        response[key] = value
22
    return response
23

  
24
def import_module_attr(path):
25
    package, module = path.rsplit('.', 1)
26
    return getattr(import_module(package), module)
27

  
28
def get_store(request):
29
    try:
30
        store_class = import_module_attr(conf.STORE)
31
    except ImportError:
32
        raise ImproperlyConfigured("OpenID store %r could not be imported" % conf.STORE)
33
    # The FileOpenIDStore requires a path to save the user files.
34
    if conf.STORE == 'openid.store.filestore.FileOpenIDStore':
35
        return store_class(conf.FILESTORE_PATH)
36
    return store_class()
src/authentic2_idp_openid/views.py
1
# -*- coding: utf-8 -*-
2
# some code from http://www.djangosnippets.org/snippets/310/ by simon
3
# and from examples/djopenid from python-openid-2.2.4
4

  
5
import logging
6
import hashlib
7
import urlparse
8

  
9
from django.core.urlresolvers import reverse
10
from django.shortcuts import render_to_response
11
from django.template import RequestContext
12
from django.utils.translation import ugettext as _
13
try:
14
    from django.views.decorators.csrf import csrf_exempt
15
except ImportError:
16
    from django.contrib.csrf.middleware import csrf_exempt
17
import django.forms as forms
18
from django.conf import settings
19
from django.http import Http404
20
from django.views.generic import DeleteView
21

  
22
from openid.consumer.discover import OPENID_IDP_2_0_TYPE, \
23
    OPENID_2_0_TYPE, OPENID_1_0_TYPE, OPENID_1_1_TYPE
24
from openid.fetchers import HTTPFetchingError
25
from openid.server.server import Server, ProtocolError
26
from openid.server.trustroot import verifyReturnTo
27
from openid.yadis.discover import DiscoveryFailure
28
from openid.yadis.constants import YADIS_CONTENT_TYPE
29
from openid.message import IDENTIFIER_SELECT
30
from openid.extensions.sreg import ns_uri as SREG_TYPE, SRegRequest, \
31
        SRegResponse, data_fields
32

  
33
from utils import get_store, oresponse_to_response
34
from authentic2.utils import login_require, redirect
35
from authentic2.constants import NONCE_FIELD_NAME
36
from . import models
37
from .decorators import openid_enabled
38

  
39

  
40
logger = logging.getLogger('authentic.idp.idp_openid')
41

  
42

  
43
def check_exploded(exploded, request):
44
    username = request.user.username
45
    return not exploded.path.startswith(request.path) \
46
       or exploded.path[len(request.path):].strip('/') != username \
47
       or exploded.params \
48
       or exploded.query  \
49
       or exploded.fragment
50

  
51
@csrf_exempt
52
@openid_enabled
53
def openid_server(request):
54
    """
55
    This view is the actual OpenID server - running at the URL pointed to by
56
    the <link rel="openid.server"> tag.
57
    """
58
    server = Server(get_store(request),
59
        op_endpoint=request.build_absolute_uri(
60
            reverse('openid-provider-root')))
61

  
62
    # Cancellation
63
    if 'cancel' in request.GET:
64
        if 'OPENID_REQUEST' in request.session:
65
            return oresponse_to_response(server,
66
                request.session['OPENID_REQUEST'].answer(False))
67
        else:
68
            return redirect('auth_homepage')
69

  
70
    # Clear AuthorizationInfo session var, if it is set
71
    if request.session.get('AuthorizationInfo', None):
72
        del request.session['AuthorizationInfo']
73

  
74
    querydict = dict(request.GET.items())
75
    try:
76
        orequest = server.decodeRequest(querydict)
77
    except ProtocolError, why:
78
        logger.error('Invalid OpenID message %s' % querydict)
79
        return oresponse_to_response(server, why)
80
    if not orequest:
81
        orequest = request.session.get('OPENID_REQUEST', None)
82
        if orequest:
83
            logger.info('Restarting saved request by %s' % orequest.trust_root)
84
            # remove session stored data:
85
            pass
86
            # del request.session['OPENID_REQUEST']
87
        else:
88
            logger.info('No OpenID request redirecting to homepage')
89
            return redirect('auth_homepage')
90
    else:
91
        logger.info('Received OpenID request: %s' % querydict)
92
    sreg_request = SRegRequest.fromOpenIDRequest(orequest)
93
    logger.debug('SREG request: %s' % sreg_request.__dict__)
94

  
95
    if orequest.mode in ("checkid_immediate", "checkid_setup"):
96
        # User is not logged
97
        if not request.user.is_authenticated():
98
            # Site does not want interaction
99
            if orequest.immediate:
100
                logger.debug('User not logged and checkid immediate request, \
101
returning OpenID failure')
102
                return oresponse_to_response(server, orequest.answer(False))
103
            else:
104
            # Try to login
105
                request.session['OPENID_REQUEST'] = orequest
106
                logger.debug('User not logged and checkid request, \
107
redirecting to login page')
108
                return login_require(request, params={NONCE_FIELD_NAME: '1'})
109
        else:
110
            identity = orequest.identity
111
            if identity != IDENTIFIER_SELECT:
112
               exploded = urlparse.urlparse(identity)
113
               # Allows only /openid/<user_id>
114
               if check_exploded(exploded, request):
115
                   # We only support directed identity
116
                   logger.debug('Invalid OpenID identity %s' % identity)
117
                   return oresponse_to_response(server, orequest.answer(False))
118
            if getattr(settings, 'RESTRICT_OPENID_RP', None):
119
                logger.debug('RP restriction is activated')
120
                if orequest.trust_root in getattr(settings, 'RESTRICT_OPENID_RP'):
121
                    logger.debug('The RP %s is authorized' % orequest.trust_root)
122
                else:
123
                    logger.debug('The RP %s is not authorized, return 404.' \
124
                        % orequest.trust_root)
125
                    raise Http404
126
            try:
127
                trusted_root = models.TrustedRoot.objects.get(
128
                        user=request.user.id, trust_root=orequest.trust_root)
129
                # Check the choices are sufficient
130
                if not set(sreg_request.required)\
131
                        .issubset(set(trusted_root.choices)):
132
                    # Current assertion is not sufficent, ask again !
133
                    if orequest.immediate:
134
                        logger.debug('Attributes authorization unsufficient \
135
and checkid immediate, returning OpenID failure')
136
                        return oresponse_to_response(server,
137
                                orequest.answer(False))
138
                    request.session['OPENID_REQUEST'] = orequest
139
                    logger.debug('Attributes authorization unsufficient \
140
for %s, redirecting to consent page' % orequest.trust_root)
141
                    return redirect('openid-provider-decide')
142
                user_data = {}
143
                for field in trusted_root.choices:
144
                    if field == 'email':
145
                        user_data[field] = request.user.email
146
                    elif field == 'fullname':
147
                        user_data[field] = '%s %s' % (request.user.first_name,
148
                                request.user.last_name)
149
                    elif field == 'nickname':
150
                        user_data[field] = getattr(request.user, 'username',
151
                                '')
152
                    else:
153
                        logger.debug('Could not provide SReg field %s' % field)
154
            except models.TrustedRoot.MultipleObjectsReturned:
155
                # Too much trustedroots remove
156
                models.TrustedRoot.objects.filter(user=request.user.id,
157
                        trust_root=orequest.trust_root).delete()
158
                # RP does not want any interaction
159
                if orequest.immediate:
160
                    logger.warning('Too much trusted root records and \
161
checkid immediate, returning OpenID failure')
162
                    return oresponse_to_response(server,
163
                            orequest.answer(False))
164
                request.session['OPENID_REQUEST'] = orequest
165
                logger.info('Too much trusted root for %s, redirecting to \
166
consent page' % orequest.trust_root)
167
                return redirect('openid-provider-decide')
168
            except models.TrustedRoot.DoesNotExist:
169
                # RP does not want any interaction
170
                if orequest.immediate:
171
                    logger.info('Trusted root unknown and checkid \
172
immediate, returning OpenID failure')
173
                    return oresponse_to_response(server,
174
                            orequest.answer(False))
175
                request.session['OPENID_REQUEST'] = orequest
176
                logger.info('Trusted root %s unknown, redirecting to \
177
consent page' % orequest.trust_root)
178
                return redirect('openid-provider-decide')
179

  
180
        # Create a directed identity if needed
181
        if identity == IDENTIFIER_SELECT:
182
            hash = hashlib.sha1(str(request.user.id)+'|'+orequest.trust_root) \
183
                    .hexdigest()
184
            claimed_id = request.build_absolute_uri(
185
                    reverse('openid-provider-identity', args=[hash]))
186
            logger.info('Giving directed identity %r to trusted root %r \
187
with sreg data %s' % (claimed_id, orequest.trust_root, user_data))
188
        else:
189
            claimed_id = identity
190
            logger.info('Giving claimed identity %r to trusted root %r \
191
with sreg data %s' % (claimed_id, orequest.trust_root, user_data))
192

  
193
        oresponse = orequest.answer(True, identity=claimed_id)
194
        sreg_response = SRegResponse.extractResponse(sreg_request, user_data)
195
        oresponse.addExtension(sreg_response)
196
    else:
197
        oresponse = server.handleRequest(orequest)
198
    logger.info('Returning OpenID response %s' % oresponse)
199
    return oresponse_to_response(server, oresponse)
200

  
201
@openid_enabled
202
def openid_xrds(request, identity=False, id=None):
203
    '''XRDS discovery page'''
204
    logger.debug('OpenID XRDS identity:%(identity)s id:%(id)s' % locals())
205
    if identity:
206
        types = [OPENID_2_0_TYPE, OPENID_1_0_TYPE, OPENID_1_1_TYPE, SREG_TYPE]
207
        local_ids = []
208
    else:
209
        types = [OPENID_IDP_2_0_TYPE,SREG_TYPE]
210
        local_ids = []
211
    endpoints = [request.build_absolute_uri(reverse('openid-provider-root'))]
212
    return render_to_response('idp/openid/xrds.xml', {
213
        'host': request.build_absolute_uri('/'),
214
        'types': types,
215
        'endpoints': endpoints,
216
        'local_ids': local_ids,
217
    }, context_instance=RequestContext(request), mimetype=YADIS_CONTENT_TYPE)
218

  
219
class DecideForm(forms.Form):
220
    def __init__(self, sreg_request=None, *args, **kwargs):
221
        super(DecideForm, self).__init__(*args, **kwargs)
222
        for field in sreg_request.optional:
223
            self.fields[str(field)] = forms.BooleanField(
224
                    label=data_fields[str(field)], required=False)
225
        logger.info('3SREG request: %s' % self.fields)
226

  
227
@openid_enabled
228
def openid_decide(request):
229
    """
230
    The page that asks the user if they really want to sign in to the site, and
231
    lets them add the consumer to their trusted whitelist.
232
    # If user is logged in, ask if they want to trust this trust_root
233
    # If they are NOT logged in, show the landing page
234
    """
235
    orequest = request.session.get('OPENID_REQUEST')
236
    # No request ? Failure..
237
    if not orequest:
238
        logger.warning('OpenID decide view failed, \
239
because no OpenID request is saved')
240
        return redirect('auth_homepage')
241
    sreg_request = SRegRequest.fromOpenIDRequest(orequest)
242
    logger.debug('SREG request: %s' % sreg_request.__dict__)
243
    if not request.user.is_authenticated():
244
        # Not authenticated ? Authenticate and go back to the server endpoint
245
        return login_require(request, params={NONCE_FIELD_NAME: '1'})
246

  
247
    if request.method == 'POST':
248
        if 'cancel' in request.POST:
249
            # User refused
250
            logger.info('OpenID decide canceled')
251
            return redirect(openid_server, params={'cancel': ''})
252
        else:
253
            form = DecideForm(sreg_request=sreg_request, data=request.POST)
254
            if form.is_valid():
255
                data = form.cleaned_data
256
                # Remember the choice
257
                t, created = models.TrustedRoot.objects.get_or_create(
258
                        user=request.user.id, trust_root=orequest.trust_root)
259
		t.choices = sreg_request.required \
260
                    + [ field for field in data if data[field] ]
261
                t.save()
262
                logger.debug('OpenID decide, user choice:%s' % data)
263
                return redirect('openid-provider-root')
264
    else:
265
        form = DecideForm(sreg_request=sreg_request)
266
    logger.info('OpenID device view, orequest:%s' % orequest)
267

  
268
    # verify return_to of trust_root
269
    try:
270
        trust_root_valid = verifyReturnTo(orequest.trust_root,
271
                orequest.return_to) and "Valid" or "Invalid"
272
    except HTTPFetchingError:
273
        trust_root_valid = "Unreachable"
274
    except DiscoveryFailure:
275
        trust_root_valid = "DISCOVERY_FAILED"
276

  
277
    return render_to_response('idp/openid/decide.html', {
278
        'title': _('Trust this site?'),
279
        'required': sreg_request.required,
280
        'optional': sreg_request.optional,
281
        'trust_root_valid': trust_root_valid,
282
        'form': form,
283
    }, context_instance=RequestContext(request))
284

  
285
@openid_enabled
286
def openid_discovery(request, id):
287
    '''HTML discovery page'''
288
    xrds_url = request.build_absolute_uri(
289
            reverse('openid-provider-identity-xrds', args=[id]))
290
    response = render_to_response('idp/openid/discovery.html', {
291
        'xrds': xrds_url,
292
        'openid_server': request.build_absolute_uri(
293
            reverse('openid-provider-root'))
294
    }, context_instance=RequestContext(request))
295
    response['X-XRDS-Location'] = xrds_url
296
    return response
297

  
298
class TrustedRootDelete(DeleteView):
299
    model = models.TrustedRoot
300
    success_url = '/'
301
    template_name = 'idp/openid/trustedroot_confirm_delete.html'
302

  
303
openid_trustedroot_delete = openid_enabled(TrustedRootDelete.as_view())
304
-