@mcp-abap-adt/auth-broker 2.2.0 → 3.0.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.
- package/CHANGELOG.md +235 -0
- package/README.md +324 -284
- package/dist/AuthBroker.d.ts +81 -106
- package/dist/AuthBroker.d.ts.map +1 -1
- package/dist/AuthBroker.js +209 -567
- package/dist/bin/mcp-auth.js +54 -31
- package/dist/bin/mcp-sso.js +52 -44
- package/dist/bin/mcpSsoConfig.js +169 -1
- package/dist/bin/samlMetadata.js +175 -0
- package/dist/bin/workDir.js +79 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/providers/ITokenProvider.d.ts +2 -2
- package/dist/providers/ITokenProvider.d.ts.map +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/package.json +12 -8
- package/dist/utils/formatting.d.ts +0 -16
- package/dist/utils/formatting.d.ts.map +0 -1
- package/dist/utils/formatting.js +0 -34
package/dist/AuthBroker.d.ts
CHANGED
|
@@ -1,144 +1,119 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* AuthBroker: tokens for a destination, from a provider, kept in a session store.
|
|
3
|
+
*
|
|
4
|
+
* The broker orchestrates and nothing more. It resolves what the stores know
|
|
5
|
+
* about a destination, hands it to the provider, asks the provider for a token
|
|
6
|
+
* and writes the answer back. Whether a token is still valid, whether to use the
|
|
7
|
+
* refresh token or log in, and how a login is conducted (browser, headless,
|
|
8
|
+
* pasted code) are the provider's decisions — made by its strategy — and the
|
|
9
|
+
* broker does not repeat or override any of them.
|
|
3
10
|
*/
|
|
4
|
-
import type { ITokenRefresher } from '@mcp-abap-adt/interfaces-auth';
|
|
11
|
+
import type { IRefreshableTokenProvider, ITokenRefresher } from '@mcp-abap-adt/interfaces-auth';
|
|
5
12
|
import type { ILogger } from '@mcp-abap-adt/interfaces-utils';
|
|
6
|
-
import type { ITokenProvider } from './providers';
|
|
7
13
|
import type { IAuthorizationConfig, IConnectionConfig, IServiceKeyStore, ISessionStore } from './stores/interfaces';
|
|
8
14
|
/**
|
|
9
|
-
*
|
|
15
|
+
* Builds the provider for one destination, from what the stores hold for it.
|
|
16
|
+
*
|
|
17
|
+
* - `authConfig`: the UAA credentials — from the session when it holds them,
|
|
18
|
+
* else from the service key — with the refresh token the session stored, or
|
|
19
|
+
* `null` when neither store has credentials (a SAML flow needs none).
|
|
20
|
+
* - `connConfig`: the session's connection config, with `serviceUrl` resolved
|
|
21
|
+
* and the last token the session stored, so the provider can reuse it while
|
|
22
|
+
* it is valid.
|
|
23
|
+
*
|
|
24
|
+
* Called once per destination; the broker keeps the provider it returns.
|
|
25
|
+
*/
|
|
26
|
+
export type TokenProviderFactory = (destination: string, authConfig: IAuthorizationConfig | null, connConfig: IConnectionConfig) => IRefreshableTokenProvider;
|
|
27
|
+
/**
|
|
28
|
+
* Configuration object for the AuthBroker constructor
|
|
10
29
|
*/
|
|
11
30
|
export interface AuthBrokerConfig {
|
|
12
|
-
/** Session store (required)
|
|
31
|
+
/** Session store (required) — where tokens and the refresh token are kept */
|
|
13
32
|
sessionStore: ISessionStore;
|
|
14
|
-
/** Service key store (optional)
|
|
33
|
+
/** Service key store (optional) — UAA credentials and the service URL */
|
|
15
34
|
serviceKeyStore?: IServiceKeyStore;
|
|
16
|
-
/** Token provider (required) - handles token refresh and authentication flows through browser-based authorization (e.g., XSUAA provider) */
|
|
17
|
-
tokenProvider: ITokenProvider;
|
|
18
35
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
36
|
+
* The token provider, or a factory building one per destination.
|
|
37
|
+
*
|
|
38
|
+
* An instance is used as given, for every destination. A factory is seeded
|
|
39
|
+
* with what the stores hold for the destination (see `TokenProviderFactory`).
|
|
22
40
|
*/
|
|
23
|
-
|
|
41
|
+
provider: IRefreshableTokenProvider | TokenProviderFactory;
|
|
24
42
|
}
|
|
25
43
|
/**
|
|
26
|
-
* AuthBroker manages
|
|
44
|
+
* AuthBroker manages authentication tokens for destinations
|
|
27
45
|
*/
|
|
28
46
|
export declare class AuthBroker {
|
|
29
|
-
private
|
|
30
|
-
private
|
|
31
|
-
private
|
|
32
|
-
private
|
|
33
|
-
private
|
|
34
|
-
private allowBrowserAuth;
|
|
35
|
-
/**
|
|
36
|
-
* Create a new AuthBroker instance
|
|
37
|
-
* @param config Configuration object with stores and token provider
|
|
38
|
-
* - sessionStore: Store for session data (required)
|
|
39
|
-
* - serviceKeyStore: Store for service keys (optional)
|
|
40
|
-
* - tokenProvider: Token provider implementing ITokenProvider interface (required) - handles browser-based authorization
|
|
41
|
-
* @param browser Optional browser name for authentication (chrome, edge, firefox, system, headless, none).
|
|
42
|
-
* Default: 'system' (system default browser).
|
|
43
|
-
* Use 'headless' for SSH/remote sessions - logs URL and waits for manual callback.
|
|
44
|
-
* Use 'none' for automated tests - logs URL and rejects immediately.
|
|
45
|
-
* @param logger Optional logger instance implementing ILogger interface. If not provided, uses no-op logger.
|
|
46
|
-
*/
|
|
47
|
-
constructor(config: AuthBrokerConfig, browser?: string, logger?: ILogger);
|
|
47
|
+
private readonly logger;
|
|
48
|
+
private readonly serviceKeyStore;
|
|
49
|
+
private readonly sessionStore;
|
|
50
|
+
private readonly provider;
|
|
51
|
+
private readonly providers;
|
|
48
52
|
/**
|
|
49
|
-
*
|
|
53
|
+
* @param config Stores and the provider (instance or factory)
|
|
54
|
+
* @param logger Optional logger. Nothing the broker logs contains a token.
|
|
50
55
|
*/
|
|
51
|
-
|
|
56
|
+
constructor(config: AuthBrokerConfig, logger?: ILogger);
|
|
52
57
|
/**
|
|
53
|
-
*
|
|
58
|
+
* A token for the destination: the provider's current one, which it refreshes
|
|
59
|
+
* or obtains by login when it judges the cached one unusable.
|
|
60
|
+
*
|
|
61
|
+
* The result is written to the session store. Errors from the provider
|
|
62
|
+
* (its typed errors included) propagate unchanged.
|
|
54
63
|
*/
|
|
55
|
-
|
|
64
|
+
getToken(destination: string): Promise<string>;
|
|
56
65
|
/**
|
|
57
|
-
*
|
|
66
|
+
* A new token for the destination, never the cached one — for a caller whose
|
|
67
|
+
* token the server has just refused. Calls the provider's `refreshTokens()`,
|
|
68
|
+
* writes the result to the session store and returns it.
|
|
58
69
|
*/
|
|
59
|
-
|
|
70
|
+
refreshToken(destination: string): Promise<string>;
|
|
71
|
+
private obtain;
|
|
72
|
+
private providerFor;
|
|
60
73
|
/**
|
|
61
|
-
*
|
|
74
|
+
* The credentials the provider is built with: the session's own when it holds
|
|
75
|
+
* them, else the service key's, carrying the refresh token the session
|
|
76
|
+
* stored. The session keeps a refresh token without credentials when the
|
|
77
|
+
* credentials came from the service key, since the broker does not copy the
|
|
78
|
+
* client secret into it; `loadSession` is where such a token is read.
|
|
62
79
|
*/
|
|
63
|
-
private
|
|
64
|
-
private
|
|
65
|
-
private persistTokenResult;
|
|
80
|
+
private resolveAuthorizationConfig;
|
|
81
|
+
private resolveServiceUrl;
|
|
66
82
|
/**
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* **Flow:**
|
|
71
|
-
* **Step 0: Initialize Session with Token (if needed)**
|
|
72
|
-
* - Check if session has `authorizationToken` AND UAA credentials
|
|
73
|
-
* - If both are empty AND serviceKeyStore is available:
|
|
74
|
-
* - Get UAA credentials from service key
|
|
75
|
-
* - Use tokenProvider for browser-based authentication
|
|
76
|
-
* - Save token and refresh token to session
|
|
77
|
-
*
|
|
78
|
-
* **Step 1: Token Validation**
|
|
79
|
-
* - If token exists in session, validate it (if provider supports validation)
|
|
80
|
-
* - If valid → return token
|
|
81
|
-
* - If invalid or no token → continue to refresh
|
|
83
|
+
* Writes the result by its type: a SAML result is session cookies, anything
|
|
84
|
+
* else a bearer token. The refresh token is written only when the result has
|
|
85
|
+
* one, so a provider that returns none does not erase the stored one.
|
|
82
86
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* - If refresh token exists:
|
|
86
|
-
* - Use tokenProvider to refresh token (browser-based or refresh grant)
|
|
87
|
-
* - Save new token to session
|
|
88
|
-
* - Return new token
|
|
89
|
-
* - Otherwise → proceed to Step 3
|
|
90
|
-
*
|
|
91
|
-
* **Step 3: New Token Flow**
|
|
92
|
-
* - Get UAA credentials from session or service key
|
|
93
|
-
* - Use tokenProvider for browser-based authentication
|
|
94
|
-
* - Save new token to session
|
|
95
|
-
* - Return new token
|
|
96
|
-
*
|
|
97
|
-
* **Important Notes:**
|
|
98
|
-
* - All authentication is handled by tokenProvider (e.g., XSUAA provider)
|
|
99
|
-
* - Provider uses browser-based authorization to ensure proper role assignment
|
|
100
|
-
* - Direct UAA HTTP requests are not used to avoid role assignment issues
|
|
101
|
-
*
|
|
102
|
-
* @param destination Destination name (e.g., "TRIAL")
|
|
103
|
-
* @returns Promise that resolves to JWT token string
|
|
104
|
-
* @throws Error if session initialization fails or authentication failed
|
|
87
|
+
* `ITokenResult.expiresAt` has no field in `IConnectionConfig` to go to; the
|
|
88
|
+
* provider seeded with the stored token reads the expiry from the JWT itself.
|
|
105
89
|
*/
|
|
106
|
-
|
|
90
|
+
private persist;
|
|
107
91
|
/**
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
92
|
+
* A store read where absence is an answer and anything else is not.
|
|
93
|
+
*
|
|
94
|
+
* A store says "nothing here" with `null`, or with `FILE_NOT_FOUND`, and the
|
|
95
|
+
* flow goes on to the next source. Any other failure — a service key that is
|
|
96
|
+
* not valid JSON, a file the process may not read — is a different problem
|
|
97
|
+
* with a different fix, and reaches the caller as the store raised it. It
|
|
98
|
+
* used to be logged and answered as absent, so the caller saw only the
|
|
99
|
+
* consequence ("missing required field 'serviceUrl'") and went looking for a
|
|
100
|
+
* file that was there.
|
|
112
101
|
*/
|
|
113
|
-
|
|
102
|
+
private read;
|
|
114
103
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* @returns Promise that resolves to IAuthorizationConfig or null if not found
|
|
104
|
+
* Authorization configuration for the destination: the session's, else the
|
|
105
|
+
* service key's, else null.
|
|
118
106
|
*/
|
|
119
107
|
getAuthorizationConfig(destination: string): Promise<IAuthorizationConfig | null>;
|
|
120
108
|
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* @returns Promise that resolves to IConnectionConfig or null if not found
|
|
109
|
+
* Connection configuration for the destination: the session's, else the
|
|
110
|
+
* service key's (which has URLs but no token), else null.
|
|
124
111
|
*/
|
|
125
112
|
getConnectionConfig(destination: string): Promise<IConnectionConfig | null>;
|
|
126
113
|
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* allowing the connection to handle token refresh transparently without knowing
|
|
131
|
-
* about authentication internals.
|
|
132
|
-
*
|
|
133
|
-
* **Usage:**
|
|
134
|
-
* ```typescript
|
|
135
|
-
* const broker = new AuthBroker(config);
|
|
136
|
-
* const tokenRefresher = broker.createTokenRefresher('TRIAL');
|
|
137
|
-
* const connection = new JwtAbapConnection(config, tokenRefresher);
|
|
138
|
-
* ```
|
|
139
|
-
*
|
|
140
|
-
* @param destination Destination name (e.g., "TRIAL")
|
|
141
|
-
* @returns ITokenRefresher implementation for the given destination
|
|
114
|
+
* An `ITokenRefresher` for one destination, for injection into a connection:
|
|
115
|
+
* `getToken()` is the broker's `getToken`, `refreshToken()` its forced
|
|
116
|
+
* `refreshToken`.
|
|
142
117
|
*/
|
|
143
118
|
createTokenRefresher(destination: string): ITokenRefresher;
|
|
144
119
|
}
|
package/dist/AuthBroker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"AuthBroker.d.ts","sourceRoot":"","sources":["../src/AuthBroker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,yBAAyB,EACzB,eAAe,EAEhB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EACV,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAS7B;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,oBAAoB,GAAG,CACjC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,oBAAoB,GAAG,IAAI,EACvC,UAAU,EAAE,iBAAiB,KAC1B,yBAAyB,CAAC;AAE/B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,YAAY,EAAE,aAAa,CAAC;IAC5B,yEAAyE;IACzE,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC;;;;;OAKG;IACH,QAAQ,EAAE,yBAAyB,GAAG,oBAAoB,CAAC;CAC5D;AAUD;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAU;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA+B;IAC/D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmD;IAC5E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgD;IAE1E;;;OAGG;gBACS,MAAM,EAAE,gBAAgB,EAAE,MAAM,CAAC,EAAE,OAAO;IA2DtD;;;;;;OAMG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIpD;;;;OAIG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAI1C,MAAM;YA2BN,WAAW;IA4BzB;;;;;;OAMG;YACW,0BAA0B;YAiC1B,iBAAiB;IAuB/B;;;;;;;OAOG;YACW,OAAO;IAoDrB;;;;;;;;;;OAUG;YACW,IAAI;IAgBlB;;;OAGG;IACG,sBAAsB,CAC1B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAkBvC;;;OAGG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAkBpC;;;;OAIG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe;CAM3D"}
|