@mcp-abap-adt/auth-stores 0.2.0 → 0.2.3
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 +36 -0
- package/dist/storage/abap/envLoader.d.ts +4 -1
- package/dist/storage/abap/envLoader.js +32 -6
- package/dist/storage/abap/tokenStorage.d.ts +6 -3
- package/dist/storage/abap/tokenStorage.js +25 -5
- package/dist/stores/abap/AbapSessionStore.js +82 -11
- package/dist/stores/abap/SafeAbapSessionStore.js +38 -5
- package/dist/utils/constants.d.ts +4 -0
- package/dist/utils/constants.js +4 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.3] - 2025-12-16
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Dependency bump: `@mcp-abap-adt/interfaces` to `^0.1.17` for basic auth support
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **Basic Authentication Support for On-Premise Systems**: Added support for basic auth (username/password) in addition to JWT tokens
|
|
17
|
+
- **envLoader.ts**: Now loads `SAP_USERNAME` and `SAP_PASSWORD` from `.env` files
|
|
18
|
+
- Automatically detects auth type: if username/password present and no JWT token, uses basic auth
|
|
19
|
+
- If JWT token present, uses JWT auth
|
|
20
|
+
- **AbapSessionStore.getConnectionConfig()**: Returns basic auth config when username/password are present
|
|
21
|
+
- Returns `IConnectionConfig` with `username`, `password`, and `authType: 'basic'` for on-premise systems
|
|
22
|
+
- Returns `IConnectionConfig` with `authorizationToken` and `authType: 'jwt'` for cloud systems
|
|
23
|
+
- **tokenStorage.ts**: Now saves `SAP_USERNAME` and `SAP_PASSWORD` to `.env` files
|
|
24
|
+
- Handles both JWT and basic auth configurations
|
|
25
|
+
- Clears username/password when JWT auth is used, and vice versa
|
|
26
|
+
- **constants.ts**: Added `USERNAME: 'SAP_USERNAME'` and `PASSWORD: 'SAP_PASSWORD'` to `ABAP_CONNECTION_VARS`
|
|
27
|
+
- This enables on-premise systems to use `--mcp` parameter with basic auth instead of requiring JWT tokens
|
|
28
|
+
|
|
29
|
+
## [0.2.2] - 2025-12-13
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- Dependency bump: `@mcp-abap-adt/interfaces` to `^0.1.16` for alignment with latest interfaces docs
|
|
33
|
+
|
|
34
|
+
## [0.2.1] - 2025-12-12
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- **Import Organization**: Reorganized imports across storage modules for consistency
|
|
39
|
+
- Moved `ILogger` type import after standard library imports (`fs`, `path`, `dotenv`)
|
|
40
|
+
- Affected files: `envLoader.ts`, `tokenStorage.ts`, `xsuaaEnvLoader.ts`, `xsuaaTokenStorage.ts`
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
|
|
44
|
+
- **testLogger.ts**: Removed unused `ILogger` import
|
|
45
|
+
|
|
10
46
|
## [0.2.0] - 2025-12-08
|
|
11
47
|
|
|
12
48
|
### Breaking Changes
|
|
@@ -5,7 +5,10 @@ import type { ILogger } from '@mcp-abap-adt/interfaces';
|
|
|
5
5
|
interface EnvConfig {
|
|
6
6
|
sapUrl: string;
|
|
7
7
|
sapClient?: string;
|
|
8
|
-
jwtToken
|
|
8
|
+
jwtToken?: string;
|
|
9
|
+
username?: string;
|
|
10
|
+
password?: string;
|
|
11
|
+
authType?: 'basic' | 'jwt';
|
|
9
12
|
refreshToken?: string;
|
|
10
13
|
uaaUrl?: string;
|
|
11
14
|
uaaClientId?: string;
|
|
@@ -65,16 +65,38 @@ 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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
const username = parsed[constants_1.ABAP_CONNECTION_VARS.USERNAME];
|
|
69
|
+
const password = parsed[constants_1.ABAP_CONNECTION_VARS.PASSWORD];
|
|
70
|
+
log?.debug(`Extracted fields: hasSapUrl(${!!sapUrl}), hasJwtToken(${jwtToken !== undefined && jwtToken !== null}), hasUsername(${!!username}), hasPassword(${!!password})`);
|
|
71
|
+
// sapUrl is always required
|
|
72
|
+
if (!sapUrl) {
|
|
73
|
+
log?.warn(`Env file missing required field: sapUrl`);
|
|
72
74
|
return null;
|
|
73
75
|
}
|
|
76
|
+
// Determine auth type: if username/password present and no jwtToken, use basic auth
|
|
77
|
+
// If jwtToken present, use JWT auth
|
|
78
|
+
// If neither is present, it's OK - auth can be set later (e.g., via setAuthorizationConfig)
|
|
79
|
+
const isBasicAuth = !!(username && password) && (!jwtToken || jwtToken.trim() === '');
|
|
80
|
+
const isJwtAuth = !!(jwtToken && jwtToken.trim() !== '');
|
|
81
|
+
const hasNoAuth = !isBasicAuth && !isJwtAuth;
|
|
74
82
|
const config = {
|
|
75
83
|
sapUrl: sapUrl.trim(),
|
|
76
|
-
jwtToken: jwtToken.trim(), // Can be empty string for authorization-only sessions
|
|
77
84
|
};
|
|
85
|
+
// Set authentication fields based on type
|
|
86
|
+
if (isBasicAuth) {
|
|
87
|
+
config.username = username.trim();
|
|
88
|
+
config.password = password.trim();
|
|
89
|
+
config.authType = 'basic';
|
|
90
|
+
}
|
|
91
|
+
else if (isJwtAuth) {
|
|
92
|
+
config.jwtToken = jwtToken.trim();
|
|
93
|
+
config.authType = 'jwt';
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
// No auth yet - will be set later (e.g., via setAuthorizationConfig)
|
|
97
|
+
config.jwtToken = jwtToken || '';
|
|
98
|
+
config.authType = undefined;
|
|
99
|
+
}
|
|
78
100
|
// Optional fields
|
|
79
101
|
if (parsed[constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT]) {
|
|
80
102
|
config.sapClient = parsed[constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT].trim();
|
|
@@ -94,7 +116,11 @@ async function loadEnvFile(destination, directory, log) {
|
|
|
94
116
|
if (parsed[constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE]) {
|
|
95
117
|
config.language = parsed[constants_1.ABAP_CONNECTION_VARS.SAP_LANGUAGE].trim();
|
|
96
118
|
}
|
|
97
|
-
|
|
119
|
+
const tokenLength = config.jwtToken?.length || 0;
|
|
120
|
+
const authInfo = config.authType === 'basic'
|
|
121
|
+
? `basic auth (username: ${config.username})`
|
|
122
|
+
: `JWT token(${tokenLength} chars)`;
|
|
123
|
+
log?.info(`Env config loaded from ${envFilePath}: sapUrl(${config.sapUrl.substring(0, 50)}...), ${authInfo}, hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl})`);
|
|
98
124
|
return config;
|
|
99
125
|
}
|
|
100
126
|
catch (error) {
|
|
@@ -5,7 +5,10 @@ import type { ILogger } from '@mcp-abap-adt/interfaces';
|
|
|
5
5
|
interface EnvConfig {
|
|
6
6
|
sapUrl: string;
|
|
7
7
|
sapClient?: string;
|
|
8
|
-
jwtToken
|
|
8
|
+
jwtToken?: string;
|
|
9
|
+
username?: string;
|
|
10
|
+
password?: string;
|
|
11
|
+
authType?: 'basic' | 'jwt';
|
|
9
12
|
refreshToken?: string;
|
|
10
13
|
uaaUrl?: string;
|
|
11
14
|
uaaClientId?: string;
|
|
@@ -20,7 +23,7 @@ interface EnvConfig {
|
|
|
20
23
|
* @param log Optional logger for logging operations
|
|
21
24
|
*/
|
|
22
25
|
export declare function saveTokenToEnv(destination: string, savePath: string, config: Partial<EnvConfig> & {
|
|
23
|
-
sapUrl
|
|
24
|
-
jwtToken
|
|
26
|
+
sapUrl: string;
|
|
27
|
+
jwtToken?: string;
|
|
25
28
|
}, log?: ILogger): Promise<void>;
|
|
26
29
|
export {};
|
|
@@ -51,7 +51,9 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
51
51
|
const envFilePath = path.join(savePath, `${destination}.env`);
|
|
52
52
|
const tempFilePath = `${envFilePath}.tmp`;
|
|
53
53
|
log?.debug(`Saving token to env file: ${envFilePath}`);
|
|
54
|
-
|
|
54
|
+
const tokenLength = config.jwtToken?.length || 0;
|
|
55
|
+
const hasBasicAuth = !!(config.username && config.password);
|
|
56
|
+
log?.debug(`Config to save: hasSapUrl(${!!config.sapUrl}), token(${tokenLength} chars), hasBasicAuth(${hasBasicAuth}), hasRefreshToken(${!!config.refreshToken}), hasUaaUrl(${!!config.uaaUrl})`);
|
|
55
57
|
// Ensure directory exists
|
|
56
58
|
if (!fs.existsSync(savePath)) {
|
|
57
59
|
log?.debug(`Creating directory: ${savePath}`);
|
|
@@ -83,10 +85,25 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
83
85
|
}
|
|
84
86
|
log?.debug(`Preserved ${existingVars.size} existing variables from env file`);
|
|
85
87
|
// Update with new values
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
// sapUrl is required - always save it
|
|
89
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.SERVICE_URL, config.sapUrl);
|
|
90
|
+
// Handle authentication: JWT or basic auth
|
|
91
|
+
if (config.username && config.password) {
|
|
92
|
+
// Basic auth - save username/password
|
|
93
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.USERNAME, config.username);
|
|
94
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.PASSWORD, config.password);
|
|
95
|
+
// Clear JWT token if basic auth is used
|
|
96
|
+
if (config.jwtToken) {
|
|
97
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, '');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else if (config.jwtToken) {
|
|
101
|
+
// JWT auth - save token
|
|
102
|
+
existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, config.jwtToken);
|
|
103
|
+
// Clear username/password if JWT auth is used
|
|
104
|
+
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.USERNAME);
|
|
105
|
+
existingVars.delete(constants_1.ABAP_CONNECTION_VARS.PASSWORD);
|
|
88
106
|
}
|
|
89
|
-
existingVars.set(constants_1.ABAP_CONNECTION_VARS.AUTHORIZATION_TOKEN, config.jwtToken);
|
|
90
107
|
if (config.sapClient) {
|
|
91
108
|
existingVars.set(constants_1.ABAP_CONNECTION_VARS.SAP_CLIENT, config.sapClient);
|
|
92
109
|
}
|
|
@@ -120,5 +137,8 @@ async function saveTokenToEnv(destination, savePath, config, log) {
|
|
|
120
137
|
fs.writeFileSync(tempFilePath, envContent, 'utf8');
|
|
121
138
|
// Atomic rename
|
|
122
139
|
fs.renameSync(tempFilePath, envFilePath);
|
|
123
|
-
|
|
140
|
+
const authInfo = hasBasicAuth
|
|
141
|
+
? `basic auth (username: ${config.username})`
|
|
142
|
+
: `JWT token(${tokenLength} chars)`;
|
|
143
|
+
log?.info(`Token saved to ${envFilePath}: ${authInfo}, sapUrl(${config.sapUrl ? config.sapUrl.substring(0, 50) + '...' : 'none'}), variables(${envLines.length})`);
|
|
124
144
|
}
|
|
@@ -94,9 +94,8 @@ class AbapSessionStore {
|
|
|
94
94
|
convertToInternalFormat(config) {
|
|
95
95
|
const obj = config;
|
|
96
96
|
// Convert IConfig format (serviceUrl, authorizationToken) to internal format (sapUrl, jwtToken)
|
|
97
|
-
|
|
97
|
+
const result = {
|
|
98
98
|
sapUrl: (obj.serviceUrl || obj.sapUrl),
|
|
99
|
-
jwtToken: (obj.authorizationToken || obj.jwtToken || ''), // Ensure jwtToken is always a string
|
|
100
99
|
refreshToken: obj.refreshToken,
|
|
101
100
|
uaaUrl: obj.uaaUrl,
|
|
102
101
|
uaaClientId: obj.uaaClientId,
|
|
@@ -104,6 +103,20 @@ class AbapSessionStore {
|
|
|
104
103
|
sapClient: obj.sapClient,
|
|
105
104
|
language: obj.language,
|
|
106
105
|
};
|
|
106
|
+
// Handle authentication: JWT or basic auth
|
|
107
|
+
if (obj.username && obj.password) {
|
|
108
|
+
// Basic auth
|
|
109
|
+
result.username = obj.username;
|
|
110
|
+
result.password = obj.password;
|
|
111
|
+
result.authType = 'basic';
|
|
112
|
+
result.jwtToken = obj.authorizationToken || obj.jwtToken || '';
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// JWT auth
|
|
116
|
+
result.jwtToken = (obj.authorizationToken || obj.jwtToken || '');
|
|
117
|
+
result.authType = 'jwt';
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
107
120
|
}
|
|
108
121
|
/**
|
|
109
122
|
* Save session to ENV file
|
|
@@ -125,6 +138,9 @@ class AbapSessionStore {
|
|
|
125
138
|
await (0, tokenStorage_1.saveTokenToEnv)(destination, savePath, {
|
|
126
139
|
sapUrl: abapConfig.sapUrl,
|
|
127
140
|
jwtToken: abapConfig.jwtToken,
|
|
141
|
+
username: abapConfig.username,
|
|
142
|
+
password: abapConfig.password,
|
|
143
|
+
authType: abapConfig.authType,
|
|
128
144
|
refreshToken: abapConfig.refreshToken,
|
|
129
145
|
uaaUrl: abapConfig.uaaUrl,
|
|
130
146
|
uaaClientId: abapConfig.uaaClientId,
|
|
@@ -193,6 +209,16 @@ class AbapSessionStore {
|
|
|
193
209
|
if (rawSession.jwtToken !== undefined) {
|
|
194
210
|
result.authorizationToken = rawSession.jwtToken;
|
|
195
211
|
}
|
|
212
|
+
// Basic auth fields (if present)
|
|
213
|
+
if (rawSession.username) {
|
|
214
|
+
result.username = rawSession.username;
|
|
215
|
+
}
|
|
216
|
+
if (rawSession.password) {
|
|
217
|
+
result.password = rawSession.password;
|
|
218
|
+
}
|
|
219
|
+
if (rawSession.authType) {
|
|
220
|
+
result.authType = rawSession.authType;
|
|
221
|
+
}
|
|
196
222
|
if (rawSession.sapClient) {
|
|
197
223
|
result.sapClient = rawSession.sapClient;
|
|
198
224
|
}
|
|
@@ -230,7 +256,7 @@ class AbapSessionStore {
|
|
|
230
256
|
try {
|
|
231
257
|
const raw = await this.loadFromFile(sessionPath);
|
|
232
258
|
if (!raw || !isEnvConfig(raw)) {
|
|
233
|
-
this.log?.debug(`Invalid session format for ${destination}: missing required
|
|
259
|
+
this.log?.debug(`Invalid session format for ${destination}: missing required field (sapUrl)`);
|
|
234
260
|
return null;
|
|
235
261
|
}
|
|
236
262
|
return raw;
|
|
@@ -276,14 +302,38 @@ class AbapSessionStore {
|
|
|
276
302
|
this.log?.debug(`Connection config not found for ${destination}`);
|
|
277
303
|
return null;
|
|
278
304
|
}
|
|
279
|
-
if (!sessionConfig.
|
|
280
|
-
this.log?.warn(`Connection config for ${destination} missing required
|
|
305
|
+
if (!sessionConfig.sapUrl) {
|
|
306
|
+
this.log?.warn(`Connection config for ${destination} missing required field: sapUrl`);
|
|
281
307
|
return null;
|
|
282
308
|
}
|
|
283
|
-
|
|
309
|
+
// Check for basic auth: if username/password present and no jwtToken, use basic auth
|
|
310
|
+
const isBasicAuth = sessionConfig.authType === 'basic' ||
|
|
311
|
+
(!sessionConfig.jwtToken && sessionConfig.username && sessionConfig.password);
|
|
312
|
+
if (isBasicAuth) {
|
|
313
|
+
if (!sessionConfig.username || !sessionConfig.password) {
|
|
314
|
+
this.log?.warn(`Connection config for ${destination} missing required fields for basic auth: username(${!!sessionConfig.username}), password(${!!sessionConfig.password})`);
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
this.log?.debug(`Connection config loaded for ${destination} (basic auth): username(${sessionConfig.username}), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
318
|
+
return {
|
|
319
|
+
serviceUrl: sessionConfig.sapUrl,
|
|
320
|
+
username: sessionConfig.username,
|
|
321
|
+
password: sessionConfig.password,
|
|
322
|
+
authType: 'basic',
|
|
323
|
+
sapClient: sessionConfig.sapClient,
|
|
324
|
+
language: sessionConfig.language,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
// JWT auth: check jwtToken
|
|
328
|
+
if (!sessionConfig.jwtToken) {
|
|
329
|
+
this.log?.warn(`Connection config for ${destination} missing required field for JWT auth: jwtToken`);
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
this.log?.debug(`Connection config loaded for ${destination} (JWT auth): token(${sessionConfig.jwtToken.length} chars), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
284
333
|
return {
|
|
285
334
|
serviceUrl: sessionConfig.sapUrl,
|
|
286
335
|
authorizationToken: sessionConfig.jwtToken,
|
|
336
|
+
authType: 'jwt',
|
|
287
337
|
sapClient: sessionConfig.sapClient,
|
|
288
338
|
language: sessionConfig.language,
|
|
289
339
|
};
|
|
@@ -298,10 +348,27 @@ class AbapSessionStore {
|
|
|
298
348
|
async setAuthorizationConfig(destination, config) {
|
|
299
349
|
const current = await this.loadRawSession(destination);
|
|
300
350
|
if (!current) {
|
|
301
|
-
// Session doesn't exist - try to get serviceUrl from
|
|
351
|
+
// Session doesn't exist - try to get serviceUrl from existing session file or use defaultServiceUrl
|
|
302
352
|
// For ABAP, we need sapUrl to create session
|
|
303
|
-
|
|
304
|
-
|
|
353
|
+
let sapUrl = this.defaultServiceUrl;
|
|
354
|
+
let existingAuthToken = '';
|
|
355
|
+
let existingUsername;
|
|
356
|
+
let existingPassword;
|
|
357
|
+
let existingAuthType;
|
|
358
|
+
// Try to load existing session file to get serviceUrl and auth info
|
|
359
|
+
try {
|
|
360
|
+
const existingSession = await this.loadSession(destination);
|
|
361
|
+
if (existingSession?.serviceUrl) {
|
|
362
|
+
sapUrl = existingSession.serviceUrl;
|
|
363
|
+
existingAuthToken = existingSession.authorizationToken || '';
|
|
364
|
+
existingUsername = existingSession?.username;
|
|
365
|
+
existingPassword = existingSession?.password;
|
|
366
|
+
existingAuthType = existingSession?.authType;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
// Ignore errors when loading session - will use defaultServiceUrl
|
|
371
|
+
}
|
|
305
372
|
if (!sapUrl) {
|
|
306
373
|
this.log?.error(`Cannot set authorization config for ${destination}: session does not exist and serviceUrl is required. Missing defaultServiceUrl in constructor.`);
|
|
307
374
|
throw new Error(`Cannot set authorization config for destination "${destination}": session does not exist and serviceUrl is required for ABAP sessions. Call setConnectionConfig first or provide defaultServiceUrl in constructor.`);
|
|
@@ -309,7 +376,10 @@ class AbapSessionStore {
|
|
|
309
376
|
this.log?.debug(`Creating new session for ${destination} via setAuthorizationConfig: sapUrl(${sapUrl.substring(0, 40)}...)`);
|
|
310
377
|
const newSession = {
|
|
311
378
|
serviceUrl: sapUrl,
|
|
312
|
-
authorizationToken:
|
|
379
|
+
authorizationToken: existingAuthToken,
|
|
380
|
+
username: existingUsername,
|
|
381
|
+
password: existingPassword,
|
|
382
|
+
authType: existingAuthType,
|
|
313
383
|
uaaUrl: config.uaaUrl,
|
|
314
384
|
uaaClientId: config.uaaClientId,
|
|
315
385
|
uaaClientSecret: config.uaaClientSecret,
|
|
@@ -387,5 +457,6 @@ function isEnvConfig(config) {
|
|
|
387
457
|
if (!config || typeof config !== 'object')
|
|
388
458
|
return false;
|
|
389
459
|
const obj = config;
|
|
390
|
-
|
|
460
|
+
// Must have sapUrl (authentication fields are optional - can be set later)
|
|
461
|
+
return 'sapUrl' in obj;
|
|
391
462
|
}
|
|
@@ -55,6 +55,9 @@ class SafeAbapSessionStore {
|
|
|
55
55
|
const internal = {
|
|
56
56
|
sapUrl: (obj.serviceUrl || obj.sapUrl),
|
|
57
57
|
jwtToken: (obj.authorizationToken || obj.jwtToken),
|
|
58
|
+
username: obj.username,
|
|
59
|
+
password: obj.password,
|
|
60
|
+
authType: obj.authType,
|
|
58
61
|
refreshToken: obj.refreshToken,
|
|
59
62
|
uaaUrl: obj.uaaUrl,
|
|
60
63
|
uaaClientId: obj.uaaClientId,
|
|
@@ -130,14 +133,38 @@ class SafeAbapSessionStore {
|
|
|
130
133
|
this.log?.debug(`Connection config not found for ${destination}`);
|
|
131
134
|
return null;
|
|
132
135
|
}
|
|
133
|
-
if (!sessionConfig.
|
|
134
|
-
this.log?.warn(`Connection config for ${destination} missing required
|
|
136
|
+
if (!sessionConfig.sapUrl) {
|
|
137
|
+
this.log?.warn(`Connection config for ${destination} missing required field: sapUrl`);
|
|
135
138
|
return null;
|
|
136
139
|
}
|
|
137
|
-
|
|
140
|
+
// Check for basic auth: if username/password present and no jwtToken, use basic auth
|
|
141
|
+
const isBasicAuth = sessionConfig.authType === 'basic' ||
|
|
142
|
+
(!sessionConfig.jwtToken && sessionConfig.username && sessionConfig.password);
|
|
143
|
+
if (isBasicAuth) {
|
|
144
|
+
if (!sessionConfig.username || !sessionConfig.password) {
|
|
145
|
+
this.log?.warn(`Connection config for ${destination} missing required fields for basic auth: username(${!!sessionConfig.username}), password(${!!sessionConfig.password})`);
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
this.log?.debug(`Connection config loaded for ${destination} (basic auth): username(${sessionConfig.username}), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
149
|
+
return {
|
|
150
|
+
serviceUrl: sessionConfig.sapUrl,
|
|
151
|
+
username: sessionConfig.username,
|
|
152
|
+
password: sessionConfig.password,
|
|
153
|
+
authType: 'basic',
|
|
154
|
+
sapClient: sessionConfig.sapClient,
|
|
155
|
+
language: sessionConfig.language,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
// JWT auth: check jwtToken
|
|
159
|
+
if (!sessionConfig.jwtToken) {
|
|
160
|
+
this.log?.warn(`Connection config for ${destination} missing required field for JWT auth: jwtToken`);
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
this.log?.debug(`Connection config loaded for ${destination} (JWT auth): token(${sessionConfig.jwtToken.length} chars), sapUrl(${sessionConfig.sapUrl.substring(0, 40)}...)`);
|
|
138
164
|
return {
|
|
139
165
|
serviceUrl: sessionConfig.sapUrl,
|
|
140
166
|
authorizationToken: sessionConfig.jwtToken,
|
|
167
|
+
authType: 'jwt',
|
|
141
168
|
sapClient: sessionConfig.sapClient,
|
|
142
169
|
language: sessionConfig.language,
|
|
143
170
|
};
|
|
@@ -155,7 +182,10 @@ class SafeAbapSessionStore {
|
|
|
155
182
|
this.log?.debug(`Creating new session for ${destination} via setConnectionConfig: serviceUrl(${serviceUrl.substring(0, 40)}...), token(${config.authorizationToken?.length || 0} chars)`);
|
|
156
183
|
const newSession = {
|
|
157
184
|
sapUrl: serviceUrl,
|
|
158
|
-
jwtToken: config.authorizationToken
|
|
185
|
+
jwtToken: config.authorizationToken,
|
|
186
|
+
username: config.username,
|
|
187
|
+
password: config.password,
|
|
188
|
+
authType: config.authType,
|
|
159
189
|
sapClient: config.sapClient,
|
|
160
190
|
language: config.language,
|
|
161
191
|
};
|
|
@@ -168,7 +198,10 @@ class SafeAbapSessionStore {
|
|
|
168
198
|
const updated = {
|
|
169
199
|
...current,
|
|
170
200
|
sapUrl: config.serviceUrl || current.sapUrl,
|
|
171
|
-
jwtToken: config.authorizationToken,
|
|
201
|
+
jwtToken: config.authorizationToken || current.jwtToken || '',
|
|
202
|
+
username: config.username !== undefined ? config.username : current.username,
|
|
203
|
+
password: config.password !== undefined ? config.password : current.password,
|
|
204
|
+
authType: config.authType !== undefined ? config.authType : current.authType,
|
|
172
205
|
sapClient: config.sapClient !== undefined ? config.sapClient : current.sapClient,
|
|
173
206
|
language: config.language !== undefined ? config.language : current.language,
|
|
174
207
|
};
|
|
@@ -48,6 +48,10 @@ 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
|
+
/** Username for basic authentication (on-premise systems) */
|
|
52
|
+
readonly USERNAME: "SAP_USERNAME";
|
|
53
|
+
/** Password for basic authentication (on-premise systems) */
|
|
54
|
+
readonly PASSWORD: "SAP_PASSWORD";
|
|
51
55
|
/** SAP client number (optional) */
|
|
52
56
|
readonly SAP_CLIENT: "SAP_CLIENT";
|
|
53
57
|
/** Language (optional) */
|
package/dist/utils/constants.js
CHANGED
|
@@ -51,6 +51,10 @@ exports.ABAP_CONNECTION_VARS = {
|
|
|
51
51
|
SERVICE_URL: 'SAP_URL',
|
|
52
52
|
/** Authorization token (JWT token) */
|
|
53
53
|
AUTHORIZATION_TOKEN: 'SAP_JWT_TOKEN',
|
|
54
|
+
/** Username for basic authentication (on-premise systems) */
|
|
55
|
+
USERNAME: 'SAP_USERNAME',
|
|
56
|
+
/** Password for basic authentication (on-premise systems) */
|
|
57
|
+
PASSWORD: 'SAP_PASSWORD',
|
|
54
58
|
/** SAP client number (optional) */
|
|
55
59
|
SAP_CLIENT: 'SAP_CLIENT',
|
|
56
60
|
/** Language (optional) */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-abap-adt/auth-stores",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
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",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"node": ">=18.0.0"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@mcp-abap-adt/interfaces": "^0.1.
|
|
52
|
+
"@mcp-abap-adt/interfaces": "^0.1.17",
|
|
53
53
|
"dotenv": "^17.2.1"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|