Skip to content

Commit a84ed58

Browse files
authored
fix: use array config for apikey-auth keys and basic-auth credentials (#54)
The secret resolution system only resolves JSON object values, not keys. This meant env:// references used as object keys (e.g. API keys in apikey-auth) were never resolved at startup. Change both plugins from map-style configs to array-of-entries: - apikey-auth: keys map → array with explicit `key` field - basic-auth: credentials map → array with explicit `username` field This makes secret references work correctly for all auth config fields and aligns both plugins with the pattern used by other plugins (oauth2, s3, etc.). BREAKING CHANGE: apikey-auth `keys` and basic-auth `credentials` config fields are now arrays instead of objects.
1 parent e09e0cd commit a84ed58

14 files changed

Lines changed: 112 additions & 94 deletions

File tree

crates/barbacane-test/tests/proxy.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ paths:
212212
config:
213213
header_name: x-api-key
214214
keys:
215-
test-key-123:
215+
- key: test-key-123
216216
id: key-1
217217
name: testuser
218218
requestBody:
@@ -322,7 +322,7 @@ paths:
322322
config:
323323
header_name: x-api-key
324324
keys:
325-
test-key-123:
325+
- key: test-key-123
326326
id: key-1
327327
name: testuser
328328
requestBody:
@@ -578,7 +578,7 @@ paths:
578578
config:
579579
header_name: x-api-key
580580
keys:
581-
test-key-123:
581+
- key: test-key-123
582582
id: key-1
583583
name: testuser
584584
requestBody:
@@ -679,7 +679,7 @@ paths:
679679
config:
680680
header_name: x-api-key
681681
keys:
682-
test-key-123:
682+
- key: test-key-123
683683
id: key-1
684684
name: testuser
685685
requestBody:
@@ -785,7 +785,7 @@ paths:
785785
config:
786786
header_name: x-api-key
787787
keys:
788-
test-key-123:
788+
- key: test-key-123
789789
id: key-1
790790
name: testuser
791791
requestBody:
@@ -906,7 +906,7 @@ paths:
906906
config:
907907
header_name: x-api-key
908908
keys:
909-
test-key-123:
909+
- key: test-key-123
910910
id: key-1
911911
name: testuser
912912
requestBody:
@@ -1103,7 +1103,7 @@ paths:
11031103
config:
11041104
header_name: x-api-key
11051105
keys:
1106-
test-key-123:
1106+
- key: test-key-123
11071107
id: key-1
11081108
name: testuser
11091109
x-barbacane-dispatch:

crates/barbacane-test/tests/streaming.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ paths:
102102
config:
103103
header_name: x-api-key
104104
keys:
105-
secret-key:
105+
- key: secret-key
106106
id: key-1
107107
name: test
108108
x-barbacane-dispatch:

crates/barbacane-test/tests/workload.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ paths:
163163
config:
164164
header_name: x-api-key
165165
keys:
166-
test-key-123:
166+
- key: test-key-123
167167
id: key-1
168168
name: testuser
169169
requestBody:
@@ -233,7 +233,7 @@ paths:
233233
config:
234234
header_name: x-api-key
235235
keys:
236-
test-key-123:
236+
- key: test-key-123
237237
id: key-1
238238
name: testuser
239239
requestBody:
@@ -688,7 +688,7 @@ paths:
688688
config:
689689
header_name: x-api-key
690690
keys:
691-
test-key-123:
691+
- key: test-key-123
692692
id: key-1
693693
name: testuser
694694
requestBody:
@@ -808,7 +808,7 @@ paths:
808808
config:
809809
header_name: x-api-key
810810
keys:
811-
test-key-123:
811+
- key: test-key-123
812812
id: key-1
813813
name: testuser
814814
x-barbacane-dispatch:

docs/guide/middlewares.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -188,24 +188,26 @@ x-barbacane-middlewares:
188188
header_name: X-API-Key # when key_location is "header"
189189
query_param: api_key # when key_location is "query"
190190
keys:
191-
sk_live_abc123:
191+
- key: "env://API_KEY_PRODUCTION"
192192
id: key-001
193193
name: Production Key
194194
scopes: ["read", "write"]
195-
sk_test_xyz789:
195+
- key: sk_test_xyz789
196196
id: key-002
197197
name: Test Key
198198
scopes: ["read"]
199199
```
200200

201+
The `key` field supports secret references (`env://`, `file://`) which are resolved at gateway startup. See [Secrets](secrets.md) for details.
202+
201203
#### Configuration
202204

203205
| Property | Type | Default | Description |
204206
|----------|------|---------|-------------|
205207
| `key_location` | string | `header` | Where to find key (`header` or `query`) |
206208
| `header_name` | string | `X-API-Key` | Header name (when `key_location: header`) |
207209
| `query_param` | string | `api_key` | Query param name (when `key_location: query`) |
208-
| `keys` | object | `{}` | Map of valid API keys to metadata |
210+
| `keys` | array | `[]` | List of API key entries with metadata |
209211

210212
#### Context Headers
211213

@@ -336,10 +338,10 @@ x-barbacane-middlewares:
336338
realm: "My API"
337339
strip_credentials: true
338340
credentials:
339-
admin:
341+
- username: admin
340342
password: "env://ADMIN_PASSWORD"
341343
roles: ["admin", "editor"]
342-
readonly:
344+
- username: readonly
343345
password: "env://READONLY_PASSWORD"
344346
roles: ["viewer"]
345347
```
@@ -350,12 +352,13 @@ x-barbacane-middlewares:
350352
|----------|------|---------|-------------|
351353
| `realm` | string | `api` | Authentication realm shown in `WWW-Authenticate` challenge |
352354
| `strip_credentials` | boolean | `true` | Remove `Authorization` header before forwarding to upstream |
353-
| `credentials` | object | `{}` | Map of username to credential entry |
355+
| `credentials` | array | `[]` | List of credential entries |
354356

355357
Each credential entry:
356358

357359
| Property | Type | Default | Description |
358360
|----------|------|---------|-------------|
361+
| `username` | string | **required** | Username for this credential |
359362
| `password` | string | **required** | Password for this user (supports secret references) |
360363
| `roles` | array | `[]` | Optional roles for authorization |
361364

@@ -394,10 +397,10 @@ x-barbacane-middlewares:
394397
config:
395398
realm: "my-api"
396399
credentials:
397-
admin:
400+
- username: admin
398401
password: "env://ADMIN_PASSWORD"
399402
roles: ["admin", "editor"]
400-
viewer:
403+
- username: viewer
401404
password: "env://VIEWER_PASSWORD"
402405
roles: ["viewer"]
403406
- name: acl

docs/rulesets/functions/barbacane-validate-middleware-config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const schemas = {
2222
key_location: { type: "string" },
2323
header_name: { type: "string" },
2424
query_param: { type: "string" },
25-
keys: { type: "object" },
25+
keys: { type: "array" },
2626
},
2727
additionalProperties: false,
2828
},
@@ -32,7 +32,7 @@ const schemas = {
3232
properties: {
3333
realm: { type: "string" },
3434
strip_credentials: { type: "boolean" },
35-
credentials: { type: "object" },
35+
credentials: { type: "array" },
3636
},
3737
additionalProperties: false,
3838
},

plugins/apikey-auth/config-schema.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@
2222
"default": "api_key"
2323
},
2424
"keys": {
25-
"type": "object",
26-
"description": "Map of valid API keys to their metadata",
27-
"additionalProperties": {
25+
"type": "array",
26+
"description": "List of valid API keys with their metadata",
27+
"items": {
2828
"type": "object",
29-
"required": ["id"],
29+
"required": ["key", "id"],
3030
"properties": {
31+
"key": {
32+
"type": "string",
33+
"description": "The API key value. Supports secret references (e.g. env://MY_API_KEY)."
34+
},
3135
"id": {
3236
"type": "string",
3337
"description": "Unique identifier for this key (for logging/auditing)"
@@ -47,7 +51,7 @@
4751
},
4852
"additionalProperties": false
4953
},
50-
"default": {}
54+
"default": []
5155
}
5256
},
5357
"additionalProperties": false

plugins/apikey-auth/src/lib.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,17 @@ pub struct ApiKeyAuth {
2626
#[serde(default = "default_query_param")]
2727
query_param: String,
2828

29-
/// Map of valid API keys to their metadata.
30-
/// Key: the API key string
31-
/// Value: key metadata (id, name, optional scopes)
29+
/// List of valid API keys with their metadata.
3230
#[serde(default)]
33-
keys: BTreeMap<String, ApiKeyEntry>,
31+
keys: Vec<ApiKeyEntry>,
3432
}
3533

36-
/// Metadata for a single API key.
34+
/// A single API key entry.
3735
#[derive(Debug, Clone, Deserialize)]
3836
struct ApiKeyEntry {
37+
/// The API key value. Supports secret references (e.g. `env://MY_API_KEY`).
38+
key: String,
39+
3940
/// Unique identifier for this key (for logging/auditing).
4041
id: String,
4142

@@ -179,7 +180,10 @@ impl ApiKeyAuth {
179180

180181
/// Look up the API key in the configured key store.
181182
fn lookup_key(&self, key: &str) -> Result<&ApiKeyEntry, ApiKeyError> {
182-
self.keys.get(key).ok_or(ApiKeyError::InvalidKey)
183+
self.keys
184+
.iter()
185+
.find(|e| e.key == key)
186+
.ok_or(ApiKeyError::InvalidKey)
183187
}
184188

185189
/// Generate 401 Unauthorized response.
@@ -244,11 +248,11 @@ mod tests {
244248

245249
fn test_plugin() -> ApiKeyAuth {
246250
serde_json::from_value(serde_json::json!({
247-
"keys": {
248-
"sk-test-123": { "id": "key1", "name": "Test Key", "scopes": ["read", "write"] },
249-
"sk-readonly": { "id": "key2", "scopes": ["read"] },
250-
"sk-noname": { "id": "key3" }
251-
}
251+
"keys": [
252+
{ "key": "sk-test-123", "id": "key1", "name": "Test Key", "scopes": ["read", "write"] },
253+
{ "key": "sk-readonly", "id": "key2", "scopes": ["read"] },
254+
{ "key": "sk-noname", "id": "key3" }
255+
]
252256
}))
253257
.unwrap()
254258
}
@@ -417,8 +421,8 @@ mod tests {
417421
match plugin.on_request(req) {
418422
Action::Continue(r) => {
419423
assert_eq!(r.headers.get("x-auth-key-id").unwrap(), "key3");
420-
assert!(r.headers.get("x-auth-key-name").is_none());
421-
assert!(r.headers.get("x-auth-key-scopes").is_none());
424+
assert!(!r.headers.contains_key("x-auth-key-name"));
425+
assert!(!r.headers.contains_key("x-auth-key-scopes"));
422426
assert_eq!(r.headers.get("x-auth-consumer").unwrap(), "key3");
423427
assert!(!r.headers.contains_key("x-auth-consumer-groups"));
424428
}
@@ -456,7 +460,7 @@ mod tests {
456460
fn test_on_request_query_location() {
457461
let mut plugin: ApiKeyAuth = serde_json::from_value(serde_json::json!({
458462
"key_location": "query",
459-
"keys": { "mykey": { "id": "q1" } }
463+
"keys": [{ "key": "mykey", "id": "q1" }]
460464
}))
461465
.unwrap();
462466
let req = request_with_query("api_key=mykey");
@@ -520,7 +524,7 @@ mod tests {
520524
fn test_config_custom_header() {
521525
let plugin: ApiKeyAuth = serde_json::from_value(serde_json::json!({
522526
"header_name": "Authorization",
523-
"keys": { "Bearer tok": { "id": "t1" } }
527+
"keys": [{ "key": "Bearer tok", "id": "t1" }]
524528
}))
525529
.unwrap();
526530
assert_eq!(plugin.header_name, "Authorization");

plugins/basic-auth/config-schema.json

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@
1616
"default": true
1717
},
1818
"credentials": {
19-
"type": "object",
20-
"description": "Map of username to credential entry",
21-
"additionalProperties": {
19+
"type": "array",
20+
"description": "List of credential entries (username, password, and optional roles)",
21+
"items": {
2222
"type": "object",
23-
"required": ["password"],
23+
"required": ["username", "password"],
2424
"properties": {
25+
"username": {
26+
"type": "string",
27+
"description": "Username for this credential"
28+
},
2529
"password": {
2630
"type": "string",
27-
"description": "Password for this user"
31+
"description": "Password for this user. Supports secret references (e.g. env://MY_PASSWORD)."
2832
},
2933
"roles": {
3034
"type": "array",
@@ -35,7 +39,7 @@
3539
},
3640
"additionalProperties": false
3741
},
38-
"default": {}
42+
"default": []
3943
}
4044
},
4145
"additionalProperties": false

0 commit comments

Comments
 (0)