summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--django/sp_sso/invite/forms.py16
-rw-r--r--django/sp_sso/invite/utils.py13
-rw-r--r--django/sp_sso/invite/views.py10
-rw-r--r--django/sp_sso/saml/decorators.py16
-rw-r--r--django/sp_sso/saml/forms.py6
-rw-r--r--django/sp_sso/saml/models.py8
-rw-r--r--django/sp_sso/saml/tests.py1
-rw-r--r--django/sp_sso/saml/utils.py17
-rw-r--r--django/sp_sso/sp_sso/views.py17
-rw-r--r--misc/resume_technique7
-rw-r--r--report/draft_report004.odtbin75542 -> 76502 bytes
-rw-r--r--report/draft_report006.odtbin0 -> 840182 bytes
-rw-r--r--report/draft_report007.odtbin0 -> 840331 bytes
-rw-r--r--report/draft_report008.odtbin0 -> 1084879 bytes
-rw-r--r--report/draft_report009.odtbin0 -> 1310826 bytes
-rw-r--r--report/draft_report010.odtbin0 -> 1445299 bytes
-rw-r--r--soutenance/texte13
17 files changed, 121 insertions, 3 deletions
diff --git a/django/sp_sso/invite/forms.py b/django/sp_sso/invite/forms.py
index 1b5f3bb..0736a3c 100644
--- a/django/sp_sso/invite/forms.py
+++ b/django/sp_sso/invite/forms.py
@@ -5,7 +5,23 @@ from .utils import get_invitaton_attributes_mapping, get_additional_prefilled_fi
class InvitationForm(forms.Form):
+ """ Used when sending invites to the Campus
+
+ Invites are sent to the `email` field. Multiple adresses are handled if
+ they are separated by a blank space ` ` character.
+
+ This form is restricted to users having previously registered to the
+ Campus ; therefore they must log in to their RENATER-federated account
+ before accessing the form.
+ """
def __init__(self, *args, **kwargs):
+ """
+ Attributes fetched from the identity provider are used to pre-fill
+ the fields.
+ An extra hidden field is used to store the user's
+ eduPersonPrincipalName, used as key identity attribute in the
+ corresponding LDAP entry.
+ """
super(InvitationForm, self).__init__(*args, **kwargs)
# Add a help text for sending multiple invitations
self.fields['email'].help_text = _(
diff --git a/django/sp_sso/invite/utils.py b/django/sp_sso/invite/utils.py
index 5cc40fd..4f49b39 100644
--- a/django/sp_sso/invite/utils.py
+++ b/django/sp_sso/invite/utils.py
@@ -21,12 +21,21 @@ PASSERELLE_PEOPLE_QUERY = 'http://dir-condorcet.dev.entrouvert.org/ldapquery/con
logger = logging.getLogger('django')
def get_invitaton_attributes_mapping():
+ """ Full copy of the invitation attributes mapping dictionary """
return INVITATION_ATTRIBUTES_MAPPING.copy()
def get_additional_prefilled_fields():
+ """
+ Returns a full copy of the additional fields to be prefilled with the
+ user's fetched attributes.
+ """
return ADDITIONAL_PREFILLED_FIELDS[:]
def do_invite(invitation):
+ """
+ Sends invitation data to the invitation w.c.s. form.
+ Invitations will then be sent as part of the w.c.s. workflow.
+ """
opener = build_opener(HTTPHandler)
# Generate a JSON to bind against the wcs ReST API
form = {}
@@ -48,6 +57,10 @@ def do_invite(invitation):
def get_affectations_from_eppn(eppn):
+ """
+ Returns a tuple (<Institution identifier>, <Researcher unit identifier>)
+ for a given eduPersonPrincipalName (a.k.a. `eppn`)
+ """
if eppn:
try:
ldapquery = urlopen(PASSERELLE_PEOPLE_QUERY)
diff --git a/django/sp_sso/invite/views.py b/django/sp_sso/invite/views.py
index e5b21fd..ce85b63 100644
--- a/django/sp_sso/invite/views.py
+++ b/django/sp_sso/invite/views.py
@@ -15,10 +15,20 @@ MSG_INVITATION_SENT = _("Your invitation has been sent.")
def invitation_sent(request):
+ """
+ Notifies the user about her invitation(s) by displaying a validation
+ message.
+ """
return render_message(request, MSG_INVITATION_SENT)
class InvitationFormView(FormView):
+ """
+ Main FormView for the invitation process.
+
+ Gathers SSO attributes from the identity provider, used to pre-fill and
+ set as readonly the `InvitationForm` fields.
+ """
form_class = InvitationForm
template_name = 'invite/invitation_form.html'
success_url = '/invite/sent'
diff --git a/django/sp_sso/saml/decorators.py b/django/sp_sso/saml/decorators.py
index 518ee87..91eda4f 100644
--- a/django/sp_sso/saml/decorators.py
+++ b/django/sp_sso/saml/decorators.py
@@ -18,6 +18,10 @@ MSG_USER_NOT_REGISTERED = _("Please register to the campus before sending "
"invites.")
def user_not_in_ldap(function):
+ """
+ Restricts access to users whose eduPersonPrincipalName attribute value
+ doesn't appear in a ou=people sub-entry in the Campus LDAP.
+ """
def wrapped(request, *args, **kwargs):
if 'type' in kwargs and kwargs['type'] == 'mellon':
user_data = saml_collect_data(request)
@@ -28,6 +32,10 @@ def user_not_in_ldap(function):
return wrapped
def user_in_ldap(function):
+ """
+ Restricts access to users whose eduPersonPrincipalName attribute value
+ appear in a `ou=people...` sub-entry in the Campus LDAP.
+ """
def wrapped(request, *args, **kwargs):
if not 'mellon_session' in request.session:
return redirect(reverse('auth_login') + "?next=/invite/")
@@ -39,6 +47,14 @@ def user_in_ldap(function):
return wrapped
def user_can_declare(function):
+ """
+ Ensure that all conditions are met for a user to self-subscribe to the
+ Campus. At the moment, these two conditions are:
+ - the user's EduPersonPrincipalName attribute value mustn't appear in the
+ Campus LDAP base
+ - the user's institution or research unit should appear as registered
+ structures in the Campus LDAP base
+ """
def wrapped(request, *args, **kwargs):
if not request.session.get('mellon_session'):
return redirect(reverse('auth_login') + '?next=/declare/')
diff --git a/django/sp_sso/saml/forms.py b/django/sp_sso/saml/forms.py
index dc1c583..90c452f 100644
--- a/django/sp_sso/saml/forms.py
+++ b/django/sp_sso/saml/forms.py
@@ -53,7 +53,13 @@ ETABLISSEMENT_CHOICES = ()
UNITE_CHOICES = ()
class RegistrationForm(forms.Form):
+ """
+ Main registration form when requesting access to the Campus.
+ User data may be fetched for a single sign-on (SSO) procedure and used to
+ pre-fill the fields. Pre-filled fields are also set as readonly to ensure
+ that the data fetched from the SSO process and sent to w.c.s. is genuine.
+ """
user_help_msg = ''
user_nickname = ''
diff --git a/django/sp_sso/saml/models.py b/django/sp_sso/saml/models.py
index 0911263..ea5429b 100644
--- a/django/sp_sso/saml/models.py
+++ b/django/sp_sso/saml/models.py
@@ -3,6 +3,14 @@ from django.contrib.auth.models import AbstractUser
class SupAnnUser(AbstractUser):
+ """ Base user of the SSO scheme. OBSOLETE
+
+ eduPerson and supann2009 attributes have been added so that theses
+ attributes can be retrieved in mellon.
+
+ XXX mellon attributes are also stored in the session.
+ (see the request.session['mellon_session'] dict)
+ """
# eduPerson attributes:
ep_principal_name = models.CharField(max_length=100,default='user_eppn')
ep_primary_affiliation = models.CharField(max_length=100, default="")
diff --git a/django/sp_sso/saml/tests.py b/django/sp_sso/saml/tests.py
index e94c8ec..8134add 100644
--- a/django/sp_sso/saml/tests.py
+++ b/django/sp_sso/saml/tests.py
@@ -5,6 +5,7 @@ import requests
# Create your tests here.
class ServicesTestCase(TestCase):
+ """Ensure that all four services are up and running."""
def test_ldap_connection(self):
l = ldap_init()
self.assertTrue(l)
diff --git a/django/sp_sso/saml/utils.py b/django/sp_sso/saml/utils.py
index 5ff3502..5e5768b 100644
--- a/django/sp_sso/saml/utils.py
+++ b/django/sp_sso/saml/utils.py
@@ -29,9 +29,17 @@ supann_host_role_value = '{SUPANN}R10' # 'Responsable de mission'
def render_message(request, message):
+ """Renders a simple message to a base template"""
return render(request, 'simple_message.html', {'message': message})
def generate_eppn(lastname):
+ """
+ Used when no eduPersonPrincipalName attribute is fetched from the
+ identity provider during the single sign-on process.
+
+ Returns a randomly generated EPPN value in the form of a valid Campus
+ Condorcet email address.
+ """
return "%s-%06d@campus-condorcet.fr"%(lastname, randint(0,pow(10,6)))
@@ -59,19 +67,22 @@ def ldap_init():
def ldap_get_etablissements():
-# Used to fill the choices in hote_etablissemnt form ChoiceField:
+ """Used to fill the choices in hote_etablissemnt form ChoiceField."""
return ldap_get_attribute_from_subtree_nodes(
structures_base, '(objectClass=supannOrg)', 'ou')
def ldap_get_unites():
-# Used to fill the choices in hote_unite form ChoiceField:
+ """Used to fill the choices in hote_unite form ChoiceField."""
return ldap_get_attribute_from_subtree_nodes(
structures_base, '(supannTypeEntite=*)', 'ou')
def ldap_get_affectations():
-# Used to fill the choices in s_entite_affectation_principale form ChoiceField:
+ """
+ Used to fill the choices in s_entite_affectation_principale form
+ ChoiceField.
+ """
return ldap_get_attribute_from_subtree_nodes(
structures_base, '(objectClass=supannEntite)', 'supannCodeEntite')
diff --git a/django/sp_sso/sp_sso/views.py b/django/sp_sso/sp_sso/views.py
index e87aea8..3448150 100644
--- a/django/sp_sso/sp_sso/views.py
+++ b/django/sp_sso/sp_sso/views.py
@@ -20,6 +20,7 @@ logger = logging.getLogger('sp_sso.resource')
@csrf_exempt
def index(request):
+ """Main view for the service provider"""
if request.method != 'GET':
return HttpResponse('Bad method.', status=405)
request.session['tracking_code'] = request.GET.get('tracking_code')
@@ -27,6 +28,7 @@ def index(request):
return render(request, 'index.html', locals())
def login(request, *args, **kwargs):
+ """Defers the login scheme to the identity provider thanks to mellon"""
if any(get_idps()):
if not 'next' in request.GET:
return HttpResponseRedirect(resolve_url('mellon_login'))
@@ -35,6 +37,7 @@ def login(request, *args, **kwargs):
return auth_views.login(request, *args, **kwargs)
def logout(request, next_page=None):
+ """Defers the logout scheme to the identity provider thanks to mellon"""
if any(get_idps()):
return HttpResponseRedirect(resolve_url('mellon_logout'))
auth_logout(request)
@@ -42,10 +45,24 @@ def logout(request, next_page=None):
return HttpResponseRedirect(next_page)
def subscribed(request):
+ """Success view for the self-subscription process"""
logger.info(u'Processing request %s', request)
return render_message(request, _("Subscribed."))
class Declare(FormView):
+ """Self-subscription FormView
+
+ Users allowed to self-subscribe to the Campus MUSTN'T be registered to the
+ Campus LDAP directory yet. (Presence checking is performed against their
+ eduPersonPrincipalName).
+
+ Additionnally, their institution (supannEtablissement) or research unit
+ (supannEntiteAffectation) MUST be declared in the Campus database.
+
+ These restrictions are processed thanks to the `user_can_declare`
+ decorator.
+
+ """
form_class = RegistrationForm
template_name = 'declare_form.html'
success_url = '/declare/subscribed/'
diff --git a/misc/resume_technique b/misc/resume_technique
new file mode 100644
index 0000000..cfbecac
--- /dev/null
+++ b/misc/resume_technique
@@ -0,0 +1,7 @@
+Rapport de stage chez Entr'ouvert : État de l'art des systèmes d'approvisionnement et de synchronisation des bases d'identités numériques et mise en oeuvre de démonstrateurs
+
+Ce rapport de stage s'incrit dans la thématique de la gestion des identités numériques, en particulier des mécanismes de constitution de référentiels d'identité.
+Une étude des mécanismes d'approvisionnement et de synchronisation de ces référentiels a été effectuée. Un examen théorique et pratique des différentes solutions libres assurant ces fonctionnalités a ensuite été réalisé.
+Une seconde étude, plus générale, traitant de la littérature relative aux différents mécanismes et technologies de la gestion des identités numériques, a été réalisée et complétée tout au long de ce projet de fin d'études.
+Dans le cadre de ces travaux, ce document contient aussi une étude relative à l'outil LSC (LDAP Synchronization Connector).
+Après séléction d'un scénario de synchronisation pertinent pour une application effective, ce rapport explique la démarche adoptée pour le développement d'un démonstrateur. Ce démonstrateur, de type 'Preuve de concept' (POC), a été développé sous licence libre à l'aide du framework Web Django. Le déploiement des différentes briques logicielles (annuaire, fournisseur d'identités, connecteurs et gestionnaire de formulaires et de workflows) nécessaires au déploiement du démonstrateur est aussi expliqué dans ce document.
diff --git a/report/draft_report004.odt b/report/draft_report004.odt
index ea3202c..3921f50 100644
--- a/report/draft_report004.odt
+++ b/report/draft_report004.odt
Binary files differ
diff --git a/report/draft_report006.odt b/report/draft_report006.odt
new file mode 100644
index 0000000..0a77f55
--- /dev/null
+++ b/report/draft_report006.odt
Binary files differ
diff --git a/report/draft_report007.odt b/report/draft_report007.odt
new file mode 100644
index 0000000..cc73695
--- /dev/null
+++ b/report/draft_report007.odt
Binary files differ
diff --git a/report/draft_report008.odt b/report/draft_report008.odt
new file mode 100644
index 0000000..23f1297
--- /dev/null
+++ b/report/draft_report008.odt
Binary files differ
diff --git a/report/draft_report009.odt b/report/draft_report009.odt
new file mode 100644
index 0000000..e050dab
--- /dev/null
+++ b/report/draft_report009.odt
Binary files differ
diff --git a/report/draft_report010.odt b/report/draft_report010.odt
new file mode 100644
index 0000000..5efc771
--- /dev/null
+++ b/report/draft_report010.odt
Binary files differ
diff --git a/soutenance/texte b/soutenance/texte
new file mode 100644
index 0000000..9e1706f
--- /dev/null
+++ b/soutenance/texte
@@ -0,0 +1,13 @@
+// 15 min maxi
+
+Tout d'abord une présentation de l'entreprise
+C'est une SCOP
+Société Coopérative Ouvrière de Produduction
+(Société Coopérative et Participative)
+
+Même salaire, décision par vote, actionnaires à part égale de l'entreprise
+
+Editrice de logiciel libre
+Culture du libre
+transparence, valorisation de la connaissance et de l'expertise des coopérateurs plutôt que le
+code source