From eb8a3c0dc60d010d50243f7061e64ba0cedf8765 Mon Sep 17 00:00:00 2001 From: zryfish Date: Sun, 15 Mar 2020 17:55:55 +0800 Subject: [PATCH] refactor authentication (#1950) --- .travis.yml | 11 ++- cmd/ks-apiserver/app/options/options.go | 4 +- hack/docker_build.sh | 9 +- pkg/api/iam/authenticate.go | 16 ++- pkg/api/iam/token/issuer.go | 10 ++ pkg/api/iam/token/jwt.go | 75 ++++++++++++++ pkg/api/iam/token/jwt_test.go | 49 +++++++++ pkg/api/iam/token/user.go | 8 ++ pkg/api/iam/user.go | 8 ++ pkg/api/utils.go | 19 ++-- pkg/apiserver/apiserver.go | 7 +- .../authenticators/jwttoken/jwt_token.go | 57 +++++++++++ .../authentication/request/anonymous.go | 24 +++++ pkg/apiserver/authentication/token/token.go | 1 + .../authentication/token_authenticator.go | 36 ------- pkg/kapis/devops/v1alpha2/member.go | 34 +++---- pkg/kapis/devops/v1alpha2/pipeline_sonar.go | 8 +- pkg/kapis/devops/v1alpha2/project.go | 10 +- .../devops/v1alpha2/project_credential.go | 14 +-- pkg/kapis/devops/v1alpha2/project_pipeline.go | 20 ++-- pkg/kapis/devops/v1alpha2/s2ibinary.go | 18 ++-- pkg/kapis/iam/v1alpha2/handler.go | 99 +++++++------------ pkg/kapis/logging/v1alpha2/handler.go | 10 +- pkg/kapis/monitoring/v1alpha2/handler.go | 22 ++--- pkg/kapis/openpitrix/v1/handler.go | 82 +++++++-------- pkg/kapis/resources/v1alpha2/handler.go | 34 +++---- pkg/kapis/resources/v1alpha3/handler.go | 10 +- .../servicemesh/metrics/v1alpha2/handler.go | 4 +- pkg/kapis/tenant/v1alpha2/handler.go | 40 ++++---- pkg/models/iam/im.go | 74 ++++++++------ pkg/simple/client/ldap/simple_ldap.go | 20 +++- pkg/utils/jwtutil/jwt.go | 70 ------------- 32 files changed, 522 insertions(+), 381 deletions(-) create mode 100644 pkg/api/iam/token/issuer.go create mode 100644 pkg/api/iam/token/jwt.go create mode 100644 pkg/api/iam/token/jwt_test.go create mode 100644 pkg/api/iam/token/user.go create mode 100644 pkg/apiserver/authentication/authenticators/jwttoken/jwt_token.go create mode 100644 pkg/apiserver/authentication/request/anonymous.go create mode 100644 pkg/apiserver/authentication/token/token.go delete mode 100644 pkg/apiserver/authentication/token_authenticator.go delete mode 100644 pkg/utils/jwtutil/jwt.go diff --git a/.travis.yml b/.travis.yml index d2fc8156b..b72b24259 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,8 +31,9 @@ after_success: - bash <(curl -s https://codecov.io/bash) deploy: - skip_cleanup: true - provider: script - script: bash hack/docker_build.sh - on: - branch: master + - skip_cleanup: true + provider: script + script: bash hack/docker_build.sh + on: + all_branches: true + condition: $TRAVIS_BRANCH =~ ^(master|dev)$ diff --git a/cmd/ks-apiserver/app/options/options.go b/cmd/ks-apiserver/app/options/options.go index 5026ab5a8..4bb580406 100644 --- a/cmd/ks-apiserver/app/options/options.go +++ b/cmd/ks-apiserver/app/options/options.go @@ -99,7 +99,9 @@ const fakeInterface string = "FAKE" // NewAPIServer creates an APIServer instance using given options func (s *ServerRunOptions) NewAPIServer(stopCh <-chan struct{}) (*apiserver.APIServer, error) { - apiServer := &apiserver.APIServer{} + apiServer := &apiserver.APIServer{ + AuthenticateOptions: s.AuthenticateOptions, + } kubernetesClient, err := k8s.NewKubernetesClient(s.KubernetesOptions) if err != nil { diff --git a/hack/docker_build.sh b/hack/docker_build.sh index ee567e409..4aa51ea12 100755 --- a/hack/docker_build.sh +++ b/hack/docker_build.sh @@ -3,8 +3,9 @@ set -ex set -o pipefail +# push to kubespheredev with default latest tag REPO=kubespheredev -TAG=latest +TAG=${TRAVIS_BRANCH:-latest} # check if build was triggered by a travis cronjob if [[ -z "$TRAVIS_EVENT_TYPE" ]]; then @@ -14,17 +15,11 @@ elif [[ $TRAVIS_EVENT_TYPE == "cron" ]]; then fi -docker build -f build/ks-apigateway/Dockerfile -t $REPO/ks-apigateway:$TAG . docker build -f build/ks-apiserver/Dockerfile -t $REPO/ks-apiserver:$TAG . docker build -f build/ks-controller-manager/Dockerfile -t $REPO/ks-controller-manager:$TAG . -docker build -f build/hypersphere/Dockerfile -t $REPO/hypersphere:$TAG . -docker build -f ./pkg/db/Dockerfile -t $REPO/ks-devops:flyway-$TAG ./pkg/db/ # Push image to dockerhub, need to support multiple push echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin -docker push $REPO/ks-apigateway:$TAG docker push $REPO/ks-apiserver:$TAG docker push $REPO/ks-controller-manager:$TAG -docker push $REPO/hypersphere:$TAG -docker push $REPO/ks-devops:flyway-$TAG diff --git a/pkg/api/iam/authenticate.go b/pkg/api/iam/authenticate.go index c504728fc..46ecac6dc 100644 --- a/pkg/api/iam/authenticate.go +++ b/pkg/api/iam/authenticate.go @@ -1,6 +1,7 @@ package iam import ( + "fmt" "github.com/spf13/pflag" "time" ) @@ -14,10 +15,14 @@ type AuthenticationOptions struct { MaxAuthenticateRetries int // token validation duration, will refresh token expiration for each user request + // 0 means never expire TokenExpiration time.Duration // allow multiple users login at the same time MultipleLogin bool + + // secret to signed jwt token + JwtSecret string } func NewAuthenticateOptions() *AuthenticationOptions { @@ -27,11 +32,17 @@ func NewAuthenticateOptions() *AuthenticationOptions { MaxAuthenticateRetries: 0, TokenExpiration: 0, MultipleLogin: false, + JwtSecret: "", } } func (options *AuthenticationOptions) Validate() []error { var errs []error + + if len(options.JwtSecret) == 0 { + errs = append(errs, fmt.Errorf("jwt secret is empty")) + } + return errs } @@ -39,6 +50,7 @@ func (options *AuthenticationOptions) AddFlags(fs *pflag.FlagSet, s *Authenticat fs.IntVar(&options.AuthenticateRateLimiterMaxTries, "authenticate-rate-limiter-max-retries", s.AuthenticateRateLimiterMaxTries, "") fs.DurationVar(&options.AuthenticateRateLimiterDuration, "authenticate-rate-limiter-duration", s.AuthenticateRateLimiterDuration, "") fs.IntVar(&options.MaxAuthenticateRetries, "authenticate-max-retries", s.MaxAuthenticateRetries, "") - fs.DurationVar(&options.TokenExpiration, "token-expiration", s.TokenExpiration, "") - fs.BoolVar(&options.MultipleLogin, "multiple-login", s.MultipleLogin, "") + fs.DurationVar(&options.TokenExpiration, "token-expiration", s.TokenExpiration, "Token expire duration, for example 30m/2h/1d, 0 means token never expire unless server restart.") + fs.BoolVar(&options.MultipleLogin, "multiple-login", s.MultipleLogin, "Allow multiple login with the same account, disable means only one user can login at the same time.") + fs.StringVar(&options.JwtSecret, "jwt-secret", s.JwtSecret, "Secret to sign jwt token, must not be empty.") } diff --git a/pkg/api/iam/token/issuer.go b/pkg/api/iam/token/issuer.go new file mode 100644 index 000000000..199ce26e1 --- /dev/null +++ b/pkg/api/iam/token/issuer.go @@ -0,0 +1,10 @@ +package token + +// Issuer issues token to user, tokens are required to perform mutating requests to resources +type Issuer interface { + // IssueTo issues a token a User, return error if issuing process failed + IssueTo(User) (string, error) + + // Verify verifies a token, and return a User if it's a valid token, otherwise return error + Verify(string) (User, error) +} diff --git a/pkg/api/iam/token/jwt.go b/pkg/api/iam/token/jwt.go new file mode 100644 index 000000000..b85fe38d5 --- /dev/null +++ b/pkg/api/iam/token/jwt.go @@ -0,0 +1,75 @@ +package token + +import ( + "fmt" + "github.com/dgrijalva/jwt-go" + "kubesphere.io/kubesphere/pkg/api/iam" + "kubesphere.io/kubesphere/pkg/server/errors" + "time" +) + +const DefaultIssuerName = "kubesphere" + +var errInvalidToken = errors.New("invalid token") + +type claims struct { + Username string `json:"username"` + UID string `json:"uid"` + // Currently, we are not using any field in jwt.StandardClaims + jwt.StandardClaims +} + +type jwtTokenIssuer struct { + name string + secret []byte + keyFunc jwt.Keyfunc +} + +func (s *jwtTokenIssuer) Verify(tokenString string) (User, error) { + if len(tokenString) == 0 { + return nil, errInvalidToken + } + + clm := &claims{} + + _, err := jwt.ParseWithClaims(tokenString, clm, s.keyFunc) + if err != nil { + return nil, err + } + + return &iam.User{Username: clm.Username, Email: clm.UID}, nil +} + +func (s *jwtTokenIssuer) IssueTo(user User) (string, error) { + clm := &claims{ + Username: user.Name(), + UID: user.UID(), + StandardClaims: jwt.StandardClaims{ + IssuedAt: time.Now().Unix(), + Issuer: s.name, + NotBefore: time.Now().Unix(), + }, + } + + token := jwt.NewWithClaims(jwt.SigningMethodHS256, clm) + tokenString, err := token.SignedString(s.secret) + if err != nil { + return "", err + } + + return tokenString, nil +} + +func NewJwtTokenIssuer(issuerName string, secret []byte) Issuer { + return &jwtTokenIssuer{ + name: issuerName, + secret: secret, + keyFunc: func(token *jwt.Token) (i interface{}, err error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok { + return secret, nil + } else { + return nil, fmt.Errorf("expect token signed with HMAC but got %v", token.Header["alg"]) + } + }, + } +} diff --git a/pkg/api/iam/token/jwt_test.go b/pkg/api/iam/token/jwt_test.go new file mode 100644 index 000000000..ae5343b68 --- /dev/null +++ b/pkg/api/iam/token/jwt_test.go @@ -0,0 +1,49 @@ +package token + +import ( + "github.com/google/go-cmp/cmp" + "kubesphere.io/kubesphere/pkg/api/iam" + "testing" +) + +func TestJwtTokenIssuer(t *testing.T) { + issuer := NewJwtTokenIssuer(DefaultIssuerName, []byte("kubesphere")) + + testCases := []struct { + description string + name string + email string + }{ + { + name: "admin", + email: "admin@kubesphere.io", + }, + { + name: "bar", + email: "bar@kubesphere.io", + }, + } + + for _, testCase := range testCases { + user := &iam.User{ + Username: testCase.name, + Email: testCase.email, + } + + t.Run(testCase.description, func(t *testing.T) { + token, err := issuer.IssueTo(user) + if err != nil { + t.Fatal(err) + } + + got, err := issuer.Verify(token) + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(user, got); len(diff) != 0 { + t.Errorf("%T differ (-got, +expected), %s", user, diff) + } + }) + } +} diff --git a/pkg/api/iam/token/user.go b/pkg/api/iam/token/user.go new file mode 100644 index 000000000..d29768dd8 --- /dev/null +++ b/pkg/api/iam/token/user.go @@ -0,0 +1,8 @@ +package token + +type User interface { + // Name + Name() string + + UID() string +} diff --git a/pkg/api/iam/user.go b/pkg/api/iam/user.go index 8e12248d6..759ad9cfd 100644 --- a/pkg/api/iam/user.go +++ b/pkg/api/iam/user.go @@ -27,6 +27,14 @@ func NewUser() *User { } } +func (u *User) Name() string { + return u.Username +} + +func (u *User) UID() string { + return u.Email +} + func (u *User) Validate() error { if u.Username == "" { return errors.New("username can not be empty") diff --git a/pkg/api/utils.go b/pkg/api/utils.go index c59cd1a7a..ac6de4b29 100644 --- a/pkg/api/utils.go +++ b/pkg/api/utils.go @@ -5,20 +5,19 @@ import ( "net/http" ) -func HandleInternalError(response *restful.Response, err error) { - statusCode := http.StatusInternalServerError - - response.WriteError(statusCode, err) +func HandleInternalError(response *restful.Response, req *restful.Request, err error) { + response.WriteError(http.StatusInternalServerError, err) } -func HandleBadRequest(response *restful.Response, err error) { - +// HandleBadRequest writes http.StatusBadRequest and log error +func HandleBadRequest(response *restful.Response, req *restful.Request, err error) { + response.WriteError(http.StatusBadRequest, err) } -func HandleNotFound(response *restful.Response, err error) { - +func HandleNotFound(response *restful.Response, req *restful.Request, err error) { + response.WriteError(http.StatusNotFound, err) } -func HandleForbidden(response *restful.Response, err error) { - +func HandleForbidden(response *restful.Response, req *restful.Request, err error) { + response.WriteError(http.StatusForbidden, err) } diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 4e605fb8b..82a730d3d 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -9,11 +9,13 @@ import ( urlruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/authentication/request/bearertoken" + "k8s.io/apiserver/pkg/authentication/request/union" "k8s.io/apiserver/pkg/authorization/authorizerfactory" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" "k8s.io/klog" "kubesphere.io/kubesphere/pkg/api/iam" - "kubesphere.io/kubesphere/pkg/apiserver/authentication" + "kubesphere.io/kubesphere/pkg/apiserver/authentication/authenticators/jwttoken" + authenticationrequest "kubesphere.io/kubesphere/pkg/apiserver/authentication/request" "kubesphere.io/kubesphere/pkg/apiserver/dispatch" "kubesphere.io/kubesphere/pkg/apiserver/filters" "kubesphere.io/kubesphere/pkg/apiserver/request" @@ -179,7 +181,8 @@ func (s *APIServer) buildHandlerChain() { handler = filters.WithMultipleClusterDispatcher(handler, dispatch.DefaultClusterDispatch) handler = filters.WithAuthorization(handler, authorizerfactory.NewAlwaysAllowAuthorizer()) - handler = filters.WithAuthentication(handler, bearertoken.New(authentication.NewTokenAuthenticator(s.CacheClient)), failed) + authn := union.New(&authenticationrequest.AnonymousAuthenticator{}, bearertoken.New(jwttoken.NewTokenAuthenticator(s.CacheClient, s.AuthenticateOptions.JwtSecret))) + handler = filters.WithAuthentication(handler, authn, failed) handler = filters.WithRequestInfo(handler, requestInfoResolver) s.Server.Handler = handler diff --git a/pkg/apiserver/authentication/authenticators/jwttoken/jwt_token.go b/pkg/apiserver/authentication/authenticators/jwttoken/jwt_token.go new file mode 100644 index 000000000..f860d979c --- /dev/null +++ b/pkg/apiserver/authentication/authenticators/jwttoken/jwt_token.go @@ -0,0 +1,57 @@ +package jwttoken + +import ( + "context" + "fmt" + "k8s.io/apiserver/pkg/authentication/authenticator" + "k8s.io/apiserver/pkg/authentication/user" + "kubesphere.io/kubesphere/pkg/api/iam/token" + "kubesphere.io/kubesphere/pkg/server/errors" + "kubesphere.io/kubesphere/pkg/simple/client/cache" +) + +var errTokenExpired = errors.New("expired token") + +// TokenAuthenticator implements kubernetes token authenticate interface with our custom logic. +// TokenAuthenticator will retrieve user info from cache by given token. If empty or invalid token +// was given, authenticator will still give passed response at the condition user will be user.Anonymous +// and group from user.AllUnauthenticated. This helps requests be passed along the handler chain, +// because some resources are public accessible. +type tokenAuthenticator struct { + cacheClient cache.Interface + jwtTokenIssuer token.Issuer +} + +func NewTokenAuthenticator(cacheClient cache.Interface, jwtSecret string) authenticator.Token { + return &tokenAuthenticator{ + cacheClient: cacheClient, + jwtTokenIssuer: token.NewJwtTokenIssuer(token.DefaultIssuerName, []byte(jwtSecret)), + } +} + +func (t *tokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) { + providedUser, err := t.jwtTokenIssuer.Verify(token) + if err != nil { + return nil, false, err + } + + _, err = t.cacheClient.Get(tokenKeyForUsername(providedUser.Name(), token)) + if err != nil { + return nil, false, errTokenExpired + } + + // Should we need to refresh token? + + return &authenticator.Response{ + User: &user.DefaultInfo{ + Name: providedUser.Name(), + UID: providedUser.UID(), + Groups: []string{user.AllAuthenticated}, + }, + }, true, nil + +} + +func tokenKeyForUsername(username, token string) string { + return fmt.Sprintf("kubesphere:users:%s:token:%s", username, token) +} diff --git a/pkg/apiserver/authentication/request/anonymous.go b/pkg/apiserver/authentication/request/anonymous.go new file mode 100644 index 000000000..f309e4564 --- /dev/null +++ b/pkg/apiserver/authentication/request/anonymous.go @@ -0,0 +1,24 @@ +package request + +import ( + "k8s.io/apiserver/pkg/authentication/authenticator" + "k8s.io/apiserver/pkg/authentication/user" + "net/http" + "strings" +) + +type AnonymousAuthenticator struct{} + +func (a *AnonymousAuthenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { + auth := strings.TrimSpace(req.Header.Get("Authorization")) + if auth == "" { + return &authenticator.Response{ + User: &user.DefaultInfo{ + Name: user.Anonymous, + UID: "", + Groups: []string{user.AllUnauthenticated}, + }, + }, true, nil + } + return nil, false, nil +} diff --git a/pkg/apiserver/authentication/token/token.go b/pkg/apiserver/authentication/token/token.go new file mode 100644 index 000000000..1765cc067 --- /dev/null +++ b/pkg/apiserver/authentication/token/token.go @@ -0,0 +1 @@ +package token diff --git a/pkg/apiserver/authentication/token_authenticator.go b/pkg/apiserver/authentication/token_authenticator.go deleted file mode 100644 index 8d2ca791d..000000000 --- a/pkg/apiserver/authentication/token_authenticator.go +++ /dev/null @@ -1,36 +0,0 @@ -package authentication - -import ( - "context" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - "kubesphere.io/kubesphere/pkg/simple/client/cache" -) - -// TokenAuthenticator implements kubernetes token authenticate interface with our custom logic. -// TokenAuthenticator will retrieve user info from cache by given token. If empty or invalid token -// was given, authenticator will still give passed response at the condition user will be user.Anonymous -// and group from user.AllUnauthenticated. This helps requests be passed along the handler chain, -// because some resources are public accessible. -type tokenAuthenticator struct { - cacheClient cache.Interface -} - -func NewTokenAuthenticator(cacheClient cache.Interface) authenticator.Token { - return &tokenAuthenticator{ - cacheClient: cacheClient, - } -} - -func (t *tokenAuthenticator) AuthenticateToken(ctx context.Context, token string) (*authenticator.Response, bool, error) { - //if len(token) == 0 { - return &authenticator.Response{ - User: &user.DefaultInfo{ - Name: user.Anonymous, - UID: "", - Groups: []string{user.AllUnauthenticated}, - Extra: nil, - }, - }, true, nil - //} -} diff --git a/pkg/kapis/devops/v1alpha2/member.go b/pkg/kapis/devops/v1alpha2/member.go index 29f383fe4..d0c045f47 100644 --- a/pkg/kapis/devops/v1alpha2/member.go +++ b/pkg/kapis/devops/v1alpha2/member.go @@ -33,7 +33,7 @@ func (h ProjectPipelineHandler) GetDevOpsProjectMembersHandler(request *restful. err := h.projectOperator.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } orderBy := request.QueryParameter(params.OrderByParam) @@ -45,7 +45,7 @@ func (h ProjectPipelineHandler) GetDevOpsProjectMembersHandler(request *restful. if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -62,14 +62,14 @@ func (h ProjectPipelineHandler) GetDevOpsProjectMemberHandler(request *restful.R err := h.projectOperator.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } project, err := h.projectMemberOperator.GetProjectMember(projectId, member) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -85,26 +85,26 @@ func (h ProjectPipelineHandler) AddDevOpsProjectMemberHandler(request *restful.R err := request.ReadEntity(&member) if err != nil { klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, request, err) return } if govalidator.IsNull(member.Username) { err := fmt.Errorf("error need username") klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, request, err) return } if !reflectutils.In(member.Role, devops.AllRoleSlice) { err := fmt.Errorf("err role [%s] not in [%s]", member.Role, devops.AllRoleSlice) klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, request, err) return } err = h.projectOperator.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } @@ -113,7 +113,7 @@ func (h ProjectPipelineHandler) AddDevOpsProjectMemberHandler(request *restful.R if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -129,41 +129,41 @@ func (h ProjectPipelineHandler) UpdateDevOpsProjectMemberHandler(request *restfu err := request.ReadEntity(&member) if err != nil { klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, request, err) return } member.Username = request.PathParameter("member") if govalidator.IsNull(member.Username) { err := fmt.Errorf("error need username") klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, request, err) return } if username == member.Username { err := fmt.Errorf("you can not change your role") klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, request, err) return } if !reflectutils.In(member.Role, devops.AllRoleSlice) { err := fmt.Errorf("err role [%s] not in [%s]", member.Role, devops.AllRoleSlice) klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, request, err) return } err = h.projectOperator.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } project, err := h.projectMemberOperator.UpdateProjectMember(projectId, member) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -180,13 +180,13 @@ func (h ProjectPipelineHandler) DeleteDevOpsProjectMemberHandler(request *restfu err := h.projectOperator.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } username, err = h.projectMemberOperator.DeleteProjectMember(projectId, member) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } resp.WriteAsJson(struct { diff --git a/pkg/kapis/devops/v1alpha2/pipeline_sonar.go b/pkg/kapis/devops/v1alpha2/pipeline_sonar.go index ceee6e975..9f8456cba 100644 --- a/pkg/kapis/devops/v1alpha2/pipeline_sonar.go +++ b/pkg/kapis/devops/v1alpha2/pipeline_sonar.go @@ -15,13 +15,13 @@ func (h PipelineSonarHandler) GetPipelineSonarStatusHandler(request *restful.Req err := h.projectOperator.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } sonarStatus, err := h.pipelineSonarGetter.GetPipelineSonar(projectId, pipelineId) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } resp.WriteAsJson(sonarStatus) @@ -35,13 +35,13 @@ func (h PipelineSonarHandler) GetMultiBranchesPipelineSonarStatusHandler(request err := h.projectOperator.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } sonarStatus, err := h.pipelineSonarGetter.GetMultiBranchPipelineSonar(projectId, pipelineId, branchId) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } resp.WriteAsJson(sonarStatus) diff --git a/pkg/kapis/devops/v1alpha2/project.go b/pkg/kapis/devops/v1alpha2/project.go index 590f7e5d7..94453a597 100644 --- a/pkg/kapis/devops/v1alpha2/project.go +++ b/pkg/kapis/devops/v1alpha2/project.go @@ -30,14 +30,14 @@ func (h ProjectPipelineHandler) GetDevOpsProjectHandler(request *restful.Request err := h.projectOperator.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } project, err := h.projectOperator.GetProject(projectId) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -53,21 +53,21 @@ func (h ProjectPipelineHandler) UpdateProjectHandler(request *restful.Request, r err := request.ReadEntity(&project) if err != nil { klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, request, err) return } project.ProjectId = projectId err = h.projectOperator.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } project, err = h.projectOperator.UpdateProject(project) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } diff --git a/pkg/kapis/devops/v1alpha2/project_credential.go b/pkg/kapis/devops/v1alpha2/project_credential.go index fb5af8c60..eb452646f 100644 --- a/pkg/kapis/devops/v1alpha2/project_credential.go +++ b/pkg/kapis/devops/v1alpha2/project_credential.go @@ -29,14 +29,14 @@ func (h ProjectPipelineHandler) CreateDevOpsProjectCredentialHandler(request *re err := request.ReadEntity(&credential) if err != nil { klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } credentialId, err := h.projectCredentialOperator.CreateProjectCredential(projectId, username, credential) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -54,14 +54,14 @@ func (h ProjectPipelineHandler) UpdateDevOpsProjectCredentialHandler(request *re err := request.ReadEntity(&credential) if err != nil { klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } credentialId, err = h.projectCredentialOperator.UpdateProjectCredential(projectId, credentialId, credential) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -80,7 +80,7 @@ func (h ProjectPipelineHandler) DeleteDevOpsProjectCredentialHandler(request *re if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -99,7 +99,7 @@ func (h ProjectPipelineHandler) GetDevOpsProjectCredentialHandler(request *restf if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -113,7 +113,7 @@ func (h ProjectPipelineHandler) GetDevOpsProjectCredentialsHandler(request *rest jenkinsCredentials, err := h.projectCredentialOperator.GetProjectCredentials(projectId) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } resp.WriteAsJson(jenkinsCredentials) diff --git a/pkg/kapis/devops/v1alpha2/project_pipeline.go b/pkg/kapis/devops/v1alpha2/project_pipeline.go index e1ad0158a..5173bb8d0 100644 --- a/pkg/kapis/devops/v1alpha2/project_pipeline.go +++ b/pkg/kapis/devops/v1alpha2/project_pipeline.go @@ -29,20 +29,20 @@ func (h ProjectPipelineHandler) CreateDevOpsProjectPipelineHandler(request *rest err := request.ReadEntity(&pipeline) if err != nil { klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } err = h.projectOperator.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner, devops.ProjectMaintainer}) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } pipelineName, err := h.projectPipelineOperator.CreateProjectPipeline(projectId, pipeline) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -60,14 +60,14 @@ func (h ProjectPipelineHandler) DeleteDevOpsProjectPipelineHandler(request *rest err := h.projectOperator.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner, devops.ProjectMaintainer}) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, request, err) return } pipelineName, err := h.projectPipelineOperator.DeleteProjectPipeline(projectId, pipelineId) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -86,20 +86,20 @@ func (h ProjectPipelineHandler) UpdateDevOpsProjectPipelineHandler(request *rest err := request.ReadEntity(&pipeline) if err != nil { klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } err = h.projectOperator.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner, devops.ProjectMaintainer}) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } pipelineName, err := h.projectPipelineOperator.UpdateProjectPipeline(projectId, pipelineId, pipeline) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -118,14 +118,14 @@ func (h ProjectPipelineHandler) GetDevOpsProjectPipelineConfigHandler(request *r err := h.projectOperator.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner, devops.ProjectMaintainer}) if err != nil { klog.Errorf("%+v", err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } pipeline, err := h.projectPipelineOperator.GetProjectPipelineConfig(projectId, pipelineId) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } diff --git a/pkg/kapis/devops/v1alpha2/s2ibinary.go b/pkg/kapis/devops/v1alpha2/s2ibinary.go index 1a3a2dac0..1deb9cdb5 100644 --- a/pkg/kapis/devops/v1alpha2/s2ibinary.go +++ b/pkg/kapis/devops/v1alpha2/s2ibinary.go @@ -22,38 +22,38 @@ func (h S2iBinaryHandler) UploadS2iBinaryHandler(req *restful.Request, resp *res err := req.Request.ParseMultipartForm(bytefmt.MEGABYTE * 20) if err != nil { klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } if len(req.Request.MultipartForm.File) == 0 { err := restful.NewError(http.StatusBadRequest, "could not get file from form") klog.Errorf("%+v", err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } if len(req.Request.MultipartForm.File["s2ibinary"]) == 0 { err := restful.NewError(http.StatusBadRequest, "could not get file from form") klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } if len(req.Request.MultipartForm.File["s2ibinary"]) > 1 { err := restful.NewError(http.StatusBadRequest, "s2ibinary should only have one file") klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } defer req.Request.MultipartForm.RemoveAll() file, err := req.Request.MultipartForm.File["s2ibinary"][0].Open() if err != nil { klog.Error(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } filemd5, err := hashutil.GetMD5(file) if err != nil { klog.Error(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } md5, ok := req.Request.MultipartForm.Value["md5"] @@ -61,7 +61,7 @@ func (h S2iBinaryHandler) UploadS2iBinaryHandler(req *restful.Request, resp *res if md5[0] != filemd5 { err := restful.NewError(http.StatusBadRequest, fmt.Sprintf("md5 not match, origin: %+v, calculate: %+v", md5[0], filemd5)) klog.Error(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } } @@ -69,7 +69,7 @@ func (h S2iBinaryHandler) UploadS2iBinaryHandler(req *restful.Request, resp *res s2ibin, err := h.s2iUploader.UploadS2iBinary(ns, name, filemd5, req.Request.MultipartForm.File["s2ibinary"][0]) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } resp.WriteAsJson(s2ibin) @@ -83,7 +83,7 @@ func (h S2iBinaryHandler) DownloadS2iBinaryHandler(req *restful.Request, resp *r url, err := h.s2iUploader.DownloadS2iBinary(ns, name, fileName) if err != nil { klog.Errorf("%+v", err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } http.Redirect(resp.ResponseWriter, req.Request, url, http.StatusFound) diff --git a/pkg/kapis/iam/v1alpha2/handler.go b/pkg/kapis/iam/v1alpha2/handler.go index 0b93302b9..121040902 100644 --- a/pkg/kapis/iam/v1alpha2/handler.go +++ b/pkg/kapis/iam/v1alpha2/handler.go @@ -3,7 +3,6 @@ package v1alpha2 import ( "errors" "fmt" - "github.com/dgrijalva/jwt-go" "github.com/emicklei/go-restful" "github.com/go-ldap/ldap" rbacv1 "k8s.io/api/rbac/v1" @@ -21,7 +20,6 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/k8s" ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap" "kubesphere.io/kubesphere/pkg/utils/iputil" - "kubesphere.io/kubesphere/pkg/utils/jwtutil" "net/http" iamapi "kubesphere.io/kubesphere/pkg/api/iam" @@ -51,49 +49,22 @@ func (h *iamHandler) TokenReviewHandler(req *restful.Request, resp *restful.Resp err := req.ReadEntity(&tokenReview) if err != nil { - klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + klog.Error(err) + api.HandleBadRequest(resp, req, err) return } if err = tokenReview.Validate(); err != nil { - klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + klog.Error(err) + api.HandleBadRequest(resp, req, err) return } - token, err := jwtutil.ValidateToken(tokenReview.Spec.Token) - - if err != nil { - failed := iamv1alpha2.TokenReview{APIVersion: tokenReview.APIVersion, - Kind: kindTokenReview, - Status: &iamv1alpha2.Status{ - Authenticated: false, - }, - } - resp.WriteEntity(failed) - return - } - - claims, ok := token.Claims.(jwt.MapClaims) - - if !ok { - api.HandleBadRequest(resp, errors.New("invalid token")) - return - } - - username, ok := claims["username"].(string) - - if !ok { - api.HandleBadRequest(resp, errors.New("invalid token")) - return - } - - user, err := h.imOperator.DescribeUser(username) + user, err := h.imOperator.VerifyToken(tokenReview.Spec.Token) if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, req, err) return } @@ -143,13 +114,13 @@ func (h *iamHandler) CreateUser(req *restful.Request, resp *restful.Response) { err := req.ReadEntity(&createRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } if err := createRequest.Validate(); err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -162,7 +133,7 @@ func (h *iamHandler) CreateUser(req *restful.Request, resp *restful.Response) { return } klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -170,7 +141,7 @@ func (h *iamHandler) CreateUser(req *restful.Request, resp *restful.Response) { if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -184,7 +155,7 @@ func (h *iamHandler) DeleteUser(req *restful.Request, resp *restful.Response) { if operator == username { err := errors.New("cannot delete yourself") klog.V(4).Infoln(err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } @@ -192,7 +163,7 @@ func (h *iamHandler) DeleteUser(req *restful.Request, resp *restful.Response) { if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -201,7 +172,7 @@ func (h *iamHandler) DeleteUser(req *restful.Request, resp *restful.Response) { // TODO release user resources if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -218,20 +189,20 @@ func (h *iamHandler) ModifyUser(request *restful.Request, response *restful.Resp if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } if username != modifyUserRequest.Username { err = fmt.Errorf("the name of user (%s) does not match the name on the URL (%s)", modifyUserRequest.Username, username) klog.V(4).Infoln(err) - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } if err = modifyUserRequest.Validate(); err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } @@ -244,7 +215,7 @@ func (h *iamHandler) ModifyUser(request *restful.Request, response *restful.Resp if err != nil { klog.Errorln(err) - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -261,11 +232,11 @@ func (h *iamHandler) DescribeUser(req *restful.Request, resp *restful.Response) if err != nil { if err == iam.UserNotExists { klog.V(4).Infoln(err) - api.HandleNotFound(resp, err) + api.HandleNotFound(resp, nil, err) return } klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -274,7 +245,7 @@ func (h *iamHandler) DescribeUser(req *restful.Request, resp *restful.Response) if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -295,7 +266,7 @@ func (h *iamHandler) ListUsers(req *restful.Request, resp *restful.Response) { if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -303,7 +274,7 @@ func (h *iamHandler) ListUsers(req *restful.Request, resp *restful.Response) { if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -318,7 +289,7 @@ func (h *iamHandler) ListUserRoles(req *restful.Request, resp *restful.Response) if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -334,7 +305,7 @@ func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) { if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -342,7 +313,7 @@ func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) { if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -357,7 +328,7 @@ func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Respon if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -365,7 +336,7 @@ func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Respon if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -381,7 +352,7 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response) if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } result := make([]*iamapi.User, 0) @@ -395,7 +366,7 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response) } if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } result = append(result, user) @@ -415,7 +386,7 @@ func (h *iamHandler) ListNamespaceUsers(req *restful.Request, resp *restful.Resp if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -430,7 +401,7 @@ func (h *iamHandler) ListNamespaceUsers(req *restful.Request, resp *restful.Resp } if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } result = append(result, user) @@ -447,7 +418,7 @@ func (h *iamHandler) ListClusterRoleUsers(req *restful.Request, resp *restful.Re if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -462,7 +433,7 @@ func (h *iamHandler) ListClusterRoleUsers(req *restful.Request, resp *restful.Re } if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } result = append(result, user) @@ -488,7 +459,7 @@ func (h *iamHandler) ListClusterRoleRules(req *restful.Request, resp *restful.Re rules, err := h.amOperator.GetClusterRoleSimpleRules(clusterRole) if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } resp.WriteEntity(rules) @@ -502,7 +473,7 @@ func (h *iamHandler) ListRoleRules(req *restful.Request, resp *restful.Response) if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } diff --git a/pkg/kapis/logging/v1alpha2/handler.go b/pkg/kapis/logging/v1alpha2/handler.go index 766c1656f..585099466 100644 --- a/pkg/kapis/logging/v1alpha2/handler.go +++ b/pkg/kapis/logging/v1alpha2/handler.go @@ -47,7 +47,7 @@ func (h handler) get(req *restful.Request, lvl int, resp *restful.Response) { noHit, sf, err := h.newSearchFilter(req, lvl) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) } if noHit { handleNoHit(typ, resp) @@ -58,14 +58,14 @@ func (h handler) get(req *restful.Request, lvl int, resp *restful.Response) { case TypeStat: res, err := h.lo.GetCurrentStats(sf) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } resp.WriteAsJson(res) case TypeHist: interval := req.QueryParameter("interval") res, err := h.lo.CountLogsByInterval(sf, interval) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } resp.WriteAsJson(res) case TypeExport: @@ -73,7 +73,7 @@ func (h handler) get(req *restful.Request, lvl int, resp *restful.Response) { resp.Header().Set("Content-Disposition", "attachment") err := h.lo.ExportLogs(sf, resp.ResponseWriter) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } default: from, _ := strconv.ParseInt(req.QueryParameter("from"), 10, 64) @@ -87,7 +87,7 @@ func (h handler) get(req *restful.Request, lvl int, resp *restful.Response) { } res, err := h.lo.SearchLogs(sf, from, size, order) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } resp.WriteAsJson(res) } diff --git a/pkg/kapis/monitoring/v1alpha2/handler.go b/pkg/kapis/monitoring/v1alpha2/handler.go index 962b4f2db..04f266ebe 100644 --- a/pkg/kapis/monitoring/v1alpha2/handler.go +++ b/pkg/kapis/monitoring/v1alpha2/handler.go @@ -39,7 +39,7 @@ func newHandler(k k8s.Client, m monitoring.Interface) *handler { func (h handler) handleClusterMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelCluster) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -48,7 +48,7 @@ func (h handler) handleClusterMetricsQuery(req *restful.Request, resp *restful.R func (h handler) handleNodeMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelNode) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -57,7 +57,7 @@ func (h handler) handleNodeMetricsQuery(req *restful.Request, resp *restful.Resp func (h handler) handleWorkspaceMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelWorkspace) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -66,7 +66,7 @@ func (h handler) handleWorkspaceMetricsQuery(req *restful.Request, resp *restful func (h handler) handleNamespaceMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelNamespace) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -75,7 +75,7 @@ func (h handler) handleNamespaceMetricsQuery(req *restful.Request, resp *restful func (h handler) handleWorkloadMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelWorkload) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -84,7 +84,7 @@ func (h handler) handleWorkloadMetricsQuery(req *restful.Request, resp *restful. func (h handler) handlePodMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelPod) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -93,7 +93,7 @@ func (h handler) handlePodMetricsQuery(req *restful.Request, resp *restful.Respo func (h handler) handleContainerMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelContainer) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -102,7 +102,7 @@ func (h handler) handleContainerMetricsQuery(req *restful.Request, resp *restful func (h handler) handlePVCMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelPVC) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -111,7 +111,7 @@ func (h handler) handlePVCMetricsQuery(req *restful.Request, resp *restful.Respo func (h handler) handleComponentMetricsQuery(req *restful.Request, resp *restful.Response) { p, err := h.parseRequestParams(req, monitoring.LevelComponent) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } h.handleNamedMetricsQuery(resp, p) @@ -124,13 +124,13 @@ func (h handler) handleNamedMetricsQuery(resp *restful.Response, p params) { if p.isRangeQuery() { res, err = h.mo.GetNamedMetricsOverTime(p.start, p.end, p.step, p.option) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } } else { res, err = h.mo.GetNamedMetrics(p.time, p.option) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } diff --git a/pkg/kapis/openpitrix/v1/handler.go b/pkg/kapis/openpitrix/v1/handler.go index ccf2724ae..8139a10f3 100644 --- a/pkg/kapis/openpitrix/v1/handler.go +++ b/pkg/kapis/openpitrix/v1/handler.go @@ -41,7 +41,7 @@ func (h *openpitrixHandler) ListApplications(request *restful.Request, response if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } @@ -51,7 +51,7 @@ func (h *openpitrixHandler) ListApplications(request *restful.Request, response if err != nil { klog.Errorln(err) - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -71,7 +71,7 @@ func (h *openpitrixHandler) ListApplications(request *restful.Request, response if err != nil { klog.Errorln(err) - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -94,7 +94,7 @@ func (h *openpitrixHandler) DescribeApplication(req *restful.Request, resp *rest if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -103,7 +103,7 @@ func (h *openpitrixHandler) DescribeApplication(req *restful.Request, resp *rest if runtimeId != app.Cluster.RuntimeId { err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId) klog.V(4).Infoln(err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } @@ -117,7 +117,7 @@ func (h *openpitrixHandler) CreateApplication(req *restful.Request, resp *restfu err := req.ReadEntity(&createClusterRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -127,7 +127,7 @@ func (h *openpitrixHandler) CreateApplication(req *restful.Request, resp *restfu if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -141,7 +141,7 @@ func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restfu err := req.ReadEntity(&modifyClusterAttributesRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -157,7 +157,7 @@ func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restfu if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -166,7 +166,7 @@ func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restfu if runtimeId != app.Cluster.RuntimeId { err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId) klog.V(4).Infoln(err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } @@ -196,7 +196,7 @@ func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restfu if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -205,7 +205,7 @@ func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restfu if runtimeId != app.Cluster.RuntimeId { err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId) klog.V(4).Infoln(err) - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) return } @@ -228,7 +228,7 @@ func (h *openpitrixHandler) GetAppVersionPackage(req *restful.Request, resp *res if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -240,7 +240,7 @@ func (h *openpitrixHandler) DoAppAction(req *restful.Request, resp *restful.Resp err := req.ReadEntity(&doActionRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -262,7 +262,7 @@ func (h *openpitrixHandler) DoAppVersionAction(req *restful.Request, resp *restf err := req.ReadEntity(&doActionRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } doActionRequest.Username = req.HeaderParameter(constants.UserNameHeader) @@ -308,7 +308,7 @@ func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *res if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -336,7 +336,7 @@ func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Resp if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -344,7 +344,7 @@ func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Resp if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -361,7 +361,7 @@ func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful. if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } conditions.Match[openpitrix.AppId] = appId @@ -370,7 +370,7 @@ func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful. if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -380,7 +380,7 @@ func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful. statisticsResult, err := h.openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{"app_id": version.AppId, "version_id": version.VersionId}}, 0, 0, "", false) if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } version.ClusterTotal = &statisticsResult.TotalCount @@ -400,7 +400,7 @@ func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Respons if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -438,7 +438,7 @@ func (h *openpitrixHandler) ModifyApp(req *restful.Request, resp *restful.Respon if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -474,10 +474,10 @@ func (h *openpitrixHandler) DeleteApp(req *restful.Request, resp *restful.Respon if err != nil { if status.Code(err) == codes.NotFound { - api.HandleNotFound(resp, err) + api.HandleNotFound(resp, nil, err) return } - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -489,7 +489,7 @@ func (h *openpitrixHandler) CreateApp(req *restful.Request, resp *restful.Respon err := req.ReadEntity(createAppRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -511,10 +511,10 @@ func (h *openpitrixHandler) CreateApp(req *restful.Request, resp *restful.Respon if err != nil { if status.Code(err) == codes.InvalidArgument { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -526,7 +526,7 @@ func (h *openpitrixHandler) CreateAppVersion(req *restful.Request, resp *restful err := req.ReadEntity(&createAppVersionRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } // override app id @@ -564,7 +564,7 @@ func (h *openpitrixHandler) ModifyAppVersion(req *restful.Request, resp *restful if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -634,7 +634,7 @@ func (h *openpitrixHandler) CreateCategory(req *restful.Request, resp *restful.R err := req.ReadEntity(createCategoryRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -667,7 +667,7 @@ func (h *openpitrixHandler) ModifyCategory(req *restful.Request, resp *restful.R err := req.ReadEntity(&modifyCategoryRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -703,7 +703,7 @@ func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.R if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -737,7 +737,7 @@ func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Respo err := req.ReadEntity(createRepoRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } validate, _ := strconv.ParseBool(req.QueryParameter("validate")) @@ -770,7 +770,7 @@ func (h *openpitrixHandler) DoRepoAction(req *restful.Request, resp *restful.Res err := req.ReadEntity(repoActionRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -805,7 +805,7 @@ func (h *openpitrixHandler) ModifyRepo(req *restful.Request, resp *restful.Respo err := req.ReadEntity(&updateRepoRequest) if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -841,7 +841,7 @@ func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Respon if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -863,7 +863,7 @@ func (h *openpitrixHandler) ListRepoEvents(req *restful.Request, resp *restful.R if err != nil { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -881,14 +881,14 @@ func (h *openpitrixHandler) ListRepoEvents(req *restful.Request, resp *restful.R func handleOpenpitrixError(resp *restful.Response, err error) { if status.Code(err) == codes.NotFound { klog.V(4).Infoln(err) - api.HandleNotFound(resp, err) + api.HandleNotFound(resp, nil, err) return } if status.Code(err) == codes.InvalidArgument { klog.V(4).Infoln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } diff --git a/pkg/kapis/resources/v1alpha2/handler.go b/pkg/kapis/resources/v1alpha2/handler.go index 04ed5dc48..4eba100e1 100644 --- a/pkg/kapis/resources/v1alpha2/handler.go +++ b/pkg/kapis/resources/v1alpha2/handler.go @@ -73,7 +73,7 @@ func (r *resourceHandler) handleListNamespaceResources(request *restful.Request, result, err := r.resourcesGetter.ListResources(namespace, resource, conditions, orderBy, reverse, limit, offset) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -84,7 +84,7 @@ func (r *resourceHandler) handleGetSystemHealthStatus(_ *restful.Request, respon result, err := r.componentsGetter.GetSystemHealthStatus() if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -96,7 +96,7 @@ func (r *resourceHandler) handleGetComponentStatus(request *restful.Request, res result, err := r.componentsGetter.GetComponentStatus(component) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -107,7 +107,7 @@ func (r *resourceHandler) handleGetComponents(_ *restful.Request, response *rest result, err := r.componentsGetter.GetAllComponentsStatus() if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -117,7 +117,7 @@ func (r *resourceHandler) handleGetComponents(_ *restful.Request, response *rest func (r *resourceHandler) handleGetClusterQuotas(_ *restful.Request, response *restful.Response) { result, err := r.resourceQuotaGetter.GetClusterQuota() if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -129,7 +129,7 @@ func (r *resourceHandler) handleGetNamespaceQuotas(request *restful.Request, res quota, err := r.resourceQuotaGetter.GetNamespaceQuota(namespace) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -182,7 +182,7 @@ func (r *resourceHandler) handleGetStatefulSetRevision(request *restful.Request, result, err := r.revisionGetter.GetStatefulSetRevision(namespace, statefulset, revision) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } response.WriteAsJson(result) @@ -196,7 +196,7 @@ func (r *resourceHandler) handleGetRouter(request *restful.Request, response *re if k8serr.IsNotFound(err) { response.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err)) } else { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) } return } @@ -221,7 +221,7 @@ func (r *resourceHandler) handleCreateRouter(request *restful.Request, response router, err := r.routerOperator.CreateRouter(namespace, routerType, newRouter.Annotations) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -234,7 +234,7 @@ func (r *resourceHandler) handleDeleteRouter(request *restful.Request, response router, err := r.routerOperator.DeleteRouter(namespace) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -257,7 +257,7 @@ func (r *resourceHandler) handleUpdateRouter(request *restful.Request, response router, err := r.routerOperator.UpdateRouter(namespace, routerType, newRouter.Annotations) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -269,13 +269,13 @@ func (r *resourceHandler) handleVerifyGitCredential(request *restful.Request, re var credential api.GitCredential err := request.ReadEntity(&credential) if err != nil { - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } err = r.gitVerifier.VerifyGitCredential(credential.RemoteUrl, credential.SecretRef.Namespace, credential.SecretRef.Name) if err != nil { - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } @@ -286,13 +286,13 @@ func (r *resourceHandler) handleVerifyRegistryCredential(request *restful.Reques var credential api.RegistryCredential err := request.ReadEntity(&credential) if err != nil { - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } err = r.registryGetter.VerifyRegistryCredential(credential) if err != nil { - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } @@ -306,7 +306,7 @@ func (r *resourceHandler) handleGetRegistryEntry(request *restful.Request, respo detail, err := r.registryGetter.GetEntry(namespace, secretName, imageName) if err != nil { - api.HandleBadRequest(response, err) + api.HandleBadRequest(response, nil, err) return } @@ -335,7 +335,7 @@ func (r *resourceHandler) handleGetNamespacedAbnormalWorkloads(request *restful. res, err := r.resourcesGetter.ListResources(namespace, workloadType, ¶ms.Conditions{Match: map[string]string{v1alpha2.Status: notReadyStatus}}, "", false, -1, 0) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) } result.Count[workloadType] = len(res.Items) diff --git a/pkg/kapis/resources/v1alpha3/handler.go b/pkg/kapis/resources/v1alpha3/handler.go index 006d6934b..71883a012 100644 --- a/pkg/kapis/resources/v1alpha3/handler.go +++ b/pkg/kapis/resources/v1alpha3/handler.go @@ -29,7 +29,7 @@ func (h Handler) handleGetNamespacedResource(request *restful.Request, response result, err := h.namespacedResourceGetter.Get(resource, namespace, name) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -44,7 +44,7 @@ func (h Handler) handleListNamespacedResource(request *restful.Request, response result, err := h.namespacedResourceGetter.List(resource, namespace, query) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -56,7 +56,7 @@ func (h Handler) handleGetComponentStatus(request *restful.Request, response *re result, err := h.componentsGetter.GetComponentStatus(component) if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -67,7 +67,7 @@ func (h Handler) handleGetSystemHealthStatus(request *restful.Request, response result, err := h.componentsGetter.GetSystemHealthStatus() if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -80,7 +80,7 @@ func (h Handler) handleGetComponents(request *restful.Request, response *restful result, err := h.componentsGetter.GetAllComponentsStatus() if err != nil { - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } diff --git a/pkg/kapis/servicemesh/metrics/v1alpha2/handler.go b/pkg/kapis/servicemesh/metrics/v1alpha2/handler.go index 678dac8ce..06338a20b 100644 --- a/pkg/kapis/servicemesh/metrics/v1alpha2/handler.go +++ b/pkg/kapis/servicemesh/metrics/v1alpha2/handler.go @@ -87,7 +87,7 @@ func getServiceTracing(request *restful.Request, response *restful.Response) { if err != nil { klog.Errorf("query jaeger faile with err %v", err) - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } @@ -96,7 +96,7 @@ func getServiceTracing(request *restful.Request, response *restful.Response) { if err != nil { klog.Errorf("read response error : %v", err) - api.HandleInternalError(response, err) + api.HandleInternalError(response, nil, err) return } diff --git a/pkg/kapis/tenant/v1alpha2/handler.go b/pkg/kapis/tenant/v1alpha2/handler.go index 9fdb90ce1..9008d78bc 100644 --- a/pkg/kapis/tenant/v1alpha2/handler.go +++ b/pkg/kapis/tenant/v1alpha2/handler.go @@ -44,7 +44,7 @@ func (h *tenantHandler) ListWorkspaceRules(req *restful.Request, resp *restful.R if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -60,14 +60,14 @@ func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Respo if err != nil { klog.Errorln(err) - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } result, err := h.tenant.ListWorkspaces(username, conditions, orderBy, reverse, limit, offset) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -82,9 +82,9 @@ func (h *tenantHandler) DescribeWorkspace(req *restful.Request, resp *restful.Re if err != nil { if k8serr.IsNotFound(err) { - api.HandleNotFound(resp, err) + api.HandleNotFound(resp, nil, err) } else { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } return } @@ -107,7 +107,7 @@ func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Respo conditions, err := params.ParseConditions(req) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } @@ -116,7 +116,7 @@ func (h *tenantHandler) ListNamespaces(req *restful.Request, resp *restful.Respo result, err := h.tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -145,7 +145,7 @@ func (h *tenantHandler) CreateNamespace(req *restful.Request, resp *restful.Resp var namespace v1.Namespace err := req.ReadEntity(&namespace) if err != nil { - api.HandleNotFound(resp, err) + api.HandleNotFound(resp, nil, err) return } @@ -153,9 +153,9 @@ func (h *tenantHandler) CreateNamespace(req *restful.Request, resp *restful.Resp if err != nil { if k8serr.IsNotFound(err) { - api.HandleForbidden(resp, err) + api.HandleForbidden(resp, nil, err) } else { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } return } @@ -166,7 +166,7 @@ func (h *tenantHandler) CreateNamespace(req *restful.Request, resp *restful.Resp if k8serr.IsAlreadyExists(err) { resp.WriteHeaderAndEntity(http.StatusConflict, err) } else { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } return } @@ -181,9 +181,9 @@ func (h *tenantHandler) DeleteNamespace(req *restful.Request, resp *restful.Resp if err != nil { if k8serr.IsNotFound(err) { - api.HandleNotFound(resp, err) + api.HandleNotFound(resp, nil, err) } else { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) } return } @@ -204,7 +204,7 @@ func (h *tenantHandler) ListDevopsProjects(req *restful.Request, resp *restful.R conditions, err := params.ParseConditions(req) if err != nil { - api.HandleBadRequest(resp, err) + api.HandleBadRequest(resp, nil, err) return } conditions.Match["workspace"] = workspace @@ -212,7 +212,7 @@ func (h *tenantHandler) ListDevopsProjects(req *restful.Request, resp *restful.R result, err := h.tenant.ListDevopsProjects(username, conditions, orderBy, reverse, limit, offset) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -224,7 +224,7 @@ func (h *tenantHandler) GetDevOpsProjectsCount(req *restful.Request, resp *restf result, err := h.tenant.ListDevopsProjects(username, nil, "", false, 1, 0) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } resp.WriteEntity(struct { @@ -239,14 +239,14 @@ func (h *tenantHandler) DeleteDevopsProject(req *restful.Request, resp *restful. _, err := h.tenant.DescribeWorkspace("", workspace) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, req, err) return } err = h.tenant.DeleteDevOpsProject(username, projectId) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -264,7 +264,7 @@ func (h *tenantHandler) ListNamespaceRules(req *restful.Request, resp *restful.R rules, err := h.tenant.GetNamespaceSimpleRules(namespace, username) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } @@ -279,7 +279,7 @@ func (h *tenantHandler) ListDevopsRules(req *restful.Request, resp *restful.Resp rules, err := h.tenant.GetUserDevopsSimpleRules(username, devops) if err != nil { - api.HandleInternalError(resp, err) + api.HandleInternalError(resp, nil, err) return } diff --git a/pkg/models/iam/im.go b/pkg/models/iam/im.go index dfe31e652..010a64c9e 100644 --- a/pkg/models/iam/im.go +++ b/pkg/models/iam/im.go @@ -19,17 +19,16 @@ package iam import ( "fmt" - "github.com/dgrijalva/jwt-go" "github.com/pkg/errors" "golang.org/x/oauth2" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/klog" "kubesphere.io/kubesphere/pkg/api/iam" + "kubesphere.io/kubesphere/pkg/api/iam/token" "kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/server/params" "kubesphere.io/kubesphere/pkg/simple/client/cache" "kubesphere.io/kubesphere/pkg/simple/client/ldap" - "kubesphere.io/kubesphere/pkg/utils/jwtutil" "time" ) @@ -42,12 +41,14 @@ type IdentityManagementInterface interface { ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) GetUserRoles(username string) ([]*rbacv1.Role, error) GetUserRole(namespace string, username string) (*rbacv1.Role, error) + VerifyToken(token string) (*iam.User, error) } type imOperator struct { authenticateOptions *iam.AuthenticationOptions ldapClient ldap.Interface cacheClient cache.Interface + issuer token.Issuer } var ( @@ -57,7 +58,12 @@ var ( ) func NewIMOperator(ldapClient ldap.Interface, cacheClient cache.Interface, options *iam.AuthenticationOptions) *imOperator { - return &imOperator{ldapClient: ldapClient, cacheClient: cacheClient, authenticateOptions: options} + return &imOperator{ + ldapClient: ldapClient, + cacheClient: cacheClient, + authenticateOptions: options, + issuer: token.NewJwtTokenIssuer(token.DefaultIssuerName, []byte(options.JwtSecret)), + } } @@ -78,18 +84,6 @@ func (im *imOperator) ModifyUser(user *iam.User) (*iam.User, error) { return im.ldapClient.Get(user.Username) } -func authenticationFailedKeyForUsername(username, failedTimestamp string) string { - return fmt.Sprintf("kubesphere:authfailed:%s:%s", username, failedTimestamp) -} - -func tokenKeyForUsername(username, token string) string { - return fmt.Sprintf("kubesphere:users:%s:token:%s", username, token) -} - -func loginKeyForUsername(username, loginTimestamp, ip string) string { - return fmt.Sprintf("kubesphere:users:%s:login-log:%s:%s", username, loginTimestamp, ip) -} - func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error) { records, err := im.cacheClient.Keys(authenticationFailedKeyForUsername(username, "*")) @@ -97,7 +91,7 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error return nil, err } - if len(records) >= im.authenticateOptions.MaxAuthenticateRetries { + if len(records) > im.authenticateOptions.MaxAuthenticateRetries { return nil, AuthRateLimitExceeded } @@ -114,15 +108,12 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error return nil, err } - loginTime := time.Now() - // token without expiration time will auto sliding - claims := jwt.MapClaims{ - "iat": loginTime.Unix(), - "username": user.Username, - "email": user.Email, + issuedToken, err := im.issuer.IssueTo(user) + if err != nil { + return nil, err } - token := jwtutil.MustSigned(claims) + // TODO: I think we should come up with a better strategy to prevent multiple login. tokenKey := tokenKeyForUsername(user.Username, "*") if !im.authenticateOptions.MultipleLogin { // multi login not allowed, remove the previous token @@ -140,17 +131,17 @@ func (im *imOperator) Login(username, password, ip string) (*oauth2.Token, error } } - // cache token with expiration time - if err = im.cacheClient.Set(tokenKey, token, im.authenticateOptions.TokenExpiration); err != nil { + // save token with expiration time + if err = im.cacheClient.Set(tokenKey, issuedToken, im.authenticateOptions.TokenExpiration); err != nil { return nil, err } - im.loginRecord(user.Username, ip, loginTime) + im.logLogin(user.Username, ip, time.Now()) - return &oauth2.Token{AccessToken: token}, nil + return &oauth2.Token{AccessToken: issuedToken}, nil } -func (im *imOperator) loginRecord(username, ip string, loginTime time.Time) { +func (im *imOperator) logLogin(username, ip string, loginTime time.Time) { if ip != "" { _ = im.cacheClient.Set(loginKeyForUsername(username, loginTime.UTC().Format("2006-01-02T15:04:05Z"), ip), "", 30*24*time.Hour) } @@ -174,7 +165,6 @@ func (im *imOperator) DescribeUser(username string) (*iam.User, error) { } func (im *imOperator) getLastLoginTime(username string) string { - return "" } @@ -191,6 +181,20 @@ func (im *imOperator) CreateUser(user *iam.User) (*iam.User, error) { return user, nil } +func (im *imOperator) VerifyToken(tokenString string) (*iam.User, error) { + providedUser, err := im.issuer.Verify(tokenString) + if err != nil { + return nil, err + } + + user, err := im.ldapClient.Get(providedUser.Name()) + if err != nil { + return nil, err + } + + return user, nil +} + func (im *imOperator) uidNumberNext() int { // TODO fix me return 0 @@ -202,3 +206,15 @@ func (im *imOperator) GetUserRoles(username string) ([]*rbacv1.Role, error) { func (im *imOperator) GetUserRole(namespace string, username string) (*rbacv1.Role, error) { panic("implement me") } + +func authenticationFailedKeyForUsername(username, failedTimestamp string) string { + return fmt.Sprintf("kubesphere:authfailed:%s:%s", username, failedTimestamp) +} + +func tokenKeyForUsername(username, token string) string { + return fmt.Sprintf("kubesphere:users:%s:token:%s", username, token) +} + +func loginKeyForUsername(username, loginTimestamp, ip string) string { + return fmt.Sprintf("kubesphere:users:%s:login-log:%s:%s", username, loginTimestamp, ip) +} diff --git a/pkg/simple/client/ldap/simple_ldap.go b/pkg/simple/client/ldap/simple_ldap.go index c6b9c9ca9..78a82b4c6 100644 --- a/pkg/simple/client/ldap/simple_ldap.go +++ b/pkg/simple/client/ldap/simple_ldap.go @@ -1,6 +1,9 @@ package ldap -import "kubesphere.io/kubesphere/pkg/api/iam" +import ( + "kubesphere.io/kubesphere/pkg/api/iam" + "time" +) // simpleLdap is a implementation of ldap.Interface, you should never use this in production env! type simpleLdap struct { @@ -8,9 +11,22 @@ type simpleLdap struct { } func NewSimpleLdap() Interface { - return &simpleLdap{ + sl := &simpleLdap{ store: map[string]*iam.User{}, } + + // initialize with a admin user + admin := &iam.User{ + Username: "admin", + Email: "admin@kubesphere.io", + Lang: "eng", + Description: "administrator", + CreateTime: time.Now(), + Groups: nil, + Password: "P@88w0rd", + } + sl.store[admin.Username] = admin + return sl } func (s simpleLdap) Create(user *iam.User) error { diff --git a/pkg/utils/jwtutil/jwt.go b/pkg/utils/jwtutil/jwt.go deleted file mode 100644 index efc093c76..000000000 --- a/pkg/utils/jwtutil/jwt.go +++ /dev/null @@ -1,70 +0,0 @@ -/* - - Copyright 2019 The KubeSphere 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 jwtutil - -import ( - "fmt" - "github.com/dgrijalva/jwt-go" - "os" -) - -const secretEnv = "JWT_SECRET" - -var secretKey []byte - -func init() { - if secret := os.Getenv(secretEnv); secret != "" { - Setup(secret) - } -} - -func Setup(secret string) { - secretKey = []byte(secret) -} - -func MustSigned(claims jwt.MapClaims) string { - uToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - token, err := uToken.SignedString(secretKey) - if err != nil { - panic(err) - } - return token -} - -func provideKey(token *jwt.Token) (interface{}, error) { - if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok { - return secretKey, nil - } else { - return nil, fmt.Errorf("expect token signed with HMAC but got %v", token.Header["alg"]) - } -} - -func ValidateToken(uToken string) (*jwt.Token, error) { - - if len(uToken) == 0 { - return nil, fmt.Errorf("token length is zero") - } - - token, err := jwt.Parse(uToken, provideKey) - - if err != nil { - return nil, err - } - - return token, nil -}