ESUPSGC

Arborescence des pages

Quelques exemples de UserInfoServices sont donnés ici pour illustrer les possibilités des 5 possibilités de récupération des données d'esup-sgc depuis le Système d'Information.

Pour rappel, esup-sgc permet de consolider les champs utilisateurs au travers du calcul successif de "UserInfoServices" : chacun va être évalué l'un après l'autre pour un utilisateur donné (le  UserInfoService suivant pourra écraser une valeur calculée par le UserInfoService précédent, l'ordre d'exécution étant définie via une propriété "order"), la clef par défaut est l'eppn (qui est la clef métier de l'utilisateur dans esup-sgc), mais il est également possible d'utiliser des champs utilisateurs précédemment calculés comme identifiant d'un requêtage par exemple ; Exemple : RestUserInfoService configuré sur une route pégase et utilisant un supannEtuId précédemment récupéré via un LdapUserInforService.

On peut avoir autant de UserInfoService qu'on le souhaite, avec autant de connexions ldap, serveurs sql, api rest, règles spel que nécessaire.
La vue /admin/userinfos doit vous permettre d'avoir une bonne vue de l'ensemble de vos règles, vous pouvez y visualiser au passage le temps d'exécution de chaque règle pour un utilisateur donné, le temps de calcul total est également indiqué.

L'ensemble de ces configurations sont faites dans applicationContext-services.xml ; cf la page wiki Configurations ESUP-SGC et ESUP-NFC-TAG-SERVER#applicationContext-services.xml

ShibUserInfoService 

Ce UserInfoService récupère des champs utilisateurs au moment de l'authentification via la lecteur des entêtes HTTP de la requête, ce en plus de l'eppn (eduPersonPrincipalName) passé via REMOTE_USER.

Usuellemment, sauf cas particulier où on permet à un extérieur de demander une carte (voire importer une carte dans le cadre d'une mise en place en multi-tenants) via les seules informations récupérées depuis une authentification fédérée (fédération ESR portée par Renter ou même eduGain), ShibUserInfoService n'est en fait pas nécessaire/utile. Le problème/défaut de ShibUserInfoService étant qu'il n'est fonctionnel qu'au moment de l'authentification utilisateur et ne peut donc pas permettre de synchroniser les champs utilisateurs en dehors de cette authentification de l'utilisateur.

Si utilisé, on le configurera logiquement en début d'exécution (order à 1)

	<bean id="shibUserInfoService" class="org.esupportail.sgc.services.userinfos.ShibUserInfoService" p:order="1">
		<property name="sgcParam2requestHeader">
			<map>
				<entry key="email" value="mail"/>
				<entry key="firstname" value="givenname"/>
				<entry key="name" value="sn"/>
				<entry key="eduPersonPrimaryAffiliation" value="eduPersonPrimaryAffiliation"/>
                <entry key="schacDateOfBirth" value="schacDateOfBirth"/>
                <entry key="recto2" value="givenname"/>
				<entry key="recto3" value="sn"/>
				<entry key="recto4" value="eduPersonPrimaryAffiliation"/>
			</map>
		</property>	
	</bean>

LdapUserInfoService

C'est sans doute le UserInfoService à privilégier, car reposant sur l'annuaire supann de l'établissement, véritable référentiel standardisé du SI de l'établissement pour les comptes utilisateur.

La recherche se fait par défaut sur l'eppn (la property searchFilter est valuée à "(eduPersonPrincipalName={eppn})" et peut éventuellement être modifée au besoin, si tant est qu'un UserInfoService précédent (avec order plus faible) a récupéré un champ utilisateur le permettant.

On le configure généralement en début d'exécution (order à 2 ici).

À noter qu'une configuration ldap (cf bean avec pour id ldapTemplate ici) devra être configurée avant (voir le fichier applicationContext-services.xml donné par défaut).

	<bean id="ldapUserInfoService" class="org.esupportail.sgc.services.userinfos.LdapUserInfoService" p:order="2">
		<property name="ldapTemplate" ref="ldapTemplate"/>
		<property name="sgcParam2ldapAttr">
			<map>
				<entry key="email" value="mail"/>
				<entry key="eduPersonPrimaryAffiliation" value="eduPersonPrimaryAffiliation"/>
				<entry key="supannEtuId" value="supannEtuId"/>
				<entry key="supannEmpId" value="supannEmpId"/>
				<entry key="supannCodeINE" value="supannCodeINE"/>
				<entry key="supannEntiteAffectationPrincipale" value="supannEntiteAffectationPrincipale"/>
				<entry key="firstname" value="givenname"/>
				<entry key="name" value="sn"/>
				<entry key="schacDateOfBirth" value="schacDateOfBirth"/>
				<entry key="supannEtablissement" value="supannEtablissement"/>
				<entry key="jpegPhoto" value="jpegPhoto"/>
				<entry key="recto2" value="sn"/>
				<entry key="recto3" value="givenname"/>
				<entry key="schacExpiryDate" value="schacExpiryDate"/>
			</map>
		</property>	
	</bean>

Notez au passage la récupération de jpegPhoto ici qui permet de proposer par défaut une photo à un utilisateur dans son premier formulaire de demande de carte.

SqlUserInfoService

Avec une configuration permettant une connexion à une base de données sql (mariadb, postgresql, oracle, ...), on peut récupérer des champs utilisateurs depuis une requête SQL ainsi.

	<bean id="univvilleUserInfoService" class="org.esupportail.sgc.services.userinfos.SqlUserInfoService" p:order="3">
		<property name="dataSource" ref="dbExtDataSource"/>
		<property name="sqlQuery" value="select ligneTitre as recto1,
            ligneAnneeUniv as recto7,
			indiceinm as indice,
			concat(replace(datefindroits,'-',''),'235959Z') as schacExpiryDate,
			'Université de Ville' as institute
			from SgcTable where eppn=?"/>
	</bean>

À noter que '?' sera remplacé par l'eppn de l'utilisateur. Mais (comme pour les autres UserInfoService) il est possible aussi d'utiliser un champ préalablement calculé par un UserInfoService (même si non persité par esup-sgc).
Ainsi, si on a récupéré login depuis un LdapUserInfoService précédent, on pourrait faire par exemple : 

select ligneTitre as recto1	from SgcTable where login={login}

RestUserInfoService

RestUserInfoService se veut aussi générique que les autres UserInfoService, notez cependant qu'il a été développé et testé avec les APIs de Pégase en première cible.

Aussi, une authentification telle qu'impléméntée dans pégase est possible. Plus généralement une Authentification REST modulaire avec OAuth 2.0 Client Credentials est fonctionnelle,  une authentification basic ou via api key est possible également.

 RestUserInfoService s'attend à récupérer des résultats en JSON, sauf pour la récupération de la photo (jpegPhoto).

Voici un exemple de configuration pour des API Pégase donc ici : 

  <bean id="pegaseAuthProvider" class="org.esupportail.sgc.services.rest.BearerTokenAuthProvider">
        <property name="tokenEndpoint" value="https://authn-app.test-example.pc-scol.fr/cas/v1/tickets"/>
        <property name="bodyCredentials">
            <map>
                <entry key="username" value="usernamePegaseApi"/>
                <entry key="password" value="passwordDePegaseApi"/>
                <entry key="token" value="true"/>
            </map>
        </property>
    </bean>

    <bean id="pegaseUserInfoService" class="org.esupportail.sgc.services.userinfos.RestUserInfoService" p:order="3">
        <property name="authProvider" ref="pegaseAuthProvider"/>
		<property name="spelFilter" value="#userInfosInComputing['supannEtuId'] != null and !#userInfosInComputing['supannEtuId'].isEmpty()"/>
        <property name="url" value="https://ins.test-univ-example.pc-scol.fr/api/ins/ext/v2/gestion/inscription/ETAB00/{supannEtuId}/"/>
        <property name="sgcParam2jsonPath">
            <map>
                <entry key="name" value="$.apprenant.etatCivil.nomDeNaissance"/>
				<entry key="pegaseCibleCode" value="$.inscriptions[?(@.principale==true &amp;&amp; @.cible.periode.code=='2025')].cible.code"/>
				<entry key="pegaseFormationCode" value="$.inscriptions[?(@.principale==true &amp;&amp; @.cible.periode.code=='2025')].cible.formation.code"/>
            </map>
        </property>
    </bean>

	<bean id="photoPegaseUserInfoService" class="org.esupportail.sgc.services.userinfos.RestUserInfoService" p:order="4">
		<property name="authProvider" ref="pegaseAuthProvider"/>
		<property name="spelFilter" value="#userInfosInComputing['pegaseCibleCode'] != null and !#userInfosInComputing['pegaseCibleCode'].isEmpty()"/>
        <property name="url" value="https://piece.test-univ-example.pc-scol.fr/api/pie/ext/v1/etablissements/ETAB00/codeApprenant/{supannEtuId}/codePeriode/2025/codeChemin/{pegaseFormationCode}>{pegaseCibleCode}/photo"/>
		<property name="sgcParam2jsonPath">
			<map>
				<entry key="jpegPhoto" value=""/>
			</map>
		</property>
	</bean>

Dans sgcParam2jsonPath sont attendus des maps avec en clef le nom du champ à calculer et en valeur un jsonPath permettant de récupérer la valeur désirée pour l'utilisateur considéré.

supannEtuId devra être disponible, c'est à dire récupéré ici depuis un UserInfoService précédent.

La période "2025" est donnée en dur ici, mais on pourrait également imaginer la récupérer dynamiquement depuis une base de données externe (via un SqlUserInfoService à opérer en amont) afin d'avoir une configuration stable suivant dynamiquement les changements d'années universitaires.


Un jsonPath vide fait qu'esup-sgc prend le contenu de la réponse dans son ensemble, en texte, ou en binaire/fichier si le contentType de la réponse comme par "image/"

Enfin notez ici l'usage de spelFilter qui permet de limiter ce userInfoService aux seuls utilisateurs ayant un supannEtuId de renseigné. Cette possibilité est disponbile pour tous les userInfoService depuis la version 3.3.1 d'esup-sgc. Précédemment seul le filtre eppnFilter (limité à une expression régulière sur l'eppn simplement) était disponible. 


SpelUserInfoService

SpelUserInfoService permet de remanipuler les données calculées par des UserInfoService afin de les reformatter par exemple, d'en déduire des données adaptées à ce que demande esup-sgc.

Exemple : 


<bean id="spelUserInfoService" class="org.esupportail.sgc.services.userinfos.SpelUserInfoService" p:order="6">
        <property name="sgcParam2spelExp">
            <map>
                <entry key="institute" value=" 
                    #user.eppn matches '.*@univ-rouen\.fr' ? 'Université de Rouen' :
                    #user.eppn matches '.*@univ-lehavre\.fr' ? 'Université du Havre'  : 'Extérieur'"/>
				<entry key="template" value="#user.eppn matches '.*@univ-rouen\.fr' ? 'univ-rouen' : 'undefined'"/>
                <entry key="synchronize" value="#userInfosInComputing['name'] == Null ? 'false' : 'true'"/>
            </map>
        </property>    
    </bean>


À noter ici la possibilité de manipuler les données en cours de calcul via #userInfosInComputing et actuellement en base de données via #user




  • Aucune étiquette