[Backport release-1.5] Fix: support to test authentication with dex (#4440)

* Fix: support to test login with dex

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 8d0d20fd60)

* Fix: support to update the user when the login mode is dex

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 442d4601e9)

* Fix: systemInfoService is nil

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 392637e69d)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
This commit is contained in:
github-actions[bot]
2022-07-25 15:53:22 +08:00
committed by GitHub
co-authored by barnettZQG
parent ca2a90a097
commit 853f44cf61
5 changed files with 66 additions and 25 deletions
+22
View File
@@ -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"`
}
+21 -9
View File
@@ -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)
@@ -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())
+8 -8
View File
@@ -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
+7 -2
View File
@@ -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
}