Skip to content

Commit ff47b13

Browse files
authored
fix: skip login screen when auth header is present (#8762)
1 parent f46f99c commit ff47b13

File tree

19 files changed

+245
-36
lines changed

19 files changed

+245
-36
lines changed

charts/kubernetes-dashboard/templates/config/gateway.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ data:
3737
paths:
3838
- /api/v1/csrftoken/login
3939
strip_path: false
40+
- name: authMe
41+
paths:
42+
- /api/v1/me
43+
strip_path: false
4044
- name: api
4145
host: {{ template "kubernetes-dashboard.fullname" . }}-{{ .Values.api.role }}
4246
port: 8000

hack/gateway/dev.kong.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ services:
2828
paths:
2929
- /api/v1/csrftoken/login
3030
strip_path: false
31+
- name: authMe
32+
paths:
33+
- /api/v1/me
34+
strip_path: false
3135
- name: api
3236
host: api # Internal name of docker service
3337
port: 8000

hack/gateway/prod.kong.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ services:
2828
paths:
2929
- /api/v1/csrftoken/login
3030
strip_path: false
31+
- name: authMe
32+
paths:
33+
- /api/v1/me
34+
strip_path: false
3135
- name: api
3236
host: api # Internal name of docker service
3337
port: 8000

modules/auth/go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ go 1.22.0
44

55
require (
66
github.com/gin-gonic/gin v1.9.1
7+
github.com/golang-jwt/jwt/v4 v4.5.0
78
github.com/spf13/pflag v1.0.5
89
golang.org/x/net v0.21.0
910
k8s.io/dashboard/client v0.0.0-00010101000000-000000000000
1011
k8s.io/dashboard/csrf v0.0.0-00010101000000-000000000000
1112
k8s.io/dashboard/errors v0.0.0-00010101000000-000000000000
1213
k8s.io/dashboard/helpers v0.0.0-00010101000000-000000000000
14+
k8s.io/dashboard/types v0.0.0-00010101000000-000000000000
1315
k8s.io/klog/v2 v2.120.1
1416
)
1517

@@ -64,7 +66,6 @@ require (
6466
k8s.io/apiextensions-apiserver v0.29.2 // indirect
6567
k8s.io/apimachinery v0.29.2 // indirect
6668
k8s.io/client-go v0.29.2 // indirect
67-
k8s.io/dashboard/types v0.0.0-00010101000000-000000000000 // indirect
6869
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
6970
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
7071
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect

modules/auth/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
4040
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
4141
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
4242
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
43+
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
44+
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
4345
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
4446
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
4547
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=

modules/auth/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
// Importing route packages forces route registration
2828
_ "k8s.io/dashboard/auth/pkg/routes/csrftoken"
2929
_ "k8s.io/dashboard/auth/pkg/routes/login"
30+
_ "k8s.io/dashboard/auth/pkg/routes/me"
3031
)
3132

3233
func main() {

modules/auth/pkg/routes/login/handler.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626

2727
func init() {
2828
router.V1().POST("/login", handleLogin)
29-
router.V1().GET("/login/status", handleLoginStatus)
3029
}
3130

3231
func handleLogin(c *gin.Context) {
@@ -47,7 +46,3 @@ func handleLogin(c *gin.Context) {
4746

4847
c.JSON(code, response)
4948
}
50-
51-
func handleLoginStatus(c *gin.Context) {
52-
c.JSON(http.StatusOK, "OK")
53-
}

modules/auth/pkg/routes/me/handler.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2017 The Kubernetes Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package login
16+
17+
import (
18+
"net/http"
19+
20+
"github.com/gin-gonic/gin"
21+
"k8s.io/klog/v2"
22+
23+
"k8s.io/dashboard/auth/pkg/router"
24+
)
25+
26+
func init() {
27+
router.V1().GET("/me", handleMe)
28+
}
29+
30+
func handleMe(c *gin.Context) {
31+
response, code, err := me(c.Request)
32+
if err != nil {
33+
klog.ErrorS(err, "Could not get user")
34+
c.JSON(code, err)
35+
return
36+
}
37+
38+
c.JSON(http.StatusOK, response)
39+
}

modules/auth/pkg/routes/me/me.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright 2017 The Kubernetes Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package login
16+
17+
import (
18+
"bytes"
19+
"encoding/json"
20+
"net/http"
21+
22+
"github.com/golang-jwt/jwt/v4"
23+
24+
"k8s.io/dashboard/client"
25+
"k8s.io/dashboard/errors"
26+
"k8s.io/dashboard/types"
27+
)
28+
29+
const (
30+
tokenServiceAccountKey = "serviceaccount"
31+
)
32+
33+
type ServiceAccount struct {
34+
Name string `json:"name"`
35+
UID string `json:"uid"`
36+
}
37+
38+
func me(request *http.Request) (*types.User, int, error) {
39+
k8sClient, err := client.Client(request)
40+
if err != nil {
41+
return nil, http.StatusInternalServerError, err
42+
}
43+
44+
// Make sure that authorization token is valid
45+
if _, err = k8sClient.Discovery().ServerVersion(); err != nil {
46+
code, err := errors.HandleError(err)
47+
return nil, code, err
48+
}
49+
50+
return getUserFromToken(client.GetBearerToken(request)), http.StatusOK, nil
51+
}
52+
53+
func getUserFromToken(token string) *types.User {
54+
parsed, _ := jwt.Parse(token, nil)
55+
if parsed == nil {
56+
return &types.User{Authenticated: true}
57+
}
58+
59+
claims := parsed.Claims.(jwt.MapClaims)
60+
61+
found, value := traverse(tokenServiceAccountKey, claims)
62+
if !found {
63+
return &types.User{Authenticated: true}
64+
}
65+
66+
var sa ServiceAccount
67+
ok := transcode(value, &sa)
68+
if !ok {
69+
return &types.User{Authenticated: true}
70+
}
71+
72+
return &types.User{Name: sa.Name, Authenticated: true}
73+
}
74+
75+
func traverse(key string, m map[string]interface{}) (found bool, value interface{}) {
76+
for k, v := range m {
77+
if k == key {
78+
return true, v
79+
}
80+
81+
if innerMap, ok := v.(map[string]interface{}); ok {
82+
return traverse(key, innerMap)
83+
}
84+
}
85+
86+
return false, ""
87+
}
88+
89+
func transcode(in, out interface{}) bool {
90+
buf := new(bytes.Buffer)
91+
err := json.NewEncoder(buf).Encode(in)
92+
if err != nil {
93+
return false
94+
}
95+
96+
err = json.NewDecoder(buf).Decode(out)
97+
return err == nil
98+
}

modules/common/types/common.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,8 @@ func APIMappingByKind(kind ResourceKind) (apiMapping APIMapping, exists bool) {
8282
apiMapping, exists = kindToAPIMapping[kind]
8383
return
8484
}
85+
86+
type User struct {
87+
Name string `json:"name,omitempty"`
88+
Authenticated bool `json:"authenticated"`
89+
}

0 commit comments

Comments
 (0)