Skip to content

Commit

Permalink
Add group support to header mapping (#15)
Browse files Browse the repository at this point in the history
* Added support to header_map_file for group names, to match on groups too

* Updated tests

* Fixed tests
  • Loading branch information
rorylshanks authored Feb 29, 2024
1 parent 079b343 commit 3f17689
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 10 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ An example configuration file can be found in `example-config.yaml`. A breakdown
- `token_auth_header`: The name of the HTTP header that should contain the token (e.g., `Authorization`).
- `token_auth_header_prefix`: The prefix that should be present before the token in the HTTP header (e.g., `"Basic "`).
- `token_auth_is_base64_encoded`: Boolean value indicating whether the token is Base64 encoded (`true` or `false`).
- `request_header_map_file`: This parameter specifies the location of the external JSON file containing the header definitions for per-user request header mapping (e.g., `request_header_map.json`).
- `request_header_map_file`: This parameter specifies the location of the external JSON file containing the header definitions for per-user and per-group request header mapping (e.g., `request_header_map.json`).
- `request_header_map_headers`: This is a list of the names of the HTTP headers that should be set for the requests for per-user request header mapping
- `tls_client_cert_file`: Path to the client certificate file that should be used for upstream authentication (mTLS)
- `tls_client_key_file`: Path to the client certificate key that should be used for upstream authentication (mTLS)
Expand Down Expand Up @@ -146,7 +146,7 @@ The JSON file specified in `request_header_map_file` should contain an object fo

```json
{
"ENTER_USER_ID_HERE": {
"ENTER_USER_ID_OR_GROUP_ID_HERE": {
"Authorization": "test",
"X-test-Header": "another test"
}
Expand All @@ -155,8 +155,8 @@ The JSON file specified in `request_header_map_file` should contain an object fo

In this object:

- `"ENTER_USER_ID_HERE"` should be replaced with the ID of the user for whom you're setting the headers.
- The key-value pairs inside the user's object correspond to the headers you wish to set, with the header name as the key and the header value as the value.
- `"ENTER_USER_ID_OR_GROUP_ID_HERE"` should be replaced with the ID of the user or group for whom you're setting the headers.
- The key-value pairs inside the user or group object correspond to the headers you wish to set, with the header name as the key and the header value as the value.

Upon configuration, Veriflow will automatically add the requested headers to each upstream request based on the user that accesses the service. This allows for personalized and context-specific request handling. Please remember to keep your JSON file and the policy configuration secure due to the sensitive nature of header information.

Expand Down
24 changes: 19 additions & 5 deletions lib/authz.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ async function addRequestedHeaders(req, res, route, user, discoveredGroups) {
}
}
if (route.request_header_map_headers && route.request_header_map_file) {
var requestHeaderMap = await getRequestHeaderMapConfig(user.id, route)
var requestHeaderMap = await getRequestHeaderMapConfig(user, route)
if (requestHeaderMap) {
for (var header of route.request_header_map_headers) {
if (requestHeaderMap[header]) {
Expand All @@ -129,20 +129,34 @@ async function addRequestedHeaders(req, res, route, user, discoveredGroups) {
}
}

async function getRequestHeaderMapConfig(userId, route) {
async function getRequestHeaderMapConfig(user, route) {
var userId = user.id
var userGroups = user.groups
var requestHeaderMap = requestHeaderMapCache.get(`${userId}-${route}`)
if (requestHeaderMap) {
log.trace("Returning requestHeaderMap from cache")
return requestHeaderMap
} else {
var result = {}
try {
log.debug("Cache miss, returning requestHeaderMap from file " + route.request_header_map_file)
var requestHeaderMap = JSON.parse(await fs.readFile(route.request_header_map_file))
for (var group of userGroups) {
if (requestHeaderMap[group]) {
result = {
...result,
...requestHeaderMap[group],
}
}
}
if (requestHeaderMap[userId]) {
requestHeaderMapCache.put(`${userId}-${route}`, requestHeaderMap[userId])
return requestHeaderMap[userId]
result = {
...result,
...requestHeaderMap[userId],
}
}
return null
requestHeaderMapCache.put(`${userId}-${route}`, result)
return result
} catch (error) {
log.error({ message: "Unable to get config for requestHeaderMap", context: { error: error.message, stack: error.stack, route: route } })
return null
Expand Down
6 changes: 6 additions & 0 deletions test/e2e/configs/header-mapping-test.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,11 @@
"[email protected]": {
"Authorization": "ThisIsATestHeaderFromTheHeaderMapping",
"X-test-Header": "another test"
},
"test-header-group": {
"TestHeaderFromGroup": "TestHeaderFromGroup"
},
"test-header-group-absent": {
"TestAbsentHeaderFromGroup": "TestAbsentHeaderFromGroup"
}
}
3 changes: 2 additions & 1 deletion test/e2e/configs/idp_output.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"userPrincipalName": "[email protected]",
"id": "[email protected]",
"groups": [
"All Users"
"All Users",
"test-header-group"
]
}
}
1 change: 1 addition & 0 deletions test/e2e/configs/veriflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ policy:
request_header_map_file: "/configs/header-mapping-test.json"
request_header_map_headers:
- Authorization
- TestHeaderFromGroup
allowed_groups:
- All Users

Expand Down
2 changes: 2 additions & 0 deletions test/e2e/tests/basic_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Scenario('Testing Header Mapping', async ({ I }) => {
I.amOnPage('http://test-header-mapping.localtest.me:2080/');
I.login();
I.see("ThisIsATestHeaderFromTheHeaderMapping")
I.see("TestHeaderFromGroup")
I.dontSee("TestAbsentHeaderFromGroup")
});

Scenario('Testing Token Auth', async ({ I }) => {
Expand Down

0 comments on commit 3f17689

Please sign in to comment.