@mcp-abap-adt/auth-broker 0.1.4 → 0.1.6

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +287 -0
  2. package/README.md +186 -9
  3. package/bin/generate-env-from-service-key.ts +128 -0
  4. package/dist/AuthBroker.d.ts +19 -35
  5. package/dist/AuthBroker.d.ts.map +1 -1
  6. package/dist/AuthBroker.js +87 -149
  7. package/dist/__tests__/helpers/configHelpers.d.ts +49 -0
  8. package/dist/__tests__/helpers/configHelpers.d.ts.map +1 -0
  9. package/dist/__tests__/helpers/configHelpers.js +169 -0
  10. package/dist/index.d.ts +4 -4
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +5 -7
  13. package/dist/providers/ITokenProvider.d.ts +49 -0
  14. package/dist/providers/ITokenProvider.d.ts.map +1 -0
  15. package/dist/providers/ITokenProvider.js +10 -0
  16. package/dist/providers/index.d.ts +8 -0
  17. package/dist/providers/index.d.ts.map +1 -0
  18. package/dist/providers/index.js +8 -0
  19. package/dist/stores/index.d.ts +5 -4
  20. package/dist/stores/index.d.ts.map +1 -1
  21. package/dist/stores/index.js +4 -6
  22. package/dist/stores/interfaces.d.ts +90 -20
  23. package/dist/stores/interfaces.d.ts.map +1 -1
  24. package/dist/stores/interfaces.js +1 -2
  25. package/dist/types.d.ts +7 -31
  26. package/dist/types.d.ts.map +1 -1
  27. package/dist/types.js +2 -0
  28. package/package.json +13 -6
  29. package/dist/__tests__/testHelpers.d.ts +0 -44
  30. package/dist/__tests__/testHelpers.d.ts.map +0 -1
  31. package/dist/__tests__/testHelpers.js +0 -129
  32. package/dist/browserAuth.d.ts +0 -17
  33. package/dist/browserAuth.d.ts.map +0 -1
  34. package/dist/browserAuth.js +0 -305
  35. package/dist/cache.d.ts +0 -20
  36. package/dist/cache.d.ts.map +0 -1
  37. package/dist/cache.js +0 -46
  38. package/dist/envLoader.d.ts +0 -12
  39. package/dist/envLoader.d.ts.map +0 -1
  40. package/dist/envLoader.js +0 -90
  41. package/dist/getToken.d.ts +0 -14
  42. package/dist/getToken.d.ts.map +0 -1
  43. package/dist/getToken.js +0 -62
  44. package/dist/logger.d.ts +0 -40
  45. package/dist/logger.d.ts.map +0 -1
  46. package/dist/logger.js +0 -186
  47. package/dist/pathResolver.d.ts +0 -21
  48. package/dist/pathResolver.d.ts.map +0 -1
  49. package/dist/pathResolver.js +0 -105
  50. package/dist/refreshToken.d.ts +0 -14
  51. package/dist/refreshToken.d.ts.map +0 -1
  52. package/dist/refreshToken.js +0 -71
  53. package/dist/serviceKeyLoader.d.ts +0 -12
  54. package/dist/serviceKeyLoader.d.ts.map +0 -1
  55. package/dist/serviceKeyLoader.js +0 -72
  56. package/dist/stores/FileServiceKeyStore.d.ts +0 -38
  57. package/dist/stores/FileServiceKeyStore.d.ts.map +0 -1
  58. package/dist/stores/FileServiceKeyStore.js +0 -47
  59. package/dist/stores/FileSessionStore.d.ts +0 -50
  60. package/dist/stores/FileSessionStore.d.ts.map +0 -1
  61. package/dist/stores/FileSessionStore.js +0 -116
  62. package/dist/tokenRefresher.d.ts +0 -17
  63. package/dist/tokenRefresher.d.ts.map +0 -1
  64. package/dist/tokenRefresher.js +0 -53
  65. package/dist/tokenStorage.d.ts +0 -15
  66. package/dist/tokenStorage.d.ts.map +0 -1
  67. package/dist/tokenStorage.js +0 -107
  68. package/dist/tokenValidator.d.ts +0 -11
  69. package/dist/tokenValidator.d.ts.map +0 -1
  70. package/dist/tokenValidator.js +0 -108
@@ -1,116 +0,0 @@
1
- "use strict";
2
- /**
3
- * File-based implementation of SessionStore
4
- *
5
- * Reads/writes session data from/to {destination}.env files in search paths.
6
- */
7
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
- if (k2 === undefined) k2 = k;
9
- var desc = Object.getOwnPropertyDescriptor(m, k);
10
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
- desc = { enumerable: true, get: function() { return m[k]; } };
12
- }
13
- Object.defineProperty(o, k2, desc);
14
- }) : (function(o, m, k, k2) {
15
- if (k2 === undefined) k2 = k;
16
- o[k2] = m[k];
17
- }));
18
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
- Object.defineProperty(o, "default", { enumerable: true, value: v });
20
- }) : function(o, v) {
21
- o["default"] = v;
22
- });
23
- var __importStar = (this && this.__importStar) || (function () {
24
- var ownKeys = function(o) {
25
- ownKeys = Object.getOwnPropertyNames || function (o) {
26
- var ar = [];
27
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
- return ar;
29
- };
30
- return ownKeys(o);
31
- };
32
- return function (mod) {
33
- if (mod && mod.__esModule) return mod;
34
- var result = {};
35
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
- __setModuleDefault(result, mod);
37
- return result;
38
- };
39
- })();
40
- Object.defineProperty(exports, "__esModule", { value: true });
41
- exports.FileSessionStore = void 0;
42
- const envLoader_1 = require("../envLoader");
43
- const tokenStorage_1 = require("../tokenStorage");
44
- const pathResolver_1 = require("../pathResolver");
45
- /**
46
- * File-based session store implementation
47
- *
48
- * Searches for {destination}.env files in configured search paths.
49
- * Writes to first search path (highest priority).
50
- * Search paths priority:
51
- * 1. Constructor parameter (highest)
52
- * 2. AUTH_BROKER_PATH environment variable
53
- * 3. Current working directory (lowest)
54
- */
55
- class FileSessionStore {
56
- searchPaths;
57
- /**
58
- * Create a new FileSessionStore instance
59
- * @param searchPaths Optional search paths for .env files.
60
- * Can be a single path (string) or array of paths.
61
- * If not provided, uses AUTH_BROKER_PATH env var or current working directory.
62
- */
63
- constructor(searchPaths) {
64
- this.searchPaths = (0, pathResolver_1.resolveSearchPaths)(searchPaths);
65
- }
66
- /**
67
- * Load session configuration for destination
68
- * @param destination Destination name (e.g., "TRIAL")
69
- * @returns EnvConfig object or null if not found
70
- */
71
- async loadSession(destination) {
72
- return (0, envLoader_1.loadEnvFile)(destination, this.searchPaths);
73
- }
74
- /**
75
- * Save session configuration for destination
76
- * @param destination Destination name (e.g., "TRIAL")
77
- * @param config Session configuration to save
78
- */
79
- async saveSession(destination, config) {
80
- // Save to first search path (highest priority)
81
- const savePath = this.searchPaths[0];
82
- // Convert EnvConfig to format expected by saveTokenToEnv
83
- await (0, tokenStorage_1.saveTokenToEnv)(destination, savePath, {
84
- sapUrl: config.sapUrl,
85
- jwtToken: config.jwtToken,
86
- refreshToken: config.refreshToken,
87
- uaaUrl: config.uaaUrl,
88
- uaaClientId: config.uaaClientId,
89
- uaaClientSecret: config.uaaClientSecret,
90
- sapClient: config.sapClient,
91
- language: config.language,
92
- });
93
- }
94
- /**
95
- * Delete session for destination
96
- * @param destination Destination name (e.g., "TRIAL")
97
- */
98
- async deleteSession(destination) {
99
- // Find .env file in search paths
100
- const fileName = `${destination}.env`;
101
- const { findFileInPaths } = await Promise.resolve().then(() => __importStar(require('../pathResolver')));
102
- const fs = await Promise.resolve().then(() => __importStar(require('fs')));
103
- const envFilePath = findFileInPaths(fileName, this.searchPaths);
104
- if (envFilePath && fs.existsSync(envFilePath)) {
105
- fs.unlinkSync(envFilePath);
106
- }
107
- }
108
- /**
109
- * Get search paths (for error messages)
110
- * @returns Array of search paths
111
- */
112
- getSearchPaths() {
113
- return [...this.searchPaths];
114
- }
115
- }
116
- exports.FileSessionStore = FileSessionStore;
@@ -1,17 +0,0 @@
1
- /**
2
- * Token refresher - refreshes JWT tokens using refresh token
3
- */
4
- export interface TokenRefreshResult {
5
- accessToken: string;
6
- refreshToken?: string;
7
- }
8
- /**
9
- * Refreshes the access token using refresh token
10
- * @param refreshToken Refresh token
11
- * @param uaaUrl UAA URL (e.g., https://your-account.authentication.eu10.hana.ondemand.com)
12
- * @param clientId UAA client ID
13
- * @param clientSecret UAA client secret
14
- * @returns Promise that resolves to new tokens
15
- */
16
- export declare function refreshJwtToken(refreshToken: string, uaaUrl: string, clientId: string, clientSecret: string): Promise<TokenRefreshResult>;
17
- //# sourceMappingURL=tokenRefresher.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tokenRefresher.d.ts","sourceRoot":"","sources":["../src/tokenRefresher.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAqC7B"}
@@ -1,53 +0,0 @@
1
- "use strict";
2
- /**
3
- * Token refresher - refreshes JWT tokens using refresh token
4
- */
5
- var __importDefault = (this && this.__importDefault) || function (mod) {
6
- return (mod && mod.__esModule) ? mod : { "default": mod };
7
- };
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.refreshJwtToken = refreshJwtToken;
10
- const axios_1 = __importDefault(require("axios"));
11
- /**
12
- * Refreshes the access token using refresh token
13
- * @param refreshToken Refresh token
14
- * @param uaaUrl UAA URL (e.g., https://your-account.authentication.eu10.hana.ondemand.com)
15
- * @param clientId UAA client ID
16
- * @param clientSecret UAA client secret
17
- * @returns Promise that resolves to new tokens
18
- */
19
- async function refreshJwtToken(refreshToken, uaaUrl, clientId, clientSecret) {
20
- try {
21
- const tokenUrl = `${uaaUrl}/oauth/token`;
22
- const params = new URLSearchParams();
23
- params.append('grant_type', 'refresh_token');
24
- params.append('refresh_token', refreshToken);
25
- const authString = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');
26
- const response = await (0, axios_1.default)({
27
- method: 'post',
28
- url: tokenUrl,
29
- headers: {
30
- Authorization: `Basic ${authString}`,
31
- 'Content-Type': 'application/x-www-form-urlencoded',
32
- },
33
- data: params.toString(),
34
- });
35
- if (response.data && response.data.access_token) {
36
- return {
37
- accessToken: response.data.access_token,
38
- refreshToken: response.data.refresh_token || refreshToken, // Use new refresh token if provided, otherwise keep old one
39
- };
40
- }
41
- else {
42
- throw new Error('Response does not contain access_token');
43
- }
44
- }
45
- catch (error) {
46
- if (error.response) {
47
- throw new Error(`Token refresh failed (${error.response.status}): ${JSON.stringify(error.response.data)}`);
48
- }
49
- else {
50
- throw new Error(`Token refresh failed: ${error.message}`);
51
- }
52
- }
53
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * Token storage - saves tokens to .env files
3
- */
4
- import { EnvConfig } from './types';
5
- /**
6
- * Save token to {destination}.env file
7
- * @param destination Destination name
8
- * @param savePath Path where to save the file
9
- * @param config Configuration to save
10
- */
11
- export declare function saveTokenToEnv(destination: string, savePath: string, config: Partial<EnvConfig> & {
12
- sapUrl: string;
13
- jwtToken: string;
14
- }): Promise<void>;
15
- //# sourceMappingURL=tokenStorage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tokenStorage.d.ts","sourceRoot":"","sources":["../src/tokenStorage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAChE,OAAO,CAAC,IAAI,CAAC,CA0Ef"}
@@ -1,107 +0,0 @@
1
- "use strict";
2
- /**
3
- * Token storage - saves tokens to .env files
4
- */
5
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- var desc = Object.getOwnPropertyDescriptor(m, k);
8
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
- desc = { enumerable: true, get: function() { return m[k]; } };
10
- }
11
- Object.defineProperty(o, k2, desc);
12
- }) : (function(o, m, k, k2) {
13
- if (k2 === undefined) k2 = k;
14
- o[k2] = m[k];
15
- }));
16
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
- Object.defineProperty(o, "default", { enumerable: true, value: v });
18
- }) : function(o, v) {
19
- o["default"] = v;
20
- });
21
- var __importStar = (this && this.__importStar) || (function () {
22
- var ownKeys = function(o) {
23
- ownKeys = Object.getOwnPropertyNames || function (o) {
24
- var ar = [];
25
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
- return ar;
27
- };
28
- return ownKeys(o);
29
- };
30
- return function (mod) {
31
- if (mod && mod.__esModule) return mod;
32
- var result = {};
33
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
- __setModuleDefault(result, mod);
35
- return result;
36
- };
37
- })();
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.saveTokenToEnv = saveTokenToEnv;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
42
- /**
43
- * Save token to {destination}.env file
44
- * @param destination Destination name
45
- * @param savePath Path where to save the file
46
- * @param config Configuration to save
47
- */
48
- async function saveTokenToEnv(destination, savePath, config) {
49
- // Ensure directory exists
50
- if (!fs.existsSync(savePath)) {
51
- fs.mkdirSync(savePath, { recursive: true });
52
- }
53
- const envFilePath = path.join(savePath, `${destination}.env`);
54
- const tempFilePath = `${envFilePath}.tmp`;
55
- // Read existing .env file if it exists
56
- let existingContent = '';
57
- if (fs.existsSync(envFilePath)) {
58
- existingContent = fs.readFileSync(envFilePath, 'utf8');
59
- }
60
- // Parse existing content to preserve other values
61
- const lines = existingContent.split('\n');
62
- const existingVars = new Map();
63
- for (const line of lines) {
64
- const trimmed = line.trim();
65
- if (!trimmed || trimmed.startsWith('#')) {
66
- continue;
67
- }
68
- const match = trimmed.match(/^([^=]+)=(.*)$/);
69
- if (match) {
70
- const key = match[1].trim();
71
- const value = match[2].trim().replace(/^["']|["']$/g, ''); // Remove quotes
72
- existingVars.set(key, value);
73
- }
74
- }
75
- // Update with new values
76
- existingVars.set('SAP_URL', config.sapUrl);
77
- existingVars.set('SAP_JWT_TOKEN', config.jwtToken);
78
- if (config.sapClient) {
79
- existingVars.set('SAP_CLIENT', config.sapClient);
80
- }
81
- if (config.refreshToken) {
82
- existingVars.set('SAP_REFRESH_TOKEN', config.refreshToken);
83
- }
84
- if (config.uaaUrl) {
85
- existingVars.set('SAP_UAA_URL', config.uaaUrl);
86
- }
87
- if (config.uaaClientId) {
88
- existingVars.set('SAP_UAA_CLIENT_ID', config.uaaClientId);
89
- }
90
- if (config.uaaClientSecret) {
91
- existingVars.set('SAP_UAA_CLIENT_SECRET', config.uaaClientSecret);
92
- }
93
- // Write to temporary file first (atomic write)
94
- const envLines = [];
95
- for (const [key, value] of existingVars.entries()) {
96
- // Escape value if it contains spaces or special characters
97
- const escapedValue = value.includes(' ') || value.includes('=') || value.includes('#')
98
- ? `"${value.replace(/"/g, '\\"')}"`
99
- : value;
100
- envLines.push(`${key}=${escapedValue}`);
101
- }
102
- const envContent = envLines.join('\n') + '\n';
103
- // Write to temp file
104
- fs.writeFileSync(tempFilePath, envContent, 'utf8');
105
- // Atomic rename
106
- fs.renameSync(tempFilePath, envFilePath);
107
- }
@@ -1,11 +0,0 @@
1
- /**
2
- * Token validator - validates JWT tokens by testing connection
3
- */
4
- /**
5
- * Validate JWT token by making a test request to SAP system
6
- * @param token JWT token to validate
7
- * @param sapUrl SAP system URL
8
- * @returns true if token is valid, false if expired/invalid
9
- */
10
- export declare function validateToken(token: string, sapUrl: string): Promise<boolean>;
11
- //# sourceMappingURL=tokenValidator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tokenValidator.d.ts","sourceRoot":"","sources":["../src/tokenValidator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA0EnF"}
@@ -1,108 +0,0 @@
1
- "use strict";
2
- /**
3
- * Token validator - validates JWT tokens by testing connection
4
- */
5
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- var desc = Object.getOwnPropertyDescriptor(m, k);
8
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
- desc = { enumerable: true, get: function() { return m[k]; } };
10
- }
11
- Object.defineProperty(o, k2, desc);
12
- }) : (function(o, m, k, k2) {
13
- if (k2 === undefined) k2 = k;
14
- o[k2] = m[k];
15
- }));
16
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
- Object.defineProperty(o, "default", { enumerable: true, value: v });
18
- }) : function(o, v) {
19
- o["default"] = v;
20
- });
21
- var __importStar = (this && this.__importStar) || (function () {
22
- var ownKeys = function(o) {
23
- ownKeys = Object.getOwnPropertyNames || function (o) {
24
- var ar = [];
25
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
- return ar;
27
- };
28
- return ownKeys(o);
29
- };
30
- return function (mod) {
31
- if (mod && mod.__esModule) return mod;
32
- var result = {};
33
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
- __setModuleDefault(result, mod);
35
- return result;
36
- };
37
- })();
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.validateToken = validateToken;
40
- const axios_1 = __importStar(require("axios"));
41
- /**
42
- * Validate JWT token by making a test request to SAP system
43
- * @param token JWT token to validate
44
- * @param sapUrl SAP system URL
45
- * @returns true if token is valid, false if expired/invalid
46
- */
47
- async function validateToken(token, sapUrl) {
48
- try {
49
- // Make a lightweight request to test token validity
50
- // Using /sap/bc/adt/core/discovery as it's a simple endpoint
51
- const testUrl = `${sapUrl}/sap/bc/adt/core/discovery`;
52
- const response = await axios_1.default.get(testUrl, {
53
- headers: {
54
- 'Authorization': `Bearer ${token}`,
55
- 'Accept': 'application/xml',
56
- },
57
- timeout: 10000, // 10 second timeout
58
- validateStatus: (status) => status < 500, // Don't throw on 4xx errors
59
- });
60
- // 200-299: Token is valid
61
- if (response.status >= 200 && response.status < 300) {
62
- return true;
63
- }
64
- // 401/403: Token expired or invalid (but distinguish from permission errors)
65
- if (response.status === 401 || response.status === 403) {
66
- const responseText = typeof response.data === 'string'
67
- ? response.data
68
- : JSON.stringify(response.data || '');
69
- // Check if it's a permission error (not auth error)
70
- if (responseText.includes('ExceptionResourceNoAccess') ||
71
- responseText.includes('No authorization') ||
72
- responseText.includes('Missing authorization')) {
73
- // Permission error - token is valid but user doesn't have access
74
- // We consider this as valid token
75
- return true;
76
- }
77
- // Auth error - token expired or invalid
78
- return false;
79
- }
80
- // Other errors - assume token is valid (might be network issues, etc.)
81
- return true;
82
- }
83
- catch (error) {
84
- if (error instanceof axios_1.AxiosError) {
85
- // Network errors or timeouts - assume token might be valid
86
- // (we don't want to invalidate tokens due to network issues)
87
- if (error.code === 'ECONNABORTED' || error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED') {
88
- // Network issue - assume token is valid
89
- return true;
90
- }
91
- // 401/403 errors
92
- if (error.response?.status === 401 || error.response?.status === 403) {
93
- const responseText = typeof error.response.data === 'string'
94
- ? error.response.data
95
- : JSON.stringify(error.response.data || '');
96
- // Check if it's a permission error
97
- if (responseText.includes('ExceptionResourceNoAccess') ||
98
- responseText.includes('No authorization') ||
99
- responseText.includes('Missing authorization')) {
100
- return true;
101
- }
102
- return false;
103
- }
104
- }
105
- // Unknown error - assume token is valid to avoid false negatives
106
- return true;
107
- }
108
- }