Skip to content
Snippets Groups Projects
Commit 3a21ed7d authored by Yordan Kinkov's avatar Yordan Kinkov
Browse files

Merge branch '12-make-header-value-a-string-in-rego' into 'main'

Return string when accessing a header in Rego

Closes #12

See merge request gaia-x/data-infrastructure-federation-services/tsa/policy!6
parents 15589a53 e194f655
No related branches found
No related tags found
No related merge requests found
Pipeline #54537 passed with stages
in 1 minute and 46 seconds
...@@ -172,7 +172,26 @@ endpoints for working with arbitrary dynamically uploaded policies. ...@@ -172,7 +172,26 @@ endpoints for working with arbitrary dynamically uploaded policies.
### Access HTTP Headers inside a policy ### Access HTTP Headers inside a policy
HTTP Request Headers are passed to the evaluation runtime on each request. One could access any header by name within HTTP Request Headers are passed to the evaluation runtime on each request. One could access any header by name within
the Rego source code using `input.header.name` or `input.header["name"]`. the Rego source code using `input.headers.Name` or `input.headers["Name"]`.
##### **Important**
Header names are passed to the Rego runtime in a canonical format. This means that the first character and any characters following a
hyphen are uppercase and the rest are lowercase.
Example:
The policy service receives a request with these headers:
```
accept-encoding: gzip, deflate
Accept-Language: en-us
fOO: Bar
x-loCATion: Baz
```
Inside a policy these headers could be accessed as follows:
```
input.headers["Accept-Encoding"]
input.headers["Accept-Language"]
input.headers["Foo"]
input.headers["X-Location"]
```
### Policy Extensions Functions ### Policy Extensions Functions
......
...@@ -23,10 +23,18 @@ func Middleware() func(http.Handler) http.Handler { ...@@ -23,10 +23,18 @@ func Middleware() func(http.Handler) http.Handler {
} }
func ToContext(ctx context.Context, r *http.Request) context.Context { func ToContext(ctx context.Context, r *http.Request) context.Context {
return context.WithValue(ctx, headerKey, r.Header) headers := make(map[string]string, len(r.Header)+1)
for name := range r.Header {
headers[name] = r.Header.Get(name)
}
// add Host header to headers map
headers["Host"] = r.Host
return context.WithValue(ctx, headerKey, headers)
} }
func FromContext(ctx context.Context) (http.Header, bool) { func FromContext(ctx context.Context) (map[string]string, bool) {
header, ok := ctx.Value(headerKey).(http.Header) header, ok := ctx.Value(headerKey).(map[string]string)
return header, ok return header, ok
} }
...@@ -10,10 +10,10 @@ import ( ...@@ -10,10 +10,10 @@ import (
) )
func TestMiddleware(t *testing.T) { func TestMiddleware(t *testing.T) {
expected := http.Header{"Authorization": []string{"my-token"}} expected := map[string]string{"Authorization": "my-token", "Host": "example.com"}
req := httptest.NewRequest("POST", "/example", nil) req := httptest.NewRequest("POST", "/example", nil)
req.Header = expected req.Header = http.Header{"Authorization": []string{"my-token"}}
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
value, ok := header.FromContext(r.Context()) value, ok := header.FromContext(r.Context())
......
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
//go:generate counterfeiter . Storage //go:generate counterfeiter . Storage
//go:generate counterfeiter . RegoCache //go:generate counterfeiter . RegoCache
const HeaderKey = "header" const HeaderKey = "headers"
type Cache interface { type Cache interface {
Set(ctx context.Context, key, namespace, scope string, value []byte, ttl int) error Set(ctx context.Context, key, namespace, scope string, value []byte, ttl int) error
......
...@@ -37,7 +37,7 @@ func TestService_Evaluate(t *testing.T) { ...@@ -37,7 +37,7 @@ func TestService_Evaluate(t *testing.T) {
testPolicyWithStaticData := `package testgroup.example default allow = false allow { data.msg == "hello world" }` testPolicyWithStaticData := `package testgroup.example default allow = false allow { data.msg == "hello world" }`
// prepare test policy accessing headers during evaluation // prepare test policy accessing headers during evaluation
testPolicyAccessingHeaders := `package testgroup.example token := input.header["Authorization"]` testPolicyAccessingHeaders := `package testgroup.example token := input.headers["Authorization"]`
// prepare test query that can be retrieved from rego queryCache // prepare test query that can be retrieved from rego queryCache
testQuery, err := rego.New( testQuery, err := rego.New(
...@@ -347,7 +347,7 @@ func TestService_Evaluate(t *testing.T) { ...@@ -347,7 +347,7 @@ func TestService_Evaluate(t *testing.T) {
}, },
}, },
res: &goapolicy.EvaluateResult{ res: &goapolicy.EvaluateResult{
Result: map[string]interface{}{"token": []interface{}{"my-token"}}, Result: map[string]interface{}{"token": "my-token"},
}, },
}, },
{ {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment