L'objet de cette bibliothèque est d'offrir un certain nombre d'outils et d'interfaces pour transmettre avec les requêtes HTTP des signatures numériques afin de garantir un certain niveau de sécurité.
La sécurité apportée par une signature associée àune requete HTTP est très utile notamment dans le cadre de webservice REST où il n'y a pas de notion de session ( Mode stateless - sans état).
Le principe de la signature est de réaliser coté client un condensat (hash) d'un certain d'éléments variables de la requête (paramètres), d'un timestamp (pour limiter la validité de la signature dans le temps) et d'une clé secrète (connue que du client et du serveur). Ce condensat est obtenu à l'aide d'un algorithme de hashage (SHA-1, SHA-256, ...) et constitue la signature proprement dite de la requête. Elle se présente sous la forme d'une chaîne de caractères représentant un nombre sous forme héxadécimale.
La signature est transmise au serveur, qui devra reconstituer un condensat de son coté avec sa clé secrète. Si la signature est correctement reconstituée, la requête est valide, sinon elle refusée avec un code retour HTTP 401.
Voici ce que la signature apporte en terme de sécurité :
Voici ce que la signature n'apporte pas en terme de sécurité :
En résumé, la sécurité offerte par ce mécanisme de signature correspond bien à un besoin de fonctionnement sans session typiquement les Webservices REST. Il convient bien à la sécurisation de requêtes entre deux serveurs où provenant d'une population très faible d'utilisateurs (confidentialité du secret partagé) ou n'ayant pas accès à la clé secrète.
Afin d'assurer la confidentialité des données, le transfert des données doit être réalisé en HTTPS.
L'API RequestAuthenticator : définit un authentificateur de requete HTTP.
Le même composant peut être utilisé coté client pour signer une requête et coté serveur pour valider l'authentification. Voici l'interface et ses deux méthodes à implémenter :
/** * Check the Authentication of a request * @param request The HTTP request * @return true if authenticated, otherwise false */ boolean isRequestAuthenticated( HttpServletRequest request ); /** * Authenticate a request * @param method The HTTP method to authenticate * @param elements List of elements to include in the signature */ void authenticateRequest( HttpMethodBase method, List<String> elements );
Cette interface offre de nombreuses possibilités d'implémentations.
Une bonne pratique consiste à injecter via un contexte Spring l'implémentation
souhaitée.
La bibliothèque SignRequest propose plusieurs implémentations :
Ces authenticators doivent être configurés à l'aide de plusieurs paramètres :
La sécurisation de l'ensemble des requêtes peut se faire au niveau du plugin REST en injectant via le context Spring un authenticator.
Par défaut, le plugin REST utilise l'implémentation NoSecurityRequestAuthenticator qui autorise l'ensemble des requêtes. L'exemple ci-dessous montre une configuration utilisant le HeaderHashRequestAuthenticator et son paramètrage spécifique.
<bean id="rest.hashService" class="fr.paris.lutece.util.signrequest.security.Sha1HashService" /> <bean id="rest.requestAuthenticator" class="fr.paris.lutece.util.signrequest.HeaderHashAuthenticator" > <property name="hashService" ref="rest.hashService" /> <property name="signatureElements" > <list> <value>key</value> </list> </property> <property name="privateKey"> <value>change me</value> </property> <property name="validityTimePeriod"> <value>0</value> </property> </bean>Cette API propose une fonction de hachage dont voici l'interface :
/** * Create a Hash string from a given source * @param strSource The source * @return The Hash */ String getHash( String strSource );
La bibliothèque SignRequest propose l'implémentation SHA-1.
La bibliothèque SignRequest propose également des filtres de Servlet
qui peuvent être utilisés par les plugins de manière à valider
les requêtes coté serveur.
Ils sont basés sur les authenticator fournis avec la bibliothèque.
Voici un exemple de filtre ajouté dans le fichier XML d'un plugin :
<filters> <filter> <filter-name>myresourcesecurity</filter-name> <url-pattern>/rest/myresource/*</url-pattern> <filter-class>fr.paris.lutece.util.signrequest.servlet.HeaderHashRequestFilter</filter-class> <init-param> <param-name>elementsSignature</param-name> <param-value>id-resource,name,description</param-value> </init-param> <init-param> <param-name>validityTimePeriod</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>privateKey</param-name> <param-value>change me</param-value> </init-param> </filter> </filters>