remove authentic2_idp_openid (fixes #23515)

Code is no more used nor maintained.

Also remove diagnose.py which is obsolete too and referrred to
django-authopenid (and south and other obsolete things).

Mentions of OpenID libraries licenses were removed from license files.
This commit is contained in:
Benjamin Dauvergne 2018-05-01 00:46:41 +02:00
parent ad4b1fe051
commit d0bcf4a992
47 changed files with 6 additions and 1203 deletions

View File

@ -662,6 +662,3 @@ specific requirements.
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
OpenID idp module is derived of the project django_openid_provider which is
distributed under the Apache 2.0 license.

View File

@ -13,7 +13,6 @@ recursive-include src/authentic2/manager/static *.css *.js *.png
recursive-include src/authentic2/saml/templates *.html *.txt *.xml
recursive-include src/authentic2/templates *.html *.txt *.xml
recursive-include src/authentic2/idp/templates *.html *.txt *.xml
recursive-include src/authentic2_idp_openid/templates *.html *.txt *.xml
recursive-include src/authentic2_idp_cas/templates *.html *.txt *.xml
recursive-include src/authentic2/idp/saml/templates *.html *.txt *.xml
recursive-include src/authentic2/auth2_auth/auth2_ssl/templates *.html *.txt *.xml
@ -30,7 +29,6 @@ recursive-include src/authentic2/locale *.po *.mo
recursive-include src/authentic2/saml/locale *.po *.mo
recursive-include src/authentic2/idp/locale *.po *.mo
recursive-include src/authentic2/idp/saml/locale *.po *.mo
recursive-include src/authentic2_idp_openid/locale *.po *.mo
recursive-include src/authentic2_idp_cas/locale *.po *.mo
recursive-include src/authentic2/auth2_auth/locale *.po *.mo
recursive-include src/authentic2/auth2_auth/auth2_ssl/locale *.po *.mo

11
README
View File

@ -7,7 +7,7 @@ broad range of needs, from simple to complex setups; it has support for many
protocols and can bridge between them.
Authentic 2 supports many protocols and standards, including SAML2, CAS,
OpenID, LDAP, X509 and OAUTH2.
LDAP, X509 and OAUTH2.
Authentic 2 is under the GNU AGPL version 3 licence.
@ -23,14 +23,13 @@ Features
--------
* SAML 2.0 Identity and service provider
* OpenID 1.0 and 2.0 identity provider
* Server CAS 1.0 and 2.0 using a plugin
* Standards authentication mechanisms:
* Login/password through internal directory or LDAP
* X509 certificate over SSL/TLS
* Protocol proxying, for instance between OpenID and SAML
* Protocol proxying
* Support of LDAP v2 and v3 directories
* Support of the PAM backend
* One-time password (OATH and Google-Authenticator) using a plugin
@ -89,9 +88,3 @@ Copyright
Authentic is copyrighted by Entr'ouvert and is licensed through the GNU Affero
General Public Licence, version 3 or later. A copy of the whole license text
is available in the COPYING file.
The OpenID IdP originates in the project django_openid_provider by Roman
Barczy¿ski, which is under the Apache 2.0 licence. This imply that you must
distribute authentic2 under the AGPL3 licence when distributing this part of
the project which is the only AGPL licence version compatible with the
Apache 2.0 licence.

View File

@ -29,10 +29,8 @@ export SAML_SIGNATURE_PRIVATE_KEY="`cat /etc/authentic2/key.pem`"
# Enables some features
#export IDP_SAML2='yes'
#export IDP_OPENID='yes' # require package python-openid
#export IDP_CAS='yes'
#export AUTH_SAML2='yes'
#export AUTH_OPENID='yes' # require package python-openid
#export AUTH_SSL='yes'
# Sentry / Raven configuration

View File

@ -31,7 +31,7 @@ Depends: ${misc:Depends}, ${python:Depends},
python-django-filters (>= 1),
python-django-filters (<< 2)
Provides: ${python:Provides}
Recommends: python-openid, python-ldap
Recommends: python-ldap
Suggests: python-raven
Description: Versatile identity server
Authentic is a versatile identity provider aiming to address a broad

View File

@ -672,6 +672,3 @@ For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
External modules oath and totp-js modules are licensed under a BSD-like licence.
OpenID idp module is derived of the project django_openid_provider which is
distributed under the Apache 2.0 license.

View File

@ -137,8 +137,6 @@ def extract_settings_from_environ():
'A2_AUTH_PASSWORD_ENABLE',
'SSLAUTH_ENABLE',
'A2_IDP_SAML2_ENABLE',
'IDP_OPENID',
)
def to_boolean(name, default=True):

View File

@ -64,8 +64,6 @@ TIME_ZONE = 'Europe/Paris'
#A2_IDP_SAML2_ENABLE = False
# CAS 1.0 / 2.0 IDP
#A2_IDP_CAS_ENABLE = False
# OpenID 1.0 / 2.0 IDP
#A2_IDP_OPENID_ENABLE = False
# Authentifications
#A2_AUTH_PASSWORD_ENABLE = True

View File

@ -29,10 +29,8 @@ export SAML_SIGNATURE_PRIVATE_KEY="`cat /etc/authentic2/key.pem`"
# Enables some features
#export IDP_SAML2='yes'
#export IDP_OPENID='yes' # require package python-openid
#export IDP_CAS='yes'
#export AUTH_SAML2='yes'
#export AUTH_OPENID='yes' # require package python-openid
#export AUTH_SSL='yes'
# Sentry / Raven configuration

View File

@ -28,7 +28,7 @@ Depends: ${misc:Depends}, ${python:Depends},
python-six (>= 1.0),
python-django-filters (>= 1)
Provides: ${python:Provides}
Recommends: python-openid, python-ldap
Recommends: python-ldap
Suggests: python-raven
Description: Versatile identity server
Authentic is a versatile identity provider aiming to address a broad

View File

@ -672,6 +672,3 @@ For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
External modules oath and totp-js modules are licensed under a BSD-like licence.
OpenID idp module is derived of the project django_openid_provider which is
distributed under the Apache 2.0 license.

View File

@ -140,8 +140,6 @@ def extract_settings_from_environ():
'A2_AUTH_PASSWORD_ENABLE',
'SSLAUTH_ENABLE',
'A2_IDP_SAML2_ENABLE',
'IDP_OPENID',
)
def to_boolean(name, default=True):

View File

@ -64,8 +64,6 @@ TIME_ZONE = 'Europe/Paris'
#A2_IDP_SAML2_ENABLE = False
# CAS 1.0 / 2.0 IDP
#A2_IDP_CAS_ENABLE = False
# OpenID 1.0 / 2.0 IDP
#A2_IDP_OPENID_ENABLE = False
# Authentifications
#A2_AUTH_PASSWORD_ENABLE = True

View File

@ -11,13 +11,12 @@ Index: authentic2/setup.py
'XStatic-jQuery',
'XStatic-jquery-ui',
'xstatic-select2',
@@ -163,11 +161,9 @@ setup(name="authentic2",
@@ -163,10 +161,8 @@ setup(name="authentic2",
'authentic2.plugin': [
'authentic2-auth-ssl = authentic2.auth2_auth.auth2_ssl:Plugin',
'authentic2-auth-saml = authentic2_auth_saml:Plugin',
- 'authentic2-auth-oidc = authentic2_auth_oidc:Plugin',
'authentic2-idp-saml2 = authentic2.idp.saml:Plugin',
'authentic2-idp-openid = authentic2_idp_openid:Plugin',
'authentic2-idp-cas = authentic2_idp_cas:Plugin',
- 'authentic2-idp-oidc = authentic2_idp_oidc:Plugin',
'authentic2-provisionning-ldap = authentic2_provisionning_ldap:Plugin',

View File

@ -1,21 +0,0 @@
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'authentic2.settings'
try:
import django
print 'Django:', django.get_version()
except ImportError:
print 'django is missing: easy_install django'
sys.exit(1)
try:
import south
print 'South:', south.__version__
except ImportError:
print 'south is missing: easy_isntall south'
try:
import django_authopenid
print 'Django-authopenid:', django_authopenid.__version__
except ImportError:
raise
print 'django_authopenid is missing: easy_install django-authopenid'

View File

@ -8,11 +8,5 @@ Authentic and Authentic 2 are copyrighted by Entr'ouvert and are licensed
through the GNU AFFERO GENERAL PUBLIC LICENSE, version 3 or later. A copy of
the whole license text is available in the COPYING file.
The OpenID IdP originates in the project django_openid_provider by Roman
Barczyski, which is under the Apache 2.0 licence. This imply that you must
distribute authentic2 under the AGPL3 licence when distributing this part of the
project which is the only AGPL licence version compatible with the Apache 2.0
licence.
The Documentation is under the licence Creative Commons
`CC BY-SA 2.0 <http://creativecommons.org/licenses/by-sa/2.0/>`_.

View File

@ -86,16 +86,6 @@ If SAML_ENCRYPTION_PUBLIC_KEY or SAML_ENCRYPTION_PRIVATE_KEY are not given,
the signature keys are used for encryption.
Activate or deactivate Authentic 2 as an OpenID provider
========================================================
Variable: IDP_OPENID
Values:
* False: deactivate OpenID provider
* True: activate OpenID provider
Activate or deactivate Authentic 2 as a CAS server
==================================================

View File

@ -5,9 +5,6 @@ SECRET_KEY = 'changeme'
# Activate SAML 2 idp
A2_IDP_SAML2_ENABLE = True
# Activate OpenID idp
A2_IDP_OPENID_ENABLE = True
# Debugging helper
try:
import debug_toolbar

View File

@ -133,9 +133,6 @@ setup(name="authentic2",
'XStatic-jquery-ui<1.12',
'xstatic-select2',
],
extras_require = {
'idp-openid': ['python-openid'],
},
zip_safe=False,
classifiers=[
"Development Status :: 5 - Production/Stable",
@ -165,7 +162,6 @@ setup(name="authentic2",
'authentic2-auth-saml = authentic2_auth_saml:Plugin',
'authentic2-auth-oidc = authentic2_auth_oidc:Plugin',
'authentic2-idp-saml2 = authentic2.idp.saml:Plugin',
'authentic2-idp-openid = authentic2_idp_openid:Plugin',
'authentic2-idp-cas = authentic2_idp_cas:Plugin',
'authentic2-idp-oidc = authentic2_idp_oidc:Plugin',
'authentic2-provisionning-ldap = authentic2_provisionning_ldap:Plugin',

View File

@ -67,7 +67,6 @@ class CustomIndexDashboard(Dashboard):
'authentic2.models.AuthenticationEvent',
'authentic2.models.UserExternalId',
'authentic2.models.DeletedUser',
'authentic2.idp.idp_openid.models.*',
'django.contrib.sessions.*',
),
))

View File

@ -140,7 +140,7 @@ def fill_assertion(request, saml_request, assertion, provider_id, nid_format):
policy.
TODO: determine and add attributes from the session, for anonymous users
(pseudonymous federation, openid without accounts)
(pseudonymous federation)
# TODO: add information from the login event, of the session or linked
# to the request id
# TODO: use information from the consent event to specialize release of

View File

@ -1,44 +0,0 @@
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ImproperlyConfigured
try:
import openid
except ImportError:
from . import app_settings
if app_settings.ENABLE:
raise ImproperlyConfigured('OpenID idp is enabled by python-openid is not installed')
class Plugin(object):
pass
else:
class Plugin(object):
def get_before_urls(self):
from . import app_settings
from django.conf.urls import patterns, include
from authentic2.decorators import (setting_enabled, required,
lasso_required)
return required(
(
setting_enabled('ENABLE', settings=app_settings),
lasso_required()
),
patterns('',
(r'^idp/openid/', include(__name__ + '.urls'))))
def get_apps(self):
return [__name__]
def get_admin_modules(self):
from admin_tools.dashboard import modules
return [modules.ModelList(
_('OpenID'),
models=(
'%s.models.*' % __name__,
),
)]
def get_idp_backends(self):
return ['%s.backend.OpenIDBackend' % __name__]
def get_before_middleware(self):
return ['%s.middleware.OpenIDMiddleware' % __name__]

View File

@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from models import TrustedRoot, Association, Nonce
admin.site.register(TrustedRoot)
admin.site.register(Association)
admin.site.register(Nonce)

View File

@ -1,34 +0,0 @@
class AppSettings(object):
__DEFAULTS = dict(
ENABLE=False,
OPENID_ACTIONS={},
)
def __init__(self, prefix):
self.prefix = prefix
def _setting(self, name, dflt):
from django.conf import settings
return getattr(settings, name, dflt)
def _setting_with_prefix(self, name, dflt):
return self._setting(self.prefix + name, dflt)
@property
def ENABLE(self):
return self._setting_with_prefix('ENABLE',
self._settings('IDP_OPENID',
self.__DEFAULTS['ENABLE']))
def __getattr__(self, name):
if name not in self.__DEFAULTS:
raise AttributeError(name)
return self._setting_with_prefix(name, self.__DEFAULTS[name])
# Ugly? Guido recommends this himself ...
# http://mail.python.org/pipermail/python-ideas/2012-May/014969.html
import sys
app_settings = AppSettings('A2_IDP_OPENID_')
app_settings.__name__ = __name__
sys.modules[__name__] = app_settings

View File

@ -1,30 +0,0 @@
import logging
from django.core.urlresolvers import reverse
from authentic2.utils import Service
from . import models, app_settings
logger = logging.getLogger(__name__)
class OpenIDBackend(object):
def service_list(self, request):
if not request.user.is_authenticated():
return ()
q = models.TrustedRoot.objects.filter(user=request.user.id)
ls = []
for service_provider in q:
actions = []
actions.append(('go', 'GET', service_provider.trust_root, None))
if app_settings.OPENID_ACTIONS:
tpl = app_settings.OPENID_ACTIONS.get(service_provider.trust_root, None)
if tpl:
actions.append(('template', tpl))
actions.append(('unlink', 'GET', reverse('trustedroot_delete',
kwargs={'pk': service_provider.id}), None))
ls.append(Service(url=None, name=service_provider.trust_root,
actions=actions))
return ls

View File

@ -1,11 +0,0 @@
import os
import tempfile
from django.conf import settings
tempdir = tempfile.gettempdir()
STORE = getattr(settings, 'OPENID_PROVIDER_STORE',
'authentic2.idp.idp_openid.openid_store.DjangoOpenIDStore')
FILESTORE_PATH = getattr(settings, 'OPENID_PROVIDER_FILESTORE_PATH',
os.path.join(tempdir, 'openid-filestore'))

View File

@ -1,7 +0,0 @@
from authentic2.decorators import setting_enabled
from . import app_settings
def openid_enabled(func):
return setting_enabled('ENABLE', app_settings)(func)

View File

@ -1,83 +0,0 @@
# authentic2 idp openid french l10n
# Copyright (C) 2015 Entr'ouvert
# This file is distributed under the same license as the Authentic package.
# Frederic Peters <fpeters@entrouvert.com>, 2010.
#
msgid ""
msgstr ""
"Project-Id-Version: Authentic\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-01-24 12:02+0100\n"
"PO-Revision-Date: 2018-01-24 12:12+0100\n"
"Last-Translator: Mikaël Ates <mates@entrouvert.com>\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"
#: src/authentic2_idp_openid/__init__.py:34
msgid "OpenID"
msgstr "Gérer la connexion OpenID"
#: src/authentic2_idp_openid/models.py:35
msgid "trusted root"
msgstr "Site de confiance"
#: src/authentic2_idp_openid/models.py:36
msgid "trusted roots"
msgstr "Sites de confiance"
#: src/authentic2_idp_openid/models.py:57
msgid "association"
msgstr "association"
#: src/authentic2_idp_openid/models.py:58
msgid "associations"
msgstr "associations"
#: src/authentic2_idp_openid/models.py:125
msgid "nonce"
msgstr "nonce"
#: src/authentic2_idp_openid/models.py:126
msgid "nonces"
msgstr "nonces"
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_id.html:5
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_id_confirm.html:5
msgid "Manage OpenID"
msgstr "Gérer la connexion OpenID"
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_id.html:23
msgid "Your current OpenID"
msgstr "Vos identifiants OpenID actuels"
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_id.html:52
msgid "Add a new OpenID identity"
msgstr "Ajouter une nouvelle identité OpenID"
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_trustroot.html:5
msgid "Manage trusted site"
msgstr "Gérer vos sites de confiance"
#: src/authentic2_idp_openid/templates/django_openid_provider/manage_trustroot.html:17
msgid "Your trusted site"
msgstr "Vos sites de confiance"
#: src/authentic2_idp_openid/templates/idp/openid/trustedroot_confirm_delete.html:5
msgid "Remove Link ?"
msgstr "Supprimer le lien ?"
#: src/authentic2_idp_openid/templates/idp/openid/trustedroot_confirm_delete.html:7
msgid "Are you sure you want to delete link with"
msgstr "Êtes-vous sûr de vouloir supprimer le lien avec"
#: src/authentic2_idp_openid/templates/idp/openid/trustedroot_confirm_delete.html:10
msgid "Back"
msgstr "Retour"
#: src/authentic2_idp_openid/views.py:278
msgid "Trust this site?"
msgstr "Faire confiance à ce site ?"

View File

@ -1,13 +0,0 @@
from django.core.urlresolvers import reverse
from . import views
class OpenIDMiddleware(object):
'''Add OpenID discovery header to all responses,
if Accept header is 'application/xrds+xml' also return an XRDS document.
'''
def process_response(self, request, response):
response['X-XRDS-Location'] = request.build_absolute_uri(reverse('a2-idp-openid-xrds'))
if request.META.get('HTTP_ACCEPT') == 'application/xrds+xml':
return views.openid_xrds(request)
return response

View File

@ -1,17 +0,0 @@
"""utils to help rename apps and South migrations"""
import os
from south.models import MigrationHistory
def was_applied(migration_file_path, app_name):
"""true if migration with a given file name ``migration_file``
was applied to app with name ``app_name``"""
try:
migration_file = os.path.basename(migration_file_path)
migration_name = migration_file.split('.')[0]
MigrationHistory.objects.get(
app_name = app_name,
migration = migration_name
)
return True
except MigrationHistory.DoesNotExist:
return False

View File

@ -1,71 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import authentic2.saml.fields
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='Association',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('server_url', models.CharField(max_length=768)),
('handle', models.CharField(max_length=255)),
('secret', authentic2.saml.fields.PickledObjectField(editable=False)),
('issued', models.DateTimeField(verbose_name=b'Issue time for this association, as seconds since EPOCH', editable=False)),
('lifetime', models.IntegerField(verbose_name=b'Lifetime of this association as seconds since the issued time')),
('expire', models.DateTimeField(verbose_name=b'After this time, the association will be expired')),
('assoc_type', models.CharField(max_length=64)),
],
options={
'db_table': 'idp_openid_association',
'verbose_name': 'association',
'verbose_name_plural': 'associations',
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Nonce',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('salt', models.CharField(max_length=40)),
('server_url', models.CharField(max_length=768)),
('timestamp', models.IntegerField()),
],
options={
'db_table': 'idp_openid_nonce',
'verbose_name': 'nonce',
'verbose_name_plural': 'nonces',
},
bases=(models.Model,),
),
migrations.CreateModel(
name='TrustedRoot',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('user', models.CharField(max_length=255)),
('trust_root', models.CharField(max_length=200)),
('choices', authentic2.saml.fields.PickledObjectField()),
],
options={
'db_table': 'idp_openid_trustedroot',
'verbose_name': 'trusted root',
'verbose_name_plural': 'trusted roots',
},
bases=(models.Model,),
),
migrations.AlterUniqueTogether(
name='nonce',
unique_together=set([('server_url', 'salt')]),
),
migrations.AlterUniqueTogether(
name='association',
unique_together=set([('server_url', 'handle')]),
),
]

View File

@ -1,149 +0,0 @@
# -*- coding: utf-8 -*-
# vim: set ts=4 sw=4 : */
import datetime
import time
import calendar
import openid.association
import openid.store.nonce
from django.db import models
from django.utils.timezone import now, utc
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from authentic2.saml.fields import PickledObjectField
def utctimestamp_to_aware_datetime(tst):
if settings.USE_TZ:
return datetime.datetime.utcfromtimestamp(tst) \
.replace(tz_info=utc)
else:
return datetime.datetime.utcfromtimestamp(tst)
class TrustedRoot(models.Model):
user = models.CharField(max_length=255)
trust_root = models.CharField(max_length=200)
choices = PickledObjectField()
def __unicode__(self):
return unicode(self.trust_root)
class Meta:
verbose_name = _('trusted root')
verbose_name_plural = _('trusted roots')
db_table = 'idp_openid_trustedroot' # app was named idp_openid before
class Association(models.Model):
server_url = models.CharField(max_length=768, blank=False)
handle = models.CharField(max_length=255, blank=False)
secret = PickledObjectField(editable=False)
issued = models.DateTimeField(editable=False,
verbose_name="Issue time for this association, as seconds \
since EPOCH")
lifetime = models.IntegerField(
verbose_name="Lifetime of this association as seconds since \
the issued time")
expire = models.DateTimeField("After this time, the association will \
be expired")
assoc_type = models.CharField(max_length=64, blank=False)
class Meta:
unique_together = ('server_url', 'handle')
verbose_name = _('association')
verbose_name_plural = _('associations')
db_table = 'idp_openid_association' # app was named idp_openid before
def save(self, *args, **kwargs):
'''Overload default save() method to compute the expire field'''
self.issued = now()
self.expire = self.issued + datetime.timedelta(seconds=self.lifetime)
super(Association, self).save(*args, **kwargs)
def to_association(self):
'''Convert a model instance to an Association object of the openid
library.
'''
return openid.association.Association(handle=self.handle,
secret=self.secret,
issued=calendar.timegm(self.issued.utctimetuple()),
lifetime=self.lifetime,
assoc_type=self.assoc_type)
@classmethod
def get_association(cls, server_url, handle=None):
try:
filter = cls.objects.filter(server_url=server_url,
expire__gt=now())
if handle is not None:
filter = filter.filter(handle=handle)
return filter.latest('issued').to_association()
except cls.DoesNotExist:
return None
@classmethod
def cleanup_associations(cls):
filter = cls.objects.filter(expire__lt=now())
count = filter.count()
filter.delete()
return count
@classmethod
def remove_association(cls, server_url, handle=None):
filter = cls.objects.filter(server_url=server_url)
if handle is not None:
filter = filter.filter(handle=handle)
filter.delete()
@classmethod
def store_association(cls, server_url, association):
Association(server_url=server_url,
handle=association.handle,
secret=association.secret,
issued=utctimestamp_to_aware_datetime(association.issued),
lifetime=association.lifetime,
assoc_type=association.assoc_type).save()
class NonceManager(models.Manager):
def cleanup(self):
expire = openid.store.nonce.SKEW
timestamp = calendar.timegm(now().utctimetuple())
self.filter(timestamp__lt=timestamp-expire).delete()
class Nonce(models.Model):
salt = models.CharField(max_length=40)
server_url = models.CharField(max_length=768)
timestamp = models.IntegerField()
objects = NonceManager()
class Meta:
verbose_name = _('nonce')
verbose_name_plural = _('nonces')
unique_together = ('server_url', 'salt')
db_table = 'idp_openid_nonce' # app was named idp_openid before
@classmethod
def use_nonce(cls, server_url, timestamp, salt):
now = time.time()
if timestamp > now or timestamp + openid.store.nonce.SKEW < now:
return False
n, created = cls.objects.get_or_create(server_url=server_url,
salt=salt)
if created:
n.timestamp = timestamp
n.save()
return created
@classmethod
def cleanup_nonces(cls):
filter = cls.objects.filter(
timestamp_lt=time.time()-openid.store.nonce.SKEW)
count = filter.count()
filter.delete()
return count

View File

@ -1,38 +0,0 @@
# -*- coding: utf-8 -*-
# vim: set ts=4 sw=4 : */
import time
import openid.store.interface
from django.conf import settings
import models
from authentic2 import nonce
NONCE_TIMEOUT = getattr(settings, 'OPENID_NONCE_TIMEOUT',
getattr(settings, 'NONCE_TIMEOUT', openid.store.nonce.SKEW))
class DjangoOpenIDStore(openid.store.interface.OpenIDStore):
def cleanupAssociations(self):
return models.Association.cleanup_associations()
def cleanupNonces(self):
nonce.cleanup_nonces()
def storeAssociation(self, server_url, association):
return models.Association.store_association(server_url, association)
def getAssociation(self, server_url, handle=None):
return models.Association.get_association(server_url, handle)
def removeAssociation(self, server_url, handle):
return models.Association.remove_association(server_url, handle)
def useNonce(self, server_url, timestamp, salt):
now = time.time()
if not (timestamp < now < (timestamp + NONCE_TIMEOUT)):
return False
value = '%s_%s_%s' % (server_url, timestamp, salt)
return nonce.accept_nonce(value, 'OpenID', NONCE_TIMEOUT)

View File

@ -1,64 +0,0 @@
{% extends "authentic2/base-page.html" %}
{% load i18n %}
{% block title %}
{% trans "Manage OpenID" %}
{% endblock %}
{% load breadcrumbs %}
{% block breadcrumbs %}
{{ block.super }}
{% breadcrumb_url 'Manage OpenID' 'manage_id' %}
{% endblock %}
{% block content %}
{% if message %}
<ul class="errorlist">{{ message }}</ul>
{% endif %}
<p>
{% if nb_openids > 0 %}
<a href="/openid/manage/">Manage your trusted site</a>
</p>
<fieldset>
<legend>{% trans "Your current OpenID" %}</legend>
<p> Choose your identities to remove, be careful this will remove all the trusted site for these identities.
You can change your default OpenID by clicking on "Make Default"
</p>
<form action="." id="form1" method="post">
{% csrf_token %}
{% for key,value in openids.items %}
<p> <h4> {{ uri }}{{ oipath }}/{{ value.caption }}/
{% if value.Default %}
(Default)
{% endif %}
</h4>
{% for key2, value2 in value.trustroot.items %}
<li class="indented"> {{ value2 }} </li>
{% empty %}
There is no trusted site for this identity.
{% endfor %}
{% if not value.Default %}
<input type = "submit" name= {{ value.caption }} value = "Make default" />
{% endif %}
<input type = "submit" name = {{ value.caption }} value = "Remove"/>
</p>
{% endfor %}
</form>
</fieldset>
{% else %}
<p> You have no OpenID account for the moment</p>
{% endif %}
<fieldset>
<legend>{% trans "Add a new OpenID identity" %} </legend>
<p>
<form action = "/openid/addopenid/" id = "form2" method = "post">
{% csrf_token %}
<p> Leave blank to create an anonymous OpenID</p>
{{ uri }}{{ oipath }}/{{ form.openid }}/
{{ form.Default }}
Check if you want this OpenID account become your default OpenID account.
<input type = "submit" value = "Add" />
</p>
</form>
</fieldset>
{% endblock %}

View File

@ -1,19 +0,0 @@
{% extends "authentic2/base-page.html" %}
{% load i18n %}
{% block title %}
{% trans "Manage OpenID" %}
{% endblock %}
{% block content %}
<form action = "/openid/manageid_confirm/" id = "form" method = "post">
{% csrf_token %}
<p>Are you sure, you want to delete <strong> {{ id }} </strong> and these trusted site:</p>
{% for i in trust %}
{{ i }}
{% endfor %}
<input type = "hidden" name = "idremove" value = {{ id }}>
<input type = "submit" value = "Yes" name = "Answer" />
<input type = "submit" value = "No" name = "Answer" />
</form>
{% endblock %}

View File

@ -1,37 +0,0 @@
{% extends "authentic2/base-page.html" %}
{% load i18n %}
{% block title %}
{% trans "Manage trusted site" %}
{% endblock %}
{% load breadcrumbs %}
{% block breadcrumbs %}
{{ block.super }}
{% breadcrumb_url 'Manage OpenID' 'manage_id' %}
{% breadcrumb_url 'Manage trusted site' 'manage_trustroot' %}
{% endblock %}
{% block content %}
<fieldset>
<legend>{% trans "Your trusted site" %} </legend>
<p>Check the trusted site that you want to remove and click on remove to remove these trusted site from these </p>
<form action="." id="form" method="post">
{% csrf_token %}
{% for key, value in openids.items %}
<p> <h4> {{ uri }}{{ oipath }}/{{ value.caption }}/ </h4>
<ul class="NoBullet">
{% for key2, value2 in value.trustroot.items %}
<li class="indented"> <input type="checkbox" name = "trustremove" value = {{ key2 }} /> {{ value2 }} </li>
{% empty %}
You have no trusted site for this openid
{% endfor %}
</ul>
</p>
{% endfor %}
{% if trust_sum != 0 %}
<input type="submit" value="Remove" />
{% endif %}
</form>
</fieldset>
{% endblock %}

View File

@ -1,36 +0,0 @@
{% extends "authentic2/base-page.html" %}
{% block extrahead %}{{ block.super }}
<meta http-equiv="x-xrds-location" content="{{ host }}{% url 'openid-provider-xrds' %}">
{% endblock %}
{% block title %}
OpenID endpoint
{% endblock %}
{% load breadcrumbs %}
{% block breadcrumbs %}
{{ block.super }}
{% breadcrumb_url 'OpenID' 'openid-provider-root' %}
{% endblock %}
{% block content %}
{% if nb_openid > 0 %}
<p>To manage your OpenID accounts go on <a href='/openid/manageid/'> manage your OpenID account</a></p>
<h3>Your OpenID account are: </h3>
{% for key, value in openids.items %}
<p> <h4> {{ uri }}{{ oipath }}/{{ value.caption }}/ </h4>
{% for key2, value2 in value.trustroot.items %}
<li> {{ value2 }} </li>
{% empty %}
You have no trusted site for this openid.
{% endfor %}
</p>
{% endfor %}
{% else %}
<p>You currently have no OpenID account.
To create an OpenID account go on <a href='/openid/manageid/'> create an OpenID account</a></p>
{% endif %}
{% endblock %}

View File

@ -1 +0,0 @@
{% extends "base.html" %}

View File

@ -1,57 +0,0 @@
{% extends "authentic2/base-page.html" %}
{% block content %}
{% ifequal trust_root_valid "Valid" %}
<!-- Trust root has been validated by OpenID 2 mechanism. -->
<p>The site <tt>{{ trust_root|escape }}</tt> has requested verification
of your OpenID.</p>
{% endifequal %}
{% ifequal trust_root_valid "Invalid" %}
<div class="error">
<p>This request claims to be from {{ trust_root|escape }} but I have
determined that <em>it is a pack of lies</em>. Beware, if you release
information to them, they are likely to do unconscionable things with it,
being the lying liars that they are.</p>
<p>Please tell the <em>real</em> {{ trust_root|escape }} that someone is
trying to abuse your trust in their good name.</p>
</div>
{% endifequal %}
{% ifequal trust_root_valid "Unreachable" %}
<p>The site <tt>{{ trust_root|escape }}</tt> has requested verification
of your OpenID. I have failed to reach it and thus cannot vouch for its
authenticity. Perhaps it is on your local network.</p>
{% endifequal %}
{% ifequal trust_root_valid "DISCOVERY_FAILED" %}
<p>The site <tt>{{ trust_root|escape }}</tt> has requested verification
of your OpenID. However, <tt>{{ trust_root|escape }}</tt> does not
implement OpenID 2.0's relying party verification mechanism. Please use
extra caution in deciding whether to release information to this party,
and ask <tt>{{ trust_root|escape }}</tt> to implement relying party
verification for your future transactions.</p>
{% endifequal %}
<!-- trust_root_valid is {{ trust_root_valid }} -->
<form method="post" action="{% url 'openid-provider-decide' %}">
{% csrf_token %}
{% if required %}
<p>
It requires the following attributes:
<ul>
{% for att in required %}
<li>{{ att }}</li>
{% endfor %}
</ul>
{% endif %}
{% if optional %}
The following attributes are optional:
<ul>
{{ form.as_ul }}
</ul>
</p>
{% endif %}
<p>Allow Identity-Hub to verify your identity ?</p>
<input type="submit" value="Yes (Allow)" name="allow" />
<input type="submit" value="No (Cancel)" name="cancel" />
</form>
{% endblock %}

View File

@ -1,8 +0,0 @@
<html>
<head>
<link rel="openid.server" href="{{ openid_server }}" />
<meta http-equiv="refresh" content="1;url=/">
</head>
<body>
</body>
</html>

View File

@ -1,6 +0,0 @@
{% extends "authentic2/base-page.html" %}
{% block content %}
<h2>{{ title }}</h2>
{{ msg }}
{% endblock %}

View File

@ -1,11 +0,0 @@
{% extends "authentic2/base-page.html" %}
{% load i18n %}
{% block content %}
<h2>{% trans "Remove Link ?" %}</h2>
<form action="" method="post">{% csrf_token %}
<p>{% trans "Are you sure you want to delete link with" %} {{ trustedroot }} ?</p>
<input type="submit" value="Yes" />
</form>
<p><a href="/">{% trans "Back" %}</a></p>
{% endblock %}

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<Service priority="0">{% for uri in types %}
<Type>{{ uri|escape }}</Type>
{% endfor %}{% for endpoint in endpoints %}
<URI>{{ endpoint }}</URI>
{% endfor %}{% for local_id in local_ids %}
<LocalID>{{ local_id }}</LocalID>
{% endfor %}</Service>
</XRD>
</xrds:XRDS>

View File

@ -1,26 +0,0 @@
# vim: set ts=4 sw=4 : */
from django.conf.urls import patterns, url
from . import views
urlpatterns = patterns('authentic2.idp.idp_openid.views',
url(r'^$',
views.openid_server,
name='a2-idp-openid-root'),
url(r'^trustedroot/(?P<pk>\d+)/delete/$',
views.openid_trustedroot_delete,
name='trustedroot_delete'),
url(r'^decide/$',
views.openid_decide,
name='a2-idp-openid-decide'),
url(r'^xrds/$',
views.openid_xrds,
name='a2-idp-openid-xrds'),
url(r'^(?P<id>.+)/xrds/$',
views.openid_xrds,
{'identity': True},
name='a2-idp-openid-identity-xrds'),
url(r'^(?P<id>.+)/$',
views.openid_discovery,
name='a2-idp-openid-identity'),
)

View File

@ -1,36 +0,0 @@
# -*- coding: utf-8 -*-
# vim: set ts=4 sw=4 fdm=indent : */
# some code from http://www.djangosnippets.org/snippets/310/ by simon
# and from examples/djopenid from python-openid-2.2.4
import openid.server
from django.core.exceptions import ImproperlyConfigured
from django.utils.importlib import import_module
from django.http import HttpResponse, HttpResponseRedirect
import conf
def oresponse_to_response(server, oresponse):
try:
webresponse = server.encodeResponse(oresponse)
except openid.server.EncodingError:
return HttpResponseRedirect('/')
response = HttpResponse(webresponse.body)
response.status_code = webresponse.code
for key, value in webresponse.headers.items():
response[key] = value
return response
def import_module_attr(path):
package, module = path.rsplit('.', 1)
return getattr(import_module(package), module)
def get_store(request):
try:
store_class = import_module_attr(conf.STORE)
except ImportError:
raise ImproperlyConfigured("OpenID store %r could not be imported" % conf.STORE)
# The FileOpenIDStore requires a path to save the user files.
if conf.STORE == 'openid.store.filestore.FileOpenIDStore':
return store_class(conf.FILESTORE_PATH)
return store_class()

View File

@ -1,303 +0,0 @@
# -*- coding: utf-8 -*-
# some code from http://www.djangosnippets.org/snippets/310/ by simon
# and from examples/djopenid from python-openid-2.2.4
import logging
import hashlib
import urlparse
from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext as _
try:
from django.views.decorators.csrf import csrf_exempt
except ImportError:
from django.contrib.csrf.middleware import csrf_exempt
import django.forms as forms
from django.conf import settings
from django.http import Http404
from django.views.generic import DeleteView
from openid.consumer.discover import OPENID_IDP_2_0_TYPE, \
OPENID_2_0_TYPE, OPENID_1_0_TYPE, OPENID_1_1_TYPE
from openid.fetchers import HTTPFetchingError
from openid.server.server import Server, ProtocolError
from openid.server.trustroot import verifyReturnTo
from openid.yadis.discover import DiscoveryFailure
from openid.yadis.constants import YADIS_CONTENT_TYPE
from openid.message import IDENTIFIER_SELECT
from openid.extensions.sreg import ns_uri as SREG_TYPE, SRegRequest, \
SRegResponse, data_fields
from utils import get_store, oresponse_to_response
from authentic2.utils import login_require, redirect
from authentic2.constants import NONCE_FIELD_NAME
from . import models
from .decorators import openid_enabled
logger = logging.getLogger('authentic.idp.idp_openid')
def check_exploded(exploded, request):
username = request.user.username
return not exploded.path.startswith(request.path) \
or exploded.path[len(request.path):].strip('/') != username \
or exploded.params \
or exploded.query \
or exploded.fragment
@csrf_exempt
@openid_enabled
def openid_server(request):
"""
This view is the actual OpenID server - running at the URL pointed to by
the <link rel="openid.server"> tag.
"""
server = Server(get_store(request),
op_endpoint=request.build_absolute_uri(
reverse('openid-provider-root')))
# Cancellation
if 'cancel' in request.GET:
if 'OPENID_REQUEST' in request.session:
return oresponse_to_response(server,
request.session['OPENID_REQUEST'].answer(False))
else:
return redirect('auth_homepage')
# Clear AuthorizationInfo session var, if it is set
if request.session.get('AuthorizationInfo', None):
del request.session['AuthorizationInfo']
querydict = dict(request.GET.items())
try:
orequest = server.decodeRequest(querydict)
except ProtocolError, why:
logger.error('Invalid OpenID message %s' % querydict)
return oresponse_to_response(server, why)
if not orequest:
orequest = request.session.get('OPENID_REQUEST', None)
if orequest:
logger.info('Restarting saved request by %s' % orequest.trust_root)
# remove session stored data:
pass
# del request.session['OPENID_REQUEST']
else:
logger.info('No OpenID request redirecting to homepage')
return redirect('auth_homepage')
else:
logger.info('Received OpenID request: %s' % querydict)
sreg_request = SRegRequest.fromOpenIDRequest(orequest)
logger.debug('SREG request: %s' % sreg_request.__dict__)
if orequest.mode in ("checkid_immediate", "checkid_setup"):
# User is not logged
if not request.user.is_authenticated():
# Site does not want interaction
if orequest.immediate:
logger.debug('User not logged and checkid immediate request, \
returning OpenID failure')
return oresponse_to_response(server, orequest.answer(False))
else:
# Try to login
request.session['OPENID_REQUEST'] = orequest
logger.debug('User not logged and checkid request, \
redirecting to login page')
return login_require(request, params={NONCE_FIELD_NAME: '1'})
else:
identity = orequest.identity
if identity != IDENTIFIER_SELECT:
exploded = urlparse.urlparse(identity)
# Allows only /openid/<user_id>
if check_exploded(exploded, request):
# We only support directed identity
logger.debug('Invalid OpenID identity %s' % identity)
return oresponse_to_response(server, orequest.answer(False))
if getattr(settings, 'RESTRICT_OPENID_RP', None):
logger.debug('RP restriction is activated')
if orequest.trust_root in getattr(settings, 'RESTRICT_OPENID_RP'):
logger.debug('The RP %s is authorized' % orequest.trust_root)
else:
logger.debug('The RP %s is not authorized, return 404.' \
% orequest.trust_root)
raise Http404
try:
trusted_root = models.TrustedRoot.objects.get(
user=request.user.id, trust_root=orequest.trust_root)
# Check the choices are sufficient
if not set(sreg_request.required)\
.issubset(set(trusted_root.choices)):
# Current assertion is not sufficent, ask again !
if orequest.immediate:
logger.debug('Attributes authorization unsufficient \
and checkid immediate, returning OpenID failure')
return oresponse_to_response(server,
orequest.answer(False))
request.session['OPENID_REQUEST'] = orequest
logger.debug('Attributes authorization unsufficient \
for %s, redirecting to consent page' % orequest.trust_root)
return redirect('openid-provider-decide')
user_data = {}
for field in trusted_root.choices:
if field == 'email':
user_data[field] = request.user.email
elif field == 'fullname':
user_data[field] = '%s %s' % (request.user.first_name,
request.user.last_name)
elif field == 'nickname':
user_data[field] = getattr(request.user, 'username',
'')
else:
logger.debug('Could not provide SReg field %s' % field)
except models.TrustedRoot.MultipleObjectsReturned:
# Too much trustedroots remove
models.TrustedRoot.objects.filter(user=request.user.id,
trust_root=orequest.trust_root).delete()
# RP does not want any interaction
if orequest.immediate:
logger.warning('Too much trusted root records and \
checkid immediate, returning OpenID failure')
return oresponse_to_response(server,
orequest.answer(False))
request.session['OPENID_REQUEST'] = orequest
logger.info('Too much trusted root for %s, redirecting to \
consent page' % orequest.trust_root)
return redirect('openid-provider-decide')
except models.TrustedRoot.DoesNotExist:
# RP does not want any interaction
if orequest.immediate:
logger.info('Trusted root unknown and checkid \
immediate, returning OpenID failure')
return oresponse_to_response(server,
orequest.answer(False))
request.session['OPENID_REQUEST'] = orequest
logger.info('Trusted root %s unknown, redirecting to \
consent page' % orequest.trust_root)
return redirect('openid-provider-decide')
# Create a directed identity if needed
if identity == IDENTIFIER_SELECT:
hash = hashlib.sha1(str(request.user.id)+'|'+orequest.trust_root) \
.hexdigest()
claimed_id = request.build_absolute_uri(
reverse('openid-provider-identity', args=[hash]))
logger.info('Giving directed identity %r to trusted root %r \
with sreg data %s' % (claimed_id, orequest.trust_root, user_data))
else:
claimed_id = identity
logger.info('Giving claimed identity %r to trusted root %r \
with sreg data %s' % (claimed_id, orequest.trust_root, user_data))
oresponse = orequest.answer(True, identity=claimed_id)
sreg_response = SRegResponse.extractResponse(sreg_request, user_data)
oresponse.addExtension(sreg_response)
else:
oresponse = server.handleRequest(orequest)
logger.info('Returning OpenID response %s' % oresponse)
return oresponse_to_response(server, oresponse)
@openid_enabled
def openid_xrds(request, identity=False, id=None):
'''XRDS discovery page'''
logger.debug('OpenID XRDS identity:%(identity)s id:%(id)s' % locals())
if identity:
types = [OPENID_2_0_TYPE, OPENID_1_0_TYPE, OPENID_1_1_TYPE, SREG_TYPE]
local_ids = []
else:
types = [OPENID_IDP_2_0_TYPE,SREG_TYPE]
local_ids = []
endpoints = [request.build_absolute_uri(reverse('openid-provider-root'))]
return render_to_response('idp/openid/xrds.xml', {
'host': request.build_absolute_uri('/'),
'types': types,
'endpoints': endpoints,
'local_ids': local_ids,
}, context_instance=RequestContext(request), mimetype=YADIS_CONTENT_TYPE)
class DecideForm(forms.Form):
def __init__(self, sreg_request=None, *args, **kwargs):
super(DecideForm, self).__init__(*args, **kwargs)
for field in sreg_request.optional:
self.fields[str(field)] = forms.BooleanField(
label=data_fields[str(field)], required=False)
logger.info('3SREG request: %s' % self.fields)
@openid_enabled
def openid_decide(request):
"""
The page that asks the user if they really want to sign in to the site, and
lets them add the consumer to their trusted whitelist.
# If user is logged in, ask if they want to trust this trust_root
# If they are NOT logged in, show the landing page
"""
orequest = request.session.get('OPENID_REQUEST')
# No request ? Failure..
if not orequest:
logger.warning('OpenID decide view failed, \
because no OpenID request is saved')
return redirect('auth_homepage')
sreg_request = SRegRequest.fromOpenIDRequest(orequest)
logger.debug('SREG request: %s' % sreg_request.__dict__)
if not request.user.is_authenticated():
# Not authenticated ? Authenticate and go back to the server endpoint
return login_require(request, params={NONCE_FIELD_NAME: '1'})
if request.method == 'POST':
if 'cancel' in request.POST:
# User refused
logger.info('OpenID decide canceled')
return redirect(openid_server, params={'cancel': ''})
else:
form = DecideForm(sreg_request=sreg_request, data=request.POST)
if form.is_valid():
data = form.cleaned_data
# Remember the choice
t, created = models.TrustedRoot.objects.get_or_create(
user=request.user.id, trust_root=orequest.trust_root)
t.choices = sreg_request.required \
+ [ field for field in data if data[field] ]
t.save()
logger.debug('OpenID decide, user choice:%s' % data)
return redirect('openid-provider-root')
else:
form = DecideForm(sreg_request=sreg_request)
logger.info('OpenID device view, orequest:%s' % orequest)
# verify return_to of trust_root
try:
trust_root_valid = verifyReturnTo(orequest.trust_root,
orequest.return_to) and "Valid" or "Invalid"
except HTTPFetchingError:
trust_root_valid = "Unreachable"
except DiscoveryFailure:
trust_root_valid = "DISCOVERY_FAILED"
return render_to_response('idp/openid/decide.html', {
'title': _('Trust this site?'),
'required': sreg_request.required,
'optional': sreg_request.optional,
'trust_root_valid': trust_root_valid,
'form': form,
}, context_instance=RequestContext(request))
@openid_enabled
def openid_discovery(request, id):
'''HTML discovery page'''
xrds_url = request.build_absolute_uri(
reverse('openid-provider-identity-xrds', args=[id]))
response = render_to_response('idp/openid/discovery.html', {
'xrds': xrds_url,
'openid_server': request.build_absolute_uri(
reverse('openid-provider-root'))
}, context_instance=RequestContext(request))
response['X-XRDS-Location'] = xrds_url
return response
class TrustedRootDelete(DeleteView):
model = models.TrustedRoot
success_url = '/'
template_name = 'idp/openid/trustedroot_confirm_delete.html'
openid_trustedroot_delete = openid_enabled(TrustedRootDelete.as_view())