@mcp-abap-adt/header-validator 0.1.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 +27 -0
- package/LICENSE +22 -0
- package/README.md +473 -0
- package/dist/headerValidator.d.ts +17 -0
- package/dist/headerValidator.js +354 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +25 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +18 -0
- package/package.json +54 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2025-11-30
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Header validation** - Validates authentication headers for MCP ABAP ADT servers
|
|
12
|
+
- **Priority system** - Automatically prioritizes authentication methods:
|
|
13
|
+
- Destination-based authentication (highest priority)
|
|
14
|
+
- Direct JWT authentication (medium priority)
|
|
15
|
+
- Basic authentication (lowest priority)
|
|
16
|
+
- **Error reporting** - Detailed error messages for invalid configurations
|
|
17
|
+
- **Warning system** - Warnings for conflicting or ignored headers
|
|
18
|
+
- **TypeScript support** - Full TypeScript definitions and type safety
|
|
19
|
+
- **Unit tests** - Comprehensive test suite with mocks (34 tests)
|
|
20
|
+
- **Documentation** - Complete README with examples and API reference
|
|
21
|
+
|
|
22
|
+
### Technical Details
|
|
23
|
+
- **Dependencies**: None (zero dependencies)
|
|
24
|
+
- **Node.js version**: >= 18.0.0
|
|
25
|
+
- **Module system**: CommonJS
|
|
26
|
+
- **Build output**: TypeScript compiled to JavaScript with type definitions
|
|
27
|
+
|
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Oleksii Kyslytsia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
# @mcp-abap-adt/header-validator
|
|
2
|
+
|
|
3
|
+
Header validator for MCP ABAP ADT - validates and prioritizes authentication headers.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ✅ **Header Validation**: Validates authentication headers for MCP ABAP ADT servers
|
|
8
|
+
- ✅ **Priority System**: Automatically prioritizes authentication methods
|
|
9
|
+
- ✅ **Error Reporting**: Detailed error messages and warnings
|
|
10
|
+
- ✅ **Type Safety**: Full TypeScript support with type definitions
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @mcp-abap-adt/header-validator
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { validateAuthHeaders } from '@mcp-abap-adt/header-validator';
|
|
22
|
+
import { IncomingHttpHeaders } from 'http';
|
|
23
|
+
|
|
24
|
+
const headers: IncomingHttpHeaders = {
|
|
25
|
+
'x-sap-url': 'https://test.sap.com',
|
|
26
|
+
'x-mcp-destination': 'TRIAL',
|
|
27
|
+
// Note: x-sap-auth-type not needed - always uses JWT
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const result = validateAuthHeaders(headers);
|
|
31
|
+
|
|
32
|
+
if (result.isValid && result.config) {
|
|
33
|
+
console.log('Auth method:', result.config.priority);
|
|
34
|
+
console.log('Destination:', result.config.destination);
|
|
35
|
+
} else {
|
|
36
|
+
console.error('Validation errors:', result.errors);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Authentication Methods and Priorities
|
|
41
|
+
|
|
42
|
+
The validator supports four authentication methods, ordered by priority (highest to lowest):
|
|
43
|
+
|
|
44
|
+
### 1. SAP Destination-Based Authentication (Highest Priority)
|
|
45
|
+
|
|
46
|
+
**Priority**: `AuthMethodPriority.SAP_DESTINATION` (4)
|
|
47
|
+
|
|
48
|
+
**Required Headers**:
|
|
49
|
+
- `x-sap-url` - SAP system URL
|
|
50
|
+
- `x-sap-destination` - Destination name (e.g., "S4HANA_E19")
|
|
51
|
+
|
|
52
|
+
**Optional Headers**:
|
|
53
|
+
- `x-sap-client` - SAP client number
|
|
54
|
+
- `x-sap-login` / `x-sap-password` - Username/password (edge cases)
|
|
55
|
+
|
|
56
|
+
**Description**: Simplest configuration - uses AuthBroker to manage tokens. Always uses JWT authentication. No `x-sap-auth-type` header needed.
|
|
57
|
+
|
|
58
|
+
**Example**:
|
|
59
|
+
```typescript
|
|
60
|
+
const headers = {
|
|
61
|
+
'x-sap-url': 'https://test.sap.com',
|
|
62
|
+
'x-sap-destination': 'S4HANA_E19',
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Notes**:
|
|
67
|
+
- Does NOT require `x-sap-auth-type` (always JWT)
|
|
68
|
+
- If `x-sap-auth-type` is provided, it will be ignored (warning issued)
|
|
69
|
+
- If `x-sap-jwt-token` is also provided, it will be ignored (warning issued)
|
|
70
|
+
- Requires AuthBroker to be initialized in the server
|
|
71
|
+
- Automatically handles token refresh and validation
|
|
72
|
+
|
|
73
|
+
### 2. MCP Destination-Based Authentication
|
|
74
|
+
|
|
75
|
+
**Priority**: `AuthMethodPriority.MCP_DESTINATION` (3)
|
|
76
|
+
|
|
77
|
+
**Required Headers**:
|
|
78
|
+
- `x-sap-url` - SAP system URL
|
|
79
|
+
- `x-mcp-destination` - Destination name (e.g., "TRIAL", "PRODUCTION")
|
|
80
|
+
|
|
81
|
+
**Optional Headers**:
|
|
82
|
+
- `x-sap-client` - SAP client number
|
|
83
|
+
|
|
84
|
+
**Description**: Uses AuthBroker to manage tokens based on destination. Tokens are loaded from `{destination}.env` files, validated, and automatically refreshed when needed. Always uses JWT authentication.
|
|
85
|
+
|
|
86
|
+
**Example**:
|
|
87
|
+
```typescript
|
|
88
|
+
const headers = {
|
|
89
|
+
'x-sap-url': 'https://test.sap.com',
|
|
90
|
+
'x-mcp-destination': 'TRIAL',
|
|
91
|
+
// Note: x-sap-auth-type not needed - always uses JWT
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Notes**:
|
|
96
|
+
- Does NOT require `x-sap-auth-type` (always JWT)
|
|
97
|
+
- If `x-sap-auth-type` is provided, it will be ignored (warning issued)
|
|
98
|
+
- If `x-sap-jwt-token` is also provided, it will be ignored (warning issued)
|
|
99
|
+
- Requires AuthBroker to be initialized in the server
|
|
100
|
+
- Automatically handles token refresh and validation
|
|
101
|
+
|
|
102
|
+
### 3. Direct JWT Authentication (Medium Priority)
|
|
103
|
+
|
|
104
|
+
**Priority**: `AuthMethodPriority.DIRECT_JWT` (2)
|
|
105
|
+
|
|
106
|
+
**Required Headers**:
|
|
107
|
+
- `x-sap-url` - SAP system URL
|
|
108
|
+
- `x-sap-auth-type` - Must be `jwt` or `xsuaa`
|
|
109
|
+
- `x-sap-jwt-token` - JWT access token
|
|
110
|
+
|
|
111
|
+
**Optional Headers**:
|
|
112
|
+
- `x-sap-refresh-token` - Refresh token for automatic token renewal
|
|
113
|
+
- `x-sap-uaa-url` / `uaa-url` - UAA URL
|
|
114
|
+
- `x-sap-uaa-client-id` / `uaa-client-id` - UAA Client ID
|
|
115
|
+
- `x-sap-uaa-client-secret` / `uaa-client-secret` - UAA Client Secret
|
|
116
|
+
- `x-sap-client` - SAP client number
|
|
117
|
+
|
|
118
|
+
**Description**: Direct JWT token authentication. Token is provided directly in headers.
|
|
119
|
+
|
|
120
|
+
**Example**:
|
|
121
|
+
```typescript
|
|
122
|
+
const headers = {
|
|
123
|
+
'x-sap-url': 'https://test.sap.com',
|
|
124
|
+
'x-sap-auth-type': 'jwt',
|
|
125
|
+
'x-sap-jwt-token': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
126
|
+
'x-sap-refresh-token': 'refresh_token_here', // optional
|
|
127
|
+
};
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Notes**:
|
|
131
|
+
- Token must be at least 10 characters long
|
|
132
|
+
- Refresh token is optional but recommended for automatic token renewal
|
|
133
|
+
|
|
134
|
+
### 4. Basic Authentication (Lowest Priority)
|
|
135
|
+
|
|
136
|
+
**Priority**: `AuthMethodPriority.BASIC` (1)
|
|
137
|
+
|
|
138
|
+
**Required Headers**:
|
|
139
|
+
- `x-sap-url` - SAP system URL
|
|
140
|
+
- `x-sap-auth-type` - Must be `basic`
|
|
141
|
+
- `x-sap-login` - Username
|
|
142
|
+
- `x-sap-password` - Password
|
|
143
|
+
|
|
144
|
+
**Description**: Basic HTTP authentication with username and password.
|
|
145
|
+
|
|
146
|
+
**Example**:
|
|
147
|
+
```typescript
|
|
148
|
+
const headers = {
|
|
149
|
+
'x-sap-url': 'https://test.sap.com',
|
|
150
|
+
'x-sap-auth-type': 'basic',
|
|
151
|
+
'x-sap-login': 'username',
|
|
152
|
+
'x-sap-password': 'password',
|
|
153
|
+
};
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Notes**:
|
|
157
|
+
- Used primarily for on-premise SAP systems
|
|
158
|
+
- Credentials are sent in plain text (use HTTPS in production)
|
|
159
|
+
|
|
160
|
+
## Valid Header Combinations
|
|
161
|
+
|
|
162
|
+
### ✅ Valid Combinations
|
|
163
|
+
|
|
164
|
+
#### 1. SAP Destination Only (Simplest - Recommended)
|
|
165
|
+
```typescript
|
|
166
|
+
{
|
|
167
|
+
'x-sap-url': 'https://test.sap.com',
|
|
168
|
+
'x-sap-destination': 'S4HANA_E19',
|
|
169
|
+
}
|
|
170
|
+
// No x-sap-auth-type needed - always JWT
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### 2. MCP Destination Only
|
|
174
|
+
```typescript
|
|
175
|
+
{
|
|
176
|
+
'x-sap-url': 'https://test.sap.com',
|
|
177
|
+
'x-mcp-destination': 'TRIAL',
|
|
178
|
+
// Note: x-sap-auth-type not needed - always uses JWT
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### 3. Direct JWT Only
|
|
183
|
+
```typescript
|
|
184
|
+
{
|
|
185
|
+
'x-sap-url': 'https://test.sap.com',
|
|
186
|
+
'x-sap-auth-type': 'jwt',
|
|
187
|
+
'x-sap-jwt-token': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
188
|
+
'x-sap-refresh-token': 'refresh_token', // optional
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### 4. Basic Auth Only
|
|
193
|
+
```typescript
|
|
194
|
+
{
|
|
195
|
+
'x-sap-url': 'https://test.sap.com',
|
|
196
|
+
'x-sap-auth-type': 'basic',
|
|
197
|
+
'x-sap-login': 'username',
|
|
198
|
+
'x-sap-password': 'password',
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### 5. SAP Destination + Auth Type (Warning Issued)
|
|
203
|
+
```typescript
|
|
204
|
+
{
|
|
205
|
+
'x-sap-url': 'https://test.sap.com',
|
|
206
|
+
'x-sap-destination': 'S4HANA_E19',
|
|
207
|
+
'x-sap-auth-type': 'jwt', // ignored (warning)
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
**Result**: SAP Destination auth is used, auth-type is ignored (warning issued)
|
|
211
|
+
|
|
212
|
+
#### 6. Destination + Direct JWT (Warning Issued)
|
|
213
|
+
```typescript
|
|
214
|
+
{
|
|
215
|
+
'x-sap-url': 'https://test.sap.com',
|
|
216
|
+
'x-sap-destination': 'S4HANA_E19',
|
|
217
|
+
'x-sap-jwt-token': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...', // ignored
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
**Result**: SAP Destination auth is used (Priority 4), direct JWT token is ignored (warning issued)
|
|
221
|
+
|
|
222
|
+
#### 7. Multiple Destinations (SAP Takes Priority)
|
|
223
|
+
```typescript
|
|
224
|
+
{
|
|
225
|
+
'x-sap-url': 'https://test.sap.com',
|
|
226
|
+
'x-sap-destination': 'S4HANA_E19', // Priority 4
|
|
227
|
+
'x-mcp-destination': 'TRIAL', // Priority 3 - ignored
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
**Result**: SAP Destination auth is used, MCP destination is ignored
|
|
231
|
+
|
|
232
|
+
### ❌ Invalid Combinations
|
|
233
|
+
|
|
234
|
+
#### 1. Missing Required Headers
|
|
235
|
+
```typescript
|
|
236
|
+
{
|
|
237
|
+
'x-sap-url': 'https://test.sap.com',
|
|
238
|
+
// Missing x-sap-auth-type
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
**Error**: `x-sap-auth-type header is required`
|
|
242
|
+
|
|
243
|
+
#### 2. Invalid Auth Type
|
|
244
|
+
```typescript
|
|
245
|
+
{
|
|
246
|
+
'x-sap-url': 'https://test.sap.com',
|
|
247
|
+
'x-sap-auth-type': 'invalid',
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
**Error**: `x-sap-auth-type must be one of: jwt, xsuaa, basic`
|
|
251
|
+
|
|
252
|
+
#### 3. JWT Auth Without Token or Destination
|
|
253
|
+
```typescript
|
|
254
|
+
{
|
|
255
|
+
'x-sap-url': 'https://test.sap.com',
|
|
256
|
+
'x-sap-auth-type': 'jwt',
|
|
257
|
+
// Missing x-sap-destination, x-mcp-destination, and x-sap-jwt-token
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
**Error**: `JWT authentication requires either x-sap-destination, x-mcp-destination, or x-sap-jwt-token header`
|
|
261
|
+
|
|
262
|
+
#### 4. Basic Auth Without Credentials
|
|
263
|
+
```typescript
|
|
264
|
+
{
|
|
265
|
+
'x-sap-url': 'https://test.sap.com',
|
|
266
|
+
'x-sap-auth-type': 'basic',
|
|
267
|
+
// Missing x-sap-login and/or x-sap-password
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
**Error**: `Basic authentication requires x-sap-login and x-sap-password headers`
|
|
271
|
+
|
|
272
|
+
#### 5. Empty Values
|
|
273
|
+
```typescript
|
|
274
|
+
{
|
|
275
|
+
'x-sap-url': 'https://test.sap.com',
|
|
276
|
+
'x-sap-destination': ' ', // empty after trim
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
**Error**: `x-sap-destination header is empty`
|
|
280
|
+
|
|
281
|
+
#### 6. Invalid URL
|
|
282
|
+
```typescript
|
|
283
|
+
{
|
|
284
|
+
'x-sap-url': 'not-a-valid-url',
|
|
285
|
+
'x-sap-auth-type': 'jwt',
|
|
286
|
+
'x-sap-jwt-token': 'token',
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
**Error**: `x-sap-url is not a valid URL`
|
|
290
|
+
|
|
291
|
+
## Priority Resolution
|
|
292
|
+
|
|
293
|
+
When multiple authentication methods are detected, the validator automatically selects the highest priority method:
|
|
294
|
+
|
|
295
|
+
1. **SAP Destination** (Priority 4) - Always selected if `x-sap-destination` is present
|
|
296
|
+
2. **MCP Destination** (Priority 3) - Selected if `x-mcp-destination` is present (always uses JWT, no `x-sap-auth-type` needed)
|
|
297
|
+
3. **Direct JWT** (Priority 2) - Selected if JWT token is provided (requires `x-sap-auth-type: jwt`)
|
|
298
|
+
4. **Basic** (Priority 1) - Selected only if basic auth headers are present (requires `x-sap-auth-type: basic`)
|
|
299
|
+
|
|
300
|
+
### Example: Priority Resolution
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const headers = {
|
|
304
|
+
'x-sap-url': 'https://test.sap.com',
|
|
305
|
+
'x-sap-destination': 'S4HANA_E19', // Priority 4 (selected)
|
|
306
|
+
'x-sap-auth-type': 'jwt', // Ignored (warning)
|
|
307
|
+
'x-mcp-destination': 'TRIAL', // Priority 3 (ignored)
|
|
308
|
+
'x-sap-jwt-token': 'token', // Priority 2 (ignored)
|
|
309
|
+
'x-sap-login': 'user', // Priority 1 (ignored)
|
|
310
|
+
'x-sap-password': 'pass', // Priority 1 (ignored)
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const result = validateAuthHeaders(headers);
|
|
314
|
+
// result.config.priority === AuthMethodPriority.SAP_DESTINATION (4)
|
|
315
|
+
// result.warnings includes: "x-sap-auth-type is ignored when x-sap-destination is present"
|
|
316
|
+
// result.warnings includes: "x-sap-jwt-token is ignored when x-sap-destination is present"
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## API Reference
|
|
320
|
+
|
|
321
|
+
### `validateAuthHeaders(headers?: IncomingHttpHeaders): HeaderValidationResult`
|
|
322
|
+
|
|
323
|
+
Validates and prioritizes authentication headers.
|
|
324
|
+
|
|
325
|
+
**Parameters**:
|
|
326
|
+
- `headers` - HTTP headers object (optional)
|
|
327
|
+
|
|
328
|
+
**Returns**: `HeaderValidationResult` object with:
|
|
329
|
+
- `isValid: boolean` - Whether the configuration is valid
|
|
330
|
+
- `config?: ValidatedAuthConfig` - Validated authentication configuration (if valid)
|
|
331
|
+
- `errors: string[]` - List of validation errors
|
|
332
|
+
- `warnings: string[]` - List of warnings (e.g., ignored headers)
|
|
333
|
+
|
|
334
|
+
### `ValidatedAuthConfig`
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
interface ValidatedAuthConfig {
|
|
338
|
+
priority: AuthMethodPriority; // Authentication method priority
|
|
339
|
+
authType: AuthType; // 'jwt' | 'xsuaa' | 'basic'
|
|
340
|
+
sapUrl: string; // SAP system URL
|
|
341
|
+
destination?: string; // Destination name (for destination-based auth)
|
|
342
|
+
jwtToken?: string; // JWT token (for direct JWT auth)
|
|
343
|
+
refreshToken?: string; // Refresh token (optional, for JWT auth)
|
|
344
|
+
username?: string; // Username (for basic auth)
|
|
345
|
+
password?: string; // Password (for basic auth)
|
|
346
|
+
errors: string[]; // Validation errors
|
|
347
|
+
warnings: string[]; // Warnings
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### `AuthMethodPriority`
|
|
352
|
+
|
|
353
|
+
Enumeration of authentication method priorities:
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
enum AuthMethodPriority {
|
|
357
|
+
DESTINATION_BASED = 3, // Highest priority
|
|
358
|
+
DIRECT_JWT = 2, // Medium priority
|
|
359
|
+
BASIC = 1, // Lowest priority
|
|
360
|
+
NONE = 0 // Invalid/No auth
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Error Handling
|
|
365
|
+
|
|
366
|
+
The validator provides detailed error messages for common issues:
|
|
367
|
+
|
|
368
|
+
- Missing required headers
|
|
369
|
+
- Invalid header values
|
|
370
|
+
- Empty header values (after trimming whitespace)
|
|
371
|
+
- Invalid URL format
|
|
372
|
+
- Invalid authentication type
|
|
373
|
+
- Missing authentication credentials
|
|
374
|
+
|
|
375
|
+
All errors are collected in the `errors` array, and the validation result includes `isValid: false` if any errors are present.
|
|
376
|
+
|
|
377
|
+
## Warnings
|
|
378
|
+
|
|
379
|
+
The validator issues warnings for:
|
|
380
|
+
|
|
381
|
+
- Conflicting headers (e.g., destination and direct JWT token both present)
|
|
382
|
+
- Multiple authentication methods with the same priority (should not happen in practice)
|
|
383
|
+
|
|
384
|
+
Warnings do not prevent validation from succeeding but indicate potential configuration issues.
|
|
385
|
+
|
|
386
|
+
## Examples
|
|
387
|
+
|
|
388
|
+
### Example 1: SAP Destination Auth (Simplest)
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
import { validateAuthHeaders } from '@mcp-abap-adt/header-validator';
|
|
392
|
+
|
|
393
|
+
const headers = {
|
|
394
|
+
'x-sap-url': 'https://test.sap.com',
|
|
395
|
+
'x-sap-destination': 'S4HANA_E19',
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const result = validateAuthHeaders(headers);
|
|
399
|
+
|
|
400
|
+
if (result.isValid && result.config) {
|
|
401
|
+
console.log('Using SAP destination-based auth');
|
|
402
|
+
console.log('Destination:', result.config.destination);
|
|
403
|
+
console.log('Priority:', result.config.priority);
|
|
404
|
+
console.log('Auth Type:', result.config.authType); // Always 'jwt'
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Example 2: MCP Destination Auth
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
const headers = {
|
|
412
|
+
'x-sap-url': 'https://test.sap.com',
|
|
413
|
+
'x-mcp-destination': 'TRIAL',
|
|
414
|
+
// Note: x-sap-auth-type not needed - always uses JWT
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const result = validateAuthHeaders(headers);
|
|
418
|
+
|
|
419
|
+
if (result.isValid && result.config) {
|
|
420
|
+
console.log('Using MCP destination-based auth');
|
|
421
|
+
console.log('Destination:', result.config.destination);
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Example 3: Direct JWT Auth
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
const headers = {
|
|
429
|
+
'x-sap-url': 'https://test.sap.com',
|
|
430
|
+
'x-sap-auth-type': 'jwt',
|
|
431
|
+
'x-sap-jwt-token': 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
432
|
+
'x-sap-refresh-token': 'refresh_token',
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
const result = validateAuthHeaders(headers);
|
|
436
|
+
|
|
437
|
+
if (result.isValid && result.config) {
|
|
438
|
+
console.log('Using direct JWT auth');
|
|
439
|
+
console.log('Token:', result.config.jwtToken);
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Example 4: Error Handling
|
|
444
|
+
|
|
445
|
+
```typescript
|
|
446
|
+
const headers = {
|
|
447
|
+
'x-sap-url': 'https://test.sap.com',
|
|
448
|
+
'x-sap-auth-type': 'jwt',
|
|
449
|
+
// Missing required headers
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
const result = validateAuthHeaders(headers);
|
|
453
|
+
|
|
454
|
+
if (!result.isValid) {
|
|
455
|
+
console.error('Validation failed:');
|
|
456
|
+
result.errors.forEach(error => console.error(` - ${error}`));
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Documentation
|
|
461
|
+
|
|
462
|
+
Complete documentation is available in the [`docs/`](docs/) directory:
|
|
463
|
+
|
|
464
|
+
- **[Architecture](docs/architecture/ARCHITECTURE.md)** - System architecture, priority system, and valid header combinations
|
|
465
|
+
- **[Development](docs/development/DEVELOPMENT.md)** - Development guide and testing
|
|
466
|
+
- **[Usage](docs/using/USAGE.md)** - API reference and usage examples
|
|
467
|
+
|
|
468
|
+
See [docs/README.md](docs/README.md) for the complete documentation index.
|
|
469
|
+
|
|
470
|
+
## License
|
|
471
|
+
|
|
472
|
+
MIT
|
|
473
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header validator for MCP ABAP ADT authentication headers
|
|
3
|
+
*
|
|
4
|
+
* Validates and prioritizes authentication headers according to:
|
|
5
|
+
* 1. Destination-based auth (x-mcp-destination) - highest priority
|
|
6
|
+
* 2. Direct JWT token (x-sap-jwt-token) - medium priority
|
|
7
|
+
* 3. Basic auth (x-sap-login + x-sap-password) - lowest priority
|
|
8
|
+
*/
|
|
9
|
+
import { IncomingHttpHeaders } from 'http';
|
|
10
|
+
import { HeaderValidationResult } from './types';
|
|
11
|
+
/**
|
|
12
|
+
* Validate and prioritize authentication headers
|
|
13
|
+
*
|
|
14
|
+
* @param headers HTTP headers
|
|
15
|
+
* @returns Validation result with prioritized authentication configuration
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateAuthHeaders(headers?: IncomingHttpHeaders): HeaderValidationResult;
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Header validator for MCP ABAP ADT authentication headers
|
|
4
|
+
*
|
|
5
|
+
* Validates and prioritizes authentication headers according to:
|
|
6
|
+
* 1. Destination-based auth (x-mcp-destination) - highest priority
|
|
7
|
+
* 2. Direct JWT token (x-sap-jwt-token) - medium priority
|
|
8
|
+
* 3. Basic auth (x-sap-login + x-sap-password) - lowest priority
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.validateAuthHeaders = validateAuthHeaders;
|
|
12
|
+
const types_1 = require("./types");
|
|
13
|
+
/**
|
|
14
|
+
* Extract header value (handles array values)
|
|
15
|
+
*/
|
|
16
|
+
function getHeaderValue(headers, name) {
|
|
17
|
+
const value = headers[name];
|
|
18
|
+
if (!value) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
return value[0]?.trim();
|
|
23
|
+
}
|
|
24
|
+
return String(value).trim();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validate URL format
|
|
28
|
+
*/
|
|
29
|
+
function isValidUrl(url) {
|
|
30
|
+
try {
|
|
31
|
+
const parsed = new URL(url);
|
|
32
|
+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Validate SAP destination-based authentication (highest priority)
|
|
40
|
+
* x-sap-destination - uses AuthBroker, JWT only, no auth-type needed
|
|
41
|
+
* URL is taken from destination (service key or .env), not from x-sap-url header
|
|
42
|
+
*/
|
|
43
|
+
function validateSapDestinationAuth(headers) {
|
|
44
|
+
const destinationRaw = headers['x-sap-destination'];
|
|
45
|
+
if (!destinationRaw) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const destination = getHeaderValue(headers, 'x-sap-destination');
|
|
49
|
+
const errors = [];
|
|
50
|
+
const warnings = [];
|
|
51
|
+
// Validate destination name (check if empty after trim)
|
|
52
|
+
if (!destination || destination.length === 0) {
|
|
53
|
+
errors.push('x-sap-destination header is empty');
|
|
54
|
+
return {
|
|
55
|
+
priority: types_1.AuthMethodPriority.NONE,
|
|
56
|
+
authType: 'jwt', // SAP destination always uses JWT
|
|
57
|
+
sapUrl: '', // URL will be loaded from destination
|
|
58
|
+
errors,
|
|
59
|
+
warnings,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Extract optional SAP client
|
|
63
|
+
const sapClient = getHeaderValue(headers, 'x-sap-client');
|
|
64
|
+
// Optional: x-sap-login and x-sap-password (for cloud systems)
|
|
65
|
+
const username = getHeaderValue(headers, 'x-sap-login');
|
|
66
|
+
const password = getHeaderValue(headers, 'x-sap-password');
|
|
67
|
+
// Warning if x-sap-url is provided (URL comes from destination, not header)
|
|
68
|
+
const sapUrl = getHeaderValue(headers, 'x-sap-url');
|
|
69
|
+
if (sapUrl) {
|
|
70
|
+
warnings.push('x-sap-url is ignored when x-sap-destination is present (URL is loaded from destination service key or .env file)');
|
|
71
|
+
}
|
|
72
|
+
// Warning if direct JWT token is also provided (destination takes priority)
|
|
73
|
+
const jwtToken = getHeaderValue(headers, 'x-sap-jwt-token');
|
|
74
|
+
if (jwtToken) {
|
|
75
|
+
warnings.push('x-sap-jwt-token is ignored when x-sap-destination is present (destination-based auth takes priority)');
|
|
76
|
+
}
|
|
77
|
+
// Warning if auth-type is provided (not needed for x-sap-destination)
|
|
78
|
+
const authType = getHeaderValue(headers, 'x-sap-auth-type');
|
|
79
|
+
if (authType) {
|
|
80
|
+
warnings.push('x-sap-auth-type is ignored when x-sap-destination is present (always uses JWT)');
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
priority: types_1.AuthMethodPriority.SAP_DESTINATION,
|
|
84
|
+
authType: 'jwt', // Always JWT for x-sap-destination
|
|
85
|
+
sapUrl: '', // URL will be loaded from destination (service key or .env)
|
|
86
|
+
sapClient,
|
|
87
|
+
destination,
|
|
88
|
+
username,
|
|
89
|
+
password,
|
|
90
|
+
errors,
|
|
91
|
+
warnings,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Validate MCP destination-based authentication (medium-high priority)
|
|
96
|
+
* x-mcp-destination - uses AuthBroker, always JWT (no x-sap-auth-type needed)
|
|
97
|
+
*/
|
|
98
|
+
function validateMcpDestinationAuth(headers, sapUrl) {
|
|
99
|
+
const destinationRaw = headers['x-mcp-destination'];
|
|
100
|
+
if (!destinationRaw) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const destination = getHeaderValue(headers, 'x-mcp-destination');
|
|
104
|
+
const errors = [];
|
|
105
|
+
const warnings = [];
|
|
106
|
+
// Validate destination name (check if empty after trim)
|
|
107
|
+
if (!destination || destination.length === 0) {
|
|
108
|
+
errors.push('x-mcp-destination header is empty');
|
|
109
|
+
return {
|
|
110
|
+
priority: types_1.AuthMethodPriority.NONE,
|
|
111
|
+
authType: 'jwt', // MCP destination always uses JWT
|
|
112
|
+
sapUrl,
|
|
113
|
+
errors,
|
|
114
|
+
warnings,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
// Warning if x-sap-auth-type is provided (not needed for x-mcp-destination)
|
|
118
|
+
const authType = getHeaderValue(headers, 'x-sap-auth-type');
|
|
119
|
+
if (authType) {
|
|
120
|
+
warnings.push('x-sap-auth-type is ignored when x-mcp-destination is present (always uses JWT)');
|
|
121
|
+
}
|
|
122
|
+
// Extract optional SAP client
|
|
123
|
+
const sapClient = getHeaderValue(headers, 'x-sap-client');
|
|
124
|
+
// Warning if direct JWT token is also provided (destination takes priority)
|
|
125
|
+
const jwtToken = getHeaderValue(headers, 'x-sap-jwt-token');
|
|
126
|
+
if (jwtToken) {
|
|
127
|
+
warnings.push('x-sap-jwt-token is ignored when x-mcp-destination is present (destination-based auth takes priority)');
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
priority: types_1.AuthMethodPriority.MCP_DESTINATION,
|
|
131
|
+
authType: 'jwt', // Always JWT for x-mcp-destination
|
|
132
|
+
sapUrl,
|
|
133
|
+
sapClient,
|
|
134
|
+
destination,
|
|
135
|
+
errors,
|
|
136
|
+
warnings,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Validate direct JWT authentication (medium priority)
|
|
141
|
+
*/
|
|
142
|
+
function validateDirectJwtAuth(headers, sapUrl, authType) {
|
|
143
|
+
if (authType !== 'jwt' && authType !== 'xsuaa') {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const jwtToken = getHeaderValue(headers, 'x-sap-jwt-token');
|
|
147
|
+
if (!jwtToken) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const errors = [];
|
|
151
|
+
const warnings = [];
|
|
152
|
+
// Validate JWT token format (basic check - should start with eyJ)
|
|
153
|
+
if (jwtToken.length < 10) {
|
|
154
|
+
errors.push('x-sap-jwt-token appears to be invalid (too short)');
|
|
155
|
+
}
|
|
156
|
+
// Extract optional tokens and UAA config
|
|
157
|
+
const refreshToken = getHeaderValue(headers, 'x-sap-refresh-token');
|
|
158
|
+
const uaaUrl = getHeaderValue(headers, 'x-sap-uaa-url') || getHeaderValue(headers, 'uaa-url');
|
|
159
|
+
const uaaClientId = getHeaderValue(headers, 'x-sap-uaa-client-id') || getHeaderValue(headers, 'uaa-client-id');
|
|
160
|
+
const uaaClientSecret = getHeaderValue(headers, 'x-sap-uaa-client-secret') || getHeaderValue(headers, 'uaa-client-secret');
|
|
161
|
+
// Extract optional SAP client
|
|
162
|
+
const sapClient = getHeaderValue(headers, 'x-sap-client');
|
|
163
|
+
return {
|
|
164
|
+
priority: types_1.AuthMethodPriority.DIRECT_JWT,
|
|
165
|
+
authType,
|
|
166
|
+
sapUrl,
|
|
167
|
+
sapClient,
|
|
168
|
+
jwtToken,
|
|
169
|
+
refreshToken,
|
|
170
|
+
uaaUrl,
|
|
171
|
+
uaaClientId,
|
|
172
|
+
uaaClientSecret,
|
|
173
|
+
errors,
|
|
174
|
+
warnings,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Validate basic authentication (lowest priority)
|
|
179
|
+
*/
|
|
180
|
+
function validateBasicAuth(headers, sapUrl, authType) {
|
|
181
|
+
if (authType !== 'basic') {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
const usernameRaw = headers['x-sap-login'];
|
|
185
|
+
const passwordRaw = headers['x-sap-password'];
|
|
186
|
+
if (!usernameRaw || !passwordRaw) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
const username = getHeaderValue(headers, 'x-sap-login');
|
|
190
|
+
const password = getHeaderValue(headers, 'x-sap-password');
|
|
191
|
+
const errors = [];
|
|
192
|
+
const warnings = [];
|
|
193
|
+
// Validate username and password (check if empty after trim)
|
|
194
|
+
if (!username || username.length === 0) {
|
|
195
|
+
errors.push('x-sap-login header is empty');
|
|
196
|
+
}
|
|
197
|
+
if (!password || password.length === 0) {
|
|
198
|
+
errors.push('x-sap-password header is empty');
|
|
199
|
+
}
|
|
200
|
+
// Return config with errors if validation failed
|
|
201
|
+
if (errors.length > 0) {
|
|
202
|
+
return {
|
|
203
|
+
priority: types_1.AuthMethodPriority.NONE,
|
|
204
|
+
authType,
|
|
205
|
+
sapUrl,
|
|
206
|
+
errors,
|
|
207
|
+
warnings,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
priority: types_1.AuthMethodPriority.BASIC,
|
|
212
|
+
authType,
|
|
213
|
+
sapUrl,
|
|
214
|
+
username,
|
|
215
|
+
password,
|
|
216
|
+
errors,
|
|
217
|
+
warnings,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Validate and prioritize authentication headers
|
|
222
|
+
*
|
|
223
|
+
* @param headers HTTP headers
|
|
224
|
+
* @returns Validation result with prioritized authentication configuration
|
|
225
|
+
*/
|
|
226
|
+
function validateAuthHeaders(headers) {
|
|
227
|
+
// No headers provided
|
|
228
|
+
if (!headers) {
|
|
229
|
+
return {
|
|
230
|
+
isValid: false,
|
|
231
|
+
errors: ['No headers provided'],
|
|
232
|
+
warnings: [],
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
const errors = [];
|
|
236
|
+
const warnings = [];
|
|
237
|
+
// Check for SAP destination first (doesn't require x-sap-url)
|
|
238
|
+
const sapDestinationConfig = validateSapDestinationAuth(headers);
|
|
239
|
+
if (sapDestinationConfig) {
|
|
240
|
+
// SAP destination found - URL comes from destination, not header
|
|
241
|
+
if (sapDestinationConfig.errors.length === 0) {
|
|
242
|
+
return {
|
|
243
|
+
isValid: true,
|
|
244
|
+
config: sapDestinationConfig,
|
|
245
|
+
errors: [],
|
|
246
|
+
warnings: sapDestinationConfig.warnings,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// Has errors, continue to check other methods or return error
|
|
251
|
+
return {
|
|
252
|
+
isValid: false,
|
|
253
|
+
errors: sapDestinationConfig.errors,
|
|
254
|
+
warnings: sapDestinationConfig.warnings,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// For other auth methods, x-sap-url is required
|
|
259
|
+
const sapUrl = getHeaderValue(headers, 'x-sap-url');
|
|
260
|
+
// Validate required headers
|
|
261
|
+
if (!sapUrl) {
|
|
262
|
+
errors.push('x-sap-url header is required when x-sap-destination is not present');
|
|
263
|
+
return {
|
|
264
|
+
isValid: false,
|
|
265
|
+
errors,
|
|
266
|
+
warnings,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
// Validate URL format
|
|
270
|
+
if (!isValidUrl(sapUrl)) {
|
|
271
|
+
errors.push(`x-sap-url is not a valid URL: ${sapUrl}`);
|
|
272
|
+
return {
|
|
273
|
+
isValid: false,
|
|
274
|
+
errors,
|
|
275
|
+
warnings,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
// Try to validate authentication methods in priority order
|
|
279
|
+
const configs = [];
|
|
280
|
+
// 2. MCP destination-based auth (medium-high priority) - doesn't require x-sap-auth-type
|
|
281
|
+
const mcpDestinationConfig = validateMcpDestinationAuth(headers, sapUrl);
|
|
282
|
+
if (mcpDestinationConfig) {
|
|
283
|
+
configs.push(mcpDestinationConfig);
|
|
284
|
+
}
|
|
285
|
+
// 3. Other auth methods require x-sap-auth-type
|
|
286
|
+
const sapAuthType = getHeaderValue(headers, 'x-sap-auth-type');
|
|
287
|
+
if (sapAuthType) {
|
|
288
|
+
// Validate auth type
|
|
289
|
+
const validAuthTypes = ['jwt', 'xsuaa', 'basic'];
|
|
290
|
+
const authType = sapAuthType.toLowerCase();
|
|
291
|
+
if (!validAuthTypes.includes(authType)) {
|
|
292
|
+
errors.push(`x-sap-auth-type must be one of: ${validAuthTypes.join(', ')}, got: ${sapAuthType}`);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// Only validate direct JWT and basic auth if MCP destination is not present
|
|
296
|
+
// (MCP destination already handled above)
|
|
297
|
+
if (!mcpDestinationConfig) {
|
|
298
|
+
// 4. Direct JWT auth (medium priority)
|
|
299
|
+
const jwtConfig = validateDirectJwtAuth(headers, sapUrl, authType);
|
|
300
|
+
if (jwtConfig) {
|
|
301
|
+
configs.push(jwtConfig);
|
|
302
|
+
}
|
|
303
|
+
// 5. Basic auth (lowest priority)
|
|
304
|
+
const basicConfig = validateBasicAuth(headers, sapUrl, authType);
|
|
305
|
+
if (basicConfig) {
|
|
306
|
+
configs.push(basicConfig);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
// No auth-type provided - check if we have MCP destination or need to error
|
|
313
|
+
if (!mcpDestinationConfig && !sapDestinationConfig) {
|
|
314
|
+
errors.push('x-sap-auth-type header is required when x-sap-destination and x-mcp-destination are not present');
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// No valid authentication method found
|
|
318
|
+
if (configs.length === 0) {
|
|
319
|
+
if (sapAuthType) {
|
|
320
|
+
const authType = sapAuthType.toLowerCase();
|
|
321
|
+
if (authType === 'jwt' || authType === 'xsuaa') {
|
|
322
|
+
errors.push('JWT authentication requires either x-sap-destination, x-mcp-destination, or x-sap-jwt-token header');
|
|
323
|
+
}
|
|
324
|
+
else if (authType === 'basic') {
|
|
325
|
+
errors.push('Basic authentication requires x-sap-login and x-sap-password headers');
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else if (mcpDestinationConfig && mcpDestinationConfig.errors.length > 0) {
|
|
329
|
+
// MCP destination was found but has errors
|
|
330
|
+
errors.push(...mcpDestinationConfig.errors);
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
isValid: false,
|
|
334
|
+
errors,
|
|
335
|
+
warnings,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
// Select highest priority configuration
|
|
339
|
+
const selectedConfig = configs.reduce((prev, current) => current.priority > prev.priority ? current : prev);
|
|
340
|
+
// Check for conflicts (multiple auth methods with same priority shouldn't happen, but check anyway)
|
|
341
|
+
const samePriorityConfigs = configs.filter(c => c.priority === selectedConfig.priority);
|
|
342
|
+
if (samePriorityConfigs.length > 1) {
|
|
343
|
+
warnings.push(`Multiple authentication methods with same priority detected, using: ${types_1.AuthMethodPriority[selectedConfig.priority]}`);
|
|
344
|
+
}
|
|
345
|
+
// Merge errors and warnings
|
|
346
|
+
const allErrors = [...errors, ...selectedConfig.errors];
|
|
347
|
+
const allWarnings = [...warnings, ...selectedConfig.warnings];
|
|
348
|
+
return {
|
|
349
|
+
isValid: allErrors.length === 0,
|
|
350
|
+
config: selectedConfig,
|
|
351
|
+
errors: allErrors,
|
|
352
|
+
warnings: allWarnings,
|
|
353
|
+
};
|
|
354
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Header validator for MCP ABAP ADT
|
|
4
|
+
*
|
|
5
|
+
* Validates and prioritizes authentication headers for MCP ABAP ADT servers
|
|
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
19
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.validateAuthHeaders = void 0;
|
|
23
|
+
var headerValidator_1 = require("./headerValidator");
|
|
24
|
+
Object.defineProperty(exports, "validateAuthHeaders", { enumerable: true, get: function () { return headerValidator_1.validateAuthHeaders; } });
|
|
25
|
+
__exportStar(require("./types"), exports);
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for header validator
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Authentication type
|
|
6
|
+
*/
|
|
7
|
+
export type AuthType = 'jwt' | 'xsuaa' | 'basic';
|
|
8
|
+
/**
|
|
9
|
+
* Authentication method priority
|
|
10
|
+
* Higher number = higher priority
|
|
11
|
+
*/
|
|
12
|
+
export declare enum AuthMethodPriority {
|
|
13
|
+
SAP_DESTINATION = 4,// x-sap-destination (uses AuthBroker, JWT only)
|
|
14
|
+
MCP_DESTINATION = 3,// x-mcp-destination + x-sap-auth-type=jwt (uses AuthBroker)
|
|
15
|
+
DIRECT_JWT = 2,// x-sap-jwt-token + x-sap-auth-type=jwt
|
|
16
|
+
BASIC = 1,// x-sap-login + x-sap-password + x-sap-auth-type=basic
|
|
17
|
+
NONE = 0
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validated authentication configuration
|
|
21
|
+
*/
|
|
22
|
+
export interface ValidatedAuthConfig {
|
|
23
|
+
/** Authentication method priority */
|
|
24
|
+
priority: AuthMethodPriority;
|
|
25
|
+
/** Authentication type */
|
|
26
|
+
authType: AuthType;
|
|
27
|
+
/** SAP URL */
|
|
28
|
+
sapUrl: string;
|
|
29
|
+
/** SAP Client (optional) */
|
|
30
|
+
sapClient?: string;
|
|
31
|
+
/** Destination name (for destination-based auth: x-sap-destination or x-mcp-destination) */
|
|
32
|
+
destination?: string;
|
|
33
|
+
/** JWT token (for direct JWT auth) */
|
|
34
|
+
jwtToken?: string;
|
|
35
|
+
/** Refresh token (optional, for JWT auth) */
|
|
36
|
+
refreshToken?: string;
|
|
37
|
+
/** UAA URL (optional, for JWT auth) */
|
|
38
|
+
uaaUrl?: string;
|
|
39
|
+
/** UAA Client ID (optional, for JWT auth) */
|
|
40
|
+
uaaClientId?: string;
|
|
41
|
+
/** UAA Client Secret (optional, for JWT auth) */
|
|
42
|
+
uaaClientSecret?: string;
|
|
43
|
+
/** Username (for basic auth) */
|
|
44
|
+
username?: string;
|
|
45
|
+
/** Password (for basic auth) */
|
|
46
|
+
password?: string;
|
|
47
|
+
/** Validation errors (if any) */
|
|
48
|
+
errors: string[];
|
|
49
|
+
/** Warnings (if any) */
|
|
50
|
+
warnings: string[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Header validation result
|
|
54
|
+
*/
|
|
55
|
+
export interface HeaderValidationResult {
|
|
56
|
+
/** Is configuration valid? */
|
|
57
|
+
isValid: boolean;
|
|
58
|
+
/** Validated authentication configuration */
|
|
59
|
+
config?: ValidatedAuthConfig;
|
|
60
|
+
/** Validation errors */
|
|
61
|
+
errors: string[];
|
|
62
|
+
/** Warnings */
|
|
63
|
+
warnings: string[];
|
|
64
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Types for header validator
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AuthMethodPriority = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* Authentication method priority
|
|
9
|
+
* Higher number = higher priority
|
|
10
|
+
*/
|
|
11
|
+
var AuthMethodPriority;
|
|
12
|
+
(function (AuthMethodPriority) {
|
|
13
|
+
AuthMethodPriority[AuthMethodPriority["SAP_DESTINATION"] = 4] = "SAP_DESTINATION";
|
|
14
|
+
AuthMethodPriority[AuthMethodPriority["MCP_DESTINATION"] = 3] = "MCP_DESTINATION";
|
|
15
|
+
AuthMethodPriority[AuthMethodPriority["DIRECT_JWT"] = 2] = "DIRECT_JWT";
|
|
16
|
+
AuthMethodPriority[AuthMethodPriority["BASIC"] = 1] = "BASIC";
|
|
17
|
+
AuthMethodPriority[AuthMethodPriority["NONE"] = 0] = "NONE"; // No valid authentication
|
|
18
|
+
})(AuthMethodPriority || (exports.AuthMethodPriority = AuthMethodPriority = {}));
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcp-abap-adt/header-validator",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Header validator for MCP ABAP ADT - validates and prioritizes authentication headers",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"CHANGELOG.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"abap",
|
|
15
|
+
"sap",
|
|
16
|
+
"adt",
|
|
17
|
+
"mcp",
|
|
18
|
+
"header",
|
|
19
|
+
"validator",
|
|
20
|
+
"authentication",
|
|
21
|
+
"abap-adt"
|
|
22
|
+
],
|
|
23
|
+
"author": "Oleksii Kyslytsia <oleksij.kyslytsja@gmail.com>",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"homepage": "https://github.com/fr0ster/mcp-abap-adt-header-validator#readme",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/fr0ster/mcp-abap-adt-header-validator/issues"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/fr0ster/mcp-abap-adt-header-validator.git"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
38
|
+
"build": "npm run clean --silent && npx tsc -p tsconfig.json",
|
|
39
|
+
"build:fast": "npx tsc -p tsconfig.json",
|
|
40
|
+
"test": "jest",
|
|
41
|
+
"test:check": "npx tsc --noEmit",
|
|
42
|
+
"prepublishOnly": "npm run build"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/jest": "^30.0.0",
|
|
49
|
+
"@types/node": "^24.2.1",
|
|
50
|
+
"jest": "^30.2.0",
|
|
51
|
+
"ts-jest": "^29.2.5",
|
|
52
|
+
"typescript": "^5.9.2"
|
|
53
|
+
}
|
|
54
|
+
}
|