@mcp-abap-adt/auth-stores 0.3.0 → 1.0.0
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.
- package/CHANGELOG.md +10 -0
- package/README.md +17 -3
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -1
- package/dist/storage/abap/envLoader.d.ts +2 -1
- package/dist/storage/abap/envLoader.js +11 -3
- package/dist/storage/abap/tokenStorage.d.ts +2 -1
- package/dist/storage/abap/tokenStorage.js +13 -3
- package/dist/stores/abap/AbapSessionStore.js +30 -2
- package/dist/stores/abap/SafeAbapSessionStore.js +22 -0
- package/dist/utils/constants.d.ts +2 -0
- package/dist/utils/constants.js +2 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.0] - 2026-02-10
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- ABAP session stores now support SAML session cookies (stored as base64 in env files).
|
|
14
|
+
- Exports: `SamlSessionStore` and `SafeSamlSessionStore` aliases for ABAP stores.
|
|
15
|
+
- Tests for SAML cookie storage and connection config handling.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- Persist SAML session cookies in file-backed and in-memory ABAP session stores.
|
|
19
|
+
|
|
10
20
|
## [0.2.10] - 2025-12-25
|
|
11
21
|
|
|
12
22
|
### Changed
|
package/README.md
CHANGED
|
@@ -115,7 +115,13 @@ const safeSessionStore = new SafeBtpSessionStore('https://default.mcp.com', logg
|
|
|
115
115
|
### ABAP Stores (with sapUrl)
|
|
116
116
|
|
|
117
117
|
```typescript
|
|
118
|
-
import {
|
|
118
|
+
import {
|
|
119
|
+
AbapServiceKeyStore,
|
|
120
|
+
AbapSessionStore,
|
|
121
|
+
SafeAbapSessionStore,
|
|
122
|
+
SamlSessionStore,
|
|
123
|
+
SafeSamlSessionStore,
|
|
124
|
+
} from '@mcp-abap-adt/auth-stores';
|
|
119
125
|
|
|
120
126
|
// Service key store - reads ABAP service keys with nested uaa object
|
|
121
127
|
const serviceKeyStore = new AbapServiceKeyStore('/path/to/service-keys');
|
|
@@ -125,6 +131,10 @@ const sessionStore = new AbapSessionStore('/path/to/sessions');
|
|
|
125
131
|
|
|
126
132
|
// In-memory session store
|
|
127
133
|
const safeSessionStore = new SafeAbapSessionStore();
|
|
134
|
+
|
|
135
|
+
// SAML aliases (same behavior as ABAP stores)
|
|
136
|
+
const samlSessionStore = new SamlSessionStore('/path/to/sessions');
|
|
137
|
+
const safeSamlSessionStore = new SafeSamlSessionStore();
|
|
128
138
|
```
|
|
129
139
|
|
|
130
140
|
### XSUAA Stores
|
|
@@ -155,7 +165,7 @@ import { EnvFileSessionStore } from '@mcp-abap-adt/auth-stores';
|
|
|
155
165
|
const store = new EnvFileSessionStore('/path/to/.env', logger);
|
|
156
166
|
|
|
157
167
|
// Check the auth type from the file
|
|
158
|
-
const authType = store.getAuthType(); // 'basic' | 'jwt' | null
|
|
168
|
+
const authType = store.getAuthType(); // 'basic' | 'jwt' | 'saml' | null
|
|
159
169
|
|
|
160
170
|
// Load session (works like other session stores)
|
|
161
171
|
const config = await store.loadSession('default');
|
|
@@ -174,7 +184,7 @@ console.log(config?.authorizationToken, config?.refreshToken);
|
|
|
174
184
|
SAP_URL=https://your-sap-system.com
|
|
175
185
|
SAP_CLIENT=100
|
|
176
186
|
|
|
177
|
-
# Auth type: 'basic' or '
|
|
187
|
+
# Auth type: 'basic', 'jwt', or 'saml' (defaults to 'basic')
|
|
178
188
|
SAP_AUTH_TYPE=basic
|
|
179
189
|
|
|
180
190
|
# Basic auth credentials
|
|
@@ -188,6 +198,10 @@ SAP_PASSWORD=your-password
|
|
|
188
198
|
# SAP_UAA_URL=https://uaa.example.com
|
|
189
199
|
# SAP_UAA_CLIENT_ID=client-id
|
|
190
200
|
# SAP_UAA_CLIENT_SECRET=client-secret
|
|
201
|
+
|
|
202
|
+
# OR SAML auth (session cookies, base64-encoded)
|
|
203
|
+
# SAP_AUTH_TYPE=saml
|
|
204
|
+
# SAP_SESSION_COOKIES_B64=base64-encoded-cookie-string
|
|
191
205
|
```
|
|
192
206
|
|
|
193
207
|
**Important**: This store is **read-only** for the file. Token updates (e.g., refreshed JWT tokens) are stored in memory only and do not modify the original `.env` file.
|
package/dist/index.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export { FileNotFoundError, InvalidConfigError, ParseError, StorageError, StoreE
|
|
|
8
8
|
export { loadServiceKey } from './loaders/abap/serviceKeyLoader';
|
|
9
9
|
export { loadXSUAAServiceKey } from './loaders/xsuaa/xsuaaServiceKeyLoader';
|
|
10
10
|
export { AbapServiceKeyStore } from './stores/abap/AbapServiceKeyStore';
|
|
11
|
-
export { AbapSessionStore } from './stores/abap/AbapSessionStore';
|
|
12
|
-
export { SafeAbapSessionStore } from './stores/abap/SafeAbapSessionStore';
|
|
11
|
+
export { AbapSessionStore, AbapSessionStore as SamlSessionStore, } from './stores/abap/AbapSessionStore';
|
|
12
|
+
export { SafeAbapSessionStore, SafeAbapSessionStore as SafeSamlSessionStore, } from './stores/abap/SafeAbapSessionStore';
|
|
13
13
|
export { EnvFileSessionStore } from './stores/env/EnvFileSessionStore';
|
|
14
14
|
export { SafeXsuaaSessionStore, SafeXsuaaSessionStore as SafeBtpSessionStore, } from './stores/xsuaa/SafeXsuaaSessionStore';
|
|
15
15
|
export { XsuaaServiceKeyStore, XsuaaServiceKeyStore as BtpServiceKeyStore, } from './stores/xsuaa/XsuaaServiceKeyStore';
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Provides ABAP and XSUAA store implementations
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.resolveSearchPaths = exports.findFileInPaths = exports.JsonFileHandler = exports.EnvFileHandler = exports.XSUAA_CONNECTION_VARS = exports.XSUAA_AUTHORIZATION_VARS = exports.BTP_CONNECTION_VARS = exports.BTP_AUTHORIZATION_VARS = exports.ABAP_CONNECTION_VARS = exports.ABAP_AUTHORIZATION_VARS = exports.BtpSessionStore = exports.XsuaaSessionStore = exports.BtpServiceKeyStore = exports.XsuaaServiceKeyStore = exports.SafeBtpSessionStore = exports.SafeXsuaaSessionStore = exports.EnvFileSessionStore = exports.SafeAbapSessionStore = exports.AbapSessionStore = exports.AbapServiceKeyStore = exports.loadXSUAAServiceKey = exports.loadServiceKey = exports.StoreError = exports.StorageError = exports.ParseError = exports.InvalidConfigError = exports.FileNotFoundError = void 0;
|
|
9
|
+
exports.resolveSearchPaths = exports.findFileInPaths = exports.JsonFileHandler = exports.EnvFileHandler = exports.XSUAA_CONNECTION_VARS = exports.XSUAA_AUTHORIZATION_VARS = exports.BTP_CONNECTION_VARS = exports.BTP_AUTHORIZATION_VARS = exports.ABAP_CONNECTION_VARS = exports.ABAP_AUTHORIZATION_VARS = exports.BtpSessionStore = exports.XsuaaSessionStore = exports.BtpServiceKeyStore = exports.XsuaaServiceKeyStore = exports.SafeBtpSessionStore = exports.SafeXsuaaSessionStore = exports.EnvFileSessionStore = exports.SafeSamlSessionStore = exports.SafeAbapSessionStore = exports.SamlSessionStore = exports.AbapSessionStore = exports.AbapServiceKeyStore = exports.loadXSUAAServiceKey = exports.loadServiceKey = exports.StoreError = exports.StorageError = exports.ParseError = exports.InvalidConfigError = exports.FileNotFoundError = void 0;
|
|
10
10
|
// Error classes
|
|
11
11
|
var StoreErrors_1 = require("./errors/StoreErrors");
|
|
12
12
|
Object.defineProperty(exports, "FileNotFoundError", { enumerable: true, get: function () { return StoreErrors_1.FileNotFoundError; } });
|
|
@@ -24,8 +24,10 @@ Object.defineProperty(exports, "AbapServiceKeyStore", { enumerable: true, get: f
|
|
|
24
24
|
// ABAP stores (with sapUrl)
|
|
25
25
|
var AbapSessionStore_1 = require("./stores/abap/AbapSessionStore");
|
|
26
26
|
Object.defineProperty(exports, "AbapSessionStore", { enumerable: true, get: function () { return AbapSessionStore_1.AbapSessionStore; } });
|
|
27
|
+
Object.defineProperty(exports, "SamlSessionStore", { enumerable: true, get: function () { return AbapSessionStore_1.AbapSessionStore; } });
|
|
27
28
|
var SafeAbapSessionStore_1 = require("./stores/abap/SafeAbapSessionStore");
|
|
28
29
|
Object.defineProperty(exports, "SafeAbapSessionStore", { enumerable: true, get: function () { return SafeAbapSessionStore_1.SafeAbapSessionStore; } });
|
|
30
|
+
Object.defineProperty(exports, "SafeSamlSessionStore", { enumerable: true, get: function () { return SafeAbapSessionStore_1.SafeAbapSessionStore; } });
|
|
29
31
|
// Env file stores (for --env=path scenarios)
|
|
30
32
|
var EnvFileSessionStore_1 = require("./stores/env/EnvFileSessionStore");
|
|
31
33
|
Object.defineProperty(exports, "EnvFileSessionStore", { enumerable: true, get: function () { return EnvFileSessionStore_1.EnvFileSessionStore; } });
|
|
@@ -6,9 +6,10 @@ interface EnvConfig {
|
|
|
6
6
|
sapUrl: string;
|
|
7
7
|
sapClient?: string;
|
|
8
8
|
jwtToken?: string;
|
|
9
|
+
sessionCookies?: string;
|
|
9
10
|
username?: string;
|
|
10
11
|
password?: string;
|
|
11
|
-
authType?: 'basic' | 'jwt';
|
|
12
|
+
authType?: 'basic' | 'jwt' | 'saml';
|
|
12
13
|
refreshToken?: string;
|
|
13
14
|
uaaUrl?: string;
|
|
14
15
|
uaaClientId?: string;
|
|
@@ -65,6 +65,7 @@ async function loadEnvFile(destination, directory, log) {
|
|
|
65
65
|
// Extract required fields
|
|
66
66
|
const sapUrl = parsed[constants_1.ABAP_CONNECTION_VARS.SERVICE_URL];
|
|
67
67
|
const jwtToken = parsed[constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN];
|
|
68
|
+
const sessionCookiesB64 = parsed[constants_1.ABAP_CONNECTION_VARS.SESSION_COOKIES_B64];
|
|
68
69
|
const username = parsed[constants_1.ABAP_CONNECTION_VARS.USERNAME];
|
|
69
70
|
const password = parsed[constants_1.ABAP_CONNECTION_VARS.PASSWORD];
|
|
70
71
|
log?.debug(`Extracted fields: hasSapUrl(${!!sapUrl}), hasJwtToken(${jwtToken !== undefined && jwtToken !== null}), hasUsername(${!!username}), hasPassword(${!!password})`);
|
|
@@ -76,14 +77,19 @@ async function loadEnvFile(destination, directory, log) {
|
|
|
76
77
|
// Determine auth type: if username/password present and no jwtToken, use basic auth
|
|
77
78
|
// If jwtToken present, use JWT auth
|
|
78
79
|
// If neither is present, it's OK - auth can be set later (e.g., via setAuthorizationConfig)
|
|
80
|
+
const hasSamlCookies = !!(sessionCookiesB64 && sessionCookiesB64.trim() !== '');
|
|
79
81
|
const isBasicAuth = !!(username && password) && (!jwtToken || jwtToken.trim() === '');
|
|
80
82
|
const isJwtAuth = !!(jwtToken && jwtToken.trim() !== '');
|
|
81
|
-
const _hasNoAuth = !isBasicAuth && !isJwtAuth;
|
|
83
|
+
const _hasNoAuth = !isBasicAuth && !isJwtAuth && !hasSamlCookies;
|
|
82
84
|
const config = {
|
|
83
85
|
sapUrl: sapUrl.trim(),
|
|
84
86
|
};
|
|
85
87
|
// Set authentication fields based on type
|
|
86
|
-
if (
|
|
88
|
+
if (hasSamlCookies) {
|
|
89
|
+
config.sessionCookies = Buffer.from(sessionCookiesB64, 'base64').toString('utf8');
|
|
90
|
+
config.authType = 'saml';
|
|
91
|
+
}
|
|
92
|
+
else if (isBasicAuth) {
|
|
87
93
|
config.username = username.trim();
|
|
88
94
|
config.password = password.trim();
|
|
89
95
|
config.authType = 'basic';
|
|
@@ -121,7 +127,9 @@ async function loadEnvFile(destination, directory, log) {
|
|
|
121
127
|
const tokenLength = config.jwtToken?.length || 0;
|
|
122
128
|
const authInfo = config.authType === 'basic'
|
|
123
129
|
? `basic auth (username: ${config.username})`
|
|
124
|
-
:
|
|
130
|
+
: config.authType === 'saml'
|
|
131
|
+
? `SAML session cookies(${config.sessionCookies?.length || 0} chars)`
|
|
132
|
+
: `JWT token(${tokenLength} chars)`;
|
|
125
133
|
log?.info(`Env config loaded from ${envFilePath}: sapUrl(${config.sapUrl.substring(0, 50)}...), ${authInfo}, hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl})`);
|
|
126
134
|
return config;
|
|
127
135
|
}
|
|
@@ -6,9 +6,10 @@ interface EnvConfig {
|
|
|
6
6
|
sapUrl: string;
|
|
7
7
|
sapClient?: string;
|
|
8
8
|
jwtToken?: string;
|
|
9
|
+
sessionCookies?: string;
|
|
9
10
|
username?: string;
|
|
10
11
|
password?: string;
|
|
11
|
-
authType?: 'basic' | 'jwt';
|
|
12
|
+
authType?: 'basic' | 'jwt' | 'saml';
|
|
12
13
|
refreshToken?: string;
|
|
13
14
|
uaaUrl?: string;
|
|
14
15
|
uaaClientId?: string;
|
|
@@ -54,9 +54,10 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
54
54
|
log?.debug(`Saving token to env file: ${envFilePath}`);
|
|
55
55
|
const tokenLength = config.jwtToken?.length || 0;
|
|
56
56
|
const hasBasicAuth = !!(config.username && config.password);
|
|
57
|
+
const hasSamlCookies = !!config.sessionCookies;
|
|
57
58
|
const formattedToken = (0, formatting_1.formatToken)(config.jwtToken);
|
|
58
59
|
const formattedRefreshToken = (0, formatting_1.formatToken)(config.refreshToken);
|
|
59
|
-
log?.debug(`Config to save: hasSapUrl(${!!config.sapUrl}), token(${tokenLength} chars${formattedToken ? `, ${formattedToken}` : ''}), hasBasicAuth(${hasBasicAuth}), refreshToken(${formattedRefreshToken || 'none'}), hasUaaUrl(${!!config.uaaUrl})`);
|
|
60
|
+
log?.debug(`Config to save: hasSapUrl(${!!config.sapUrl}), token(${tokenLength} chars${formattedToken ? `, ${formattedToken}` : ''}), hasBasicAuth(${hasBasicAuth}), hasSamlCookies(${hasSamlCookies}), refreshToken(${formattedRefreshToken || 'none'}), hasUaaUrl(${!!config.uaaUrl})`);
|
|
60
61
|
// Ensure directory exists
|
|
61
62
|
if (!fs.existsSync(savePath)) {
|
|
62
63
|
log?.debug(`Creating directory: ${savePath}`);
|
|
@@ -90,8 +91,15 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
90
91
|
// Update with new values
|
|
91
92
|
// sapUrl is required - always save it
|
|
92
93
|
existingVars.set(constants_1.ABAP_CONNECTION_VARS.SERVICE_URL, config.sapUrl);
|
|
93
|
-
// Handle authentication: JWT or basic auth
|
|
94
|
-
if (config.
|
|
94
|
+
// Handle authentication: SAML cookies, JWT, or basic auth
|
|
95
|
+
if (config.sessionCookies) {
|
|
96
|
+
const cookiesB64 = Buffer.from(config.sessionCookies, 'utf8').toString('base64');
|
|
97
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.SESSION_COOKIES_B64, cookiesB64);
|
|
98
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, '');
|
|
99
|
+
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.USERNAME);
|
|
100
|
+
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.PASSWORD);
|
|
101
|
+
}
|
|
102
|
+
else if (config.username && config.password) {
|
|
95
103
|
// Basic auth - save username/password
|
|
96
104
|
existingVars.set(constants_1.ABAP_CONNECTION_VARS.USERNAME, config.username);
|
|
97
105
|
existingVars.set(constants_1.ABAP_CONNECTION_VARS.PASSWORD, config.password);
|
|
@@ -99,6 +107,7 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
99
107
|
if (config.jwtToken) {
|
|
100
108
|
existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, '');
|
|
101
109
|
}
|
|
110
|
+
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.SESSION_COOKIES_B64);
|
|
102
111
|
}
|
|
103
112
|
else if (config.jwtToken) {
|
|
104
113
|
// JWT auth - save token
|
|
@@ -106,6 +115,7 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
106
115
|
// Clear username/password if JWT auth is used
|
|
107
116
|
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.USERNAME);
|
|
108
117
|
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.PASSWORD);
|
|
118
|
+
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.SESSION_COOKIES_B64);
|
|
109
119
|
}
|
|
110
120
|
if (config.sapClient) {
|
|
111
121
|
existingVars.set(constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT, config.sapClient);
|
|
@@ -104,8 +104,13 @@ class AbapSessionStore {
|
|
|
104
104
|
sapClient: obj.sapClient,
|
|
105
105
|
language: obj.language,
|
|
106
106
|
};
|
|
107
|
-
// Handle authentication:
|
|
108
|
-
if (obj.
|
|
107
|
+
// Handle authentication: SAML cookies, basic auth, or JWT auth
|
|
108
|
+
if (obj.sessionCookies) {
|
|
109
|
+
result.sessionCookies = obj.sessionCookies;
|
|
110
|
+
result.authType = 'saml';
|
|
111
|
+
result.jwtToken = '';
|
|
112
|
+
}
|
|
113
|
+
else if (obj.username && obj.password) {
|
|
109
114
|
// Basic auth
|
|
110
115
|
result.username = obj.username;
|
|
111
116
|
result.password = obj.password;
|
|
@@ -141,6 +146,7 @@ class AbapSessionStore {
|
|
|
141
146
|
await (0, tokenStorage_1.saveTokenToEnv)(destination, savePath, {
|
|
142
147
|
sapUrl: abapConfig.sapUrl,
|
|
143
148
|
jwtToken: abapConfig.jwtToken,
|
|
149
|
+
sessionCookies: abapConfig.sessionCookies,
|
|
144
150
|
username: abapConfig.username,
|
|
145
151
|
password: abapConfig.password,
|
|
146
152
|
authType: abapConfig.authType,
|
|
@@ -216,6 +222,9 @@ class AbapSessionStore {
|
|
|
216
222
|
if (rawSession.jwtToken !== undefined) {
|
|
217
223
|
result.authorizationToken = rawSession.jwtToken;
|
|
218
224
|
}
|
|
225
|
+
if (rawSession.sessionCookies !== undefined) {
|
|
226
|
+
result.sessionCookies = rawSession.sessionCookies;
|
|
227
|
+
}
|
|
219
228
|
// Basic auth fields (if present)
|
|
220
229
|
if (rawSession.username) {
|
|
221
230
|
result.username = rawSession.username;
|
|
@@ -317,6 +326,21 @@ class AbapSessionStore {
|
|
|
317
326
|
this.log?.warn(`Connection config for ${destination} missing required field: sapUrl`);
|
|
318
327
|
return null;
|
|
319
328
|
}
|
|
329
|
+
// SAML auth: session cookies
|
|
330
|
+
if (sessionConfig.authType === 'saml' || sessionConfig.sessionCookies) {
|
|
331
|
+
if (!sessionConfig.sessionCookies) {
|
|
332
|
+
this.log?.warn(`Connection config for ${destination} missing required field for SAML auth: sessionCookies`);
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
this.log?.debug(`Connection config loaded for ${destination} (SAML auth): cookies(${sessionConfig.sessionCookies.length} chars), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
336
|
+
return {
|
|
337
|
+
serviceUrl: sessionConfig.sapUrl,
|
|
338
|
+
sessionCookies: sessionConfig.sessionCookies,
|
|
339
|
+
authType: 'saml',
|
|
340
|
+
sapClient: sessionConfig.sapClient,
|
|
341
|
+
language: sessionConfig.language,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
320
344
|
// Check for basic auth: if username/password present and no jwtToken, use basic auth
|
|
321
345
|
const isBasicAuth = sessionConfig.authType === 'basic' ||
|
|
322
346
|
(!sessionConfig.jwtToken &&
|
|
@@ -448,6 +472,7 @@ class AbapSessionStore {
|
|
|
448
472
|
const newSession = {
|
|
449
473
|
serviceUrl: serviceUrl,
|
|
450
474
|
authorizationToken: config.authorizationToken || '',
|
|
475
|
+
sessionCookies: config.sessionCookies,
|
|
451
476
|
sapClient: config.sapClient,
|
|
452
477
|
language: config.language,
|
|
453
478
|
};
|
|
@@ -460,6 +485,9 @@ class AbapSessionStore {
|
|
|
460
485
|
const updated = {
|
|
461
486
|
serviceUrl: config.serviceUrl || current.sapUrl,
|
|
462
487
|
authorizationToken: config.authorizationToken,
|
|
488
|
+
sessionCookies: config.sessionCookies !== undefined
|
|
489
|
+
? config.sessionCookies
|
|
490
|
+
: current.sessionCookies,
|
|
463
491
|
sapClient: config.sapClient !== undefined ? config.sapClient : current.sapClient,
|
|
464
492
|
language: config.language !== undefined ? config.language : current.language,
|
|
465
493
|
uaaUrl: current.uaaUrl,
|
|
@@ -84,6 +84,9 @@ class SafeAbapSessionStore {
|
|
|
84
84
|
if (rawSession.jwtToken !== undefined) {
|
|
85
85
|
result.authorizationToken = rawSession.jwtToken;
|
|
86
86
|
}
|
|
87
|
+
if (rawSession.sessionCookies !== undefined) {
|
|
88
|
+
result.sessionCookies = rawSession.sessionCookies;
|
|
89
|
+
}
|
|
87
90
|
if (rawSession.sapClient) {
|
|
88
91
|
result.sapClient = rawSession.sapClient;
|
|
89
92
|
}
|
|
@@ -141,6 +144,21 @@ class SafeAbapSessionStore {
|
|
|
141
144
|
this.log?.warn(`Connection config for ${destination} missing required field: sapUrl`);
|
|
142
145
|
return null;
|
|
143
146
|
}
|
|
147
|
+
// SAML auth: session cookies
|
|
148
|
+
if (sessionConfig.authType === 'saml' || sessionConfig.sessionCookies) {
|
|
149
|
+
if (!sessionConfig.sessionCookies) {
|
|
150
|
+
this.log?.warn(`Connection config for ${destination} missing required field for SAML auth: sessionCookies`);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
this.log?.debug(`Connection config loaded for ${destination} (SAML auth): cookies(${sessionConfig.sessionCookies.length} chars), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
154
|
+
return {
|
|
155
|
+
serviceUrl: sessionConfig.sapUrl,
|
|
156
|
+
sessionCookies: sessionConfig.sessionCookies,
|
|
157
|
+
authType: 'saml',
|
|
158
|
+
sapClient: sessionConfig.sapClient,
|
|
159
|
+
language: sessionConfig.language,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
144
162
|
// Check for basic auth: if username/password present and no jwtToken, use basic auth
|
|
145
163
|
const isBasicAuth = sessionConfig.authType === 'basic' ||
|
|
146
164
|
(!sessionConfig.jwtToken &&
|
|
@@ -189,6 +207,7 @@ class SafeAbapSessionStore {
|
|
|
189
207
|
const newSession = {
|
|
190
208
|
sapUrl: serviceUrl,
|
|
191
209
|
jwtToken: config.authorizationToken,
|
|
210
|
+
sessionCookies: config.sessionCookies,
|
|
192
211
|
username: config.username,
|
|
193
212
|
password: config.password,
|
|
194
213
|
authType: config.authType,
|
|
@@ -205,6 +224,9 @@ class SafeAbapSessionStore {
|
|
|
205
224
|
...current,
|
|
206
225
|
sapUrl: config.serviceUrl || current.sapUrl,
|
|
207
226
|
jwtToken: config.authorizationToken || current.jwtToken || '',
|
|
227
|
+
sessionCookies: config.sessionCookies !== undefined
|
|
228
|
+
? config.sessionCookies
|
|
229
|
+
: current.sessionCookies,
|
|
208
230
|
username: config.username !== undefined ? config.username : current.username,
|
|
209
231
|
password: config.password !== undefined ? config.password : current.password,
|
|
210
232
|
authType: config.authType !== undefined ? config.authType : current.authType,
|
|
@@ -48,6 +48,8 @@ export declare const ABAP_CONNECTION_VARS: {
|
|
|
48
48
|
readonly SERVICE_URL: "SAP_URL";
|
|
49
49
|
/** Authorization token (JWT token) */
|
|
50
50
|
readonly AUTHORIZATION_TOKEN: "SAP_JWT_TOKEN";
|
|
51
|
+
/** Session cookies (base64-encoded) */
|
|
52
|
+
readonly SESSION_COOKIES_B64: "SAP_SESSION_COOKIES_B64";
|
|
51
53
|
/** Username for basic authentication (on-premise systems) */
|
|
52
54
|
readonly USERNAME: "SAP_USERNAME";
|
|
53
55
|
/** Password for basic authentication (on-premise systems) */
|
package/dist/utils/constants.js
CHANGED
|
@@ -51,6 +51,8 @@ exports.ABAP_CONNECTION_VARS = {
|
|
|
51
51
|
SERVICE_URL: 'SAP_URL',
|
|
52
52
|
/** Authorization token (JWT token) */
|
|
53
53
|
AUTHORIZATION_TOKEN: 'SAP_JWT_TOKEN',
|
|
54
|
+
/** Session cookies (base64-encoded) */
|
|
55
|
+
SESSION_COOKIES_B64: 'SAP_SESSION_COOKIES_B64',
|
|
54
56
|
/** Username for basic authentication (on-premise systems) */
|
|
55
57
|
USERNAME: 'SAP_USERNAME',
|
|
56
58
|
/** Password for basic authentication (on-premise systems) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/auth-stores",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Stores for MCP ABAP ADT auth-broker - BTP, ABAP, and XSUAA implementations",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"node": ">=18.0.0"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@mcp-abap-adt/interfaces": "^
|
|
56
|
+
"@mcp-abap-adt/interfaces": "^2.3.0",
|
|
57
57
|
"dotenv": "^17.2.1"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|