@sap-ux/backend-proxy-middleware-cf 0.0.51 → 0.0.53
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/README.md +99 -24
- package/dist/middleware.js +8 -2
- package/dist/proxy.d.ts +6 -4
- package/dist/proxy.js +11 -10
- package/dist/types.d.ts +12 -2
- package/dist/validation.js +10 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -30,10 +30,11 @@ server:
|
|
|
30
30
|
- name: backend-proxy-middleware-cf
|
|
31
31
|
afterMiddleware: compression
|
|
32
32
|
configuration:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
backends:
|
|
34
|
+
- url: https://your-backend-service
|
|
35
|
+
paths:
|
|
36
|
+
- /odata/v4/visitorservice
|
|
37
|
+
- /odata
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
### [Automatic Detection (Recommended)](#automatic-detection-recommended)
|
|
@@ -46,10 +47,11 @@ server:
|
|
|
46
47
|
- name: backend-proxy-middleware-cf
|
|
47
48
|
afterMiddleware: compression
|
|
48
49
|
configuration:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
backends:
|
|
51
|
+
- url: https://your-backend-service
|
|
52
|
+
paths:
|
|
53
|
+
- /odata/v4/visitorservice
|
|
54
|
+
- /odata
|
|
53
55
|
```
|
|
54
56
|
|
|
55
57
|
The middleware will:
|
|
@@ -70,20 +72,61 @@ server:
|
|
|
70
72
|
- name: backend-proxy-middleware-cf
|
|
71
73
|
afterMiddleware: compression
|
|
72
74
|
configuration:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
backends:
|
|
76
|
+
- url: https://your-backend-service
|
|
77
|
+
paths:
|
|
78
|
+
- /odata/v4/visitorservice
|
|
79
|
+
- /odata
|
|
80
|
+
credentials:
|
|
81
|
+
clientId: "sb-your-service-instance!b123|your-app!b456"
|
|
82
|
+
clientSecret: "your-client-secret"
|
|
83
|
+
url: "https://example.authentication"
|
|
84
|
+
debug: true
|
|
82
85
|
```
|
|
83
86
|
|
|
84
87
|
The `credentials.url` should be the base URL of the UAA service (without `/oauth/token`). The middleware will automatically construct the full token endpoint.
|
|
85
88
|
|
|
86
|
-
###
|
|
89
|
+
### Multiple OData Sources
|
|
90
|
+
|
|
91
|
+
You can proxy multiple OData paths to the same destination:
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
server:
|
|
95
|
+
customMiddleware:
|
|
96
|
+
- name: backend-proxy-middleware-cf
|
|
97
|
+
afterMiddleware: compression
|
|
98
|
+
configuration:
|
|
99
|
+
backends:
|
|
100
|
+
- url: https://your-backend-service
|
|
101
|
+
paths:
|
|
102
|
+
- /odata/v4/service1
|
|
103
|
+
- /odata/v4/service2
|
|
104
|
+
- /odata/v2/legacy
|
|
105
|
+
```
|
|
106
|
+
### Miltiple Backend Services
|
|
107
|
+
|
|
108
|
+
You can proxy multiple backend services:
|
|
109
|
+
|
|
110
|
+
```yaml
|
|
111
|
+
server:
|
|
112
|
+
customMiddleware:
|
|
113
|
+
- name: backend-proxy-middleware-cf
|
|
114
|
+
afterMiddleware: compression
|
|
115
|
+
configuration:
|
|
116
|
+
backends:
|
|
117
|
+
- url: https://your-backend-service1
|
|
118
|
+
paths:
|
|
119
|
+
- /odata/v4/service1
|
|
120
|
+
- /odata/v4/service2
|
|
121
|
+
- /odata/v2/legacy
|
|
122
|
+
- url: https://your-backend-service2
|
|
123
|
+
paths:
|
|
124
|
+
- /odata/v4/service1
|
|
125
|
+
- /odata/v4/service2
|
|
126
|
+
- /odata/v2/legacy
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### With Debug Logging
|
|
87
130
|
|
|
88
131
|
Enable debug logging to troubleshoot issues:
|
|
89
132
|
|
|
@@ -93,15 +136,47 @@ server:
|
|
|
93
136
|
- name: backend-proxy-middleware-cf
|
|
94
137
|
afterMiddleware: compression
|
|
95
138
|
configuration:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
139
|
+
backends:
|
|
140
|
+
- url: https://your-backend-service.cfapps.eu12.hana.ondemand.com
|
|
141
|
+
paths:
|
|
142
|
+
- /odata
|
|
143
|
+
debug: true
|
|
100
144
|
```
|
|
101
145
|
|
|
102
|
-
##
|
|
146
|
+
## How It Works
|
|
147
|
+
|
|
148
|
+
1. **Proxy Setup**: Creates HTTP proxy middleware for each configured path, proxying to the destination URL.
|
|
149
|
+
2. **Path Rewriting**: Removes the matched path prefix before forwarding requests (e.g., `/odata/v4/service` → `/service`).
|
|
150
|
+
3. **OAuth Detection**: For automatic mode, checks if the project is a CF ADP project by reading `ui5.yaml` and looking for the `app-variant-bundler-build` custom task.
|
|
151
|
+
4. **Credentials**: Extracts `serviceInstanceName` and `serviceInstanceGuid` from the custom task configuration.
|
|
152
|
+
5. **Service Keys**: Retrieves service keys using `@sap-ux/adp-tooling`, which communicates with Cloud Foundry CLI.
|
|
153
|
+
6. **Token Endpoint**: Constructs the token endpoint from the UAA base URL as `{url}/oauth/token`.
|
|
154
|
+
7. **Token Management**: Requests OAuth tokens using client credentials flow.
|
|
155
|
+
8. **Caching**: Caches tokens in memory and refreshes them automatically 60 seconds before expiry.
|
|
156
|
+
9. **Request Proxying**: Adds `Authorization: Bearer <token>` header to proxied requests before forwarding.
|
|
157
|
+
|
|
158
|
+
## Error Handling
|
|
159
|
+
|
|
160
|
+
- If `url` is not provided, the middleware will be inactive and log a warning.
|
|
161
|
+
- If no paths are configured, the middleware will be inactive and log a warning.
|
|
162
|
+
- If auto-detection fails and no manual credentials are provided, the middleware will proxy requests without OAuth tokens (may fail if backend requires authentication).
|
|
163
|
+
- If token request fails, an error is logged but the request may still proceed (depending on the backend's authentication requirements).
|
|
164
|
+
- All errors are logged for debugging purposes.
|
|
165
|
+
|
|
166
|
+
## Security Considerations
|
|
167
|
+
|
|
168
|
+
- Credentials are never logged in production mode.
|
|
169
|
+
- Tokens are cached in memory only and never persisted to disk.
|
|
170
|
+
- Token refresh happens automatically 60 seconds before expiry to avoid using expired tokens.
|
|
171
|
+
- Service keys are obtained securely through Cloud Foundry CLI.
|
|
172
|
+
- The middleware only proxies requests matching any of the configured path prefixes.
|
|
173
|
+
- If no paths are configured, the middleware will be inactive and log a warning.
|
|
174
|
+
|
|
175
|
+
## Keywords
|
|
103
176
|
|
|
104
|
-
- OAuth2
|
|
177
|
+
- OAuth2 Middleware
|
|
105
178
|
- Cloud Foundry ADP
|
|
179
|
+
- Bearer Token
|
|
106
180
|
- Fiori tools
|
|
107
181
|
- SAP UI5
|
|
182
|
+
- Proxy Middleware
|
package/dist/middleware.js
CHANGED
|
@@ -6,7 +6,7 @@ const validation_1 = require("./validation");
|
|
|
6
6
|
const token_1 = require("./token");
|
|
7
7
|
/**
|
|
8
8
|
* UI5 middleware for proxying requests to Cloud Foundry destinations with OAuth2 authentication.
|
|
9
|
-
* Supports
|
|
9
|
+
* Supports multiple destination URLs with their own OData source paths.
|
|
10
10
|
*
|
|
11
11
|
* @param {MiddlewareParameters<CfOAuthMiddlewareConfig>} params - Input parameters for UI5 middleware.
|
|
12
12
|
* @param {CfOAuthMiddlewareConfig} params.options - Configuration options.
|
|
@@ -23,6 +23,12 @@ module.exports = async ({ options }) => {
|
|
|
23
23
|
});
|
|
24
24
|
await (0, validation_1.validateConfig)(config, logger);
|
|
25
25
|
const tokenProvider = await (0, token_1.createTokenProvider)(config, logger);
|
|
26
|
-
|
|
26
|
+
// Setup proxy routes for all backends
|
|
27
|
+
const router = (0, proxy_1.setupProxyRoutes)(config.backends, tokenProvider, logger);
|
|
28
|
+
// Log initialization
|
|
29
|
+
config.backends.forEach((backend) => {
|
|
30
|
+
logger.info(`Backend proxy middleware (CF) initialized: url=${backend.url}, paths=${backend.paths.join(', ')}`);
|
|
31
|
+
});
|
|
32
|
+
return router;
|
|
27
33
|
};
|
|
28
34
|
//# sourceMappingURL=middleware.js.map
|
package/dist/proxy.d.ts
CHANGED
|
@@ -24,13 +24,15 @@ export declare function createProxyOptions(targetUrl: string, logger: ToolsLogge
|
|
|
24
24
|
*/
|
|
25
25
|
export declare function registerProxyRoute(path: string, destinationUrl: string, tokenProvider: OAuthTokenProvider, logger: ToolsLogger, router: Router): void;
|
|
26
26
|
/**
|
|
27
|
-
* Sets up all proxy routes for the configured
|
|
27
|
+
* Sets up all proxy routes for the configured backends.
|
|
28
28
|
*
|
|
29
|
-
* @param {string[]}
|
|
30
|
-
* @param {string} destinationUrl - Target URL for proxying.
|
|
29
|
+
* @param {Array<{url: string, paths: string[]}>} backends - Array of backend configurations.
|
|
31
30
|
* @param {OAuthTokenProvider} tokenProvider - Token provider instance.
|
|
32
31
|
* @param {ToolsLogger} logger - Logger instance.
|
|
33
32
|
* @returns {Router} Configured Express router.
|
|
34
33
|
*/
|
|
35
|
-
export declare function setupProxyRoutes(
|
|
34
|
+
export declare function setupProxyRoutes(backends: Array<{
|
|
35
|
+
url: string;
|
|
36
|
+
paths: string[];
|
|
37
|
+
}>, tokenProvider: OAuthTokenProvider, logger: ToolsLogger): Router;
|
|
36
38
|
//# sourceMappingURL=proxy.d.ts.map
|
package/dist/proxy.js
CHANGED
|
@@ -53,22 +53,23 @@ function registerProxyRoute(path, destinationUrl, tokenProvider, logger, router)
|
|
|
53
53
|
logger.info(`Registered proxy for path: ${path} -> ${destinationUrl}`);
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Sets up all proxy routes for the configured
|
|
56
|
+
* Sets up all proxy routes for the configured backends.
|
|
57
57
|
*
|
|
58
|
-
* @param {string[]}
|
|
59
|
-
* @param {string} destinationUrl - Target URL for proxying.
|
|
58
|
+
* @param {Array<{url: string, paths: string[]}>} backends - Array of backend configurations.
|
|
60
59
|
* @param {OAuthTokenProvider} tokenProvider - Token provider instance.
|
|
61
60
|
* @param {ToolsLogger} logger - Logger instance.
|
|
62
61
|
* @returns {Router} Configured Express router.
|
|
63
62
|
*/
|
|
64
|
-
function setupProxyRoutes(
|
|
63
|
+
function setupProxyRoutes(backends, tokenProvider, logger) {
|
|
65
64
|
const router = (0, express_1.Router)();
|
|
66
|
-
for (const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
for (const backend of backends) {
|
|
66
|
+
for (const path of backend.paths) {
|
|
67
|
+
try {
|
|
68
|
+
registerProxyRoute(path, backend.url, tokenProvider, logger, router);
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
throw new Error(`Failed to register proxy for ${path}. Check configuration in yaml file. \n\t${e.message}`);
|
|
72
|
+
}
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
return router;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Configuration for
|
|
2
|
+
* Configuration for a single backend destination.
|
|
3
3
|
*/
|
|
4
|
-
export interface
|
|
4
|
+
export interface BackendDestination {
|
|
5
5
|
/**
|
|
6
6
|
* Destination URL to proxy requests to.
|
|
7
7
|
*/
|
|
@@ -12,6 +12,16 @@ export interface CfOAuthMiddlewareConfig {
|
|
|
12
12
|
* Requests matching these paths will have the path prefix removed before forwarding.
|
|
13
13
|
*/
|
|
14
14
|
paths: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Configuration for Cloud Foundry OAuth middleware.
|
|
18
|
+
*/
|
|
19
|
+
export interface CfOAuthMiddlewareConfig {
|
|
20
|
+
/**
|
|
21
|
+
* Array of backend destinations.
|
|
22
|
+
* Each destination has its own URL and paths.
|
|
23
|
+
*/
|
|
24
|
+
backends: BackendDestination[];
|
|
15
25
|
/**
|
|
16
26
|
* Manual OAuth credentials (optional).
|
|
17
27
|
* If not provided, middleware will attempt to auto-detect from Cloud Foundry ADP project.
|
package/dist/validation.js
CHANGED
|
@@ -10,11 +10,17 @@ const adp_tooling_1 = require("@sap-ux/adp-tooling");
|
|
|
10
10
|
* @throws {Error} If configuration is invalid.
|
|
11
11
|
*/
|
|
12
12
|
async function validateConfig(config, logger) {
|
|
13
|
-
if (!config.
|
|
14
|
-
throw new Error('Backend proxy middleware (CF) requires
|
|
13
|
+
if (!config.backends || !Array.isArray(config.backends) || config.backends.length === 0) {
|
|
14
|
+
throw new Error('Backend proxy middleware (CF) requires "backends" array configuration.');
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// Validate each backend
|
|
17
|
+
for (const backend of config.backends) {
|
|
18
|
+
if (!backend.url) {
|
|
19
|
+
throw new Error('Backend proxy middleware (CF) requires url for each backend.');
|
|
20
|
+
}
|
|
21
|
+
if (!backend.paths || !Array.isArray(backend.paths) || backend.paths.length === 0) {
|
|
22
|
+
throw new Error(`Backend proxy middleware (CF) has no paths configured for URL: ${backend.url}`);
|
|
23
|
+
}
|
|
18
24
|
}
|
|
19
25
|
const cfConfig = (0, adp_tooling_1.loadCfConfig)(logger);
|
|
20
26
|
if (!(await (0, adp_tooling_1.isLoggedInCf)(cfConfig, logger))) {
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"bugs": {
|
|
10
10
|
"url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Abackend-proxy-middleware-cf"
|
|
11
11
|
},
|
|
12
|
-
"version": "0.0.
|
|
12
|
+
"version": "0.0.53",
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"author": "@SAP/ux-tools-team",
|
|
15
15
|
"main": "dist/index.js",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"axios": "1.13.5",
|
|
25
25
|
"http-proxy-middleware": "3.0.5",
|
|
26
|
-
"@sap-ux/adp-tooling": "0.18.
|
|
26
|
+
"@sap-ux/adp-tooling": "0.18.63",
|
|
27
27
|
"@sap-ux/logger": "0.8.1",
|
|
28
|
-
"@sap-ux/project-access": "1.35.
|
|
28
|
+
"@sap-ux/project-access": "1.35.3"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/express": "4.17.21",
|