@mcp-abap-adt/connection 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -83,6 +83,14 @@ declare abstract class AbstractAbapConnection implements AbapConnection {
|
|
|
83
83
|
private updateCookiesFromResponse;
|
|
84
84
|
private getAxiosInstance;
|
|
85
85
|
private ensureFreshCsrfToken;
|
|
86
|
+
/**
|
|
87
|
+
* Clear SAP-side session state when SAP rejects the cached CSRF token + session
|
|
88
|
+
* cookies (HTTP 401 on a mutation while a cached token exists). This forces the
|
|
89
|
+
* next request path to fetch a fresh token and a fresh SAP_SESSIONID cookie.
|
|
90
|
+
*
|
|
91
|
+
* Distinct from reset(): this leaves the axios instance and interceptors in place.
|
|
92
|
+
*/
|
|
93
|
+
private invalidateSession;
|
|
86
94
|
private shouldRetryCsrf;
|
|
87
95
|
}
|
|
88
96
|
export { AbstractAbapConnection };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/AbstractAbapConnection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,0BAA0B,CAAC;AAM7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG9E,uBAAe,sBAAuB,YAAW,cAAc;IAW3D,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAX3C,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,eAAe,CAAU;IAEjC,SAAS,aACU,MAAM,EAAE,SAAS,EACf,MAAM,EAAE,OAAO,GAAG,IAAI,EACzC,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE;IAqBzC;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI;IAUpD;;OAEG;IACH,cAAc,IAAI,WAAW,GAAG,UAAU;IAI1C;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKrC;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,SAAS,IAAI,SAAS;IAItB,KAAK,IAAI,IAAI;IAYP,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAevD;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE3B,cAAc,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EACnC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"AbstractAbapConnection.d.ts","sourceRoot":"","sources":["../../src/connection/AbstractAbapConnection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,0BAA0B,CAAC;AAM7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG9E,uBAAe,sBAAuB,YAAW,cAAc;IAW3D,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAX3C,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,eAAe,CAAU;IAEjC,SAAS,aACU,MAAM,EAAE,SAAS,EACf,MAAM,EAAE,OAAO,GAAG,IAAI,EACzC,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE;IAqBzC;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI;IAUpD;;OAEG;IACH,cAAc,IAAI,WAAW,GAAG,UAAU;IAI1C;;;OAGG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKrC;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B,SAAS,IAAI,SAAS;IAItB,KAAK,IAAI,IAAI;IAYP,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAevD;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE3B,cAAc,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EACnC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IA+R9B,SAAS,CAAC,QAAQ,CAAC,wBAAwB,IAAI,MAAM;IAErD;;;OAGG;cACa,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,UAAU,GAAE,MAAgC,EAC5C,UAAU,GAAE,MAAgC,GAC3C,OAAO,CAAC,MAAM,CAAC;IA2ClB;;OAEG;YACW,0BAA0B;IAsKxC;;OAEG;IACH,SAAS,CAAC,YAAY,IAAI,MAAM,GAAG,IAAI;IAIvC;;OAEG;IACH,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIlD;;OAEG;IACH,SAAS,CAAC,UAAU,IAAI,MAAM,GAAG,IAAI;IAIrC,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlD,OAAO,CAAC,yBAAyB;IAkEjC,OAAO,CAAC,gBAAgB;YAqBV,oBAAoB;IAiClC;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,eAAe;CA+BxB;AAGD,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
|
|
@@ -263,22 +263,51 @@ class AbstractAbapConnection {
|
|
|
263
263
|
else {
|
|
264
264
|
this.logger?.error(errorDetails.message, errorDetails);
|
|
265
265
|
}
|
|
266
|
-
//
|
|
267
|
-
|
|
268
|
-
|
|
266
|
+
// Detect the "login-form 401" pattern: SAP returned 401 for a mutation while
|
|
267
|
+
// we have a cached CSRF token. The token and its bound SAP session must be
|
|
268
|
+
// discarded before the retry. Basic auth only — JWT/SAML lifecycles are
|
|
269
|
+
// managed elsewhere.
|
|
270
|
+
const isCachedTokenStale = error instanceof axios_1.AxiosError &&
|
|
271
|
+
this.config.authType === 'basic' &&
|
|
272
|
+
(normalizedMethod === 'POST' ||
|
|
273
|
+
normalizedMethod === 'PUT' ||
|
|
274
|
+
normalizedMethod === 'DELETE') &&
|
|
275
|
+
error.response?.status === 401 &&
|
|
276
|
+
this.getCsrfToken() !== null;
|
|
277
|
+
// Retry logic for CSRF token errors (403 with CSRF message) and the
|
|
278
|
+
// login-form 401 pattern.
|
|
279
|
+
if (this.shouldRetryCsrf(error) || isCachedTokenStale) {
|
|
280
|
+
this.logger?.debug(isCachedTokenStale
|
|
281
|
+
? 'Stale CSRF token / SAP session — invalidating and retrying'
|
|
282
|
+
: 'CSRF token validation failed, fetching new token and retrying request', {
|
|
269
283
|
url: requestUrl,
|
|
270
284
|
method: normalizedMethod,
|
|
271
285
|
});
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
requestHeaders
|
|
286
|
+
if (isCachedTokenStale) {
|
|
287
|
+
this.invalidateSession();
|
|
288
|
+
delete requestHeaders.Cookie;
|
|
289
|
+
delete requestHeaders.cookie;
|
|
275
290
|
}
|
|
276
|
-
|
|
277
|
-
|
|
291
|
+
try {
|
|
292
|
+
this.setCsrfToken(await this.fetchCsrfToken(requestUrl, 5, 2000));
|
|
293
|
+
const refreshedToken = this.getCsrfToken();
|
|
294
|
+
if (refreshedToken) {
|
|
295
|
+
requestHeaders['x-csrf-token'] = refreshedToken;
|
|
296
|
+
}
|
|
297
|
+
const refreshedCookies = this.getCookies();
|
|
298
|
+
if (refreshedCookies) {
|
|
299
|
+
requestHeaders.Cookie = refreshedCookies;
|
|
300
|
+
}
|
|
301
|
+
const retryResponse = await this.getAxiosInstance()(requestConfig);
|
|
302
|
+
this.updateCookiesFromResponse(retryResponse.headers);
|
|
303
|
+
return retryResponse;
|
|
304
|
+
}
|
|
305
|
+
catch (retryError) {
|
|
306
|
+
this.logger?.debug(`CSRF retry failed; rethrowing original error: ${retryError instanceof Error
|
|
307
|
+
? retryError.message
|
|
308
|
+
: String(retryError)}`);
|
|
309
|
+
throw error;
|
|
278
310
|
}
|
|
279
|
-
const retryResponse = await this.getAxiosInstance()(requestConfig);
|
|
280
|
-
this.updateCookiesFromResponse(retryResponse.headers);
|
|
281
|
-
return retryResponse;
|
|
282
311
|
}
|
|
283
312
|
// Retry logic for 401 errors on GET requests (authentication issue - need cookies)
|
|
284
313
|
// Only for basic auth - JWT auth will be handled by refresh logic below
|
|
@@ -585,6 +614,18 @@ class AbstractAbapConnection {
|
|
|
585
614
|
throw error;
|
|
586
615
|
}
|
|
587
616
|
}
|
|
617
|
+
/**
|
|
618
|
+
* Clear SAP-side session state when SAP rejects the cached CSRF token + session
|
|
619
|
+
* cookies (HTTP 401 on a mutation while a cached token exists). This forces the
|
|
620
|
+
* next request path to fetch a fresh token and a fresh SAP_SESSIONID cookie.
|
|
621
|
+
*
|
|
622
|
+
* Distinct from reset(): this leaves the axios instance and interceptors in place.
|
|
623
|
+
*/
|
|
624
|
+
invalidateSession() {
|
|
625
|
+
this.setCsrfToken(null);
|
|
626
|
+
this.cookies = null;
|
|
627
|
+
this.cookieStore.clear();
|
|
628
|
+
}
|
|
588
629
|
shouldRetryCsrf(error) {
|
|
589
630
|
if (!(error instanceof axios_1.AxiosError)) {
|
|
590
631
|
return false;
|