help: remove section about API accesses (now written online) (#75607)
This commit is contained in:
parent
00222aae84
commit
42c904394f
|
@ -1,317 +0,0 @@
|
||||||
<page xmlns="http://projectmallard.org/1.0/"
|
|
||||||
type="topic" id="api-auth" xml:lang="fr">
|
|
||||||
|
|
||||||
<info>
|
|
||||||
<link type="guide" xref="index#api" />
|
|
||||||
<revision docversion="0.1" date="2013-01-04" status="draft"/>
|
|
||||||
<revision docversion="0.2" date="2015-12-18" status="draft"/>
|
|
||||||
<credit type="author">
|
|
||||||
<name>Frédéric Péters</name>
|
|
||||||
<email>fpeters@entrouvert.com</email>
|
|
||||||
</credit>
|
|
||||||
<desc>Accès aux API, identifiants et clé d’utilisation, utilisateurs, signature, etc.</desc>
|
|
||||||
|
|
||||||
</info>
|
|
||||||
|
|
||||||
<title>Authentification</title>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<title>Gestion des accès aux API</title>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
La création d’accès aux API se fait dans l’espace de paramétrage, dans la
|
|
||||||
section « Sécurité », en suivant le lien « Accès aux API ». Le bouton « Nouvel
|
|
||||||
accès aux API » permet d’ajouter un accès, et il faut indiquer :
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<list>
|
|
||||||
|
|
||||||
<item><p>Nom : le nom choisi pour l’accès, qui sera affiché dans la page des
|
|
||||||
accès ;</p></item>
|
|
||||||
|
|
||||||
<item><p>Description : pour se rappeler de l’usage prévu pour cet
|
|
||||||
accès ;</p></item>
|
|
||||||
|
|
||||||
<item><p>Identifiant d’accès : le nom de l’utilisateur à utiliser pour
|
|
||||||
l’authentification HTTP Basic, ou le paramètre <code>orig</code> pour
|
|
||||||
l’authentification par signature ;</p></item>
|
|
||||||
|
|
||||||
<item><p>Clé d’accès : le mot de passe pour l’authentification HTTP Basic de
|
|
||||||
cet utilisateur, ou la clé partagée à utiliser pour l’authentification par
|
|
||||||
signature ;</p></item>
|
|
||||||
|
|
||||||
<item><p>Rôles : liste des rôles automatiquement obtenus lorsque cet accès est
|
|
||||||
utilisé. Par exemple, s’il s’agit de permettre de lister des demandes d’une
|
|
||||||
certaine démarche, il faut indiquer un rôle qui permet de voir les demandes.
|
|
||||||
Ce rôle est à déterminer selon le paramétrage du formulaire de la démarche
|
|
||||||
et/ou de son workflow.</p></item>
|
|
||||||
|
|
||||||
</list>
|
|
||||||
|
|
||||||
<note><p>Il est conseillé de créer des «rôles techniques» dédiés aux API. Ces
|
|
||||||
rôles ne sont jamais donnés à des utilisateurs de la plateforme, ils sont
|
|
||||||
utilisés uniquement dans le paramétrage des accès. Typiquement une démarche est
|
|
||||||
paramétrée pour qu’un certain rôle technique ait accès à ses demandes, et ce
|
|
||||||
même rôle est indiqué dans l’accès aux API dédié.</p></note>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<title>Définitions de l’usager concerné</title>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Si l’authentification utilisée passe par un accès aux API qui ne donne pas de
|
|
||||||
rôle spécifique, alors il faut indiquer dans la query-string un usager qui aura
|
|
||||||
les rôles nécessaires.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
C'est aussi nécessaire pour les appels concernant un usager particulier, tel
|
|
||||||
que la récupération de la liste de ses formulaires en cours.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>L’usager est précisé en ajoutant dans la query string :</p>
|
|
||||||
|
|
||||||
<list>
|
|
||||||
<item><p>soit un paramètre <code>email</code> pour trouver l’usager selon son
|
|
||||||
adresse électronique</p></item>
|
|
||||||
<item><p>soit un paramètre <code>NameID</code> pour trouver l’usager selon son
|
|
||||||
NameID SAML.</p></item>
|
|
||||||
</list>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<title>Authentification simple HTTP Basic</title>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Pour accéder aux API avec l’authentification HTTP Basic classique, il faut
|
|
||||||
utiliser le nom d’utilisateur (identifiant d’accès) et le mot de passe (clé
|
|
||||||
d’accès) de l’accès configuré ci-dessus.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<title>Authentification par signature de l’URL</title>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Un système d’authentification basé sur une signature ajoutée à la fin de l’URL
|
|
||||||
est également disponible. Il peut être jugé plus sécurisé que
|
|
||||||
l’authentification HTTP Basic, par ailleurs il assure une protection plus
|
|
||||||
explicite contre le rejeu. Ce système est spécifique à Publik/w.c.s.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<section id="req-security-shared-secret">
|
|
||||||
<title>Signature des requêtes</title>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
La signature d’un appel aux API passe par une clé partagée à
|
|
||||||
configurer des deux cotés de la liaison, la signature est du type HMAC;
|
|
||||||
l’algorithme de hash à employer est passé en paramètre.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<note><p>En ce qui concerne l’algorithme de hash, il est préconisé d’utiliser
|
|
||||||
SHA-256 par respect du <link
|
|
||||||
href="http://references.modernisation.gouv.fr/securite">Référentiel Général
|
|
||||||
de Sécurité (RGS)</link>.</p></note>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
La signature est à calculer sur la query string encodée complète, en
|
|
||||||
enlevant les paramètres terminaux <code>algo</code>, <code>timestamp</code>,
|
|
||||||
<code>nonce</code>, <code>orig</code> et <code>signature</code> s’ils sont
|
|
||||||
présents.</p>
|
|
||||||
|
|
||||||
<p>La formule de calcul de la signature est la suivante :</p>
|
|
||||||
|
|
||||||
<code>
|
|
||||||
BASE64(HMAC-HASH(query_string+'algo=HASH&timestamp=' + timestamp + '&nonce=' + nonce '&orig=" + orig, clé))
|
|
||||||
</code>
|
|
||||||
|
|
||||||
<list>
|
|
||||||
|
|
||||||
<item><p><code>timestamp</code> est la date dans la zone GMT au format ISO8601
|
|
||||||
en se limitant à la précision des secondes (ex : 2012-04-04T12:34:00Z),
|
|
||||||
</p></item>
|
|
||||||
|
|
||||||
<item><p><code>nonce</code> est un aléa, typiquement la réprésentation hexa
|
|
||||||
d’un nombre pseudo-aléatoire de 128 bits,</p></item>
|
|
||||||
|
|
||||||
<item><p><code>orig</code> est une chaîne précisant l’émetteur de la
|
|
||||||
requête,</p></item>
|
|
||||||
|
|
||||||
<item><p>algo est une chaîne représentant l’algorithme de hachage utilisé, sont
|
|
||||||
définis : sha1, sha256, sha512 pour les trois algorithmes correspondant.
|
|
||||||
L’utilisation d’une valeur différente n’est pas définie. L’algorithme sha256
|
|
||||||
est préconisé.</p></item>
|
|
||||||
|
|
||||||
</list>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
La query string définitive est ainsi :
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<code>
|
|
||||||
<var>qs_initial</var>&algo=<var>algo</var>&timestamp=<var>timestamp</var>&nonce=<var>nonce</var>&orig=<var>orig</var>&signature=<var>signature</var>
|
|
||||||
</code>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<title>Configuration des clés partagées</title>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
La définition des clés se fait lors de la création des accès aux API (voir
|
|
||||||
plus haut). Lors de la création d'un nouvel accès, l’identifiant d'accès
|
|
||||||
correspond au «orig» et la clé d'accès est la clé de signature. Les rôles sont
|
|
||||||
ceux qui seront obtenus lors de l’usage de l’accès.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Les clés partagées peuvent aussi être définies dans le fichier
|
|
||||||
<code>site-options.cfg</code>, dans une section <code>[api-secrets]</code>, par
|
|
||||||
exemple :
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<code>
|
|
||||||
[api-secrets]
|
|
||||||
intranet = 12345
|
|
||||||
</code>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<title>Exemples d'implémentation de l’algorithme de signature</title>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Voici des exemples de code pour créer des URLs signées selon l’algorithme
|
|
||||||
expliqué ci-dessus.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<listing>
|
|
||||||
<title>Python</title>
|
|
||||||
<code mime="text/x-python">
|
|
||||||
#! /usr/bin/env python3
|
|
||||||
|
|
||||||
import base64
|
|
||||||
import datetime
|
|
||||||
import hashlib
|
|
||||||
import hmac
|
|
||||||
import random
|
|
||||||
import urllib.parse
|
|
||||||
|
|
||||||
|
|
||||||
def sign_url(url, key, algo='sha256', orig=None, timestamp=None, nonce=None):
|
|
||||||
parsed = urllib.parse.urlparse(url)
|
|
||||||
new_query = sign_query(parsed.query, key, algo, orig, timestamp, nonce)
|
|
||||||
return urllib.parse.urlunparse(parsed[:4] + (new_query,) + parsed[5:])
|
|
||||||
|
|
||||||
|
|
||||||
def sign_query(query, key, algo='sha256', orig=None, timestamp=None, nonce=None):
|
|
||||||
if timestamp is None:
|
|
||||||
timestamp = datetime.datetime.utcnow()
|
|
||||||
timestamp = timestamp.strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
||||||
if nonce is None:
|
|
||||||
nonce = hex(random.getrandbits(128))[2:].rstrip('L')
|
|
||||||
new_query = query
|
|
||||||
if new_query:
|
|
||||||
new_query += '&'
|
|
||||||
new_query += urllib.parse.urlencode((('algo', algo), ('timestamp', timestamp), ('nonce', nonce)))
|
|
||||||
if orig is not None:
|
|
||||||
new_query += '&' + urllib.parse.urlencode({'orig': orig})
|
|
||||||
signature = base64.b64encode(sign_string(new_query, key, algo=algo))
|
|
||||||
new_query += '&' + urllib.parse.urlencode({'signature': signature})
|
|
||||||
return new_query
|
|
||||||
|
|
||||||
|
|
||||||
def sign_string(s, key, algo='sha256', timedelta=30):
|
|
||||||
if not isinstance(key, bytes):
|
|
||||||
key = key.encode('utf-8')
|
|
||||||
if not isinstance(s, bytes):
|
|
||||||
s = s.encode('utf-8')
|
|
||||||
digestmod = getattr(hashlib, algo)
|
|
||||||
hash = hmac.HMAC(key, digestmod=digestmod, msg=s)
|
|
||||||
return hash.digest()
|
|
||||||
|
|
||||||
|
|
||||||
# usage:
|
|
||||||
url = sign_url('https://www.example.net/uri/?arg=val&arg2=val2', 'user-key', orig='user')
|
|
||||||
</code>
|
|
||||||
</listing>
|
|
||||||
|
|
||||||
<listing>
|
|
||||||
<title>PHP</title>
|
|
||||||
<code mime="application/x-php">
|
|
||||||
<?php
|
|
||||||
|
|
||||||
function sign_url(string $url, string $orig, string $key) {
|
|
||||||
$parsed_url = parse_url($url);
|
|
||||||
$timestamp = gmstrftime("%Y-%m-%dT%H:%M:%SZ");
|
|
||||||
$nonce = bin2hex(random_bytes(16));
|
|
||||||
$new_query = '';
|
|
||||||
if (isset($parsed_url['query'])) {
|
|
||||||
$new_query .= $parsed_url['query'] . '&';
|
|
||||||
}
|
|
||||||
$new_query .= http_build_query(array(
|
|
||||||
'algo' => 'sha256',
|
|
||||||
'timestamp' => $timestamp,
|
|
||||||
'nonce' => $nonce,
|
|
||||||
'orig' => $orig));
|
|
||||||
$signature = base64_encode(hash_hmac('sha256', $new_query, $key, $raw_output = true));
|
|
||||||
$new_query .= '&' . http_build_query(array('signature' => $signature));
|
|
||||||
$scheme = isset($parsed_url['scheme']) ? $parsed_url['scheme'] . '://' : '';
|
|
||||||
$host = isset($parsed_url['host']) ? $parsed_url['host'] : '';
|
|
||||||
$port = isset($parsed_url['port']) ? ':' . $parsed_url['port'] : '';
|
|
||||||
$user = isset($parsed_url['user']) ? $parsed_url['user'] : '';
|
|
||||||
$pass = isset($parsed_url['pass']) ? ':' . $parsed_url['pass'] : '';
|
|
||||||
$pass = ($user || $pass) ? "$pass@" : '';
|
|
||||||
$path = isset($parsed_url['path']) ? $parsed_url['path'] : '';
|
|
||||||
$fragment = isset($parsed_url['fragment']) ? '#' . $parsed_url['fragment'] : '';
|
|
||||||
return "$scheme$user$pass$host$port$path?$new_query$fragment";
|
|
||||||
}
|
|
||||||
|
|
||||||
# usage:
|
|
||||||
url = sign_url("http://www.example.net/uri/?arg=val&arg2=val2", "user", "user-key");
|
|
||||||
|
|
||||||
?>
|
|
||||||
</code>
|
|
||||||
</listing>
|
|
||||||
|
|
||||||
<listing>
|
|
||||||
<title>Shell (bash)</title>
|
|
||||||
<code mime="application/x-shellscript">
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
url="http://www.example.net/uri/?arg=val&arg2=val2"
|
|
||||||
orig="user"
|
|
||||||
key="user-key"
|
|
||||||
|
|
||||||
function rawurlencode() {
|
|
||||||
local string="${1}"
|
|
||||||
local strlen=${#string}
|
|
||||||
local encoded=""
|
|
||||||
local pos c o
|
|
||||||
for ((pos=0; pos<strlen; pos++)); do
|
|
||||||
c=${string:$pos:1}
|
|
||||||
case "$c" in
|
|
||||||
[-_.~a-zA-Z0-9] ) o="${c}" ;;
|
|
||||||
* ) printf -v o '%%%02x' "'$c"
|
|
||||||
esac
|
|
||||||
encoded+="${o}"
|
|
||||||
done
|
|
||||||
echo "${encoded}"
|
|
||||||
}
|
|
||||||
|
|
||||||
now=$(date -u +%FT%TZ);
|
|
||||||
nonce=$(od -N16 -txL /dev/urandom | cut -c8- | tr -d " ")
|
|
||||||
qs="algo=sha256&timestamp=$now&nonce=$nonce&orig=$orig"
|
|
||||||
sig=$(rawurlencode $(echo -n "$qs" | openssl dgst -binary -sha256 -hmac "$key" | base64))
|
|
||||||
signed="${url}?$qs&signature=$sig"
|
|
||||||
echo "$signed"
|
|
||||||
</code>
|
|
||||||
</listing>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
</page>
|
|
|
@ -181,8 +181,7 @@ comme un commentaire ou une erreur lors de l’appel d’un <em>web service</em>
|
||||||
<note>
|
<note>
|
||||||
<p>
|
<p>
|
||||||
Il est bien sûr nécessaire de disposer des autorisations nécessaires pour
|
Il est bien sûr nécessaire de disposer des autorisations nécessaires pour
|
||||||
accéder ainsi aux données d’un formulaire. (cf <link
|
accéder ainsi aux données d’un formulaire.
|
||||||
xref="api-auth"/> pour les explications sur le sujet)
|
|
||||||
</p>
|
</p>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue