soajs.controller 4.2.42 → 4.3.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.
Files changed (37) hide show
  1. package/.github/workflows/ci.yml +43 -0
  2. package/.github/workflows/release.yml +94 -0
  3. package/ARCHITECTURE.md +193 -0
  4. package/Gruntfile.js +1 -1
  5. package/docs/configuration-custom-registry.md +421 -0
  6. package/docs/configuration-services-config.md +275 -0
  7. package/docs/data-flow.md +138 -0
  8. package/docs/deployment.md +205 -0
  9. package/docs/external-integrations.md +159 -0
  10. package/docs/gateway-routes.md +259 -0
  11. package/docs/maintenance-routes.md +308 -0
  12. package/docs/middleware/awareness.md +120 -0
  13. package/docs/middleware/cors.md +88 -0
  14. package/docs/middleware/enhancer.md +75 -0
  15. package/docs/middleware/favicon.md +36 -0
  16. package/docs/middleware/gotoService.md +146 -0
  17. package/docs/middleware/ip2ban.md +70 -0
  18. package/docs/middleware/key.md +196 -0
  19. package/docs/middleware/keyACL.md +139 -0
  20. package/docs/middleware/lastSeen.md +111 -0
  21. package/docs/middleware/maintenanceMode.md +81 -0
  22. package/docs/middleware/mt.md +568 -0
  23. package/docs/middleware/oauth.md +173 -0
  24. package/docs/middleware/response.md +106 -0
  25. package/docs/middleware/soajs.md +71 -0
  26. package/docs/middleware/traffic.md +190 -0
  27. package/docs/middleware/url.md +102 -0
  28. package/docs/multi-tenant-security.md +183 -0
  29. package/docs/request-flow.md +230 -0
  30. package/docs/service-discovery.md +167 -0
  31. package/mw/key/index.js +16 -1
  32. package/mw/mt/urac.js +21 -1
  33. package/mw/mt/utils.js +2 -0
  34. package/package.json +13 -13
  35. package/test/unit/mw/key/index.js +150 -0
  36. package/test/unit/mw/mt/urac.js +157 -4
  37. package/.travis.yml +0 -72
@@ -0,0 +1,173 @@
1
+ # OAuth Middleware
2
+
3
+ **File:** `mw/oauth/index.js`
4
+
5
+ **Order:** 15
6
+
7
+ The OAuth middleware handles authentication by validating OAuth2 tokens or JWT tokens.
8
+
9
+ ## Purpose
10
+
11
+ - Validates OAuth2 access tokens via oauth2-server
12
+ - Validates JWT tokens via jsonwebtoken
13
+ - Supports tenant-specific OAuth configuration
14
+ - Sets `req.oauth` with token information
15
+
16
+ ## Flow
17
+
18
+ ```
19
+ Incoming Request
20
+ │
21
+ ▼
22
+ ┌─────────────────────────┐
23
+ │ Determine OAuth Type │ tenantOauth.type or
24
+ │ │ registry.serviceConfig.oauth.type
25
+ └────────┬────────────────┘
26
+ │
27
+ ├─── Type 0 (JWT) ──▶ JWT Validation
28
+ │
29
+ ├─── Type 2 (OAuth2) ──▶ OAuth2 Server Validation
30
+ │
31
+ ▼
32
+ ┌─────────────────────────┐
33
+ │ Set req.oauth │ { bearerToken, type }
34
+ └────────┬────────────────┘
35
+ │
36
+ ▼
37
+ next() or Error
38
+ ```
39
+
40
+ ## OAuth Types
41
+
42
+ ### Type 2: OAuth2 (Default)
43
+
44
+ Uses oauth2-server library for token validation.
45
+
46
+ ```
47
+ Request with access_token
48
+ │
49
+ ▼
50
+ ┌─────────────────────────┐
51
+ │ oauth2-server │ Validates token against DB
52
+ │ authorise() │
53
+ └────────┬────────────────┘
54
+ │
55
+ ├─── Invalid ──▶ OAuth2Error
56
+ │
57
+ ▼
58
+ ┌─────────────────────────┐
59
+ │ req.oauth = { │
60
+ │ bearerToken: user, │
61
+ │ type: 2 │
62
+ │ } │
63
+ └─────────────────────────┘
64
+ ```
65
+
66
+ ### Type 0: JWT
67
+
68
+ Uses jsonwebtoken library for JWT validation.
69
+
70
+ ```
71
+ Request with Authorization: Bearer <jwt>
72
+ │
73
+ ▼
74
+ ┌─────────────────────────┐
75
+ │ Extract Bearer Token │ from Authorization header
76
+ └────────┬────────────────┘
77
+ │
78
+ ├─── No match ──▶ Error 143
79
+ │
80
+ ▼
81
+ ┌─────────────────────────┐
82
+ │ jwt.verify() │ Using secret and algorithms
83
+ └────────┬────────────────┘
84
+ │
85
+ ├─── Invalid ──▶ Error 143
86
+ │
87
+ ▼
88
+ ┌─────────────────────────┐
89
+ │ req.oauth = { │
90
+ │ bearerToken: decoded,│
91
+ │ type: 0 │
92
+ │ } │
93
+ └─────────────────────────┘
94
+ ```
95
+
96
+ ## Configuration
97
+
98
+ ### OAuth2 Configuration
99
+
100
+ Located in `registry.serviceConfig.oauth`:
101
+
102
+ ```javascript
103
+ {
104
+ "oauth": {
105
+ "type": 2,
106
+ "grants": ["password", "refresh_token"],
107
+ "debug": false,
108
+ "accessTokenLifetime": 7200,
109
+ "refreshTokenLifetime": 1209600
110
+ }
111
+ }
112
+ ```
113
+
114
+ ### JWT Configuration
115
+
116
+ ```javascript
117
+ {
118
+ "oauth": {
119
+ "type": 0,
120
+ "secret": "jwt_secret_key",
121
+ "algorithms": ["HS256"],
122
+ "audience": "my-app"
123
+ }
124
+ }
125
+ ```
126
+
127
+ ### Tenant-Specific OAuth
128
+
129
+ Tenants can override OAuth settings via `tenantOauth`:
130
+
131
+ ```javascript
132
+ {
133
+ "type": 0, // Override to JWT
134
+ "secret": "tenant_jwt_secret"
135
+ }
136
+ ```
137
+
138
+ ## OAuth Service Integration
139
+
140
+ Default OAuth service configuration:
141
+
142
+ ```javascript
143
+ {
144
+ "oauthService": {
145
+ "name": "oauth",
146
+ "tokenApi": "/token",
147
+ "authorizationApi": "/authorization",
148
+ "pinApi": "/pin"
149
+ }
150
+ }
151
+ ```
152
+
153
+ ## Error Codes
154
+
155
+ | Code | Description |
156
+ |------|-------------|
157
+ | 143 | Invalid or missing JWT token |
158
+ | OAuth2Error | Various OAuth2 errors (invalid_token, expired, etc.) |
159
+
160
+ ## Properties Set
161
+
162
+ | Property | Type | Description |
163
+ |----------|------|-------------|
164
+ | `req.oauth.bearerToken` | object | Decoded token or user object |
165
+ | `req.oauth.type` | number | OAuth type (0=JWT, 2=OAuth2) |
166
+
167
+ ## Usage Notes
168
+
169
+ - OAuth type can be set globally or per-tenant
170
+ - JWT requires `Authorization: Bearer <token>` header
171
+ - OAuth2 uses `access_token` query parameter or header
172
+ - Tenant OAuth settings override global settings
173
+ - OAuth model is provided by configuration (provision module)
@@ -0,0 +1,106 @@
1
+ # Response Middleware
2
+
3
+ **File:** `mw/response/index.js`
4
+
5
+ **Order:** 4
6
+
7
+ The Response middleware adds standardized response builder methods to the request object.
8
+
9
+ ## Purpose
10
+
11
+ - Adds `req.soajs.buildResponse()` for creating SOAJS-formatted responses
12
+ - Adds `req.soajs.controllerResponse()` for sending gateway responses
13
+ - Provides consistent error/success response structure
14
+
15
+ ## Flow
16
+
17
+ ```
18
+ Incoming Request
19
+ │
20
+ ▼
21
+ ┌─────────────────────────┐
22
+ │ Attach buildResponse() │ Creates SOAJS response objects
23
+ └────────────┬────────────┘
24
+ │
25
+ ▼
26
+ ┌─────────────────────────────┐
27
+ │ Attach controllerResponse()│ Sends JSON responses
28
+ └────────────┬────────────────┘
29
+ │
30
+ ▼
31
+ next()
32
+ ```
33
+
34
+ ## Methods Added
35
+
36
+ ### `req.soajs.buildResponse(error, data)`
37
+
38
+ Creates a SOAJS-formatted response object.
39
+
40
+ **Parameters:**
41
+ - `error` - Error object or array of errors (optional)
42
+ - `data` - Response data (optional)
43
+
44
+ **Returns:**
45
+ ```javascript
46
+ // Success
47
+ {
48
+ "result": true,
49
+ "data": { ... }
50
+ }
51
+
52
+ // Error
53
+ {
54
+ "result": false,
55
+ "errors": {
56
+ "codes": [100, 101],
57
+ "details": [
58
+ { "code": 100, "message": "Error message" },
59
+ { "code": 101, "message": "Another error" }
60
+ ]
61
+ }
62
+ }
63
+ ```
64
+
65
+ ### `req.soajs.controllerResponse(jsonObj)`
66
+
67
+ Sends a JSON response and ends the request.
68
+
69
+ **Parameters:**
70
+ - `jsonObj` - Response object with optional `status`, `headObj`, `code`, `msg`
71
+
72
+ **Examples:**
73
+ ```javascript
74
+ // Success response
75
+ req.soajs.controllerResponse({ data: { user: "john" } });
76
+
77
+ // Error response
78
+ req.soajs.controllerResponse({
79
+ status: 403,
80
+ code: 150,
81
+ msg: "Access denied"
82
+ });
83
+
84
+ // With custom headers
85
+ req.soajs.controllerResponse({
86
+ status: 429,
87
+ msg: "Too many requests",
88
+ headObj: {
89
+ "Retry-After": 60,
90
+ "X-RateLimit-Limit": 100
91
+ }
92
+ });
93
+ ```
94
+
95
+ ## Response Format
96
+
97
+ All responses include:
98
+ - `Content-Type: application/json` header
99
+ - HTTP status code (default: 200)
100
+ - JSON body
101
+
102
+ ## Usage Notes
103
+
104
+ - `controllerResponse()` only available when `controllerResponse: true` in config
105
+ - Prevents double-ending responses (tracks `ended` state)
106
+ - Automatically formats errors using `buildResponse()` when `code` and `msg` provided
@@ -0,0 +1,71 @@
1
+ # SOAJS Middleware
2
+
3
+ **File:** `mw/soajs/index.js`
4
+
5
+ **Order:** 1
6
+
7
+ The SOAJS middleware is the first middleware in the pipeline. It initializes the `req.soajs` context object that all subsequent middleware depend on.
8
+
9
+ ## Purpose
10
+
11
+ - Creates the `req.soajs` namespace
12
+ - Attaches the logger instance
13
+ - Attaches the current registry reference
14
+ - Attaches core utility modules (meta, validator)
15
+
16
+ ## Flow
17
+
18
+ ```
19
+ Incoming Request
20
+ │
21
+ ▼
22
+ ┌─────────────────┐
23
+ │ Create │ if (!req.soajs) req.soajs = {}
24
+ │ req.soajs │
25
+ └────────┬────────┘
26
+ │
27
+ ▼
28
+ ┌─────────────────┐
29
+ │ Attach Logger │ req.soajs.log = log
30
+ └────────┬────────┘
31
+ │
32
+ ▼
33
+ ┌─────────────────┐
34
+ │ Attach │ req.soajs.registry = registryModule.get()
35
+ │ Registry │
36
+ └────────┬────────┘
37
+ │
38
+ ▼
39
+ ┌─────────────────┐
40
+ │ Attach Core │ req.soajs.meta = core.meta
41
+ │ Modules │ req.soajs.validator = core.validator
42
+ └────────┬────────┘
43
+ │
44
+ ▼
45
+ next()
46
+ ```
47
+
48
+ ## Configuration
49
+
50
+ ```javascript
51
+ {
52
+ "log": logger, // Logger instance
53
+ "core": coreModule // soajs.core.libs module
54
+ }
55
+ ```
56
+
57
+ ## Properties Set
58
+
59
+ | Property | Type | Description |
60
+ |----------|------|-------------|
61
+ | `req.soajs.log` | object | Logger instance for request-scoped logging |
62
+ | `req.soajs.registry` | object | Current environment registry |
63
+ | `req.soajs.meta` | object | Metadata utilities from core |
64
+ | `req.soajs.validator` | object | JSON schema validator |
65
+
66
+ ## Usage Notes
67
+
68
+ - This middleware MUST be first in the pipeline
69
+ - All other middleware assume `req.soajs` exists
70
+ - The registry is fetched fresh on each request (reference, not copy)
71
+ - Logger supports: `debug()`, `info()`, `warn()`, `error()`, `fatal()`
@@ -0,0 +1,190 @@
1
+ # Traffic Middleware
2
+
3
+ **File:** `mw/traffic/index.js`
4
+
5
+ **Order:** 16
6
+
7
+ The Traffic middleware implements rate limiting (throttling) with configurable strategies and storage backends.
8
+
9
+ ## Purpose
10
+
11
+ - Enforces rate limiting per tenant/IP
12
+ - Supports configurable throttling strategies
13
+ - Provides memory and MongoDB storage backends
14
+ - Returns rate limit headers in responses
15
+
16
+ ## Flow
17
+
18
+ ```
19
+ Incoming Request
20
+ │
21
+ ▼
22
+ ┌─────────────────────────┐
23
+ │ Check Prerequisites │ registry, tenant, controller exist?
24
+ └────────┬────────────────┘
25
+ │
26
+ ├─── Missing ──▶ next()
27
+ │
28
+ ▼
29
+ ┌─────────────────────────┐
30
+ │ Determine Strategy │ publicAPIStrategy or privateAPIStrategy
31
+ └────────┬────────────────┘
32
+ │
33
+ ├─── No strategy ──▶ next()
34
+ │
35
+ ▼
36
+ ┌─────────────────────────┐
37
+ │ Get Throttling Config │ Priority:
38
+ │ │ 1. servicesConfig.gateway.throttling
39
+ │ │ 2. custom.gateway.value.traffic.throttling
40
+ │ │ 3. serviceConfig.throttling
41
+ └────────┬────────────────┘
42
+ │
43
+ ▼
44
+ ┌─────────────────────────┐
45
+ │ Check Throttling │ Get/increment counter
46
+ │ Counter │ Compare to limit
47
+ └────────┬────────────────┘
48
+ │
49
+ ├─── Under limit ──▶ next()
50
+ │
51
+ ├─── Over limit, retries left ──▶ Delay and retry
52
+ │
53
+ └─── Over limit, no retries ──▶ 429 Too Many Requests
54
+ ```
55
+
56
+ ## Configuration
57
+
58
+ ### Strategy Definition
59
+
60
+ Located in `registry.serviceConfig.throttling`:
61
+
62
+ ```javascript
63
+ {
64
+ "throttling": {
65
+ "publicAPIStrategy": "default", // For unauthenticated requests
66
+ "privateAPIStrategy": "heavy", // For authenticated requests
67
+ "default": {
68
+ "status": 1, // 0=Off, 1=On
69
+ "type": 1, // 0=tenant, 1=tenant+IP
70
+ "window": 60000, // Time window in ms
71
+ "limit": 50, // Max requests per window
72
+ "retries": 2, // Retries when over limit
73
+ "delay": 1000 // Delay between retries (ms)
74
+ },
75
+ "heavy": {
76
+ "status": 1,
77
+ "type": 1,
78
+ "window": 60000,
79
+ "limit": 500,
80
+ "retries": 2,
81
+ "delay": 1000
82
+ },
83
+ "strict": {
84
+ "status": 1,
85
+ "type": 1,
86
+ "window": 60000,
87
+ "limit": 10,
88
+ "retries": 0,
89
+ "delay": 0
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ### Service-Specific Override
96
+
97
+ Via custom registry or tenant config:
98
+
99
+ ```javascript
100
+ {
101
+ "throttling": {
102
+ "oauth": {
103
+ "publicAPIStrategy": "strict",
104
+ "apis": ["/token"] // Only these APIs
105
+ },
106
+ "payment": {
107
+ "publicAPIStrategy": "strict",
108
+ "privateAPIStrategy": "heavy",
109
+ "apis": ["/charge", "/refund"]
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ ## Strategy Selection
116
+
117
+ | Request Type | Strategy Used |
118
+ |--------------|---------------|
119
+ | Public API (no auth) | `publicAPIStrategy` |
120
+ | Private API (authenticated) | `privateAPIStrategy` |
121
+
122
+ Determined by: `req.soajs.controller.serviceParams.isAPIPublic`
123
+
124
+ ## Storage Backends
125
+
126
+ ### Memory (Default)
127
+
128
+ - Fast, in-process storage
129
+ - Lost on restart
130
+ - Good for single-instance deployments
131
+
132
+ ### MongoDB
133
+
134
+ - Persistent storage
135
+ - Shared across instances
136
+ - Required for multi-instance deployments
137
+
138
+ Configure via `registry.custom.gateway.value.traffic.model`:
139
+
140
+ ```javascript
141
+ {
142
+ "traffic": {
143
+ "model": "mongo" // or "memory"
144
+ }
145
+ }
146
+ ```
147
+
148
+ ## Rate Limit Response
149
+
150
+ When rate limit exceeded:
151
+
152
+ ```
153
+ HTTP/1.1 429 Too Many Requests
154
+ Content-Type: application/json
155
+ Retry-After: 45
156
+ X-RateLimit-Limit: 50
157
+ X-RateLimit-Remaining: 0
158
+
159
+ {
160
+ "result": false,
161
+ "errors": { ... }
162
+ }
163
+ ```
164
+
165
+ ## Response Headers
166
+
167
+ | Header | Description |
168
+ |--------|-------------|
169
+ | `X-RateLimit-Limit` | Maximum requests allowed |
170
+ | `X-RateLimit-Remaining` | Requests remaining in window |
171
+ | `Retry-After` | Seconds until window resets |
172
+
173
+ ## Throttle Key Structure
174
+
175
+ ```javascript
176
+ {
177
+ "l1": "tenant_id",
178
+ "l2": "client_ip"
179
+ }
180
+ ```
181
+
182
+ Creates unique tracking per tenant per IP.
183
+
184
+ ## Usage Notes
185
+
186
+ - Throttling disabled if no strategy configured
187
+ - Service-specific config overrides global config
188
+ - APIs array allows targeting specific endpoints
189
+ - Retries add delay before rejection
190
+ - MongoDB model required for horizontal scaling
@@ -0,0 +1,102 @@
1
+ # URL Middleware
2
+
3
+ **File:** `mw/url/index.js`
4
+
5
+ **Order:** 8
6
+
7
+ The URL middleware parses the request URL and extracts service routing information.
8
+
9
+ ## Purpose
10
+
11
+ - Parses URL into components (service name, version, path)
12
+ - Validates service exists in registry
13
+ - Normalizes header and query parameters (key, access_token)
14
+ - Creates `req.soajs.controller.serviceParams` structure
15
+
16
+ ## Flow
17
+
18
+ ```
19
+ Incoming Request
20
+ │
21
+ ▼
22
+ ┌─────────────────┐
23
+ │ Ensure │ if (!req.soajs.controller)
24
+ │ Controller │ req.soajs.controller = {}
25
+ └────────┬────────┘
26
+ │
27
+ ▼
28
+ ┌─────────────────┐
29
+ │ Parse URL │ url.parse(req.url, true)
30
+ └────────┬────────┘
31
+ │
32
+ ▼
33
+ ┌─────────────────┐
34
+ │ Extract │ service_n, service_v, service_nv
35
+ │ Service Info │ serviceInfo, path
36
+ └────────┬────────┘
37
+ │
38
+ ├─── No service name? ──▶ Error 136
39
+ │
40
+ ├─── Service not in registry? ──▶ Error 130
41
+ │
42
+ ▼
43
+ ┌─────────────────┐
44
+ │ Normalize │ key, access_token from headers/query
45
+ │ Auth Params │
46
+ └────────┬────────┘
47
+ │
48
+ ▼
49
+ next()
50
+ ```
51
+
52
+ ## URL Parsing
53
+
54
+ **URL Format:** `/{service}/{version}/{path}`
55
+
56
+ | Component | Example | Description |
57
+ |-----------|---------|-------------|
58
+ | `service_n` | `oauth` | Service name |
59
+ | `service_v` | `1` | Service version (optional) |
60
+ | `service_nv` | `oauth/1` | Service with version |
61
+ | `path` | `/token` | API path |
62
+
63
+ **Examples:**
64
+ ```
65
+ /oauth/token → service: oauth, version: null, path: /token
66
+ /oauth/1/token → service: oauth, version: 1, path: /token
67
+ /urac/3/user/login → service: urac, version: 3, path: /user/login
68
+ ```
69
+
70
+ ## Properties Set
71
+
72
+ | Property | Description |
73
+ |----------|-------------|
74
+ | `req.soajs.controller.serviceParams.service_n` | Service name |
75
+ | `req.soajs.controller.serviceParams.service_v` | Service version |
76
+ | `req.soajs.controller.serviceParams.service_nv` | Service with version |
77
+ | `req.soajs.controller.serviceParams.serviceInfo` | URL path segments array |
78
+ | `req.soajs.controller.serviceParams.parsedUrl` | Full parsed URL object |
79
+ | `req.query` | Query parameters |
80
+
81
+ ## Auth Parameter Normalization
82
+
83
+ The middleware normalizes authentication parameters:
84
+
85
+ 1. **Key:** `req.headers.key` ← `req.headers.key || req.query.key`
86
+ 2. **Access Token:** `req.query.access_token` ←
87
+ - `req.query.access_token`
88
+ - `req.headers.access_token`
89
+ - Bearer token from `Authorization` header
90
+
91
+ ## Error Codes
92
+
93
+ | Code | Description |
94
+ |------|-------------|
95
+ | 130 | Service not found in registry |
96
+ | 136 | Empty or missing service name |
97
+
98
+ ## Usage Notes
99
+
100
+ - Throws TypeError if SOAJS middleware hasn't run first
101
+ - Special handling for `soajs` service name (gateway routes)
102
+ - Authorization header is deleted after extracting Bearer token