Documentation en ligne

Authentification

Usager concerné

Pour les appels concernant un usager particulier (tel que la récupération de la liste de ses formulaires en cours), l'usager est précisé en ajoutant une query string avec un paramètre email (pour trouver l'usager selon son adresse électronique) ou un paramètre NameID (pour trouver l'usager selon son NameID SAML).

Signature des requêtes

Les appels aux API doivent être signés, cela 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.

En ce qui concerne l'algorithme de hash, il est préconisé d'utiliser SHA-256 par respect du Référentiel Général de Sécurité (RGS).

La signature est à calculer sur la query string encodée complète, en enlevant les paramètres terminaux algo, timestamp, nonce, orig et signature s'ils sont présents.

La formule de calcul de la signature est la suivante :

BASE64(HMAC-HASH(query_string+'algo=HASH&timestamp=' + timestamp + '&nonce=' + nonce '&orig=" + orig, clé))
  • timestamp est la date dans la zone GMT au format ISO8601 en se limitant à la précision des secondes (ex : 2012-04-04T12:34:00Z),

  • nonce est un aléa, typiquement la réprésentation hexa d'un nombre pseudo-aléatoire de 128 bits,

  • orig est une chaîne précisant l'émetteur de la requête,

  • 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é.

La query string définitive est ainsi :

qs_initial&algo=algo&timestamp=timestamp&nonce=nonce&orig=orig&signature=signature

Configuration des clés partagées

Les clés partagées doivent être définies dans le fichier site-options.cfg, dans une section [api-secrets], par exemple :

[api-secrets]
intranet = 12345

Exemples de code de signature

Voici des exemples de code pour créer des URLs signées selon l'algorithme expliqué ci-dessus.

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')

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");

?>

Shell (bash)

#!/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"

Dernière mise à jour le 20 septembre 2020 19:43 — Éditer