Refactorize application to make it an authentic2 plugin (2/2)

This commit is contained in:
Benjamin Dauvergne 2014-11-06 21:22:23 +01:00
parent 058af0c133
commit 957aae3ff7
19 changed files with 144 additions and 270 deletions

16
.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
MANIFEST
*.pyc
*.pyo
*.db
.*.swp
cache/
dist/
./static/
doc/_build
authentic.egg-info
local_settings.py
log.log
authentic2/locale/fr/LC_MESSAGES/django.mo
local_settings.*
*.egg-info
*.mo

View File

@ -1,4 +1,4 @@
include COPYING
recursive-include src/authentic2_auth_msp/templates *.html
recursive-include src/authentic2_auth_msp/static *.js *.css *.png
recursive-include src/authentic2_auth_msp/static *.js *.css *.png *.gif *.jpg
recursive-include src/authentic2_auth_msp/locale *.po *.mo

View File

@ -61,6 +61,7 @@ setup(name='authentic2-auth-msp',
'authentic2',
'requests',
'requests-oauthlib',
'django-sekizai',
],
entry_points={
'authentic2.plugin': [

View File

@ -0,0 +1,15 @@
__version__ = '1.0.0a'
class Plugin(object):
def get_before_urls(self):
from . import urls
return urls.urlpatterns
def get_apps(self):
return [__name__, 'sekizai']
def get_authentication_backends(self):
return ['authentic2_auth_msp.backends.MspBackend']
def get_auth_frontends(self):
return ['authentic2_auth_msp.auth_frontends.MspFrontend']

View File

@ -1,6 +1,5 @@
import sys
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
@ -18,6 +17,10 @@ class AppSettings(object):
raise ImproperlyConfigured('Missing setting %r' % (self.prefix + name))
return v
@property
def enabled(self):
return self._setting('ENABLED', False)
@property
def authorize_url(self):
return self._setting('AUTHORIZE_URL')
@ -55,6 +58,6 @@ class AppSettings(object):
return self._setting('MORE_URL', 'https://mon.service-public.fr/')
app_settings = AppSettings('MSP_')
app_settings = AppSettings('A2_MSP_')
app_settings.__name__ = __name__
sys.modules[__name__] = app_settings

View File

@ -0,0 +1,25 @@
from django.utils.translation import gettext_noop
from django.template.loader import render_to_string
from django import forms
from . import app_settings
class MspFrontend(object):
def enabled(self):
return app_settings.enabled
def name(self):
return gettext_noop('mon.service-public.fr')
def id(self):
return 'msp'
def form(self):
return forms.Form
def template(self):
return 'authentic2_auth_msp/connecting.html'
def profile(self, request):
return render_to_string('authentic2_auth_msp/linking.html')

View File

@ -1,78 +0,0 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'MspAccount'
db.create_table(u'msp_mspaccount', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('user', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['portail_citoyen.Citoyen'], unique=True)),
('agc', self.gf('django.db.models.fields.CharField')(max_length=64)),
))
db.send_create_signal(u'msp', ['MspAccount'])
def backwards(self, orm):
# Deleting model 'MspAccount'
db.delete_table(u'msp_mspaccount')
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'msp.mspaccount': {
'Meta': {'object_name': 'MspAccount'},
'agc': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['portail_citoyen.Citoyen']", 'unique': 'True'})
},
u'portail_citoyen.citoyen': {
'Meta': {'object_name': 'Citoyen'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'backend': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'backend_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '128', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'mobile': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'phone': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '5', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'})
}
}
complete_apps = ['msp']

View File

@ -1,76 +0,0 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'MspAccount.token'
db.add_column(u'msp_mspaccount', 'token',
self.gf('django.db.models.fields.TextField')(default=''),
keep_default=False)
def backwards(self, orm):
# Deleting field 'MspAccount.token'
db.delete_column(u'msp_mspaccount', 'token')
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'msp.mspaccount': {
'Meta': {'object_name': 'MspAccount'},
'agc': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'token': ('django.db.models.fields.TextField', [], {}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': u"orm['portail_citoyen.Citoyen']", 'unique': 'True'})
},
u'portail_citoyen.citoyen': {
'Meta': {'object_name': 'Citoyen'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'backend': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'backend_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '128', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'mobile': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'phone': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '5', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'})
}
}
complete_apps = ['msp']

View File

@ -1,78 +0,0 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'MspAccount.user'
db.alter_column(u'msp_mspaccount', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['portail_citoyen.Citoyen'], unique=True, null=True, on_delete=models.SET_NULL))
def backwards(self, orm):
# User chose to not deal with backwards NULL issues for 'MspAccount.user'
raise RuntimeError("Cannot reverse this migration. 'MspAccount.user' and its values cannot be restored.")
# The following code is provided here to aid in writing a correct migration
# Changing field 'MspAccount.user'
db.alter_column(u'msp_mspaccount', 'user_id', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['portail_citoyen.Citoyen'], unique=True))
models = {
u'auth.group': {
'Meta': {'object_name': 'Group'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
u'auth.permission': {
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
u'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
u'msp.mspaccount': {
'Meta': {'object_name': 'MspAccount'},
'agc': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'token': ('django.db.models.fields.TextField', [], {}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'default': 'None', 'to': u"orm['portail_citoyen.Citoyen']", 'unique': 'True', 'null': 'True', 'on_delete': 'models.SET_NULL'})
},
u'portail_citoyen.citoyen': {
'Meta': {'object_name': 'Citoyen'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'backend': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'backend_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '128', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'mobile': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'phone': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '5', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'})
}
}
complete_apps = ['msp']

View File

@ -5,10 +5,10 @@
{% block content %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/domready.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/getElementsByClassName-1.0.1.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/oauth.js" %}"></script>{% endaddtoblock %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'authentic2_auth_msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/domready.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/getElementsByClassName-1.0.1.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/oauth.js" %}"></script>{% endaddtoblock %}
<div id="msp-confirm-unlink">
<div class="msp">
<div class="cadre">

View File

@ -1,10 +1,10 @@
{% load staticfiles %}
{% load sekizai_tags %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/domready.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/getElementsByClassName-1.0.1.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/oauth.js" %}"></script>{% endaddtoblock %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'authentic2_auth_msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/domready.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/getElementsByClassName-1.0.1.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/oauth.js" %}"></script>{% endaddtoblock %}
{% comment %}
Emprunté sur caf.fr
@ -22,7 +22,7 @@ Emprunté sur caf.fr
<p>
<strong class="fz">
Nouveau&nbsp;: connectez-vous avec
<img src="{% static "msp/img/mon_service-public.fr_petit.png" %}" width="100" height="25" alt="mon.service-public.fr" />
<img src="{% static "authentic2_auth_msp/img/mon_service-public.fr_petit.png" %}" width="100" height="25" alt="mon.service-public.fr" />
</strong>
</p>
<p class="lien">

View File

@ -5,7 +5,7 @@
{% block content %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'authentic2_auth_msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
<div id="msp-link-management">
<div class="msp">
<div class="cadre">
@ -52,7 +52,7 @@
<p>
<a href="{% url "msp-confirm-unlink" %}?next={{ next }}" class="marges user">Supprimer toutes les liaisons</a>
<img src="{% static "msp/img/mon_service-public.fr.png" %}" width="125" height="30" alt="mon.service-public.fr" />
<img src="{% static "authentic2_auth_msp/img/mon_service-public.fr.png" %}" width="125" height="30" alt="mon.service-public.fr" />
</p>
</div>
<div class="menu">
@ -61,7 +61,7 @@
<h2>Qu&rsquo;est-ce que mon.service-public.fr&nbsp;?</h2>
<p> Simplifiez votre relation avec les services publics, acc&eacute;dez à une information adapt&eacute;e &agrave; votre cas personnel, r&eacute;alisez et suivez vos d&eacute;marches administratives en ligne. </p>
<p class="centrer">
<img src="{% static "msp/img/mon_service-public.fr.png" %}" width="125" height="30" alt="mon.service-public.fr" />
<img src="{% static "authentic2_auth_msp/img/mon_service-public.fr.png" %}" width="125" height="30" alt="mon.service-public.fr" />
</p>
<p class="lien">
<a href="https://mon.service-public.fr/portail/app/cms/public/a_propos_du_site" class="roll" target="_blank">En savoir plus</a>

View File

@ -2,18 +2,18 @@
{% load sekizai_tags %}
{% load staticfiles %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/domready.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/getElementsByClassName-1.0.1.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "msp/js/oauth.js" %}"></script>{% endaddtoblock %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'authentic2_auth_msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/domready.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/getElementsByClassName-1.0.1.js" %}"></script>{% endaddtoblock %}
{% addtoblock "js" %}<script type="text/javascript" src="{% static "authentic2_auth_msp/js/oauth.js" %}"></script>{% endaddtoblock %}
<div id="msp-linking">
{% if user.is_authenticated and user.mspaccount and user.mspaccount.refresh_token %}
<div class="msp">
<div class="cadre">
<p class="centrer">
<img src="{% static "msp/img/toutes_vos_demarches.png" %}" width="140" height="35" alt="Vous &ecirc;tes actuellement en connexion avec" />
<img src="{% static "msp/img/mon_service-public.fr.png" %}" width="125" height="30" alt="mon.Service-Public.fr" />
<img src="{% static "authentic2_auth_msp/img/toutes_vos_demarches.png" %}" width="140" height="35" alt="Vous &ecirc;tes actuellement en connexion avec" />
<img src="{% static "authentic2_auth_msp/img/mon_service-public.fr.png" %}" width="125" height="30" alt="mon.Service-Public.fr" />
</p>
<ul class="fond">
<li class="picto">
@ -33,8 +33,8 @@
<div class="msp" style="width: 300px">
<div class="cadre">
<p class="centrer">
<img src="{% static "msp/img/toutes_vos_demarches.png" %}" width="140" height="35" alt="Vous &ecirc;tes actuellement en connexion avec" />
<img src="{% static "msp/img/mon_service-public.fr.png" %}" width="125" height="30" alt="mon.service-public.fr" />
<img src="{% static "authentic2_auth_msp/img/toutes_vos_demarches.png" %}" width="140" height="35" alt="Vous &ecirc;tes actuellement en connexion avec" />
<img src="{% static "authentic2_auth_msp/img/mon_service-public.fr.png" %}" width="125" height="30" alt="mon.service-public.fr" />
</p>
<ul class="fond">
<li class="picto">

View File

@ -5,7 +5,7 @@
{% block content %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
{% addtoblock "css" %}<link rel="stylesheet" type="text/css" href="{% static 'authentic2_auth_msp/css/screen.msp.css' %}"></link>{% endaddtoblock %}
<div class="msp">
<div class="cadre">
<div class="bordure">

View File

@ -1,16 +1,26 @@
from django.conf.urls import patterns, url
from django.conf.urls import patterns, url, include
urlpatterns = patterns('portail_citoyen.apps.msp.views',
url(r'^login/$', 'login', name='msp-login'),
url(r'^link/$', 'link', name='msp-link'),
url(r'^login-or-link/$', 'login_or_link', name='msp-login-or-link'),
url(r'^link-management/$', 'link_management', name='msp-link-management'),
url(r'^link-management/unlink/confirm/$', 'confirm_unlink', name='msp-confirm-unlink'),
url(r'^link-management/unlink/done/$', 'unlink_done', name='msp-unlink-done'),
url(r'^link-management/unlink/$', 'unlink', name='msp-unlink'),
url(r'^authorize/$', 'authorize', name='msp-authorize'),
url(r'^access_token/$', 'access_token', name='msp-access-token'),
url(r'^documents/$', 'documents', name='msp-documents'),
url(r'^documents/(?P<doc_id>[^/]*)/$', 'document', name='msp-document'),
url(r'^more/$', 'more_redirect', name='msp-more-redirect'),
from . import views
msppatterns = patterns('',
url(r'^login/$', views.login, name='msp-login'),
url(r'^link/$', views.link, name='msp-link'),
url(r'^login-or-link/$', views.login_or_link, name='msp-login-or-link'),
url(r'^link-management/$', views.link_management,
name='msp-link-management'),
url(r'^link-management/unlink/confirm/$', views.confirm_unlink,
name='msp-confirm-unlink'),
url(r'^link-management/unlink/done/$', views.unlink_done,
name='msp-unlink-done'),
url(r'^link-management/unlink/$', views.unlink, name='msp-unlink'),
url(r'^authorize/$', views.authorize, name='msp-authorize'),
url(r'^access_token/$', views.access_token, name='msp-access-token'),
url(r'^documents/$', views.documents, name='msp-documents'),
url(r'^documents/(?P<doc_id>[^/]*)/$', views.document,
name='msp-document'),
url(r'^more/$', views.more_redirect, name='msp-more-redirect'),
)
urlpatterns = patterns('',
url(r'^msp/', include(msppatterns)),
)

View File

@ -9,6 +9,7 @@ import json
from requests_oauthlib import OAuth2Session
from django.core.urlresolvers import reverse
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View, RedirectView
@ -25,8 +26,10 @@ from django.conf import settings
from django.core.cache import InvalidCacheBackendError, get_cache
from django.views.decorators.clickjacking import xframe_options_exempt
from . import app_settings, models
def user_has_mspaccount(user):
'''Return True if user a link to MSP'''
try:
@ -34,18 +37,22 @@ def user_has_mspaccount(user):
except models.MspAccount.DoesNotExist:
return False
mspaccount_required = user_passes_test(user_has_mspaccount, '/')
logger = logging.getLogger(__name__)
try:
cache = get_cache('msp')
except InvalidCacheBackendError:
cache = get_cache('default')
CACHE_TIMEOUT = 60
def ask_authorization(request, scopes):
'''Compute an authorize URL for obtaining the given scope'''
if not isinstance(scopes, (list, tuple)):
@ -62,7 +69,9 @@ def ask_authorization(request, scopes):
urllib.urlencode(params))
return HttpResponseRedirect(url)
def resolve_access_token(authorization_code, redirect_uri):
'''Exchange an authorization_code for an access_token'''
data = {
'code': authorization_code,
'client_id': app_settings.client_id,
@ -75,6 +84,7 @@ def resolve_access_token(authorization_code, redirect_uri):
cert=app_settings.client_certificate)
return response.json()
def access_token_from_request(request):
'''Resolve an access token given a request returning from the authorization
endpoint.
@ -87,9 +97,12 @@ def access_token_from_request(request):
redirect_uri = request.GET['redirect_uri']
return resolve_access_token(authorization_code, redirect_uri)
ACCESS_GRANT_CODE = 'accessgrantcode'
class MspOAuthSessionViewMixin(object):
'''Add the OAuth2 dance to a view'''
scopes = []
redirect_field_name = REDIRECT_FIELD_NAME
in_popup = False
@ -163,6 +176,7 @@ class PopupViewMixin(object):
return 'popup' in self.request.REQUEST
class LoginView(PopupViewMixin, MspOAuthSessionViewMixin, View):
'''Authenticate an user with MSP'''
scopes = [ 'GET_AGC', 'DELETE_AGC' ]
def dispatch(self, request, *args, **kwargs):
@ -183,6 +197,7 @@ class LoginView(PopupViewMixin, MspOAuthSessionViewMixin, View):
login = LoginView.as_view()
class LinkView(PopupViewMixin, MspOAuthSessionViewMixin, View):
'''Link current user to its MSP account'''
scopes = [ 'GET_AGC', 'DELETE_AGC' ]
def dispatch(self, request, *args, **kwargs):
@ -207,6 +222,7 @@ class LinkView(PopupViewMixin, MspOAuthSessionViewMixin, View):
link = LinkView.as_view()
class UnlinkView(PopupViewMixin, MspOAuthSessionViewMixin, TemplateView):
'''Delete link with user MSP account'''
scopes = [ 'DELETE_AGC' ]
def get(self, request, *args, **kwargs):
@ -230,6 +246,11 @@ class UnlinkView(PopupViewMixin, MspOAuthSessionViewMixin, TemplateView):
unlink = login_required(UnlinkView.as_view())
class AuthorizeView(View):
'''OAuth2/MSP proxy authorization view.
It works exactly like MSP authorization endpoint but hide the real
access token and allocate a pseudonym instead.
'''
def get(self, request, *args, **kwargs):
GET = request.GET
if 'code' in GET:
@ -299,6 +320,11 @@ class AuthorizeView(View):
authorize = xframe_options_exempt(AuthorizeView.as_view())
class AccessToken(View):
'''OAuth2/MSP proxy access token view.
It works exactly like MSP authorization endpoint but hide the real
access token and allocate a pseudonym instead.
'''
def post(self, request, *args, **kwargs):
try:
return self.access_token(request, *args, **kwargs)
@ -349,6 +375,7 @@ access_token = csrf_exempt(AccessToken.as_view())
class BearerTokenUnauthorized(HttpResponse):
'''Customized error to when web-service OAuth2 authentication fails'''
status_code = 401
def __init__(self, error=None):
@ -360,6 +387,8 @@ class BearerTokenUnauthorized(HttpResponse):
class OAuth2ProxyView(View):
'''Base class to implement proxy view toward MSP resource endpoints
protected by OAuth2 bearer authentication'''
def dispatch(self, request, *args, **kwargs):
# enforce Bearer authentication
authorization = request.META.get('HTTP_AUTHORIZATION')
@ -388,6 +417,7 @@ class OAuth2ProxyView(View):
class DocumentsView(OAuth2ProxyView):
'''Proxy to the list of documents resource of MSP'''
scopes = [ 'LIST_DOCS' ]
def get(self, request, *args, **kwargs):
@ -399,6 +429,7 @@ documents = DocumentsView.as_view()
class DocumentView(OAuth2ProxyView):
'''Proxy to the document resource of MSP'''
scopes = [ 'GET_DOC' ]
def get(self, request, *args, **kwargs):
@ -410,6 +441,10 @@ document = DocumentView.as_view()
class LoginOrLinkView(PopupViewMixin, MspOAuthSessionViewMixin, View):
'''Login with MSP, if the MSP account is already linked, connect this user,
if a user is logged link the user to this account, otherwise display an
error message.
'''
scopes = [ 'GET_AGC', 'DELETE_AGC' ]
def get(self, request, *args, **kwargs):
@ -442,6 +477,7 @@ class LoginOrLinkView(PopupViewMixin, MspOAuthSessionViewMixin, View):
login_or_link = LoginOrLinkView.as_view()
class TemplateWithNextUrlView(TemplateView):
'''Mixin to pass a next URL variable to templates'''
def get_context_data(self, **kwargs):
ctx = super(TemplateWithNextUrlView, self).get_context_data(**kwargs)
ctx['next'] = self.request.GET.get('next') or \