soajs.controller 4.2.42 → 4.2.43
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/.github/workflows/ci.yml +43 -0
- package/.github/workflows/release.yml +92 -0
- package/ARCHITECTURE.md +193 -0
- package/Gruntfile.js +1 -1
- package/docs/configuration-custom-registry.md +421 -0
- package/docs/configuration-services-config.md +275 -0
- package/docs/data-flow.md +138 -0
- package/docs/deployment.md +205 -0
- package/docs/external-integrations.md +159 -0
- package/docs/gateway-routes.md +259 -0
- package/docs/maintenance-routes.md +308 -0
- package/docs/middleware/awareness.md +120 -0
- package/docs/middleware/cors.md +88 -0
- package/docs/middleware/enhancer.md +75 -0
- package/docs/middleware/favicon.md +36 -0
- package/docs/middleware/gotoService.md +146 -0
- package/docs/middleware/ip2ban.md +70 -0
- package/docs/middleware/key.md +196 -0
- package/docs/middleware/keyACL.md +139 -0
- package/docs/middleware/lastSeen.md +111 -0
- package/docs/middleware/maintenanceMode.md +81 -0
- package/docs/middleware/mt.md +188 -0
- package/docs/middleware/oauth.md +173 -0
- package/docs/middleware/response.md +106 -0
- package/docs/middleware/soajs.md +71 -0
- package/docs/middleware/traffic.md +190 -0
- package/docs/middleware/url.md +102 -0
- package/docs/multi-tenant-security.md +183 -0
- package/docs/request-flow.md +230 -0
- package/docs/service-discovery.md +167 -0
- package/mw/key/index.js +16 -1
- package/mw/mt/urac.js +21 -1
- package/mw/mt/utils.js +2 -0
- package/package.json +7 -7
- package/test/unit/mw/key/index.js +150 -0
- package/test/unit/mw/mt/urac.js +157 -4
- package/.travis.yml +0 -72
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# CORS Middleware
|
|
2
|
+
|
|
3
|
+
**File:** `mw/cors/index.js`
|
|
4
|
+
|
|
5
|
+
**Order:** 2
|
|
6
|
+
|
|
7
|
+
The CORS middleware handles Cross-Origin Resource Sharing headers and preflight (OPTIONS) requests.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
- Handles OPTIONS preflight requests
|
|
12
|
+
- Sets appropriate CORS headers on all responses
|
|
13
|
+
- Configurable via registry `serviceConfig.cors`
|
|
14
|
+
|
|
15
|
+
## Flow
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Incoming Request
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
┌─────────────────┐
|
|
22
|
+
│ Check CORS │ registry.serviceConfig.cors.enabled?
|
|
23
|
+
│ Enabled? │
|
|
24
|
+
└────────┬────────┘
|
|
25
|
+
│
|
|
26
|
+
├─── No ──▶ next()
|
|
27
|
+
│
|
|
28
|
+
▼
|
|
29
|
+
┌─────────────────┐
|
|
30
|
+
│ Is OPTIONS │ req.method === 'OPTIONS'?
|
|
31
|
+
│ Request? │
|
|
32
|
+
└────────┬────────┘
|
|
33
|
+
│
|
|
34
|
+
├─── Yes ──▶ Set headers, return 204 No Content
|
|
35
|
+
│
|
|
36
|
+
▼
|
|
37
|
+
┌─────────────────┐
|
|
38
|
+
│ Set CORS │ Access-Control-Allow-Origin
|
|
39
|
+
│ Headers │ Access-Control-Allow-Credentials
|
|
40
|
+
└────────┬────────┘ Access-Control-Expose-Headers
|
|
41
|
+
│
|
|
42
|
+
▼
|
|
43
|
+
next()
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
Located in `registry.serviceConfig.cors`:
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
{
|
|
52
|
+
"cors": {
|
|
53
|
+
"enabled": true,
|
|
54
|
+
"origin": "*", // Default: "*"
|
|
55
|
+
"credentials": "true", // Default: "true"
|
|
56
|
+
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
|
|
57
|
+
"headers": "__env,key,soajsauth,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type",
|
|
58
|
+
"maxage": 1728000 // Default: 1728000 (20 days)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Response Headers
|
|
64
|
+
|
|
65
|
+
### Preflight (OPTIONS) Response
|
|
66
|
+
|
|
67
|
+
| Header | Value |
|
|
68
|
+
|--------|-------|
|
|
69
|
+
| `Access-Control-Allow-Origin` | Configured origin or `*` |
|
|
70
|
+
| `Access-Control-Allow-Credentials` | `true` |
|
|
71
|
+
| `Access-Control-Allow-Methods` | Configured methods |
|
|
72
|
+
| `Access-Control-Allow-Headers` | Configured headers |
|
|
73
|
+
| `Access-Control-Max-Age` | Configured max age |
|
|
74
|
+
| `Access-Control-Expose-Headers` | Configured headers |
|
|
75
|
+
|
|
76
|
+
### Regular Response
|
|
77
|
+
|
|
78
|
+
| Header | Value |
|
|
79
|
+
|--------|-------|
|
|
80
|
+
| `Access-Control-Allow-Origin` | Configured origin or `*` |
|
|
81
|
+
| `Access-Control-Allow-Credentials` | `true` |
|
|
82
|
+
| `Access-Control-Expose-Headers` | Configured headers |
|
|
83
|
+
|
|
84
|
+
## Usage Notes
|
|
85
|
+
|
|
86
|
+
- If CORS is not enabled in config, middleware passes through without action
|
|
87
|
+
- OPTIONS requests return immediately with 204 status (no body)
|
|
88
|
+
- Default headers include SOAJS-specific headers (`__env`, `key`, `soajsauth`)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Enhancer Middleware
|
|
2
|
+
|
|
3
|
+
**File:** `mw/enhancer/index.js`
|
|
4
|
+
|
|
5
|
+
**Order:** 5
|
|
6
|
+
|
|
7
|
+
The Enhancer middleware adds utility methods to the request object for header handling and client IP detection.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
- Adds `req.get()` for case-insensitive header retrieval
|
|
12
|
+
- Adds `req.getClientIP()` for client IP address extraction
|
|
13
|
+
- Handles proxy headers (X-Forwarded-For)
|
|
14
|
+
|
|
15
|
+
## Flow
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Incoming Request
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
┌─────────────────┐
|
|
22
|
+
│ Attach get() │ Case-insensitive header getter
|
|
23
|
+
└────────┬────────┘
|
|
24
|
+
│
|
|
25
|
+
▼
|
|
26
|
+
┌─────────────────┐
|
|
27
|
+
│ Attach │ Client IP extraction
|
|
28
|
+
│ getClientIP() │
|
|
29
|
+
└────────┬────────┘
|
|
30
|
+
│
|
|
31
|
+
▼
|
|
32
|
+
next()
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Methods Added
|
|
36
|
+
|
|
37
|
+
### `req.get(headerName)`
|
|
38
|
+
|
|
39
|
+
Retrieves a header value (case-insensitive).
|
|
40
|
+
|
|
41
|
+
**Parameters:**
|
|
42
|
+
- `headerName` - Name of the header to retrieve
|
|
43
|
+
|
|
44
|
+
**Returns:** Header value or `undefined`
|
|
45
|
+
|
|
46
|
+
**Example:**
|
|
47
|
+
```javascript
|
|
48
|
+
let key = req.get("key"); // Works
|
|
49
|
+
let key = req.get("Key"); // Also works
|
|
50
|
+
let key = req.get("KEY"); // Also works
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `req.getClientIP()`
|
|
54
|
+
|
|
55
|
+
Extracts the client's IP address, handling proxy scenarios.
|
|
56
|
+
|
|
57
|
+
**Logic:**
|
|
58
|
+
1. Check `X-Forwarded-For` header (first IP if comma-separated)
|
|
59
|
+
2. Fall back to `req.connection.remoteAddress`
|
|
60
|
+
3. Fall back to `req.socket.remoteAddress`
|
|
61
|
+
4. Fall back to `req.connection.socket.remoteAddress`
|
|
62
|
+
|
|
63
|
+
**Returns:** Client IP address string
|
|
64
|
+
|
|
65
|
+
**Example:**
|
|
66
|
+
```javascript
|
|
67
|
+
let clientIP = req.getClientIP();
|
|
68
|
+
// "192.168.1.100" or "::1" for localhost
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage Notes
|
|
72
|
+
|
|
73
|
+
- `get()` is used throughout the codebase for header access
|
|
74
|
+
- `getClientIP()` is used by IP whitelist/blacklist checks
|
|
75
|
+
- Proxy support requires `X-Forwarded-For` header from load balancer
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Favicon Middleware
|
|
2
|
+
|
|
3
|
+
**File:** `mw/favicon/index.js`
|
|
4
|
+
|
|
5
|
+
**Order:** 3
|
|
6
|
+
|
|
7
|
+
The Favicon middleware serves favicon requests to prevent them from being routed as service requests.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
- Intercepts `/favicon.ico` requests
|
|
12
|
+
- Returns an empty response immediately
|
|
13
|
+
- Prevents favicon requests from reaching service routing
|
|
14
|
+
|
|
15
|
+
## Flow
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Incoming Request
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
┌─────────────────┐
|
|
22
|
+
│ Is Favicon │ req.url === '/favicon.ico'?
|
|
23
|
+
│ Request? │
|
|
24
|
+
└────────┬────────┘
|
|
25
|
+
│
|
|
26
|
+
├─── Yes ──▶ res.writeHead(200), res.end()
|
|
27
|
+
│
|
|
28
|
+
▼
|
|
29
|
+
next()
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage Notes
|
|
33
|
+
|
|
34
|
+
- Simple passthrough middleware for non-favicon requests
|
|
35
|
+
- Returns 200 OK with empty body for favicon requests
|
|
36
|
+
- Prevents unnecessary service resolution for browser favicon requests
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# GotoService Middleware
|
|
2
|
+
|
|
3
|
+
**File:** `mw/gotoService/index.js`
|
|
4
|
+
|
|
5
|
+
**Order:** 13
|
|
6
|
+
|
|
7
|
+
The GotoService middleware determines the routing strategy and prepares service parameters for request forwarding.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
- Extracts and validates service build parameters
|
|
12
|
+
- Handles special routes (`/soajs/acl`, `/soajs/proxy`, `/proxy/redirect`)
|
|
13
|
+
- Selects appropriate routing strategy
|
|
14
|
+
- Validates external key when required
|
|
15
|
+
|
|
16
|
+
## Flow
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
Incoming Request
|
|
20
|
+
│
|
|
21
|
+
▼
|
|
22
|
+
┌─────────────────┐
|
|
23
|
+
│ Is /soajs/acl │ Gateway ACL route?
|
|
24
|
+
│ Route? │
|
|
25
|
+
└────────┬────────┘
|
|
26
|
+
│
|
|
27
|
+
├─── Yes ──▶ soajs_keyACL handler
|
|
28
|
+
│
|
|
29
|
+
▼
|
|
30
|
+
┌─────────────────┐
|
|
31
|
+
│ Is Proxy │ /soajs/proxy or /proxy/redirect?
|
|
32
|
+
│ Route? │
|
|
33
|
+
└────────┬────────┘
|
|
34
|
+
│
|
|
35
|
+
├─── Yes ──▶ Mark as proxy, continue
|
|
36
|
+
│
|
|
37
|
+
▼
|
|
38
|
+
┌──────────────────────────┐
|
|
39
|
+
│ Extract Build │ extractBuildParameters()
|
|
40
|
+
│ Parameters │
|
|
41
|
+
└────────┬─────────────────┘
|
|
42
|
+
│
|
|
43
|
+
├─── Error ──▶ Error 130
|
|
44
|
+
│
|
|
45
|
+
▼
|
|
46
|
+
┌──────────────────────────┐
|
|
47
|
+
│ Validate External │ If extKeyRequired
|
|
48
|
+
│ Key (if required) │
|
|
49
|
+
└────────┬─────────────────┘
|
|
50
|
+
│
|
|
51
|
+
├─── Invalid key ──▶ Error 132
|
|
52
|
+
│
|
|
53
|
+
▼
|
|
54
|
+
┌──────────────────────────┐
|
|
55
|
+
│ Select Routing │ Based on request type
|
|
56
|
+
│ Strategy │
|
|
57
|
+
└────────┬─────────────────┘
|
|
58
|
+
│
|
|
59
|
+
▼
|
|
60
|
+
next()
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Routing Strategies
|
|
64
|
+
|
|
65
|
+
The middleware sets `req.soajs.controller.gotoservice` to one of:
|
|
66
|
+
|
|
67
|
+
### 1. simpleRTS
|
|
68
|
+
|
|
69
|
+
**Trigger:** `/oauth/passport/login`
|
|
70
|
+
|
|
71
|
+
Lightweight OAuth flow for passport-based authentication.
|
|
72
|
+
|
|
73
|
+
### 2. roaming
|
|
74
|
+
|
|
75
|
+
**Trigger:** `soajsroaming` header present
|
|
76
|
+
|
|
77
|
+
Cross-environment request forwarding.
|
|
78
|
+
|
|
79
|
+
### 3. proxyRequest
|
|
80
|
+
|
|
81
|
+
**Trigger:** `/soajs/proxy` or `/proxy/redirect` (deprecated)
|
|
82
|
+
|
|
83
|
+
Service-to-service or external URL proxying.
|
|
84
|
+
|
|
85
|
+
### 4. redirectToService (Default)
|
|
86
|
+
|
|
87
|
+
**Trigger:** Standard service requests
|
|
88
|
+
|
|
89
|
+
Standard REST API proxy to target service.
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
┌─────────────────────────┐
|
|
93
|
+
│ Incoming Request │
|
|
94
|
+
└───────────┬─────────────┘
|
|
95
|
+
│
|
|
96
|
+
┌───────────────────┼───────────────────┐
|
|
97
|
+
│ │ │
|
|
98
|
+
▼ ▼ ▼
|
|
99
|
+
┌───────────────────┐ ┌─────────────────┐ ┌─────────────────────┐
|
|
100
|
+
│ Passport Login? │ │ Roaming Header?│ │ Proxy Route? │
|
|
101
|
+
│ /oauth/passport │ │ soajsroaming │ │ /soajs/proxy │
|
|
102
|
+
│ /login │ │ │ │ │
|
|
103
|
+
└─────────┬─────────┘ └────────┬────────┘ └──────────┬──────────┘
|
|
104
|
+
│ │ │
|
|
105
|
+
┌─────────▼─────────┐ ┌────────▼────────┐ ┌──────────▼──────────┐
|
|
106
|
+
│ simpleRTS │ │ roaming │ │ proxyRequest │
|
|
107
|
+
└───────────────────┘ └─────────────────┘ └─────────────────────┘
|
|
108
|
+
│
|
|
109
|
+
│ (Default)
|
|
110
|
+
▼
|
|
111
|
+
┌─────────────────────────┐
|
|
112
|
+
│ redirectToService │
|
|
113
|
+
└─────────────────────────┘
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Build Parameters Extracted
|
|
117
|
+
|
|
118
|
+
| Parameter | Description |
|
|
119
|
+
|-----------|-------------|
|
|
120
|
+
| `name` | Service name |
|
|
121
|
+
| `version` | Service version |
|
|
122
|
+
| `path` | API path |
|
|
123
|
+
| `registry` | Service registry entry |
|
|
124
|
+
| `extKeyRequired` | Whether external key is required |
|
|
125
|
+
| `url` | Target URL (for endpoint services) |
|
|
126
|
+
|
|
127
|
+
## Error Codes
|
|
128
|
+
|
|
129
|
+
| Code | Description |
|
|
130
|
+
|------|-------------|
|
|
131
|
+
| 130 | Service not found or missing port/hosts |
|
|
132
|
+
| 132 | Missing or invalid external key |
|
|
133
|
+
|
|
134
|
+
## Related Files
|
|
135
|
+
|
|
136
|
+
- `lib/extractBuildParameters.js` - Parameter extraction logic
|
|
137
|
+
- `simpleRTS.js` - Passport login handler
|
|
138
|
+
- `roaming.js` - Cross-environment handler
|
|
139
|
+
- `proxyRequest.js` - Proxy route handler
|
|
140
|
+
- `redirectToService.js` - Standard service proxy
|
|
141
|
+
|
|
142
|
+
## Usage Notes
|
|
143
|
+
|
|
144
|
+
- `/proxy/redirect` is deprecated, logs warning
|
|
145
|
+
- External key validation uses `core.key.getInfo()`
|
|
146
|
+
- Build parameters stored in `req.soajs.controller.serviceParams`
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# IP2Ban Middleware
|
|
2
|
+
|
|
3
|
+
**File:** `mw/ip2ban/index.js`
|
|
4
|
+
|
|
5
|
+
**Order:** 6
|
|
6
|
+
|
|
7
|
+
The IP2Ban middleware blocks requests from blacklisted IP addresses.
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
- Enforces IP blacklist from custom registry
|
|
12
|
+
- Returns 403 Forbidden for banned IPs
|
|
13
|
+
- Early rejection before any service processing
|
|
14
|
+
|
|
15
|
+
## Flow
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Incoming Request
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
┌─────────────────┐
|
|
22
|
+
│ Get ip2ban │ registry.custom.gateway.value.traffic.ip2ban
|
|
23
|
+
│ List │
|
|
24
|
+
└────────┬────────┘
|
|
25
|
+
│
|
|
26
|
+
▼
|
|
27
|
+
┌─────────────────┐
|
|
28
|
+
│ Get Client IP │ req.getClientIP()
|
|
29
|
+
└────────┬────────┘
|
|
30
|
+
│
|
|
31
|
+
▼
|
|
32
|
+
┌─────────────────┐
|
|
33
|
+
│ IP in │ ip2ban.includes(clientIP)?
|
|
34
|
+
│ Blacklist? │
|
|
35
|
+
└────────┬────────┘
|
|
36
|
+
│
|
|
37
|
+
├─── Yes ──▶ 403 Forbidden { msg: "banned" }
|
|
38
|
+
│
|
|
39
|
+
▼
|
|
40
|
+
next()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Configuration
|
|
44
|
+
|
|
45
|
+
Located in `registry.custom.gateway.value.traffic.ip2ban`:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
{
|
|
49
|
+
"traffic": {
|
|
50
|
+
"ip2ban": [
|
|
51
|
+
"192.168.1.100",
|
|
52
|
+
"10.0.0.50",
|
|
53
|
+
"::1"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Response
|
|
60
|
+
|
|
61
|
+
Banned IPs receive:
|
|
62
|
+
- HTTP Status: `403`
|
|
63
|
+
- Body: `{ "msg": "banned" }`
|
|
64
|
+
|
|
65
|
+
## Usage Notes
|
|
66
|
+
|
|
67
|
+
- Runs early in the pipeline (order 6) for quick rejection
|
|
68
|
+
- Simple exact-match comparison (no CIDR support at this level)
|
|
69
|
+
- Use MT whitelist for CIDR range support
|
|
70
|
+
- IPv6 addresses supported (e.g., `::1` for localhost)
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Key Middleware
|
|
2
|
+
|
|
3
|
+
**File:** `mw/key/index.js`
|
|
4
|
+
|
|
5
|
+
The Key middleware is responsible for loading and validating external tenant keys. It extracts the key from the request headers and retrieves the associated tenant, application, and package data from the provision database.
|
|
6
|
+
|
|
7
|
+
## Flow Diagram
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ KEY MIDDLEWARE FLOW │
|
|
12
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
13
|
+
|
|
14
|
+
Incoming Request
|
|
15
|
+
│
|
|
16
|
+
▼
|
|
17
|
+
┌─────────────────┐
|
|
18
|
+
│ Extract Key │ req.get("key") - from headers
|
|
19
|
+
│ from Headers │
|
|
20
|
+
└────────┬────────┘
|
|
21
|
+
│
|
|
22
|
+
├─── No key? ──▶ next() (continue without key data)
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
┌─────────────────┐
|
|
26
|
+
│ Get External │ provision.getExternalKeyData(key, serviceConfig.key)
|
|
27
|
+
│ Key Data │
|
|
28
|
+
└────────┬────────┘
|
|
29
|
+
│
|
|
30
|
+
├─── Error/Not found? ──▶ Error 148 (Invalid or disabled key)
|
|
31
|
+
│
|
|
32
|
+
▼
|
|
33
|
+
┌─────────────────┐
|
|
34
|
+
│ Store keyObj │ req.soajs.controller.serviceParams.keyObj = keyObj
|
|
35
|
+
└────────┬────────┘
|
|
36
|
+
│
|
|
37
|
+
▼
|
|
38
|
+
┌─────────────────┐
|
|
39
|
+
│ Validate Key │ Check if key.env matches current environment
|
|
40
|
+
│ Environment │
|
|
41
|
+
└────────┬────────┘
|
|
42
|
+
│
|
|
43
|
+
├─── Mismatch? ──▶ Error 144 (Key not valid for this environment)
|
|
44
|
+
│
|
|
45
|
+
▼
|
|
46
|
+
┌─────────────────────┐
|
|
47
|
+
│ Network Package │ Check keyObj.config.gateway.networkPackages
|
|
48
|
+
│ Override │ for network-based package substitution
|
|
49
|
+
└────────┬────────────┘
|
|
50
|
+
│
|
|
51
|
+
├─── Override found? ──▶ Replace keyObj.application.package
|
|
52
|
+
│ Log debug message
|
|
53
|
+
▼
|
|
54
|
+
┌─────────────────┐
|
|
55
|
+
│ Get Package │ provision.getPackageData(keyObj.application.package)
|
|
56
|
+
│ Data │
|
|
57
|
+
└────────┬────────┘
|
|
58
|
+
│
|
|
59
|
+
├─── Not found? ──▶ Error 149 (Package not found)
|
|
60
|
+
│
|
|
61
|
+
▼
|
|
62
|
+
┌─────────────────┐
|
|
63
|
+
│ Store packObj │ req.soajs.controller.serviceParams.packObj = packObj
|
|
64
|
+
└────────┬────────┘
|
|
65
|
+
│
|
|
66
|
+
▼
|
|
67
|
+
next()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Key Object Structure (keyObj)
|
|
71
|
+
|
|
72
|
+
Source: `soajs.core.modules/soajs.core/provision/mongo.js` → `getKeyFromDb()`
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
{
|
|
76
|
+
"key": "internal_key_value", // Internal key identifier
|
|
77
|
+
"tenant": {
|
|
78
|
+
"id": "tenant_id", // Tenant MongoDB _id as string
|
|
79
|
+
"code": "TCODE", // Tenant code (uppercase)
|
|
80
|
+
"name": "Tenant Name", // Tenant display name
|
|
81
|
+
"locked": false, // Whether tenant is locked
|
|
82
|
+
"type": "product", // "product" or "client"
|
|
83
|
+
"profile": {}, // Tenant profile metadata
|
|
84
|
+
"main": { // Only for type="client" tenants
|
|
85
|
+
"id": "main_tenant_id", // Parent tenant ID
|
|
86
|
+
"code": "MAIN_TCODE" // Parent tenant code
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"application": {
|
|
90
|
+
"product": "PRODUCT_CODE", // Product code
|
|
91
|
+
"package": "PRODUCT_PACK", // Package code for ACL lookup
|
|
92
|
+
"appId": "application_id", // Application MongoDB _id as string
|
|
93
|
+
"acl": { ... }, // Environment-specific ACL (resolved)
|
|
94
|
+
"acl_all_env": { ... } // Full ACL object for all environments
|
|
95
|
+
},
|
|
96
|
+
"extKeys": [ // Array of external keys for this key
|
|
97
|
+
{
|
|
98
|
+
"extKey": "encrypted_external_key", // The external key value
|
|
99
|
+
"env": "DEV", // Environment this extKey is valid for
|
|
100
|
+
"device": { ... }, // Optional: Device restrictions
|
|
101
|
+
"geo": { ... }, // Optional: Geo restrictions
|
|
102
|
+
"dashboardAccess": false, // Whether key has dashboard access
|
|
103
|
+
"expDate": null // Expiration date (null = no expiry)
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"config": { // Environment-specific key configuration
|
|
107
|
+
// See configuration-services-config.md for details
|
|
108
|
+
},
|
|
109
|
+
"_TTL": 86400000, // Cache TTL in milliseconds
|
|
110
|
+
"_TIME": 1699999999999 // Timestamp when loaded
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Package Object Structure (packObj)
|
|
115
|
+
|
|
116
|
+
Source: `soajs.core.modules/soajs.core/provision/mongo.js` → `getPackagesFromDb()`
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
{
|
|
120
|
+
"acl": { ... }, // Environment-specific ACL (resolved)
|
|
121
|
+
"acl_all_env": { ... }, // Full ACL object for all environments
|
|
122
|
+
"_TTL": 86400000, // Cache TTL in milliseconds
|
|
123
|
+
"_TIME": 1699999999999 // Timestamp when loaded
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## ACL Structure
|
|
128
|
+
|
|
129
|
+
ACL can be defined in either `keyObj.application.acl` or `packObj.acl`:
|
|
130
|
+
|
|
131
|
+
```javascript
|
|
132
|
+
{
|
|
133
|
+
"serviceName": {
|
|
134
|
+
"version": {
|
|
135
|
+
"access": true, // or false, or ["group1", "group2"]
|
|
136
|
+
"apisPermission": "restricted", // "restricted" means whitelist mode
|
|
137
|
+
"get": {
|
|
138
|
+
"apis": {
|
|
139
|
+
"/api/path": {
|
|
140
|
+
"access": ["owner", "admin"] // Groups allowed for this API
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"post": { ... },
|
|
145
|
+
"put": { ... },
|
|
146
|
+
"delete": { ... }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Network Package Override
|
|
153
|
+
|
|
154
|
+
The key middleware supports network-based package substitution, allowing different packages to be loaded based on the network identifier configured in the custom registry.
|
|
155
|
+
|
|
156
|
+
See [Services Config](../configuration-services-config.md) for the full configuration structure.
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
┌─────────────────────────────────────────────────────────────────────────────────┐
|
|
160
|
+
│ NETWORK PACKAGE OVERRIDE FLOW (Key Middleware) │
|
|
161
|
+
└─────────────────────────────────────────────────────────────────────────────────┘
|
|
162
|
+
|
|
163
|
+
1. Get network from registry
|
|
164
|
+
network = registry.custom.gateway.value.lastSeen.network (e.g., "mw")
|
|
165
|
+
|
|
166
|
+
2. Get product from keyObj
|
|
167
|
+
product = keyObj.application.product (e.g., "AVAPP")
|
|
168
|
+
|
|
169
|
+
3. Check for network package config
|
|
170
|
+
config = keyObj.config.gateway.networkPackages[network][product]
|
|
171
|
+
|
|
172
|
+
4. If config.default exists:
|
|
173
|
+
├── Original: keyObj.application.package = "AVAPP_EXMPL"
|
|
174
|
+
├── Override: keyObj.application.package = "AVAPP_DEFAU"
|
|
175
|
+
└── Log: "Network package override: replaced package [AVAPP_EXMPL]
|
|
176
|
+
with [AVAPP_DEFAU] for network [mw] and product [AVAPP]"
|
|
177
|
+
|
|
178
|
+
5. Continue to load the (possibly overridden) package
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Error Codes
|
|
182
|
+
|
|
183
|
+
| Code | Description |
|
|
184
|
+
|------|-------------|
|
|
185
|
+
| 144 | External key is not valid for this environment |
|
|
186
|
+
| 148 | External key is invalid or has been disabled |
|
|
187
|
+
| 149 | Product package not found |
|
|
188
|
+
|
|
189
|
+
## Usage Notes
|
|
190
|
+
|
|
191
|
+
- The key is extracted from the `key` header (case-insensitive)
|
|
192
|
+
- If no key is provided, the middleware continues without setting key data
|
|
193
|
+
- Key environment validation ensures keys are only used in their designated environment
|
|
194
|
+
- Network package override allows different packages per network (requires `lastSeen.network` in custom registry)
|
|
195
|
+
- The keyObj and packObj are stored in `req.soajs.controller.serviceParams` for downstream middleware
|
|
196
|
+
- Subsequent middleware (keyACL, mt, oauth) depends on this data for ACL and authentication
|