Skip to content

Commit 4413551

Browse files
committed
add header-name flag, set header-name to default auth if set, add tests for header-name and cookie configs
1 parent 959eb35 commit 4413551

File tree

4 files changed

+88
-18
lines changed

4 files changed

+88
-18
lines changed

internal/cli/cli.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ func NewRootCommand() *cobra.Command {
3535
cmd.PersistentFlags().String("grafana-proxy-url", "http://grafana.example.com", "Grafana url to proxy to")
3636
cmd.PersistentFlags().String("grafana-user-header", "X-WEBAUTH-USER", "Header to containing the user to authenticate")
3737
cmd.PersistentFlags().String("cookie-name", "auth_token", "Cookie name with jwt token. If set will take precedence over auth header")
38+
cmd.PersistentFlags().String("header-name", "", "header name with jwt token. If set will take precedence over cookie-name")
3839
cmd.PersistentFlags().String("admin-user", "admin", "Admin user")
3940
cmd.PersistentFlags().String("admin-password", "", "Admin password")
4041
cmd.PersistentFlags().String("jwt-claim-login", "email", "JWT claim to be used as user Login in Grafana. Valid values are 'email' or 'sub'")
@@ -84,6 +85,7 @@ func defaultServerOptions() []server.ServerFuncOpt {
8485

8586
opts := []server.ServerFuncOpt{
8687
server.WithCookieName(viper.GetString("cookie-name")),
88+
server.WithHeaderName(viper.GetString("header-name")),
8789
server.WithGrafanaResponseHeaders(responseHeaders),
8890
}
8991

internal/server/options.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ func WithCookieName(cookie string) ServerFuncOpt {
1414
}
1515
}
1616

17+
func WithHeaderName(header string) ServerFuncOpt {
18+
return func(s *Server) error {
19+
s.headerName = header
20+
return nil
21+
}
22+
}
23+
1724
func WithConfigGroups(groups config.Groups) ServerFuncOpt {
1825
return func(s *Server) error {
1926
s.groups = groups

internal/server/server.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type GrafanaClaimsConfig struct {
2626
type Server struct {
2727
router *http.ServeMux
2828
cookieName string
29+
headerName string
2930
groups config.Groups
3031
grafanaProxyUrl *url.URL
3132
grafanaClient *grafana.Client
@@ -65,15 +66,27 @@ func getValidClaim(claims *jwt.Claims, input string) string {
6566

6667
func (s *Server) handleRoot() http.HandlerFunc {
6768
return func(w http.ResponseWriter, r *http.Request) {
68-
// Extract token from cookie
69-
cookie, err := r.Cookie(s.cookieName)
70-
if err != nil {
71-
logAndError(w, http.StatusUnauthorized, err, "error reading cookie")
72-
return
69+
// Get token
70+
var token string
71+
72+
if s.headerName != "" {
73+
token = r.Header.Get(s.headerName)
74+
// replicate the cookie look up behavior for a missing header
75+
if token == "" {
76+
logAndError(w, http.StatusUnauthorized, fmt.Errorf("No value for header %s", s.headerName), "error reading header")
77+
return
78+
}
79+
} else {
80+
cookie, err := r.Cookie(s.cookieName)
81+
if err != nil {
82+
logAndError(w, http.StatusUnauthorized, err, "error reading cookie")
83+
return
84+
}
85+
token = cookie.Value
7386
}
7487

7588
// Get claims from token
76-
claims, err := jwt.TokenClaims(cookie.Value)
89+
claims, err := jwt.TokenClaims(token)
7790
if err != nil {
7891
logAndError(w, http.StatusUnauthorized, err, "error reading claims from jwt token")
7992
return

internal/server/server_test.go

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,33 +37,41 @@ func TestTokenValidations(t *testing.T) {
3737
defer backendServer.Close()
3838
backendURL, _ := url.Parse(backendServer.URL)
3939

40+
headerName := "X-Test-Header"
41+
42+
validToken := newTestJWTToken("jhon")
43+
noSubToken := newTestJWTToken("")
44+
invalidToken := "this-is-no-valid-jwt"
45+
emptyToken := ""
46+
4047
client := grafana.NewMockClient(gapi.User{Login: "jhon", ID: 1}, map[int64]grafana.RoleType{})
4148

4249
tests := []struct {
4350
name string
4451
cookie *http.Cookie
52+
header *string
4553
authorized bool
4654
}{
4755
{
4856
name: "valid JWT token and cookie",
4957
cookie: &http.Cookie{
5058
Name: "auth_token",
51-
Value: newTestJWTToken("jhon"),
59+
Value: validToken,
5260
},
5361
authorized: true,
5462
},
5563
{
5664
name: "valid JWT token without sub",
5765
cookie: &http.Cookie{
5866
Name: "auth_token",
59-
Value: newTestJWTToken(""),
67+
Value: noSubToken,
6068
},
6169
},
6270
{
6371
name: "invalid JWT token",
6472
cookie: &http.Cookie{
6573
Name: "auth_token",
66-
Value: "this-is-no-valid-jwt",
74+
Value: invalidToken,
6775
},
6876
},
6977
{
@@ -72,34 +80,74 @@ func TestTokenValidations(t *testing.T) {
7280
Name: "",
7381
},
7482
},
83+
{
84+
name: "valid JWT token and header",
85+
header: &validToken,
86+
authorized: true,
87+
},
88+
{
89+
name: "valid JWT token without sub",
90+
header: &noSubToken,
91+
},
92+
{
93+
name: "invalid JWT token",
94+
header: &invalidToken,
95+
},
96+
{
97+
name: "Empty Header",
98+
header: &emptyToken,
99+
},
100+
{
101+
name: "valid JWT token header and cookie",
102+
header: &validToken,
103+
cookie: &http.Cookie{
104+
Name: "auth_token",
105+
Value: validToken,
106+
},
107+
authorized: true,
108+
},
109+
{
110+
name: "valid JWT token header invalid cookie",
111+
header: &validToken,
112+
cookie: &http.Cookie{
113+
Name: "auth_token",
114+
Value: invalidToken,
115+
},
116+
authorized: true,
117+
},
75118
}
76119

77120
for _, test := range tests {
78121
req := httptest.NewRequest("GET", "/", nil)
79122
req.Host = "http://grafana.example.com"
80123

81-
if test.cookie.Name != "" {
82-
req.AddCookie(test.cookie)
83-
}
84-
85-
server, err := New(
124+
opts := []ServerFuncOpt{
86125
WithGrafanaProxyURL(backendURL),
87-
WithCookieName(test.cookie.Name),
88126
WithConfigGroups(config.Groups{}),
89127
WithGrafanaClient(client),
90128
WithGrafanaResponseHeaders(GrafanaResponseHeaders{
91129
User: "X-WEBAUTH-USER",
92130
}),
93-
)
131+
}
132+
133+
if test.cookie != nil && test.cookie.Name != "" {
134+
req.AddCookie(test.cookie)
135+
opts = append(opts, WithCookieName(test.cookie.Name))
136+
}
137+
if test.header != nil {
138+
req.Header.Add(headerName, *test.header)
139+
opts = append(opts, WithHeaderName(headerName))
140+
}
141+
server, err := New(opts...)
94142
assert.NoError(t, err)
95143

96144
w := httptest.NewRecorder()
97145
server.ServeHTTP(w, req)
98146

99147
if test.authorized {
100-
assert.Equal(t, http.StatusOK, w.Code)
148+
assert.Equal(t, http.StatusOK, w.Code, test.name)
101149
} else {
102-
assert.Equal(t, http.StatusUnauthorized, w.Code)
150+
assert.Equal(t, http.StatusUnauthorized, w.Code, test.name)
103151
}
104152
}
105153
}

0 commit comments

Comments
 (0)