API TransfertPro

Signature des requêtes

Introduction

Pour utiliser l'API TransfertPro, chaque requête doit être authentifiée. Les requêtes sont authentifiées en calculant une signature numérique à l'aide de la méthode HMAC-SHA512. Un client doit signer chaque requête à l'API à l'aide d'une clé privée connue uniquement du client et des serveurs TransfertPro. L'API TransfertPro utilise également des informations d'horodatage pour s'assurer que personne d'autre n'utilise l'API au nom du client.

Authentifier les requêtes aux API TransfertPro

Chaque requête aux API TransfertPro doit inclure les paramètres suivants :
apiKeyName La clé publique fournie au client qui permet aux API TransfertPro de déterminer quel client réalise la requête. Il s'agit du nom de la clé d'API.
hashKey hashKey Une signature HMAC-SHA512 de la requête qui est généré par le client à l'aide de sa clé privée
nonce Un id unique généré aléatoirement par le client pour identifier la requête.

Nom de la clé d'API

Quand une société souscrit à TransfertPro, elle a la possibilité de faire une demande d'accès aux API TransfertPro. Pour cela elle doit créer une clé d'API. TransfertPro fournit alors au client une clé publique (le nom de la clé d'API) et une clé privée (la valeur de la clé d'API). La clé privée est utilisée pour signer les requêtes et ne doit jamais être inclus dans la requête. La clé publique doit, au contraire, être inclus dans chaque requête afin que le système puisse déterminer la clé privée du client pour générer la même signature de requête afin d'autoriser ou de rejeter la requête.

HashKey

Il s'agit de la signature de la requête. La manière de signer une requête est décrite en détail dans la section suivante.

nonce

Nonce signifie "un nombre utilisé une seule fois", ce qui pour l'API signifie une chaine de caractère aléatoire unique utilisée pour identifier une requête. Le nonce doit être une chaîne de caractère aléatoire unique d'au moins 8 caractères. Le nonce est utilisé pour prévenir des attaques de type "man in the middle", où quelqu'un essaye de répéter une requête qu'un client a déjà faite.

Signature d'une requête

Quand le client crée une requête aux API TransfertPro, il doit d'abord générer une signature numérique de la requête en utilisant sa clé privée. Cette signature est incluse dans la requête ainsi que la clé publique du client. Lorsque l'API TransfertPro reçoit la requête, le système détermine la clé privée du client à partir de la clé publique fournie. Le système essaye alors de générer la même signature en utilisant la clé privée du client. Si la signature générée correspond à la signature dans la requête la requête est acceptée et l'action est effectuée. Autrement, le serveur retournera un message d'erreur.
Puisque seuls le client et le serveur ont accès à la clé privée du client, personne d'autre ne peut générer une signature de requête valide au nom du client. Pour s'assurer que la signature du client et la signature du serveur correspondent, les étapes suivantes doivent être suivies par les 2 parties.
Concaténez les paramètres "apiKeyName" et "nonce" et leur valeurs (dans l'ordre indiqué) avec comme séparateur le caractère '|' (aussi bien entre chaque couple clé/valeur qu'entre la clé et la valeur - ne pas utiliser '&' et '='). Au résultat obtenu, concaténez la valeur de la clé d'API (la clé privée) avec comme séparateur le caractère '|'. Calculez le HMAC (Hash-based Message Authentication Code) de la chaîne de caractères obtenue en utilisant la fonction de hachage SHA512. Exemple de signature d'une requête de récupération de dossier de premier niveau :'
API key : 1854-SalesforceKey Secret key : 68f4bf5c-58a0-4b88-9fbc-1c4540e0e5dc nonce : 636021993082569669 Url sans la signature : https://ext.transfertpro.com/api/v5/Directory/Root?apiKeyName=1854-SalesforceKey&nonce=636021993082569669 Chaîne concaténée : apiKeyName|1854-SalesforceKey|nonce|636021993082569669|68f4bf5c-58a0-4b88-9fbc-1c4540e0e5dc Signature : 19c8497e1189ba6feb0802c337f243db5b5be9d1b7cee86267c8e32e936c4a01173f0667098316b3f77376807024e7320889d0ad146072f58c84b94745b676f5 Url avec la signature : https://ext.transfertpro.com/api/v5/Directory/Root?apiKeyName=1854-SalesforceKey&nonce=636021993082569669&hashkey=19c8497e1189ba6feb0802c337f243db5b5be9d1b7cee86267c8e32e936c4a01173f0667098316b3f77376807024e7320889d0ad146072f58c84b94745b676f5
Utilisation de la clé d'API dans les requêtes :

        protected string privateApiKeyName; // Nom de la clé d'API utilisé pour réaliser vos requêtes.
        protected HttpRequestMessage createRequest(string url, string mediaType, HttpMethod method, Dictionary<string, string> requestParameters)
        {
        Dictionary<string, string> globalParameters = new Dictionary<string, string>();
        globalParameters["apiKeyName"] = privateApiKeyName.ToString();
        globalParameters["nonce"] = DateTime.Now.Ticks.ToString();
        string hashKey = GetHashKey(globalParameters, privateApiKeyValue);
        globalParameters.Add("hashKey", hashKey);

        var parametersToSend = globalParameters.Concat(requestParameters).ToDictionary(x => x.Key, x => x.Value);

        StringBuilder urlParameters = new StringBuilder();

        foreach (string parameterName in parametersToSend.Keys)
        {
        if (urlParameters.Length != 0)
        {
        urlParameters.Append("&");
        }

        urlParameters.Append(parameterName);
        urlParameters.Append("=");
        urlParameters.Append(parametersToSend[parameterName]);
        }

        var request = new HttpRequestMessage();
        request.RequestUri = new Uri(string.Format("{0}?{1}",url, urlParameters.ToString()));
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mediaType));
        request.Method = method;
        return request;
        }

        private string GetHashKey(Dictionary<string, string> urlParameters, string keyPassValue)
        {
        StringBuilder sb = new StringBuilder();
        SortedSet<string> urlParameterNames = new SortedSet<string>(urlParameters.Keys);

        foreach (string urlParameterName in urlParameterNames)
        {
        if (sb.Length != 0)
        {
        sb.Append(hashSeparator);
        }

        sb.Append(urlParameterName);
        sb.Append(hashSeparator);
        sb.Append(urlParameters[urlParameterName]);
        }

        sb.Append(hashSeparator);
        sb.Append(keyPassValue);
        return ConvertSHA512(keyPassValue, sb.ToString());
        }

        private string ConvertSHA512(string keyPassValue, string value)
        {
        byte[] key = Encoding.UTF8.GetBytes(keyPassValue);
        byte[] valueBytes = Encoding.UTF8.GetBytes(value);
        HMACSHA512 myhmacsha512 = new HMACSHA512(key);
        byte[] hashValue = myhmacsha512.ComputeHash(valueBytes);
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < hashValue.Length; i++)
        {
        sb.Append(hashValue[i].ToString("x2"));
        }

        return sb.ToString();
        }