From 853f44cf6183d2e97eba9c7fb307e17f62b84ff5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Jul 2022 15:53:22 +0800 Subject: [PATCH] [Backport release-1.5] Fix: support to test authentication with dex (#4440) * Fix: support to test login with dex Signed-off-by: barnettZQG (cherry picked from commit 8d0d20fd603beaaf9d812606ac701906996415fb) * Fix: support to update the user when the login mode is dex Signed-off-by: barnettZQG (cherry picked from commit 442d4601e95cbe866204fb051c3250c27fb86f8d) * Fix: systemInfoService is nil Signed-off-by: barnettZQG (cherry picked from commit 392637e69d474f2f1ca93017dd5090590c1f2b37) Co-authored-by: barnettZQG --- pkg/apiserver/domain/model/system_info.go | 22 ++++++++++++++ .../domain/service/authentication.go | 30 +++++++++++++------ .../domain/service/authentication_test.go | 14 +++++---- pkg/apiserver/domain/service/user.go | 16 +++++----- pkg/apiserver/domain/service/velaql.go | 9 ++++-- 5 files changed, 66 insertions(+), 25 deletions(-) diff --git a/pkg/apiserver/domain/model/system_info.go b/pkg/apiserver/domain/model/system_info.go index 9a7d158c0..0092153c1 100644 --- a/pkg/apiserver/domain/model/system_info.go +++ b/pkg/apiserver/domain/model/system_info.go @@ -57,6 +57,8 @@ type DexConfig struct { Issuer string `json:"issuer"` Web DexWeb `json:"web"` Storage DexStorage `json:"storage"` + Telemetry Telemetry `json:"telemetry"` + Frontend WebConfig `json:"frontend"` StaticClients []DexStaticClient `json:"staticClients"` Connectors []map[string]interface{} `json:"connectors,omitempty"` EnablePasswordDB bool `json:"enablePasswordDB"` @@ -95,6 +97,26 @@ type DexStorageConfig struct { // DexWeb dex web type DexWeb struct { + HTTP string `json:"http"` + HTTPS string `json:"https"` + TLSCert string `json:"tlsCert"` + TLSKey string `json:"tlsKey"` + AllowedOrigins []string `json:"allowedOrigins"` +} + +// WebConfig holds the server's frontend templates and asset configuration. +type WebConfig struct { + LogoURL string + + // Defaults to "dex" + Issuer string + + // Defaults to "light" + Theme string +} + +// Telemetry is the config format for telemetry including the HTTP server config. +type Telemetry struct { HTTP string `json:"http"` } diff --git a/pkg/apiserver/domain/service/authentication.go b/pkg/apiserver/domain/service/authentication.go index b9b94724e..f54d187e8 100644 --- a/pkg/apiserver/domain/service/authentication.go +++ b/pkg/apiserver/domain/service/authentication.go @@ -129,9 +129,10 @@ func (a *authenticationServiceImpl) newDexHandler(ctx context.Context, req apisv return nil, err } return &dexHandlerImpl{ - idToken: idToken, - Store: a.Store, - projectService: a.ProjectService, + idToken: idToken, + Store: a.Store, + projectService: a.ProjectService, + systemInfoService: a.SystemInfoService, }, nil } @@ -156,13 +157,13 @@ func (a *authenticationServiceImpl) Login(ctx context.Context, loginReq apisv1.L } loginType := sysInfo.LoginType - switch loginType { - case model.LoginTypeDex: + switch { + case loginType == model.LoginTypeDex || (loginReq.Code != "" && loginReq.Username == ""): handler, err = a.newDexHandler(ctx, loginReq) if err != nil { return nil, err } - case model.LoginTypeLocal: + case loginType == model.LoginTypeLocal: handler, err = a.newLocalHandler(loginReq) if err != nil { return nil, err @@ -288,6 +289,11 @@ func generateDexConfig(ctx context.Context, kubeClient client.Client, update *mo if len(update.StaticPasswords) > 0 { dexConfig.StaticPasswords = update.StaticPasswords } + // This is the title that the dex login page. + // It will be: Log in to KubeVela + if dexConfig.Frontend.Issuer == "" { + dexConfig.Frontend.Issuer = "KubeVela" + } config, err := model.NewJSONStructByStruct(dexConfig) if err != nil { return err @@ -323,7 +329,7 @@ func initDexConfig(ctx context.Context, kubeClient client.Client, velaAddress st StaticClients: []model.DexStaticClient{ { ID: "velaux", - Name: "Vela UX", + Name: "VelaUX", Secret: "velaux-secret", RedirectURIs: []string{fmt.Sprintf("%s/callback", velaAddress)}, }, @@ -403,9 +409,13 @@ func getDexConfig(ctx context.Context, kubeClient client.Client) (*model.DexConf Namespace: velatypes.DefaultKubeVelaNS, }, dexConfigSecret); err != nil { if kerrors.IsNotFound(err) { - return nil, bcode.ErrDexConfigNotFound + dexConfigSecret, err = initDexConfig(ctx, kubeClient, "http://velaux.com") + if err != nil { + return nil, err + } + } else { + return nil, err } - return nil, err } if dexConfigSecret.Data == nil { return nil, bcode.ErrInvalidDexConfig @@ -468,6 +478,7 @@ func (d *dexHandlerImpl) login(ctx context.Context) (*apisv1.UserBase, error) { if len(users) > 0 { u := users[0].(*model.User) u.LastLoginTime = time.Now() + u.DexSub = claims.Sub if err := d.Store.Put(ctx, u); err != nil { return nil, err } @@ -481,6 +492,7 @@ func (d *dexHandlerImpl) login(ctx context.Context) (*apisv1.UserBase, error) { LastLoginTime: time.Now(), } if err := d.Store.Add(ctx, user); err != nil { + log.Logger.Errorf("failed to save the user from the dex: %s", err.Error()) return nil, err } systemInfo, err := d.systemInfoService.GetSystemInfo(ctx) diff --git a/pkg/apiserver/domain/service/authentication_test.go b/pkg/apiserver/domain/service/authentication_test.go index 457c075b9..657c8fb11 100644 --- a/pkg/apiserver/domain/service/authentication_test.go +++ b/pkg/apiserver/domain/service/authentication_test.go @@ -19,6 +19,7 @@ package service import ( "context" "encoding/json" + "fmt" "io/ioutil" "reflect" "strconv" @@ -64,8 +65,9 @@ var _ = Describe("Test authentication service functions", func() { }) It("Test Dex login", func() { testIDToken := &oidc.IDToken{} + sub := "248289761001" patch := ApplyMethod(reflect.TypeOf(testIDToken), "Claims", func(_ *oidc.IDToken, v interface{}) error { - return json.Unmarshal([]byte(`{"email":"test@test.com", "name":"show name", "sub": "testuser"}`), v) + return json.Unmarshal([]byte(fmt.Sprintf(`{"email":"test@test.com", "name":"show name", "sub": "%s"}`, sub)), v) }) defer patch.Reset() @@ -94,22 +96,22 @@ var _ = Describe("Test authentication service functions", func() { resp, err := dexHandler.login(context.Background()) Expect(err).Should(BeNil()) Expect(resp.Email).Should(Equal("test@test.com")) - Expect(resp.Name).Should(Equal("testuser")) + Expect(resp.Name).Should(Equal(sub)) Expect(resp.Alias).Should(Equal("show name")) - projects, err := projectService.ListUserProjects(context.TODO(), "testuser") + projects, err := projectService.ListUserProjects(context.TODO(), sub) Expect(err).Should(BeNil()) Expect(len(projects)).Should(Equal(1)) user := &model.User{ - Name: "testuser", + Name: sub, } err = ds.Get(context.Background(), user) Expect(err).Should(BeNil()) Expect(user.Email).Should(Equal("test@test.com")) existUser := &model.User{ - Name: "testuser", + Name: sub, } err = ds.Delete(context.Background(), existUser) Expect(err).Should(BeNil()) @@ -131,7 +133,7 @@ var _ = Describe("Test authentication service functions", func() { existUser = &model.User{ Name: "zhangsan", Email: "test2@test.com", - DexSub: "testuser", + DexSub: sub, } err = ds.Add(context.Background(), existUser) Expect(err).Should(BeNil()) diff --git a/pkg/apiserver/domain/service/user.go b/pkg/apiserver/domain/service/user.go index 3b3f20d86..04de1ddac 100644 --- a/pkg/apiserver/domain/service/user.go +++ b/pkg/apiserver/domain/service/user.go @@ -192,18 +192,17 @@ func (u *userServiceImpl) UpdateUser(ctx context.Context, user *model.User, req if err != nil { return nil, err } - if sysInfo.LoginType == model.LoginTypeDex { - return nil, bcode.ErrUserCannotModified - } if req.Alias != "" { user.Alias = req.Alias } - if req.Password != "" { - hash, err := GeneratePasswordHash(req.Password) - if err != nil { - return nil, err + if sysInfo.LoginType != model.LoginTypeDex { + if req.Password != "" { + hash, err := GeneratePasswordHash(req.Password) + if err != nil { + return nil, err + } + user.Password = hash } - user.Password = hash } if req.Email != "" { if user.Email != "" { @@ -211,6 +210,7 @@ func (u *userServiceImpl) UpdateUser(ctx context.Context, user *model.User, req } user.Email = req.Email } + // TODO: validate the roles, they must be platform roles if req.Roles != nil { user.UserRoles = *req.Roles diff --git a/pkg/apiserver/domain/service/velaql.go b/pkg/apiserver/domain/service/velaql.go index f76975b83..72a460b14 100644 --- a/pkg/apiserver/domain/service/velaql.go +++ b/pkg/apiserver/domain/service/velaql.go @@ -82,8 +82,13 @@ func (v *velaQLServiceImpl) QueryView(ctx context.Context, velaQL string) (*apis return nil, bcode.ErrParseQuery2Json } if strings.Contains(velaQL, "collect-logs") { - enc, _ := base64.StdEncoding.DecodeString(resp["logs"].(string)) - resp["logs"] = string(enc) + logs, ok := resp["logs"].(string) + if ok { + enc, _ := base64.StdEncoding.DecodeString(logs) + resp["logs"] = string(enc) + } else { + resp["logs"] = "" + } } return &resp, err }