summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Marillonnet <pmarillonnet@entrouvert.com>2017-06-29 15:51:03 (GMT)
committerPaul Marillonnet <pmarillonnet@entrouvert.com>2017-06-29 15:51:03 (GMT)
commit514dfee6f98b6e016076d1dbeff5e2b707b5cbf6 (patch)
tree1799a367f219da908e37cadcb92ac98e011349a6
parent214c5fb3d87775ed6963616388c19bde92922e9f (diff)
downloadpaul-synchro-514dfee6f98b6e016076d1dbeff5e2b707b5cbf6.zip
paul-synchro-514dfee6f98b6e016076d1dbeff5e2b707b5cbf6.tar.gz
paul-synchro-514dfee6f98b6e016076d1dbeff5e2b707b5cbf6.tar.bz2
POC Campus Condorcet : code snapshot avant WF declare (inscription)
-rw-r--r--django/sp_sso/invite/forms.py28
-rw-r--r--django/sp_sso/invite/urls.py1
-rw-r--r--django/sp_sso/invite/utils.py6
-rw-r--r--django/sp_sso/invite/views.py31
-rw-r--r--django/sp_sso/saml/decorators.py43
-rw-r--r--django/sp_sso/saml/forms.py7
-rw-r--r--django/sp_sso/saml/models.py8
-rw-r--r--django/sp_sso/saml/urls.py2
-rw-r--r--django/sp_sso/saml/utils.py76
-rw-r--r--django/sp_sso/saml/views.py45
-rw-r--r--django/sp_sso/sp_sso/urls.py3
-rw-r--r--django/sp_sso/sp_sso/views.py31
-rw-r--r--django/sp_sso/templates/index.html6
-rw-r--r--django/sp_sso/templates/registration_form.html2
14 files changed, 139 insertions, 150 deletions
diff --git a/django/sp_sso/invite/forms.py b/django/sp_sso/invite/forms.py
index 7ca07a2..1b5f3bb 100644
--- a/django/sp_sso/invite/forms.py
+++ b/django/sp_sso/invite/forms.py
@@ -5,43 +5,43 @@ from .utils import get_invitaton_attributes_mapping, get_additional_prefilled_fi
class InvitationForm(forms.Form):
-
-
def __init__(self, *args, **kwargs):
super(InvitationForm, self).__init__(*args, **kwargs)
# Add a help text for sending multiple invitations
self.fields['email'].help_text = _(
_('Blank-separated emails if multiple adresses.'))
# Pre-filled fields are readonly
- for prefilled_field in get_invitaton_attributes_mapping().values() + get_additional_prefilled_fields():
+ for prefilled_field in get_invitaton_attributes_mapping().values() + \
+ get_additional_prefilled_fields():
if kwargs['initial'].get(prefilled_field):
self.fields[prefilled_field].widget.attrs['readonly'] = True
-
# Blank-seperated list of recipient email adresses
- email = forms.CharField(max_length=100, label=_('''Email address(es) where
- to send an invite'''))
+ email = forms.CharField(
+ max_length=100,
+ label=_('Email address(es) where to send an invite'))
# Invitation message that will be sent with the invite
message = forms.CharField(
- widget=forms.Textarea(), max_length=999, label=_("Invitation message"),
- required=False)
+ widget=forms.Textarea(), max_length=999,
+ label=_("Invitation message"), required=False)
+
# Host identity
# If the RENATER identity federation is used, this field will be pre-
# filled with the host's EPPN (EduPersonPrincalName)
hote_identite = forms.CharField(
- max_length=100, label=_("Your RENATER identifier"))
+ max_length=100, label=_("Your RENATER identifier"))
hote_nom = forms.CharField(
- max_length=100, label=_("Your lastname"))
+ max_length=100, label=_("Your lastname"))
hote_prenom = forms.CharField(
- max_length=100, label=_("Your firstname"))
+ max_length=100, label=_("Your firstname"))
hote_etablissement = forms.CharField(
- max_length=100, label=_("Your institution"))
+ max_length=100, label=_("Your institution"))
hote_unite = forms.CharField(
- max_length=100, label=_("Your research unit"))
+ max_length=100, label=_("Your research unit"))
hote_courriel = forms.CharField(
- max_length=100, label=_("Your email address"))
+ max_length=100, label=_("Your email address"))
diff --git a/django/sp_sso/invite/urls.py b/django/sp_sso/invite/urls.py
index 55ca8e2..133077f 100644
--- a/django/sp_sso/invite/urls.py
+++ b/django/sp_sso/invite/urls.py
@@ -6,5 +6,4 @@ from saml.decorators import user_in_ldap
urlpatterns = [
url(r'^$', user_in_ldap(views.InvitationFormView.as_view()), name='invitation'),
url(r'^sent/$', views.invitation_sent , name='sent'),
- url(r'^not_registered/$', views.not_registered , name='not_registered'),
]
diff --git a/django/sp_sso/invite/utils.py b/django/sp_sso/invite/utils.py
index dbe2ac5..5cc40fd 100644
--- a/django/sp_sso/invite/utils.py
+++ b/django/sp_sso/invite/utils.py
@@ -1,4 +1,5 @@
import json
+import logging
from urllib2 import build_opener, HTTPHandler, Request, urlopen
@@ -17,6 +18,8 @@ ADDITIONAL_PREFILLED_FIELDS = ['hote_etablissement', 'hote_unite']
PASSERELLE_PEOPLE_QUERY = 'http://dir-condorcet.dev.entrouvert.org/ldapquery/condorcet/run/6/'
+logger = logging.getLogger('django')
+
def get_invitaton_attributes_mapping():
return INVITATION_ATTRIBUTES_MAPPING.copy()
@@ -56,5 +59,6 @@ def get_affectations_from_eppn(eppn):
user['attributes'].get('supannEntiteAffectation', [''])[0])
raise Exception('Invalid user')
# fall back in except block
- except:
+ except Exception, e:
+ logger.error('%s' % e)
return ('', '')
diff --git a/django/sp_sso/invite/views.py b/django/sp_sso/invite/views.py
index 463f450..e996799 100644
--- a/django/sp_sso/invite/views.py
+++ b/django/sp_sso/invite/views.py
@@ -1,30 +1,27 @@
import logging
from django.views.generic import FormView
-from django.shortcuts import render, redirect
from django.utils.translation import ugettext as _
from .forms import InvitationForm
-from .utils import do_invite, get_invitaton_attributes_mapping, get_affectations_from_eppn
+from .utils import do_invite, get_invitaton_attributes_mapping, \
+ get_affectations_from_eppn
+
+from saml.utils import render_message
logger = logging.getLogger('django')
+MSG_INVITATION_SENT = _("Your invitation has been sent.")
+
def invitation_sent(request):
- return render(
- request, 'simple_message.html',
- {'message':_("Your invitation has been sent.")})
+ return render_message(request, MSG_INVITATION_SENT)
-def not_registered(request):
- return render(
- request, 'simple_message.html',
- {'message':_("Please register to the campus before sending invites.")})
-#TODO login_required dans les urls
class InvitationFormView(FormView):
form_class = InvitationForm
template_name = 'invite/invitation_form.html'
- success_url = '/invite/sent' # Mandatory?
+ success_url = '/invite/sent'
def get_initial(self):
initial = super(InvitationFormView, self).get_initial()
@@ -40,12 +37,13 @@ class InvitationFormView(FormView):
attribute_element = data.get(attribute_key)[0]
initial[attribute_value] = attribute_element
- etablissement, unite = get_affectations_from_eppn(data.get('ep_principal_name',[None])[0])
+ etablissement, unite = get_affectations_from_eppn(
+ data.get('ep_principal_name',[None])[0])
initial['hote_etablissement'] = etablissement
initial['hote_unite'] = unite
initial['hote_commentaire'] = '''EduPersonPrincipalName de
- l\'invitant'''
+ l\'invitant'''
return initial
def form_valid(self, form):
@@ -53,13 +51,6 @@ class InvitationFormView(FormView):
post_dict = self.request.POST
logger.info("Invitation POST data : {}".format(''))
- hote_identite = post_dict.get('hote_identite')
-
- # User cannot invite if she's not in the destination directory yet
- """if not hote_identite or not ldap_contains_user(
- {'ep_principal_name':hote_identite}):
- return redirect('not_registered')"""
-
# Craft any relevant invitation data
for form_attribute in self.form_class.base_fields.keys():
sanitized_form_entry = post_dict.get(form_attribute, False)
diff --git a/django/sp_sso/saml/decorators.py b/django/sp_sso/saml/decorators.py
index 575392f..d28d9f2 100644
--- a/django/sp_sso/saml/decorators.py
+++ b/django/sp_sso/saml/decorators.py
@@ -1,15 +1,30 @@
+import logging
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
+from django.utils.translation import ugettext as _
-from .utils import ldap_contains_user, saml_collect_data
+from .utils import ldap_contains_user, saml_collect_data, \
+ ldap_get_affectations, render_message
+from .views import MSG_USERNONE
+
+logger = logging.getLogger('django')
+
+MSG_USER_REGISTERED = _("Your account is already registered to the Campus.")
+
+MSG_STRUCT_NOT_IN_CAMPUS = _(
+ "Your institution and research unit aren't declared to the Campus.")
+
+MSG_USER_NOT_REGISTERED = _(
+ "Please register to the campus before sending invites.")
def user_not_in_ldap(function):
def wrapped(request, *args, **kwargs):
if 'type' in kwargs and kwargs['type'] == 'mellon':
user_data = saml_collect_data(request)
if ldap_contains_user(user_data):
- return redirect('usernone')
+ logger.info(u'usernone error for request %s' % request)
+ return render_message(request, MSG_USERNONE)
return function(request, *args, **kwargs)
return wrapped
@@ -19,6 +34,28 @@ def user_in_ldap(function):
return redirect(reverse('auth_login') + "?next=/invite/")
user_data = saml_collect_data(request)
if not ldap_contains_user(user_data):
- return redirect('not_registered')
+ logger.info(u'user not registered error for request %s' % request)
+ return render_message(request, MSG_USER_NOT_REGISTERED)
return function(request, *args, **kwargs)
return wrapped
+
+def user_can_declare(function):
+ def wrapped(request, *args, **kwargs):
+ if not request.session.get('mellon_session'):
+ return redirect(reverse('auth_login') + '?next=/declare/')
+ user_data = saml_collect_data(request)
+
+ if ldap_contains_user(user_data):
+ return render_message(request, MSG_USER_REGISTERED)
+
+ affectations = [code for code, _ in ldap_get_affectations()]
+ try:
+ affectations.remove(None) # remove extra null entry
+ except:
+ pass
+ user_affectations = set([user_data.get('s_etablissement'),
+ user_data.get('s_entite_affectation')])
+ if user_affectations & set(affectations):
+ return function(request, *args, **kwargs)
+ return render_message(request, MSG_STRUCT_NOT_IN_CAMPUS)
+ return wrapped
diff --git a/django/sp_sso/saml/forms.py b/django/sp_sso/saml/forms.py
index b715c31..2fdbadd 100644
--- a/django/sp_sso/saml/forms.py
+++ b/django/sp_sso/saml/forms.py
@@ -1,7 +1,7 @@
from django.utils.translation import ugettext_lazy as _
from django import forms
from .utils import ldap_get_unites, ldap_get_etablissements, sso_attributes, \
- ldap_get_affectations, sso_select_attributes
+ sso_select_attributes
AFFILIATION_CHOICES = (
@@ -25,7 +25,6 @@ EMP_CORPS_CHOICES = (
('PROFESSEUR ASSOCIE', _('ASSOCIATE TEACHER')),
('PROFESSEUR DES UNIVERSITES', _('UNIVERSITY TEACHER')),
('MAITRE DE CONFERENCES DES UNIVERSITES', _('UNIVERSITY LECTURER')),
-
)
ETABLISSEMENT_CHOICES = ()
@@ -88,10 +87,6 @@ class RegistrationForm(forms.Form):
initial=True, required=False, label=_("Unlist contact information"))
# hote_* -> host attributes:
- #hote_prenom = forms.CharField(max_length=100, label=_("First name"))
- #hote_nom = forms.CharField(max_length=100, label=_("Last name"))
- #hote_identite = forms.CharField(
- # max_length=100, label=_("Identity (name or email address)"))
hote_etablissement = forms.ChoiceField(
required=False, choices=ldap_get_etablissements(),
label=_("Institution"), initial=None)
diff --git a/django/sp_sso/saml/models.py b/django/sp_sso/saml/models.py
index d061a63..0911263 100644
--- a/django/sp_sso/saml/models.py
+++ b/django/sp_sso/saml/models.py
@@ -2,13 +2,6 @@ from django.db import models
from django.contrib.auth.models import AbstractUser
-
-# Create your models here.
-class Unit(models.Model):
- name = models.CharField(max_length=100)
-
- # TODO enum ?
-
class SupAnnUser(AbstractUser):
# eduPerson attributes:
ep_principal_name = models.CharField(max_length=100,default='user_eppn')
@@ -22,4 +15,3 @@ class SupAnnUser(AbstractUser):
s_liste_rouge = models.BooleanField(default=False)
REQUIRED_FIELDS = []
- #USERNAME_FIELD = 'ep_principal_name'
diff --git a/django/sp_sso/saml/urls.py b/django/sp_sso/saml/urls.py
index 341aefd..8b95358 100644
--- a/django/sp_sso/saml/urls.py
+++ b/django/sp_sso/saml/urls.py
@@ -5,7 +5,5 @@ from .decorators import user_not_in_ldap
urlpatterns = [
url(r'^$', user_not_in_ldap(views.RegistrationFormView.as_view()), name='register'),
- url(r'^usernone/$', views.usernone, name='usernone'),
url(r'^wcs_post/$', views.wcs_post , name='wcs_post'),
-
]
diff --git a/django/sp_sso/saml/utils.py b/django/sp_sso/saml/utils.py
index 185c0e5..fc0e76b 100644
--- a/django/sp_sso/saml/utils.py
+++ b/django/sp_sso/saml/utils.py
@@ -5,6 +5,7 @@ import logging
from urllib2 import build_opener, urlopen, HTTPHandler, Request, HTTPError
from random import randint
from django.utils.translation import ugettext as _
+from django.shortcuts import render
rootdn = 'dc=condorcet,dc=dev,dc=entrouvert,dc=org'
people_base = 'ou=people,'+rootdn
@@ -27,14 +28,20 @@ supann_host_role_attribute = 'supannRoleGenerique'
supann_host_role_value = '{SUPANN}R10' # 'Responsable de mission'
+def render_message(request, message):
+ return render(request, 'simple_message.html', {'message': message})
+
+
def generate_eppn(lastname):
return "%s-%06d@campus-condorcet.fr"%(lastname, randint(0,pow(10,6)))
+
def craft_user_nickname(mellon_dict):
prenom = mellon_dict.get('prenom')[0]
nom = mellon_dict.get('nom')[0]
return " "+prenom+" "+nom
+
def ldap_init():
# The server's hostname:
server = "condorcet.dev.entrouvert.org"
@@ -52,20 +59,20 @@ def ldap_init():
return l
-# Used to fill the choices in hote_etablissemnt form ChoiceField:
def ldap_get_etablissements():
+# Used to fill the choices in hote_etablissemnt form ChoiceField:
return ldap_get_attribute_from_subtree_nodes(
structures_base, '(objectClass=supannOrg)', 'ou')
-# Used to fill the choices in hote_unite form ChoiceField:
def ldap_get_unites():
+# Used to fill the choices in hote_unite form ChoiceField:
return ldap_get_attribute_from_subtree_nodes(
structures_base, '(supannTypeEntite=*)', 'ou')
-# Used to fill the choices in s_entite_affectation_principale form ChoiceField:
def ldap_get_affectations():
+# Used to fill the choices in s_entite_affectation_principale form ChoiceField:
return ldap_get_attribute_from_subtree_nodes(
structures_base, '(objectClass=supannEntite)', 'supannCodeEntite')
@@ -151,6 +158,8 @@ def wcs_submit(user_data, posturl):
logger.error('HTTP error %d during WCS form submission'%(e.code))
def initial_from_tracking_code(tracking_code):
+ if not tracking_code:
+ return {}
base_url = "http://forms-condorcet.dev.entrouvert.org/api/code/"
tracking_url = base_url+tracking_code
try:
@@ -179,64 +188,3 @@ def initial_from_tracking_code(tracking_code):
return {}
return initial_response.get('fields', {})
-
-
-def grant_registration_approval_from_list(user_data, notify_list):
- if type(notify_list) != list:
- logger.error('Function argument type "%s" should be a list')
- return
-
- #posturl = '''http://forms-condorcet.dev.entrouvert.org/api/formdefs/
- # notification/submit'''
-
- form_var_host_email_address = {
- 'host_email_address': " ; ".join(notify_list)
- }
- user_data.update(form_var_host_email_address)
-
-def get_campus_registration_admin_email(user_data):
- return "pmarillonnet@entrouvert.com"
-
-# Registration approval emails will be filled in a backoffice form entry
-def grant_registration_approval_to_hosts(user_data):
-
- campusrdn = 'campuscondorcet'
- notify_to = []
-
- if user_data.get('hote_unite'):
- host_structure = user_data['hote_unite']
- else:
- host_structure = user_data.get('hote_etablissement')
-
- l_handle = ldap_init()
-
- if host_structure:
- structures_ldap_filter = '(ou=%s)'% \
- host_structure
- res_structures = l_handle.search(structures_base, scope,
- structures_ldap_filter)
- rtype_structures, rdata_structures = l_handle.result(res_structures, 0)
-
- #TODO
- additional_ldap_filter = '(supannEtablissement=%s)'% \
- host_structure
- elif user_data.get('hote_etablissement'):
- additional_ldap_filter = '(supannEtablissement=%s)'% \
- user_data['hote_etablissement']
- elif user_data.get('hote_identite'):
- additional_ldap_filter = '(eduPersonPrincipalName=%s)'% \
- user_data['hote_identite']
- else:
- additional_ldap_filter = '(supannEtablissement=%s)'% \
- campusrdn
-
- ldap_filter = '(&(objectClass=supannPerson)%s)'%additional_ldap_filter
-
- res_identite = l_handle.search(people_base, scope, ldap_filter)
- rtype_identite, rdata_identite = l_handle.result(res_identite, 1)
- ldap_terminate(l_handle)
-
- for host in rdata_identite:
- notify_to.append(host[1].get('mail')[0])
-
- return grant_registration_approval_from_list(user_data, notify_to)
diff --git a/django/sp_sso/saml/views.py b/django/sp_sso/saml/views.py
index 9674015..a344da9 100644
--- a/django/sp_sso/saml/views.py
+++ b/django/sp_sso/saml/views.py
@@ -1,43 +1,35 @@
import logging
from django.views.generic import FormView
-from django.shortcuts import render
from django.utils.translation import ugettext as _
-from django.utils.translation import ugettext_lazy as ugtl
from .forms import RegistrationForm
from .utils import ldap_contains_user, wcs_submit, sso_attributes, \
craft_user_nickname, generate_eppn, \
- initial_from_tracking_code#, grant_registration_approval_to_hosts
+ initial_from_tracking_code, render_message
-logger = logging.getLogger('django')
-# TODOs
-# export global config variables in settings.py
+MSG_WCS_POST = _("""Your account creation request has been sent. An
+ email summing up your request has just been sent to you. It
+ contains all the information needed for you to follow up
+ with the account creation process.""")
+
+MSG_USERNONE = _("""Your account has already been registered to the Campus
+ Condorcet account base.""")
-# Create your views here.
wcs_fields = [
'prenom', 'nom', 'email', 'ep_principal_name', 's_etablissement',
'ep_primary_affiliation', 's_entite_affectation_principale', 's_emp_corps',
's_liste_rouge', 'hote_etablissement', 'hote_unite', 'hote_commentaire']
-
wcs_multiple_fields = ['s_entite_affectation', 'ep_affiliation']
-def usernone(request):
- logger.info(u'User %s already registered to the LDAP user branch.',
- request.user)
- message = _("Your account has already been registered to the Campus "
- "Condorcet account base.")
- template = 'simple_message.html'
- return render(request, template, {'message' : message})
+
+logger = logging.getLogger('django')
+
def wcs_post(request):
- logger.info(u'Processing request %s', request)
- return render(request, 'simple_message.html',
- {'message': _("""Your account creation request has been sent. An
- email summing up your request has just been sent to you. It
- contains all the information needed for you to follow up
- with the account creation process.""")})
+ logger.info(u'Processing request %s' % request)
+ return render_message(request, MSG_WCS_POST)
class RegistrationFormView(FormView):
form_class = RegistrationForm
@@ -47,14 +39,14 @@ class RegistrationFormView(FormView):
def get_initial(self):
initial = super(RegistrationFormView, self).get_initial()
- if 'tracking_code' in self.request.session:
+ if self.request.session.get('tracking_code'):
initial.update(initial_from_tracking_code(
self.request.session['tracking_code']))
initial['user_help_msg'] = _("""Please check the entries below,
- fill in the empty fields and submit your account request."""
- )+_( "Reminder:")+initial.get('hote_courriel')+_(
- ' sent an invite with the following invitation message: "'
+ fill in the empty fields and submit your account request.\n
+ """)+_( "Reminder:")+initial.get('hote_courriel')+_(
+ ' sent an invite with the following invitation message:\n"'
) + initial['message'] + '"'
else:
initial['user_help_msg'] = _("Please fill in the empty fields and "
@@ -82,7 +74,7 @@ class RegistrationFormView(FormView):
if form_adequate_data['ep_principal_name'] \
and ldap_contains_user(form_adequate_data):
- return usernone(self.request)
+ return render_message(self.request, MSG_USERNONE)
else:
delimiter = ','
wcs_rest_data = {}
@@ -100,6 +92,5 @@ class RegistrationFormView(FormView):
wcs_rest_data['ep_principal_name'] = generate_eppn(
post_dict.get('nom',''))
- #grant_registration_approval_to_hosts(wcs_rest_data) # Now in wcs
wcs_submit(wcs_rest_data, posturl)
return super(RegistrationFormView, self).form_valid(form)
diff --git a/django/sp_sso/sp_sso/urls.py b/django/sp_sso/sp_sso/urls.py
index 9cb94ae..583eac9 100644
--- a/django/sp_sso/sp_sso/urls.py
+++ b/django/sp_sso/sp_sso/urls.py
@@ -2,11 +2,14 @@ from django.conf.urls import include, url
from django.contrib import admin
from . import views
+from saml.decorators import user_can_declare
urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^register/', include('saml.urls')),
url(r'^invite/', include('invite.urls'), name="invite"),
+ url(r'^declare/', user_can_declare(views.declare), name="declare"),
+ url(r'^declare/subscribed/$', views.subscribed, name='subscribed'),
url(r'^$', views.index),
url(r'^accounts/mellon/', include('mellon.urls')),
url(r'^logout/$', views.logout, name='auth_logout'),
diff --git a/django/sp_sso/sp_sso/views.py b/django/sp_sso/sp_sso/views.py
index 5f82c6e..6c3d449 100644
--- a/django/sp_sso/sp_sso/views.py
+++ b/django/sp_sso/sp_sso/views.py
@@ -3,8 +3,13 @@ from django.http import HttpResponseRedirect, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import logout as auth_logout
from django.contrib.auth import views as auth_views
+from django.utils.translation import ugettext as _
+from django.views.generic import FormView
from mellon.utils import get_idps
+from saml.forms import RegistrationForm
+from saml.utils import sso_attributes, craft_user_nickname, render_message
+
import urllib
import logging
@@ -30,5 +35,29 @@ def logout(request, next_page=None):
if any(get_idps()):
return HttpResponseRedirect(resolve_url('mellon_logout'))
auth_logout(request)
- next_page = '/login' # TODO IdP-initiated SLO
+ next_page = '/login'
return HttpResponseRedirect(next_page)
+
+def subscribed(request):
+ logger.info(u'Processing request %s', request)
+ return render_message(request, _("Subscribed."))
+
+class Declare(FormView):
+ form_class = RegistrationForm
+ template_name = 'declare_form.html'
+ success_url = '/declare/subscribed/'
+
+ def get_initial(self):
+ initial = super(Declare, self).get_initial()
+
+ if 'mellon_session' in self.request.session:
+ data = self.request.session['mellon_session']
+ for attribute in sso_attributes:
+ if data.get(attribute):
+ attribute_element = data.get(attribute)[0]
+ initial[attribute] = attribute_element
+ initial['user_nickname'] = craft_user_nickname(data)
+
+ return initial
+
+declare = Declare.as_view()
diff --git a/django/sp_sso/templates/index.html b/django/sp_sso/templates/index.html
index 8a204e7..64ad2b7 100644
--- a/django/sp_sso/templates/index.html
+++ b/django/sp_sso/templates/index.html
@@ -14,10 +14,12 @@
<div id="padding-left">&nbsp;</div>
<div id="centered-column">
<p style='text-align:center'>
-<h2>Invité</h2>
+<h2>Vous emménagez sur le site du Campus</h2>
+<a class='button inline' href="{% url "declare" %}">Vous inscrire</a><br/><br/>
+<h2>Vous êtes invité</h2>
<a class='button inline' href="{% url "auth_login" %}">{% trans "Register using your source institution account" %}</a><br/><br/>
<a class='button inline' href="{% url "register" %}">{% trans "Register using an empty form" %}</a><br/><br/>
-<h2>Invitant</h2>
+<h2>Vous souhaitez inviter</h2>
<a class='button inline' href="{% url "invitation" %}">{% trans "Send invites" %}</a><br/>
</div>
<div id="padding-right">&nbsp;</div>
diff --git a/django/sp_sso/templates/registration_form.html b/django/sp_sso/templates/registration_form.html
index 8a263ff..05c04a9 100644
--- a/django/sp_sso/templates/registration_form.html
+++ b/django/sp_sso/templates/registration_form.html
@@ -9,7 +9,7 @@
{% endif %}
{{ form.user_nickname }}<br><br>
-{{ form.user_help_msg }}<br><br>
+{{ form.user_help_msg|linebreaksbr }}<br><br>
<form action="{% url "register" %}" method="post">
{% csrf_token %}