Merge branch 'master' of git.entrouvert.org:paul-synchro
This commit is contained in:
commit
8235164ecc
|
@ -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 = _(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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/')
|
||||
|
|
|
@ -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 = ''
|
||||
|
||||
|
|
|
@ -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="")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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/'
|
||||
|
|
|
@ -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.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
Reference in New Issue