AUTHENTIFICATION DIGEST AVEC WINDEV

Ce tuto a pour objet de détailler l’accès à une ressource HTTPS qui requiert une authentification de type digest en WinDev.
Dans cet exemple, nous utilisons une gateway GSM qui dispose d’une api permettant d’obtenir un certain nombre d’informations sur son état.
IP : 192.168.10.241
user : admin
password : Password2019
accès à l’api pour connaitre l’état des ports GSM : https://192.168.10.241/api/get_port_...te,signal,gprs
Cette gateway utilise le mode d’authentification digest pas si simple à implémenter en Windev.
1. L’authentification digest
Lorsqu'un client HTTP demande une ressource protégée au serveur, celui-ci répond de différente façon selon la requête :
  • soit la requête ne contient pas d'en-tête HTTP d'identification, dans ce cas le serveur répond avec le code HTTP 401 (Unauthorized : non autorisé) et envoie les en-têtes d'information sur l'identification demandée
  • soit la requête contient les en-têtes HTTP d'identification, dans ce cas, après vérification du nom et du mot de passe, si l'identification échoue, le serveur répond par le code 401 comme dans le cas précédent, sinon il répond de manière normale (code 200 OK).


Pour ma part pour tracer ce que me demandait le serveur j’ai utilisé postman.

J’ai simplement écrit ma requête en get puis j’ai défini dans l’onglet authorization mes paramètres login et password en spécifiant digest comme authentification

Cliquer sur SEND me renvoie le résultat attendu :

Pour comprendre le processus, j’ai utilisé la console de postman. Atl+ Ctrl+ C

On voit bien deux échanges :

1. La requête initiale qui renvoie les headers décrivant les informations requises pour la connexion :

La partie la plus importante pour nous est :
WWW-Authenticate: "Digest realm="Web Server", domain="",qop="auth", nonce="9438e54d808eaafbc34eb2c70cb81215", opaque="5ccc069c403ebaf9f0171e9517f40e41",algorithm="MD5", stale="FALSE""
Set-Cookie: "devckie=db59-0306-1055-0123;path=/"
On distingue plusieurs paramètres qui sont renseignés :
  • Realm Ce paramètre est affiché à l'utilisateur pour qu'il sache quel nom et mot de passe il peut utiliser
  • Qop (optionnel) (Quality Of Protection) Ce paramètre indique les niveaux de protection supportés : auth ou auth-int.
  • Nonce Chaîne générée par le serveur à chaque réponse 401. Utilisé dans le calcul de la réponse par le client.
  • Opaque (optionnel) Chaîne générée par le serveur que le client doit retourner telle quelle.
  • Algorithm (optionnel) Indique l'algorithme à utiliser pour les fonctions de hashages. Deux valeurs possibles : MD5 ou MD5-sess.
  • Stale (optionnel) Ce paramètre a 2 valeurs possibles : true ou false. Il vaut true si la demande d'identification précédente a été rejetée seulement à cause de l'utilisation d'une ancienne valeur du paramètre « nonce », false sinon. La valeur true indique que le client doit retenter la requête en utilisant la nouvelle valeur de nonce fournie par le serveur sans redemander un nom et un mot de passe à l'utilisateur.



2. la seconde requête qui utilise les informations décrites dans la première requête ci-dessus :
La partie request header nous renseigne sur ce que le client doit renseigner :
User-Agent: "PostmanRuntime/7.20.1"
Accept: "*/*"
Cache-Control: "no-cache"
Postman-Token: "4a76aafd-0037-4f54-8e56-bb81299414ae"
Host: "192.168.10.241"
Accept-Encoding: "gzip, deflate"
Connection: "keep-alive"
Authorization: "Digest username="admin", realm="Web Server", nonce="9438e54d808eaafbc34eb2c70cb81215", uri="/api/get_port_info?port=1,2,3&info_type=imei,imsi,iccid,smsc,type,number,reg,slot,callstate,signal,gprs", algorithm="MD5", qop=auth, nc=00000001, cnonce="QvxOanaM", response="c3b4e7b2d80e674554c245256d14b471", opaque="5ccc069c403ebaf9f0171e9517f40e41""
Cookie: "devckie=db59-0306-1055-0123"
Une fois encore la partie Authorization est fondamentale et contient les éléments suivants :

  • Username Nom de l'utilisateur.
  • Realm Même valeur que celle de la réponse du serveur.
  • Nonce Même valeur que celle de la réponse du serveur.
  • Algorithm Même valeur que celle de la réponse du serveur.
  • Opaque Même valeur que celle de la réponse du serveur.
  • Uri URI de la ressource protégée demandée
  • Qop (optionnel) (Quality Of Protection) Ce paramètre indique le niveau de protection appliqué. Il doit correspondre à l'une des valeurs retournées par le serveur.
  • Cnonce (si qop est présent) Chaîne générée arbitrairement par le client.
  • Nc (si qop est présent) (Nonce Count) 8 chiffres hexadécimaux représentant le nombre de fois que la valeur du paramètre « nonce » retournée par le serveur a été utilisée par le client. nc=00000001 la première fois.
  • Response Ce paramètre contenant 32 chiffres hexadécimaux représentant la valeur calculée par le client prouvant qu'il connaît le mot de passe.


Calcul de response
Attention à enlever tous les espaces autour des : pour le calcul et les résultats des hash sont en minuscule

Param Valeur
Username admin
Password password2019
Realm Web Server
Opaque 5ccc069c403ebaf9f0171e9517f40e41
Nonce 9438e54d808eaafbc34eb2c70cb81215
Cnonce QvxOanaM
Nc nounce count 00000001
Httpmethod GET
Uri :/api/get_port_info?port=1,2,3&info_type=imei,imsi,iccid,smsc,type,number,reg,slot,callstate,signal,gprs
Algorithm MD5
Qop auth
Entité html><head><title>Document Error: Unauthorized</title></head><body><h2>Access Error: Unauthorized</h2> <p>Access to this document requires a User ID</p></body></html>
Si algorithm vaut MD5 ou n’est pas spécifié :
HA1 = MD5(username :realm :password),
Si algorithm vaut MD5-sees
HA1 = MD5(username:realm:password):nonce:cnone
Si qop=auth ou bien n’est pas spécifié :
HA2 = MD5(httpmethod :uri),
Si qop=auth-int
HA2 = httpmethod :uri :MD5(entité)
Si qop est spécifié
response = MD5(HA1:nonce:nc:cnonce:qop:HA2)
sinon
response = MD5( HA1, nonce:HA2 )

2.Code windev
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// Résumé : la procédure getport info permet de récupérer les informations de l'état des ports d'une gateway gsm DINSTAR-UC2000 qui utilise une authentification digest.
PROCEDURE getportinfo()
// authentification digest :
// L'authentification Digest est un peu plus complexe que Basic car elle se fait en deux étapes. 
// A la première requête, le serveur envoie une réponse 401 et un header WWW-Authenticate avec le nonce et les valeurs qui vont servir a calculer la réponse a donner. 
// Le client renvoie une deuxième requête avec le mot de passe haché en utilisant le nonce fourni par le serveur.
 
//1ere requete
HTTP.IgnoreErreur = httpIgnoreCertificatInvalide+httpIgnoreCertificatExpiré+httpIgnoreNomCertificatInvalide
HTTPRequête("https://192.168.10.241/api/get_port_info?port=1,2,3&info_type=imei,imsi,iccid,smsc,type,number,reg,slot,callstate,signal,gprs")
 
//maintenant on récupère certaines infos de la 1ere requete
sNonce est une chaîne = ExtraitChaîne(HTTPDonneRésultat(httpEntête),4,",")
sOpaque est une chaîne = ExtraitChaîne(HTTPDonneRésultat(httpEntête),5,",")
sCookie est une chaîne = HTTPDonneRésultat(httpCookie)
 
sRealm est une chaîne ="Web Server"
sQop est une chaîne = "auth" 
//(Quality Of Protection) Ce paramètre indique le niveau de protection appliqué. Il doit correspondre à l'une des valeurs retournées par le serveur. auth ou auth-int
 
sNonce = ExtraitChaîne(sNonce,2,"""") 
//Chaîne générée par le serveur à chaque réponse 401
 
sOpaque = ExtraitChaîne(sOpaque,2,"""") 
//Chaîne générée par le serveur que le client doit retourner telle quelle
 
sHeader est une chaîne
sCnonce est une chaîne = "RdHlfmls" 
//chaine cliente arbitrairement choisie au pif (peut etre la meme tout le temps)
 
sNoncecount est une chaîne = "00000001" 
//(Nonce Count) 8 chiffres hexadécimaux représentant le nombre de fois que la valeur du paramètre « nonce » retournée par le serveur a été utilisée par le client. nc=00000001 la première fois
 
reponse est une chaîne 
//Ce paramètre contenant 32 chiffres hexadécimaux représentant la valeur calculée par le client prouvant qu'il connaît le mot de passe.
 
//calcul de la réponse à fournir
 
HA1 est une chaîne =BufferVersHexa( HashChaîne(HA_MD5_128, "admin:Web Server:Password2019"))
HA1 = Minuscule(ChaîneSupprime(HA1," "))
HA2 est une chaîne = BufferVersHexa(HashChaîne(HA_MD5_128,"GET:/api/get_port_info?port=1,2,3&info_type=imei,imsi,iccid,smsc,type,number,reg,slot,callstate,signal,gprs"))
HA2 = Minuscule(ChaîneSupprime(HA2," "))
reponse = BufferVersHexa(HashChaîne(HA_MD5_128,HA1+ ":" + sNonce + ":" + sNoncecount + ":" + sCnonce + ":" + sQop + ":" +  HA2))
reponse = Minuscule(ChaîneSupprime(reponse," "))
 
sHeader = " Digest username= ""admin"" , realm=""%1"", nonce=""%2"", uri=""/api/get_port_info?port=1,2,3&info_type=imei,imsi,iccid,smsc,type,number,reg,slot,callstate,signal,gprs"", algorithm=""MD5"", qop=auth, nc=00000001, cnonce=""RdHlfmls"", response=""%3"", opaque=""%4"" "
sHeader = ChaîneConstruit(sHeader,sRealm,sNonce, reponse,sOpaque)
 
//creation de la requete avec les autres infos récupérées dans postman
cMaRequête est un httpRequête
cMaRequête..URL = "https://192.168.10.241/api/get_port_info?port=1,2,3&info_type=imei,imsi,iccid,smsc,type,number,reg,slot,callstate,signal,gprs"
cMaRequête..Entête["Cache-Control"] = "no-cache"
cMaRequête..Entête["host"] = "192.168.10.241"
cMaRequête..Entête["Accept-Encoding"] = "gzip, deflate"
cMaRequête..Entête["Cookie"] = sCookie
cMaRequête..Entête["Connection"] = "keep-alive"
cMaRequête..Entête["Authorization"] = sHeader
cMaRequête..IgnoreErreur = httpIgnoreCertificatInvalide+httpIgnoreCertificatExpiré+httpIgnoreNomCertificatInvalide
cMaRéponse est un httpRéponse = HTTPEnvoie(cMaRequête)
 
bufRésultat est Buffer = cMaRéponse..Contenu