Documentation en ligne

Authentification

Gestion des accès aux API

La crĂ©ation d’accès aux API se gère globalement depuis le module de gestion d’identitĂ©s (Authentic). L’écran de configuration est accessible depuis la page d’accueil de ce module, via le bouton « Clients d’API » dans sa barre latĂ©rale droite.

Capture d’écran de l’accueil du module de gestion d’identités, un bouton « Client d’API » apparait dans la colonne de droite

Le bouton « Ajouter un nouveau client d’API » permet d’ajouter un accès, et il faut indiquer :

  • Nom : le nom choisi pour l’accès, qui sera affichĂ© dans la page des accès ;

  • Description : pour se rappeler de l’usage prĂ©vu pour cet accès ;

  • Identifiant : le nom de l’utilisateur Ă  utiliser pour l’authentification HTTP Basic, ou le paramètre orig pour l’authentification par signature ;

  • Mot de passe : le mot de passe pour l’authentification HTTP Basic de cet utilisateur ;

  • CollectivitĂ© : dans un environnement multi-collectivitĂ©s, la collectivitĂ© Ă  laquelle attacher cet accès ;

  • RĂ´les : la 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.

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

Définitions de l’usager concerné

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.

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.

L’usager est prĂ©cisĂ© en ajoutant dans la query string :

  • soit un paramètre email pour trouver l’usager selon son adresse Ă©lectronique

  • soit un paramètre NameID pour trouver l’usager selon son NameID SAML.

Authentification simple HTTP Basic

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.

Authentification par signature de l’URL

Historiquement un système d’authentification alternatif, basé sur une signature ajoutée à la fin de l’URL était également disponible. Avec la généralisation de l’HTTPS, il est obsolète.

Signature des requĂŞtes

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.

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

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.

Historiquement les clĂ©s partagĂ©es pouvaient aussi ĂŞtre dĂ©finies dans le fichier site-options.cfg, dans une section [api-secrets], cette mĂ©thode n'est pas conseillĂ©e car elle ne permet pas de prĂ©ciser finement les rĂ´les. Exemple :

[api-secrets]
intranet = 12345

Exemples d'implémentation de l’algorithme 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 17/09/2024 11:38 — Éditer