Skip to content

Commit 1de5847

Browse files
fix: add double auth header value separated by comma (#9)
1 parent 87c00ac commit 1de5847

File tree

5 files changed

+85
-13
lines changed

5 files changed

+85
-13
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ tmp
88

99
coverage.html
1010
coverage.out
11+
.vscode

internal/server/handlerCategory.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,16 @@ func _categoryHandler(s *shared, req *http.Request, res *response) (*response, *
4646

4747
var config k8s.KubeConfig
4848
if data.ProjectName != "" && data.WorkspaceName != "" && data.McpName != "" {
49-
config, err = openmcp.GetControlPlaneKubeconfig(s.crateKube, data.ProjectName, data.WorkspaceName, data.McpName, data.Authorization, crateKubeconfig)
49+
config, err = openmcp.GetControlPlaneKubeconfig(s.crateKube, data.ProjectName, data.WorkspaceName, data.McpName, data.CrateAuthorizationToken, crateKubeconfig)
5050
if err != nil {
5151
slog.Error("failed to get control plane api config", "err", err)
5252
return nil, NewInternalServerError("failed to get control plane api config")
5353
}
54-
if data.Authorization != "" {
55-
config.SetUserToken(data.Authorization)
54+
if data.McpAuthorizationToken == "" {
55+
slog.Error("MCP authorization token not provided")
56+
return nil, NewBadRequestError("MCP authorization token not provided")
5657
}
58+
config.SetUserToken(data.McpAuthorizationToken)
5759
} else {
5860
slog.Error("either use %s: true or provide %s, %s and %s headers", useCrateClusterHeader, projectNameHeader, workspaceNameHeader, mcpName)
5961
return nil, NewBadRequestError(

internal/server/handlerMain.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ type ExtractedRequestData struct {
5454
McpName string
5555
ContextName string
5656
UseCrateCluster bool
57-
Authorization string
57+
CrateAuthorizationToken string
58+
McpAuthorizationToken string
5859
Headers map[string][]string
5960
JQ string
6061
Category string
@@ -87,16 +88,18 @@ func mainHandler(s *shared, req *http.Request, res *response) (*response, *HttpE
8788
var config k8s.KubeConfig
8889
if data.UseCrateCluster {
8990
config = crateKubeconfig
90-
config.SetUserToken(data.Authorization)
91+
config.SetUserToken(data.CrateAuthorizationToken)
9192
} else if data.ProjectName != "" && data.WorkspaceName != "" && data.McpName != "" {
92-
config, err = openmcp.GetControlPlaneKubeconfig(s.crateKube, data.ProjectName, data.WorkspaceName, data.McpName, data.Authorization, crateKubeconfig)
93+
config, err = openmcp.GetControlPlaneKubeconfig(s.crateKube, data.ProjectName, data.WorkspaceName, data.McpName, data.CrateAuthorizationToken, crateKubeconfig)
9394
if err != nil {
9495
slog.Error("failed to get control plane api config", "err", err)
9596
return nil, NewInternalServerError("failed to get control plane api config")
9697
}
97-
if data.Authorization != "" {
98-
config.SetUserToken(data.Authorization)
98+
if data.McpAuthorizationToken == "" {
99+
slog.Error("MCP authorization token not provided")
100+
return nil, NewBadRequestError("MCP authorization token not provided")
99101
}
102+
config.SetUserToken(data.McpAuthorizationToken)
100103
} else {
101104
slog.Error("either use %s: true or provide %s, %s and %s headers", useCrateClusterHeader, projectNameHeader, workspaceNameHeader, mcpName)
102105
return nil, NewBadRequestError(
@@ -138,6 +141,15 @@ func mainHandler(s *shared, req *http.Request, res *response) (*response, *HttpE
138141
}
139142

140143
func extractRequestData(r *http.Request) (ExtractedRequestData, error) {
144+
if r.Header.Get(authorizationHeader) == "" {
145+
return ExtractedRequestData{}, fmt.Errorf("%s header is required", authorizationHeader)
146+
}
147+
148+
crateToken, mcpToken, err := parseAuthorizationHeaderWithDoubleTokens(r.Header.Get(authorizationHeader))
149+
if err != nil {
150+
return ExtractedRequestData{}, fmt.Errorf("invalid %s header: %w", authorizationHeader, err)
151+
}
152+
141153
rd := ExtractedRequestData{
142154
Path: r.URL.Path,
143155
Query: r.URL.Query(),
@@ -150,7 +162,8 @@ func extractRequestData(r *http.Request) (ExtractedRequestData, error) {
150162
WorkspaceName: r.Header.Get(workspaceNameHeader),
151163
ContextName: r.Header.Get(contextHeader),
152164
McpName: r.Header.Get(mcpName),
153-
Authorization: r.Header.Get(authorizationHeader),
165+
CrateAuthorizationToken: crateToken,
166+
McpAuthorizationToken: mcpToken,
154167
JQ: r.Header.Get(jqHeader),
155168
Category: r.Header.Get(categoryHeader),
156169
}
@@ -166,10 +179,6 @@ func extractRequestData(r *http.Request) (ExtractedRequestData, error) {
166179
rd.UseCrateCluster = useCrateCluster
167180
}
168181

169-
if rd.Authorization == "" {
170-
return ExtractedRequestData{}, fmt.Errorf("%s header is required", authorizationHeader)
171-
}
172-
173182
return rd, nil
174183
}
175184

internal/server/utils.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package server
33
import (
44
"bytes"
55
"encoding/json"
6+
"fmt"
67
"io"
78
"net/http"
89
"strings"
@@ -103,3 +104,21 @@ func ParseJQ(inputJson []byte, inputJQ string) (string, error) {
103104

104105
return strings.Join(result[:], "\n"), nil
105106
}
107+
108+
// parseAuthorizationHeaderWithDoubleTokens parses an authorization header that may contain two tokens separated by a comma.
109+
// It returns the first token and the second token (if present). If the second token is absent, it returns an empty string for it.
110+
// If the header is empty or contains more than two tokens, it returns an error.
111+
func parseAuthorizationHeaderWithDoubleTokens(authHeader string) (string, string, error) {
112+
if authHeader == "" {
113+
return "", "", fmt.Errorf("authorization header is empty")
114+
}
115+
116+
tokens := strings.Split(authHeader, ",")
117+
if len(tokens) > 2 {
118+
return "", "", fmt.Errorf("authorization header must contain two or less tokens separated by a space")
119+
}
120+
if len(tokens) == 1 {
121+
return tokens[0], "", nil
122+
}
123+
return tokens[0], tokens[1], nil
124+
}

internal/server/utils_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package server
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestParseAuthorizationHeaderWithDoubleTokens(t *testing.T) {
8+
tests := []struct {
9+
authHeader string
10+
token1 string
11+
token2 string
12+
expectErr bool
13+
}{
14+
{"token1,token2", "token1", "token2", false},
15+
{"token1", "token1", "", false},
16+
{"", "", "", true},
17+
{"token1,token2,token3", "", "", true},
18+
}
19+
20+
for _, test := range tests {
21+
t.Run(test.authHeader, func(t *testing.T) {
22+
token1, token2, err := parseAuthorizationHeaderWithDoubleTokens(test.authHeader)
23+
24+
if test.expectErr {
25+
if err == nil {
26+
t.Errorf("expected an error but got none")
27+
}
28+
} else {
29+
if err != nil {
30+
t.Errorf("expected no error but got: %v", err)
31+
}
32+
if token1 != test.token1 {
33+
t.Errorf("expected token1 to be %q but got %q", test.token1, token1)
34+
}
35+
if token2 != test.token2 {
36+
t.Errorf("expected token2 to be %q but got %q", test.token2, token2)
37+
}
38+
}
39+
})
40+
}
41+
}

0 commit comments

Comments
 (0)