L3.2 : fait remonter statut et corps de la réponse STS dans les erreurs d'auth
authenticate() ré-enveloppait l'erreur axios en "Authentication failed:
Request failed with status code 400" et jetait le corps de la réponse du
STS, qui contenait le diagnostic exact ({"error":"invalid_request",
"error_description":"Tenant not found"} sur le profil AD).
Réutilise _enrichHttpError (L1.1) dans authenticate() et
refreshOAuthToken(), avec payload volontairement omis : il contient les
credentials (password grant) ou le refresh_token ; l'helper n'inclut
jamais les headers. Le chemin "token trop vieux -> password grant" de
refreshOAuthToken() sort du try : un échec d'authenticate() y était
rattrapé pour... rappeler authenticate() à l'identique ; il propage
désormais son erreur enrichie directement.
Mesure (via le protocole) : switch_wms_profile("AD") puis
count_wms_entities("Products") ->
Count failed for Products: Authentication failed: POST
https://10.255.255.2/EasySTS/OAuth/Token failed (HTTP 400): Request
failed with status code 400
Response body: {"error":"invalid_request","error_description":"Tenant
not found"}
Aucun credential ni header dans la réponse (vérifié : pas de
password/Basic/Bearer/payload).
ROADMAP : L3.2 retirée, point ouvert "profil AD" mis à jour.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+3
-17
@@ -26,21 +26,6 @@ garde-fous d'arguments manquants) est livré — voir **D21** et **D23**.
|
|||||||
- Renvoyer `truncated: true` explicitement plutôt que de laisser le client se
|
- Renvoyer `truncated: true` explicitement plutôt que de laisser le client se
|
||||||
faire rejeter.
|
faire rejeter.
|
||||||
|
|
||||||
### L3.2 — Erreurs d'authentification muettes
|
|
||||||
|
|
||||||
`authenticate()` (`api-service.js`) ré-enveloppe l'erreur axios en
|
|
||||||
`new Error('Authentication failed: ' + error.message)` : le **corps de la
|
|
||||||
réponse du STS est perdu**, alors qu'il contient le diagnostic complet.
|
|
||||||
|
|
||||||
Preuve (24/08/2026, profil `AD`) : le smoke test affiche seulement
|
|
||||||
`Authentication failed: Request failed with status code 400` ; en rejouant la
|
|
||||||
même requête à la main, le corps était
|
|
||||||
`{"error":"invalid_request","error_description":"Tenant not found"}` — le
|
|
||||||
diagnostic exact, invisible depuis les outils comme depuis le smoke test.
|
|
||||||
|
|
||||||
Faire remonter `error.response.data` dans le message, comme L1.1 l'a fait pour
|
|
||||||
les outils. Même contrainte : ne jamais logguer les credentials.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lot 4 — Modèle de données et applications
|
## Lot 4 — Modèle de données et applications
|
||||||
@@ -197,8 +182,9 @@ plus riche que `/AD/api/Application/GetAll`), `GET /healthcheck?tenantCode=` et
|
|||||||
le tenant `AD`. L'hôte et le STS fonctionnent (LIMAGRAIN, même hôte, passe
|
le tenant `AD`. L'hôte et le STS fonctionnent (LIMAGRAIN, même hôte, passe
|
||||||
4/4) : c'est la valeur `AD_TENANT` du `.env` qui ne correspond plus à un
|
4/4) : c'est la valeur `AD_TENANT` du `.env` qui ne correspond plus à un
|
||||||
tenant existant. Correction côté propriétaire du dépôt (mettre à jour ou
|
tenant existant. Correction côté propriétaire du dépôt (mettre à jour ou
|
||||||
retirer le profil) — pas un bug du code. Le message opaque du smoke test est
|
retirer le profil) — pas un bug du code. Depuis L3.2, le corps de la réponse
|
||||||
traité à part (L3.2).
|
du STS (`Tenant not found`) remonte dans les erreurs d'outils et du smoke
|
||||||
|
test.
|
||||||
- **`select_expression`** : les projections via le paramètre `Select` provoquent
|
- **`select_expression`** : les projections via le paramètre `Select` provoquent
|
||||||
des erreurs de compilation côté serveur (D13). Irritant principal restant.
|
des erreurs de compilation côté serveur (D13). Irritant principal restant.
|
||||||
- **Déploiement SSH sur la VM** : l'exécutable est validé, la configuration SSH
|
- **Déploiement SSH sur la VM** : l'exécutable est validé, la configuration SSH
|
||||||
|
|||||||
@@ -77,8 +77,12 @@ class APIService {
|
|||||||
console.error(`[API] Authentication successful. Token expires in ~${this.tokenMaxAge}s`);
|
console.error(`[API] Authentication successful. Token expires in ~${this.tokenMaxAge}s`);
|
||||||
return this.token;
|
return this.token;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[API] Authentication failed:', error.message);
|
// Statut + corps de la réponse STS dans le message : c'est là que vit le
|
||||||
throw new Error(`Authentication failed: ${error.message}`);
|
// diagnostic ("Tenant not found", ...). Payload volontairement omis — il
|
||||||
|
// contient les credentials ; _enrichHttpError n'inclut jamais les headers.
|
||||||
|
const enriched = this._enrichHttpError(error, 'POST', profile.tokenUrl, undefined);
|
||||||
|
console.error('[API] Authentication failed:', enriched.message);
|
||||||
|
throw new Error(`Authentication failed: ${enriched.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,17 +92,17 @@ class APIService {
|
|||||||
async refreshOAuthToken() {
|
async refreshOAuthToken() {
|
||||||
const tokenAge = this.getTokenAge();
|
const tokenAge = this.getTokenAge();
|
||||||
|
|
||||||
try {
|
|
||||||
// If token is too old (>= maxAge), use password grant
|
// If token is too old (>= maxAge), use password grant
|
||||||
if (tokenAge >= this.tokenMaxAge) {
|
if (tokenAge >= this.tokenMaxAge) {
|
||||||
console.error('[API] Token too old, re-authenticating with password...');
|
console.error('[API] Token too old, re-authenticating with password...');
|
||||||
return await this.authenticate();
|
return await this.authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const profile = profileManager.getCurrent();
|
||||||
|
try {
|
||||||
// Otherwise use refresh_token grant
|
// Otherwise use refresh_token grant
|
||||||
console.error('[API] Refreshing token with refresh_token grant...');
|
console.error('[API] Refreshing token with refresh_token grant...');
|
||||||
|
|
||||||
const profile = profileManager.getCurrent();
|
|
||||||
const response = await this.httpClient.post(
|
const response = await this.httpClient.post(
|
||||||
profile.tokenUrl,
|
profile.tokenUrl,
|
||||||
new URLSearchParams({
|
new URLSearchParams({
|
||||||
@@ -120,7 +124,10 @@ class APIService {
|
|||||||
console.error('[API] Token refreshed successfully');
|
console.error('[API] Token refreshed successfully');
|
||||||
return this.token;
|
return this.token;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[API] Token refresh failed, re-authenticating:', error.message);
|
// Même enrichissement que authenticate() : statut + corps STS, sans le
|
||||||
|
// payload (refresh_token) ni les headers.
|
||||||
|
const enriched = this._enrichHttpError(error, 'POST', profile.tokenUrl, undefined);
|
||||||
|
console.error('[API] Token refresh failed, re-authenticating:', enriched.message);
|
||||||
return await this.authenticate();
|
return await this.authenticate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user