add support for pomerium.request.headers for set_request_headers (#5563)

* add support for pomerium.request.headers for set_request_headers

* add peg grammar
This commit is contained in:
Caleb Doxsey 2025-04-07 10:32:03 -06:00 committed by GitHub
parent 5f95dd32db
commit a1eb75a8fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 338 additions and 15 deletions

View file

@ -7,8 +7,8 @@ import (
"encoding/json"
"fmt"
"net/http"
"os"
"reflect"
"slices"
"strings"
"time"
@ -20,6 +20,8 @@ import (
"github.com/pomerium/datasource/pkg/directory"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/headertemplate"
"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/grpc/session"
@ -149,20 +151,20 @@ func (e *headersEvaluatorEvaluation) fillSetRequestHeaders(ctx context.Context)
}
for k, v := range e.request.Policy.SetRequestHeaders {
e.response.Headers.Add(k, os.Expand(v, func(name string) string {
switch name {
case "$":
return "$"
case "pomerium.access_token":
e.response.Headers.Add(k, headertemplate.Render(v, func(ref []string) string {
switch {
case slices.Equal(ref, []string{"pomerium", "access_token"}):
s, _ := e.getSessionOrServiceAccount(ctx)
return s.GetOauthToken().GetAccessToken()
case "pomerium.client_cert_fingerprint":
case slices.Equal(ref, []string{"pomerium", "client_cert_fingerprint"}):
return e.getClientCertFingerprint()
case "pomerium.id_token":
case slices.Equal(ref, []string{"pomerium", "id_token"}):
s, _ := e.getSessionOrServiceAccount(ctx)
return s.GetIdToken().GetRaw()
case "pomerium.jwt":
case slices.Equal(ref, []string{"pomerium", "jwt"}):
return e.getSignedJWT(ctx)
case len(ref) > 3 && ref[0] == "pomerium" && ref[1] == "request" && ref[2] == "headers":
return e.request.HTTP.Headers[httputil.CanonicalHeaderKey(ref[3])]
}
return ""

View file

@ -218,15 +218,19 @@ func TestHeadersEvaluator(t *testing.T) {
HTTP: RequestHTTP{
Hostname: "from.example.com",
ClientCertificate: ClientCertificateInfo{Leaf: testValidCert},
Headers: map[string]string{
"X-Incoming-Header": "INCOMING",
},
},
Policy: &config.Policy{
SetRequestHeaders: map[string]string{
"X-Custom-Header": "CUSTOM_VALUE",
"X-ID-Token": "${pomerium.id_token}",
"X-Access-Token": "${pomerium.access_token}",
"Client-Cert-Fingerprint": "${pomerium.client_cert_fingerprint}",
"Authorization": "Bearer ${pomerium.jwt}",
"Foo": "escaped $$dollar sign",
"X-Custom-Header": "CUSTOM_VALUE",
"X-ID-Token": "${pomerium.id_token}",
"X-Access-Token": "${pomerium.access_token}",
"Client-Cert-Fingerprint": "${pomerium.client_cert_fingerprint}",
"Authorization": "Bearer ${pomerium.jwt}",
"Foo": "escaped $$dollar sign",
"X-Incoming-Custom-Header": `From-Incoming ${pomerium.request.headers["X-Incoming-Header"]}`,
},
},
Session: RequestSession{ID: "s1"},
@ -239,6 +243,7 @@ func TestHeadersEvaluator(t *testing.T) {
assert.Equal(t, "3febe6467787e93f0a01030e0803072feaa710f724a9dc74de05cfba3d4a6d23",
output.Headers.Get("Client-Cert-Fingerprint"))
assert.Equal(t, "escaped $dollar sign", output.Headers.Get("Foo"))
assert.Equal(t, "From-Incoming INCOMING", output.Headers.Get("X-Incoming-Custom-Header"))
authHeader := output.Headers.Get("Authorization")
assert.True(t, strings.HasPrefix(authHeader, "Bearer "))
authHeader = strings.TrimPrefix(authHeader, "Bearer ")