mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-27 16:17:34 +00:00
Feat: add dex login in apiserver (#3417)
* Feat: add dex login in apiserver Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com> * resolve comments Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com> * Fix: get dex config from secret Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com> * Fix: delete cache for dex config Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com> * fix ci Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
This commit is contained in:
@@ -19,7 +19,7 @@ unit-test-core:
|
||||
go test -coverprofile=coverage.txt $(shell go list ./pkg/... ./cmd/... ./apis/... | grep -v apiserver)
|
||||
go test $(shell go list ./references/... | grep -v apiserver)
|
||||
unit-test-apiserver:
|
||||
go test -coverprofile=coverage.txt $(shell go list ./pkg/... ./cmd/... | grep -E 'apiserver|velaql')
|
||||
go test -gcflags=all=-l -coverprofile=coverage.txt $(shell go list ./pkg/... ./cmd/... | grep -E 'apiserver|velaql')
|
||||
|
||||
# Build vela cli binary
|
||||
build: fmt vet lint staticcheck vela-cli kubectl-vela
|
||||
|
||||
@@ -14,6 +14,7 @@ require (
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
|
||||
github.com/briandowns/spinner v1.11.1
|
||||
github.com/containerd/containerd v1.4.13
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible
|
||||
github.com/coreos/prometheus-operator v0.41.1
|
||||
github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
@@ -214,6 +215,7 @@ require (
|
||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
@@ -260,6 +262,7 @@ require (
|
||||
gopkg.in/gorp.v1 v1.7.2 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.2.2 // indirect
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
|
||||
@@ -353,6 +353,7 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
@@ -1359,6 +1360,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/polyfloyd/go-errorlint v0.0.0-20210510181950-ab96adb96fea/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 h1:0XM1XL/OFFJjXsYXlG30spTkV/E9+gmd5GD1w2HE8xM=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/prometheus-community/prom-label-proxy v0.1.1-0.20200616110844-0fbfa11fa8f3/go.mod h1:XdjyZg7LCbCC5FADHtpgNp6kQ0W9beXVGfmcvndMj5Y=
|
||||
github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE=
|
||||
@@ -2385,6 +2387,7 @@ gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
|
||||
@@ -20,11 +20,22 @@ func init() {
|
||||
RegistModel(&SystemInfo{})
|
||||
}
|
||||
|
||||
// LoginType is the type of login
|
||||
type LoginType string
|
||||
|
||||
const (
|
||||
// LoginTypeDex is the dex login type
|
||||
LoginTypeDex LoginType = "dex"
|
||||
// LoginTypeLocal is the local login type
|
||||
LoginTypeLocal LoginType = "local"
|
||||
)
|
||||
|
||||
// SystemInfo systemInfo model
|
||||
type SystemInfo struct {
|
||||
BaseModel
|
||||
InstallID string `json:"installID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
InstallID string `json:"installID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
LoginType LoginType `json:"loginType"`
|
||||
}
|
||||
|
||||
// TableName return custom table name
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
import "strings"
|
||||
|
||||
func init() {
|
||||
RegistModel(&User{})
|
||||
}
|
||||
|
||||
// User is the model of user
|
||||
type User struct {
|
||||
BaseModel
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
Alias string `json:"alias,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Disabled bool `json:"disabled"`
|
||||
}
|
||||
|
||||
// TableName return custom table name
|
||||
func (u *User) TableName() string {
|
||||
return tableNamePrefix + "user"
|
||||
}
|
||||
|
||||
// PrimaryKey return custom primary key
|
||||
func (u *User) PrimaryKey() string {
|
||||
return verifyUserValue(u.Name)
|
||||
}
|
||||
|
||||
// Index return custom index
|
||||
func (u *User) Index() map[string]string {
|
||||
index := make(map[string]string)
|
||||
if u.Name != "" {
|
||||
index["name"] = verifyUserValue(u.Name)
|
||||
}
|
||||
if u.Email != "" {
|
||||
index["email"] = verifyUserValue(u.Email)
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
func verifyUserValue(v string) string {
|
||||
s := strings.ReplaceAll(v, "@", "-")
|
||||
s = strings.ReplaceAll(s, " ", "-")
|
||||
return s
|
||||
}
|
||||
@@ -1080,3 +1080,25 @@ type ChartVersionListResponse struct {
|
||||
type SimpleResponse struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// LoginResponse is the response of login request
|
||||
type LoginResponse struct {
|
||||
UserInfo DetailUserResponse `json:"userInfo"`
|
||||
AccessToken string `json:"accessToken,omitempty"`
|
||||
RefreshToken string `json:"refreshToken,omitempty"`
|
||||
}
|
||||
|
||||
// DetailUserResponse is the detail user info for the response
|
||||
type DetailUserResponse struct {
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias,omitempty"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
// DexConfigResponse is the response of dex config
|
||||
type DexConfigResponse struct {
|
||||
ClientID string `json:"clientID"`
|
||||
ClientSecret string `json:"clientSecret"`
|
||||
RedirectURL string `json:"redirectURL"`
|
||||
Issuer string `json:"issuer"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package usecase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/coreos/go-oidc"
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"golang.org/x/oauth2"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
velatypes "github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/clients"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/log"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils/bcode"
|
||||
)
|
||||
|
||||
const (
|
||||
secretDexConfig = "dex-config"
|
||||
)
|
||||
|
||||
// AuthenticationUsecase is the usecase of authentication
|
||||
type AuthenticationUsecase interface {
|
||||
Login(ctx context.Context, req *restful.Request) (*apisv1.LoginResponse, error)
|
||||
GetDexConfig(ctx context.Context) (*apisv1.DexConfigResponse, error)
|
||||
}
|
||||
|
||||
type authenticationUsecaseImpl struct {
|
||||
sysUsecase SystemInfoUsecase
|
||||
ds datastore.DataStore
|
||||
kubeClient client.Client
|
||||
}
|
||||
|
||||
// NewAuthenticationUsecase new authentication usecase
|
||||
func NewAuthenticationUsecase(ds datastore.DataStore, sysUsecase SystemInfoUsecase) AuthenticationUsecase {
|
||||
kubecli, err := clients.GetKubeClient()
|
||||
if err != nil {
|
||||
log.Logger.Fatalf("failed to get kube client: %s", err.Error())
|
||||
}
|
||||
return &authenticationUsecaseImpl{
|
||||
sysUsecase: sysUsecase,
|
||||
ds: ds,
|
||||
kubeClient: kubecli,
|
||||
}
|
||||
}
|
||||
|
||||
type authHandler interface {
|
||||
login(ctx context.Context) (*apisv1.LoginResponse, error)
|
||||
}
|
||||
|
||||
type dexHandlerImpl struct {
|
||||
token *oauth2.Token
|
||||
idToken *oidc.IDToken
|
||||
ds datastore.DataStore
|
||||
}
|
||||
|
||||
func (a *authenticationUsecaseImpl) newDexHandler(ctx context.Context, req *restful.Request) (*dexHandlerImpl, error) {
|
||||
dexConfig, err := a.GetDexConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
provider, err := oidc.NewProvider(ctx, dexConfig.Issuer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idTokenVerifier := provider.Verifier(&oidc.Config{ClientID: dexConfig.ClientID})
|
||||
code := req.HeaderParameter("code")
|
||||
oauth2Config := &oauth2.Config{
|
||||
ClientID: dexConfig.ClientID,
|
||||
ClientSecret: dexConfig.ClientSecret,
|
||||
Endpoint: provider.Endpoint(),
|
||||
RedirectURL: dexConfig.RedirectURL,
|
||||
}
|
||||
oidcCtx := oidc.ClientContext(ctx, http.DefaultClient)
|
||||
token, err := oauth2Config.Exchange(oidcCtx, code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idToken, err := idTokenVerifier.Verify(ctx, token.Extra("id_token").(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dexHandlerImpl{
|
||||
token: token,
|
||||
idToken: idToken,
|
||||
ds: a.ds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *authenticationUsecaseImpl) Login(ctx context.Context, req *restful.Request) (*apisv1.LoginResponse, error) {
|
||||
var handler authHandler
|
||||
var err error
|
||||
sysInfo, err := a.sysUsecase.GetSystemInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loginType := sysInfo.LoginType
|
||||
|
||||
switch loginType {
|
||||
case model.LoginTypeDex:
|
||||
handler, err = a.newDexHandler(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case model.LoginTypeLocal:
|
||||
default:
|
||||
return nil, bcode.ErrUnsupportedLoginType
|
||||
}
|
||||
return handler.login(ctx)
|
||||
}
|
||||
|
||||
func (a *authenticationUsecaseImpl) GetDexConfig(ctx context.Context) (*apisv1.DexConfigResponse, error) {
|
||||
secret := &v1.Secret{}
|
||||
if err := a.kubeClient.Get(ctx, types.NamespacedName{
|
||||
Name: secretDexConfig,
|
||||
Namespace: velatypes.DefaultKubeVelaNS,
|
||||
}, secret); err != nil {
|
||||
log.Logger.Errorf("failed to get dex config: %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
var config struct {
|
||||
Issuer string `json:"issuer"`
|
||||
StaticClients []struct {
|
||||
ID string `json:"id"`
|
||||
Secret string `json:"secret"`
|
||||
RedirectURIs []string `json:"redirectURIs"`
|
||||
} `json:"staticClients"`
|
||||
}
|
||||
if err := json.Unmarshal(secret.Data[secretDexConfig], &config); err != nil {
|
||||
log.Logger.Errorf("failed to unmarshal dex config: %s", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if len(config.StaticClients) < 1 || len(config.StaticClients[0].RedirectURIs) < 1 {
|
||||
return nil, fmt.Errorf("invalid dex config")
|
||||
}
|
||||
return &apisv1.DexConfigResponse{
|
||||
Issuer: config.Issuer,
|
||||
ClientID: config.StaticClients[0].ID,
|
||||
ClientSecret: config.StaticClients[0].Secret,
|
||||
RedirectURL: config.StaticClients[0].RedirectURIs[0],
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *dexHandlerImpl) login(ctx context.Context) (*apisv1.LoginResponse, error) {
|
||||
var claims struct {
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
if err := d.idToken.Claims(&claims); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user := &model.User{Email: claims.Email}
|
||||
users, err := d.ds.List(ctx, user, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(users) > 0 {
|
||||
u := users[0].(*model.User)
|
||||
if u.Name != claims.Name {
|
||||
u.Name = claims.Name
|
||||
if err := d.ds.Put(ctx, u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else if err := d.ds.Add(ctx, &model.User{
|
||||
Email: claims.Email,
|
||||
Name: claims.Name,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &apisv1.LoginResponse{
|
||||
UserInfo: apisv1.DetailUserResponse{
|
||||
Name: claims.Name,
|
||||
Email: claims.Email,
|
||||
},
|
||||
AccessToken: d.token.AccessToken,
|
||||
RefreshToken: d.token.RefreshToken,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package usecase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
. "github.com/agiledragon/gomonkey/v2"
|
||||
"github.com/coreos/go-oidc"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"golang.org/x/oauth2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
var _ = Describe("Test authentication usecase functions", func() {
|
||||
var (
|
||||
authUsecase *authenticationUsecaseImpl
|
||||
ds datastore.DataStore
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
ds, err = NewDatastore(datastore.Config{Type: "kubeapi", Database: "auth-test-" + strconv.FormatInt(time.Now().UnixNano(), 10)})
|
||||
Expect(ds).ToNot(BeNil())
|
||||
Expect(err).Should(BeNil())
|
||||
authUsecase = &authenticationUsecaseImpl{kubeClient: k8sClient, ds: ds}
|
||||
})
|
||||
It("Test Dex login", func() {
|
||||
testIDToken := &oidc.IDToken{}
|
||||
patch := ApplyMethod(reflect.TypeOf(testIDToken), "Claims", func(_ *oidc.IDToken, v interface{}) error {
|
||||
return json.Unmarshal([]byte(`{"email":"test@test.com","name":"test"}`), v)
|
||||
})
|
||||
defer patch.Reset()
|
||||
dexHandler := dexHandlerImpl{
|
||||
token: &oauth2.Token{
|
||||
AccessToken: "access-token",
|
||||
RefreshToken: "refresh-token",
|
||||
},
|
||||
idToken: testIDToken,
|
||||
ds: ds,
|
||||
}
|
||||
resp, err := dexHandler.login(context.Background())
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(resp.UserInfo.Email).Should(Equal("test@test.com"))
|
||||
Expect(resp.UserInfo.Name).Should(Equal("test"))
|
||||
Expect(resp.AccessToken).Should(Equal("access-token"))
|
||||
Expect(resp.RefreshToken).Should(Equal("refresh-token"))
|
||||
|
||||
user := &model.User{
|
||||
Name: "test",
|
||||
}
|
||||
err = ds.Get(context.Background(), user)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(user.Email).Should(Equal("test@test.com"))
|
||||
})
|
||||
|
||||
It("Test get dex config", func() {
|
||||
err := k8sClient.Create(context.Background(), &corev1.Namespace{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "vela-system",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
err = k8sClient.Create(context.Background(), &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secretDexConfig,
|
||||
Namespace: "vela-system",
|
||||
},
|
||||
StringData: map[string]string{
|
||||
secretDexConfig: `{"issuer":"https://dex.oam.dev","staticClients":[{"id":"client-id","secret":"client-secret","redirectURIs":["http://localhost:8080/auth/callback"]}]}`,
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
config, err := authUsecase.GetDexConfig(context.Background())
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(config.Issuer).Should(Equal("https://dex.oam.dev"))
|
||||
Expect(config.ClientID).Should(Equal("client-id"))
|
||||
Expect(config.ClientSecret).Should(Equal("client-secret"))
|
||||
Expect(config.RedirectURL).Should(Equal("http://localhost:8080/auth/callback"))
|
||||
})
|
||||
|
||||
})
|
||||
@@ -60,6 +60,7 @@ func (u systemInfoUsecaseImpl) GetSystemInfo(ctx context.Context) (*v1.SystemInf
|
||||
installID := rand.String(16)
|
||||
info.InstallID = installID
|
||||
info.EnableCollection = true
|
||||
info.LoginType = model.LoginTypeLocal
|
||||
err = u.ds.Add(ctx, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package bcode
|
||||
|
||||
// ErrUnsupportedLoginType is the error of unsupported login type
|
||||
var ErrUnsupportedLoginType = NewBcode(400, 12001, "the login type is not supported")
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package webservice
|
||||
|
||||
import (
|
||||
restfulspec "github.com/emicklei/go-restful-openapi/v2"
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
|
||||
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/usecase"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils/bcode"
|
||||
)
|
||||
|
||||
type authenticationWebService struct {
|
||||
authenticationUsecase usecase.AuthenticationUsecase
|
||||
}
|
||||
|
||||
// NewAuthenticationWebService is the webservice of authentication
|
||||
func NewAuthenticationWebService(authenticationUsecase usecase.AuthenticationUsecase) WebService {
|
||||
return &authenticationWebService{
|
||||
authenticationUsecase: authenticationUsecase,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *authenticationWebService) GetWebService() *restful.WebService {
|
||||
ws := new(restful.WebService)
|
||||
ws.Path(versionPrefix).
|
||||
Consumes(restful.MIME_XML, restful.MIME_JSON).
|
||||
Produces(restful.MIME_JSON, restful.MIME_XML).
|
||||
Doc("api for authentication manage")
|
||||
|
||||
tags := []string{"authentication"}
|
||||
|
||||
ws.Route(ws.GET("/login").To(c.login).
|
||||
Doc("handle login request").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Returns(200, "", apis.LoginResponse{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.LoginResponse{}))
|
||||
|
||||
ws.Route(ws.GET("/dexConfig").To(c.getDexConfig).
|
||||
Doc("get Dex config").
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Returns(200, "", apis.DexConfigResponse{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.DexConfigResponse{}))
|
||||
return ws
|
||||
}
|
||||
|
||||
func (c *authenticationWebService) login(req *restful.Request, res *restful.Response) {
|
||||
base, err := c.authenticationUsecase.Login(req.Request.Context(), req)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := res.WriteEntity(base); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (c *authenticationWebService) getDexConfig(req *restful.Request, res *restful.Response) {
|
||||
base, err := c.authenticationUsecase.GetDexConfig(req.Request.Context())
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := res.WriteEntity(base); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@ func Init(ds datastore.DataStore, addonCacheTime time.Duration) {
|
||||
webhookUsecase := usecase.NewWebhookUsecase(ds, applicationUsecase)
|
||||
systemInfoUsecase := usecase.NewSystemInfoUsecase(ds)
|
||||
helmUsecase := usecase.NewHelmUsecase()
|
||||
authenticationUsecase := usecase.NewAuthenticationUsecase(ds, systemInfoUsecase)
|
||||
|
||||
// init for default values
|
||||
|
||||
@@ -97,6 +98,9 @@ func Init(ds datastore.DataStore, addonCacheTime time.Duration) {
|
||||
RegisterWebService(NewVelaQLWebService(velaQLUsecase))
|
||||
RegisterWebService(NewWebhookWebService(webhookUsecase, applicationUsecase))
|
||||
|
||||
// Authentication
|
||||
RegisterWebService(NewAuthenticationWebService(authenticationUsecase))
|
||||
|
||||
RegisterWebService(NewSystemInfoWebService(systemInfoUsecase))
|
||||
|
||||
RegisterWebService(NewHelmWebService(helmUsecase))
|
||||
|
||||
Reference in New Issue
Block a user