Skip to content

Commit 73bcb30

Browse files
author
i.r.shamsutdinov
committed
feat(ui-server): add forward of static headers from env
1 parent bead6b3 commit 73bcb30

File tree

7 files changed

+129
-5
lines changed

7 files changed

+129
-5
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Once you have the prerequisites going, run the following:
3737
pnpm install
3838
```
3939

40-
Running `pnpm install` will attempt to download and install the most recent version of [Temporal CLI][] into `./bin/cli/temporal`. The development server will attempt to use use this version of this Temporal when starting up.
40+
Running `pnpm install` will attempt to download and install the most recent version of [Temporal CLI][] into `./bin/cli/temporal`. The development server will attempt to use this version of this Temporal when starting up.
4141

4242
- If that port is already in use, the UI will fallback to trying to talk to whatever process is running on that port.
4343
- If you do not have a version of Temporal CLI at `./bin/cli/temporal`, the development server will look for a version of Temporal CLI in your path.

server/cmd/server/main.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,17 @@ func buildCLI() *cli.App {
9393
return cli.Exit(err, 1)
9494
}
9595

96+
middlewares := []api.Middleware{
97+
headers.WithForwardHeaders(cfg.ForwardHeaders),
98+
}
99+
100+
if len(cfg.StaticHeaders) > 0 {
101+
middlewares = append(middlewares, headers.WithStaticHeaders(cfg.StaticHeaders))
102+
}
103+
96104
opts := []server_options.ServerOption{
97105
server_options.WithConfigProvider(cfgProvider),
98-
server_options.WithAPIMiddleware([]api.Middleware{
99-
headers.WithForwardHeaders(cfg.ForwardHeaders),
100-
}),
106+
server_options.WithAPIMiddleware(middlewares),
101107
}
102108

103109
s := server.NewServer(opts...)

server/config/development.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,5 @@ codec:
6161
defaultErrorLink:
6262
forwardHeaders: # can be used to pass additional HTTP headers from HTTP requests to Temporal gRPC backend
6363
- X-Forwarded-For
64+
staticHeaders: # can be used to always pass static headers to Temporal gRPC frontend
65+
# authorization: some-tkn

server/config/docker.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,12 @@ forwardHeaders:
7979
{{- end }}
8080
{{- end }}
8181

82+
staticHeaders:
83+
{{- if env "TEMPORAL_SERVER_STATIC_HEADERS" }}
84+
{{- range $pair := env "TEMPORAL_SERVER_STATIC_HEADERS" | split "," }}
85+
{{- $kv := $pair | split "=" }}
86+
{{$kv._0}}: {{$kv._1}}
87+
{{- end }}
88+
{{- end }}
89+
8290
hideLogs: {{ env "TEMPORAL_HIDE_LOGS" | default "false" }}

server/server/config/config.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ type (
7070
ActivityCommandsDisabled bool `yaml:"activityCommandsDisabled"`
7171
// Forward specified HTTP headers from HTTP API requests to Temporal gRPC backend
7272
ForwardHeaders []string `yaml:"forwardHeaders"`
73-
HideLogs bool `yaml:"hideLogs"`
73+
// Static headers to always forward to Temporal gRPC backend
74+
StaticHeaders map[string]string `yaml:"staticHeaders"`
75+
HideLogs bool `yaml:"hideLogs"`
7476
// TLS configuration options to start UI Server in TLS mode
7577
UIServerTLS UIServerTLS `yaml:"uiServerTLS"`
7678
}

server/server/headers/headers.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ func WithForwardHeaders(headers []string) api.Middleware {
4040
}
4141
}
4242

43+
func WithStaticHeaders(headers map[string]string) api.Middleware {
44+
return func(c echo.Context) runtime.ServeMuxOption {
45+
return runtime.WithMetadata(handleStaticHeaders(headers))
46+
}
47+
}
48+
4349
func handleForwardHeaders(c echo.Context, headers []string) func(context.Context, *http.Request) metadata.MD {
4450
return func(ctx context.Context, req *http.Request) metadata.MD {
4551
md := metadata.MD{}
@@ -61,6 +67,26 @@ func handleForwardHeaders(c echo.Context, headers []string) func(context.Context
6167
}
6268
}
6369

70+
func handleStaticHeaders(headers map[string]string) func(context.Context, *http.Request) metadata.MD {
71+
return func(ctx context.Context, req *http.Request) metadata.MD {
72+
md := metadata.MD{}
73+
for header, value := range headers {
74+
if value != "" {
75+
if len(header) > 4 && header[len(header)-4:] == "-bin" {
76+
decoded, err := base64DecodeWithOrWithoutPadding(value)
77+
if err == nil {
78+
md.Set(header, string(decoded))
79+
}
80+
} else {
81+
md.Append(header, value)
82+
}
83+
}
84+
}
85+
86+
return md
87+
}
88+
}
89+
6490
func base64DecodeWithOrWithoutPadding(s string) ([]byte, error) {
6591
s = strings.TrimRight(s, "=")
6692
return base64.RawStdEncoding.DecodeString(s)

server/server/headers/headers_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,83 @@ func TestHandleForwardHeaders(t *testing.T) {
165165
})
166166
}
167167
}
168+
169+
func TestHandleStaticHeaders(t *testing.T) {
170+
tests := []struct {
171+
name string
172+
headers map[string]string
173+
expectedMetadata map[string][]string
174+
}{
175+
{
176+
name: "static regular headers",
177+
headers: map[string]string{
178+
"authorization": "Bearer static-token",
179+
"x-custom-header": "static-value",
180+
},
181+
expectedMetadata: map[string][]string{
182+
"authorization": {"Bearer static-token"},
183+
"x-custom-header": {"static-value"},
184+
},
185+
},
186+
{
187+
name: "static binary header in base64 encoding with padding",
188+
headers: map[string]string{
189+
"x-binary-header-bin": "YmluYXJ5IGRhdGE=",
190+
},
191+
expectedMetadata: map[string][]string{
192+
"x-binary-header-bin": {"binary data"},
193+
},
194+
},
195+
{
196+
name: "static binary header in base64 encoding without padding",
197+
headers: map[string]string{
198+
"x-data-bin": "YmluYXJ5IGRhdGE",
199+
},
200+
expectedMetadata: map[string][]string{
201+
"x-data-bin": {"binary data"},
202+
},
203+
},
204+
{
205+
name: "mixed regular and binary static headers",
206+
headers: map[string]string{
207+
"x-regular": "regular-value",
208+
"x-binary-bin": "YmluYXJ5LXZhbHVl",
209+
},
210+
expectedMetadata: map[string][]string{
211+
"x-regular": {"regular-value"},
212+
"x-binary-bin": {"binary-value"},
213+
},
214+
},
215+
{
216+
name: "skip empty static headers",
217+
headers: map[string]string{
218+
"authorization": "Bearer static-token",
219+
"x-empty-header": "",
220+
},
221+
expectedMetadata: map[string][]string{
222+
"authorization": {"Bearer static-token"},
223+
},
224+
},
225+
{
226+
name: "skip invalid base64 in static binary header",
227+
headers: map[string]string{
228+
"x-invalid-bin": "not-valid-base64!!!",
229+
},
230+
expectedMetadata: map[string][]string{},
231+
},
232+
}
233+
234+
for _, tt := range tests {
235+
t.Run(tt.name, func(t *testing.T) {
236+
handle := handleStaticHeaders(tt.headers)
237+
var actualMetadata metadata.MD = handle(nil, nil)
238+
239+
assert.Equal(t, len(tt.expectedMetadata), len(actualMetadata), "metadata length mismatch")
240+
241+
for expectedKey, expectedValues := range tt.expectedMetadata {
242+
values := actualMetadata.Get(expectedKey)
243+
assert.Equal(t, expectedValues, values, "metadata mismatch for key %s", expectedKey)
244+
}
245+
})
246+
}
247+
}

0 commit comments

Comments
 (0)