code refactor (#1786)
* implement LDAP mock client Signed-off-by: hongming <talonwan@yunify.com> * update Signed-off-by: hongming <talonwan@yunify.com> * update Signed-off-by: hongming <talonwan@yunify.com> * resolve conflict Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
@@ -29,7 +29,7 @@ func NewKubeSphereControllerManagerOptions() *KubeSphereControllerManagerOptions
|
||||
KubernetesOptions: k8s.NewKubernetesOptions(),
|
||||
DevopsOptions: jenkins.NewDevopsOptions(),
|
||||
S3Options: s3.NewS3Options(),
|
||||
OpenPitrixOptions: openpitrix.NewOpenPitrixOptions(),
|
||||
OpenPitrixOptions: openpitrix.NewOptions(),
|
||||
LeaderElection: &leaderelection.LeaderElectionConfig{
|
||||
LeaseDuration: 30 * time.Second,
|
||||
RenewDeadline: 15 * time.Second,
|
||||
|
||||
@@ -42,7 +42,7 @@ func NewServerRunOptions() *ServerRunOptions {
|
||||
MySQLOptions: mysql.NewMySQLOptions(),
|
||||
MonitoringOptions: prometheus.NewPrometheusOptions(),
|
||||
S3Options: s3.NewS3Options(),
|
||||
OpenPitrixOptions: openpitrix.NewOpenPitrixOptions(),
|
||||
OpenPitrixOptions: openpitrix.NewOptions(),
|
||||
LoggingOptions: esclient.NewElasticSearchOptions(),
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ func createDeps(s *options.ServerRunOptions, stopCh <-chan struct{}) *apiserver.
|
||||
}
|
||||
|
||||
if s.OpenPitrixOptions != nil && !s.OpenPitrixOptions.IsEmpty() {
|
||||
deps.OpenPitrix, err = openpitrix.NewOpenPitrixClient(s.OpenPitrixOptions)
|
||||
deps.OpenPitrix, err = openpitrix.NewClient(s.OpenPitrixOptions)
|
||||
if err != nil {
|
||||
klog.Fatalf("error happened when initializing openpitrix client, %v", err)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func NewServerRunOptions() *ServerRunOptions {
|
||||
s := &ServerRunOptions{
|
||||
GenericServerRunOptions: genericoptions.NewServerRunOptions(),
|
||||
KubernetesOptions: k8s.NewKubernetesOptions(),
|
||||
LdapOptions: ldap.NewLdapOptions(),
|
||||
LdapOptions: ldap.NewOptions(),
|
||||
MySQLOptions: mysql.NewMySQLOptions(),
|
||||
RedisOptions: cache.NewRedisOptions(),
|
||||
}
|
||||
|
||||
1
go.mod
1
go.mod
@@ -70,6 +70,7 @@ require (
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/openshift/api v3.9.0+incompatible // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/projectcalico/libcalico-go v1.7.2-0.20191104213956-8f81e1e344ce
|
||||
github.com/prometheus/common v0.4.0
|
||||
github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009
|
||||
|
||||
@@ -47,12 +47,16 @@ type LoginRequest struct {
|
||||
Password string `json:"password" description:"password"`
|
||||
}
|
||||
|
||||
type UserCreateRequest struct {
|
||||
type UserDetail struct {
|
||||
*iam.User
|
||||
ClusterRole string `json:"cluster_role"`
|
||||
}
|
||||
|
||||
func (request *UserCreateRequest) Validate() error {
|
||||
type CreateUserRequest struct {
|
||||
*UserDetail
|
||||
}
|
||||
|
||||
func (request *CreateUserRequest) Validate() error {
|
||||
if request.Username == "" {
|
||||
return fmt.Errorf("username must not be empty")
|
||||
}
|
||||
@@ -68,3 +72,39 @@ func (request *UserCreateRequest) Validate() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ModifyUserRequest struct {
|
||||
*UserDetail
|
||||
CurrentPassword string `json:"current_password,omitempty" description:"this is necessary if you need to change your password"`
|
||||
}
|
||||
|
||||
func (request *TokenReview) Validate() error {
|
||||
if request.Spec == nil || request.Spec.Token == "" {
|
||||
return fmt.Errorf("token must not be null")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (request ModifyUserRequest) Validate() error {
|
||||
|
||||
// Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg@example.com>"
|
||||
if _, err := mail.ParseAddress(request.Email); err != nil {
|
||||
return fmt.Errorf("invalid email: %s", request.Email)
|
||||
}
|
||||
|
||||
if request.Password != "" {
|
||||
if len(request.Password) < minPasswordLength {
|
||||
return fmt.Errorf("password must be at least %d characters long", minPasswordLength)
|
||||
}
|
||||
if len(request.CurrentPassword) < minPasswordLength {
|
||||
return fmt.Errorf("password must be at least %d characters long", minPasswordLength)
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListUserResponse struct {
|
||||
Items []*UserDetail `json:"items"`
|
||||
TotalCount int `json:"total_count"`
|
||||
}
|
||||
|
||||
@@ -1,18 +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 iam
|
||||
@@ -1,69 +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 iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/utils/iputil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type OAuthRequest struct {
|
||||
GrantType string `json:"grant_type"`
|
||||
Username string `json:"username,omitempty" description:"username"`
|
||||
Password string `json:"password,omitempty" description:"password"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
}
|
||||
|
||||
func OAuth(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
authRequest := &OAuthRequest{}
|
||||
|
||||
err := req.ReadEntity(authRequest)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
var result *models.AuthGrantResponse
|
||||
switch authRequest.GrantType {
|
||||
case "refresh_token":
|
||||
result, err = iam.RefreshToken(authRequest.RefreshToken)
|
||||
case "password":
|
||||
ip := iputil.RemoteIp(req.Request)
|
||||
result, err = iam.PasswordCredentialGrant(authRequest.Username, authRequest.Password, ip)
|
||||
default:
|
||||
resp.Header().Set("WWW-Authenticate", "grant_type is not supported")
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.Wrap(fmt.Errorf("grant_type is not supported")))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.Header().Set("WWW-Authenticate", err.Error())
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
|
||||
}
|
||||
@@ -1,201 +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 iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-ldap/ldap"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
)
|
||||
|
||||
func CreateGroup(req *restful.Request, resp *restful.Response) {
|
||||
var group models.Group
|
||||
|
||||
err := req.ReadEntity(&group)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if !regexp.MustCompile("[a-z0-9]([-a-z0-9]*[a-z0-9])?").MatchString(group.Name) {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(fmt.Sprintf("incalid group name %s", group)))
|
||||
return
|
||||
}
|
||||
|
||||
created, err := iam.CreateGroup(&group)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(created)
|
||||
}
|
||||
|
||||
func DeleteGroup(req *restful.Request, resp *restful.Response) {
|
||||
path := req.PathParameter("group")
|
||||
|
||||
if path == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("group path must not be null")))
|
||||
return
|
||||
}
|
||||
|
||||
err := iam.DeleteGroup(path)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
|
||||
}
|
||||
|
||||
func UpdateGroup(req *restful.Request, resp *restful.Response) {
|
||||
groupPathInPath := req.PathParameter("group")
|
||||
|
||||
var group models.Group
|
||||
|
||||
req.ReadEntity(&group)
|
||||
|
||||
if groupPathInPath != group.Path {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("the path of group (%s) does not match the path on the URL (%s)", group.Path, groupPathInPath)))
|
||||
return
|
||||
}
|
||||
|
||||
edited, err := iam.UpdateGroup(&group)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(edited)
|
||||
|
||||
}
|
||||
|
||||
func DescribeGroup(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
path := req.PathParameter("group")
|
||||
|
||||
group, err := iam.DescribeGroup(path)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(group)
|
||||
|
||||
}
|
||||
|
||||
func ListGroupUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
path := req.PathParameter("group")
|
||||
|
||||
group, err := iam.DescribeGroup(path)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
users := make([]*iam.User, 0)
|
||||
|
||||
modify := false
|
||||
|
||||
for i := 0; i < len(group.Members); i++ {
|
||||
name := group.Members[i]
|
||||
user, err := iam.GetUserInfo(name)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
group.Members = append(group.Members[:i], group.Members[i+1:]...)
|
||||
i--
|
||||
modify = true
|
||||
continue
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
if modify {
|
||||
go iam.UpdateGroup(group)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
|
||||
}
|
||||
|
||||
func ListGroups(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
array := req.QueryParameter("path")
|
||||
|
||||
if array == "" {
|
||||
groups, err := iam.ChildList("")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(groups)
|
||||
} else {
|
||||
paths := strings.Split(array, ",")
|
||||
|
||||
groups := make([]*models.Group, 0)
|
||||
|
||||
for _, v := range paths {
|
||||
path := strings.TrimSpace(v)
|
||||
group, err := iam.DescribeGroup(path)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
groups = append(groups, group)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(groups)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,259 +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 iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-ldap/ldap"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
)
|
||||
|
||||
func DeleteUser(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("user")
|
||||
|
||||
operator := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
if operator == username {
|
||||
err := fmt.Errorf("cannot delete yourself")
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err := iam.DeleteUser(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func UpdateUser(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
usernameInPath := req.PathParameter("user")
|
||||
usernameInHeader := req.HeaderParameter(constants.UserNameHeader)
|
||||
var user iam.User
|
||||
|
||||
err := req.ReadEntity(&user)
|
||||
|
||||
if err != nil {
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if usernameInPath != user.Username {
|
||||
err = fmt.Errorf("the name of user (%s) does not match the name on the URL (%s)", user.Username, usernameInPath)
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = mail.ParseAddress(user.Email); err != nil {
|
||||
err = fmt.Errorf("invalid email: %s", user.Email)
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if user.Password != "" && len(user.Password) < 6 {
|
||||
err = fmt.Errorf("invalid password")
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
// change password by self
|
||||
if usernameInHeader == user.Username && user.Password != "" {
|
||||
isUserManager, err := isUserManager(usernameInHeader)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if !isUserManager {
|
||||
_, err = iam.Login(usernameInHeader, user.CurrentPassword, "")
|
||||
}
|
||||
if err != nil {
|
||||
err = fmt.Errorf("incorrect current password")
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if usernameInHeader == user.Username {
|
||||
// change cluster role by self is not permitted
|
||||
user.ClusterRole = ""
|
||||
}
|
||||
|
||||
result, err := iam.UpdateUser(&user)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
klog.Error(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func isUserManager(username string) (bool, error) {
|
||||
rules, err := iam.GetUserClusterRules(username)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"update"}, Resources: []string{"users"}, APIGroups: []string{"iam.kubesphere.io"}}) {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func UserLoginLogs(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("user")
|
||||
logs, err := iam.LoginLog(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := make([]map[string]string, 0)
|
||||
|
||||
for _, v := range logs {
|
||||
item := strings.Split(v, ",")
|
||||
time := item[0]
|
||||
var ip string
|
||||
if len(item) > 1 {
|
||||
ip = item[1]
|
||||
}
|
||||
result = append(result, map[string]string{"login_time": time, "login_ip": ip})
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func DescribeUser(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("user")
|
||||
|
||||
user, err := iam.DescribeUser(username)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
klog.Error(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
clusterRole, err := iam.GetUserClusterRole(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.ClusterRole = clusterRole.Name
|
||||
|
||||
clusterRules, err := iam.GetUserClusterSimpleRules(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := struct {
|
||||
*iam.User
|
||||
ClusterRules []iam.SimpleRule `json:"cluster_rules"`
|
||||
}{
|
||||
User: user,
|
||||
ClusterRules: clusterRules,
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func Precheck(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
check := req.QueryParameter("check")
|
||||
|
||||
exist, err := iam.UserCreateCheck(check)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(map[string]bool{"exist": exist})
|
||||
}
|
||||
|
||||
func ListUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
if check := req.QueryParameter("check"); check != "" {
|
||||
Precheck(req, resp)
|
||||
return
|
||||
}
|
||||
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
klog.Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
users, err := iam.ListUsers(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
@@ -1,18 +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 iam
|
||||
@@ -1,165 +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 iam
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ListWorkspaceRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("workspace")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListWorkspaceRoles(workspace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result.Items)
|
||||
}
|
||||
|
||||
func ListWorkspaceRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
role := req.PathParameter("role")
|
||||
|
||||
rules := iam.GetWorkspaceRoleSimpleRules(workspace, role)
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func DescribeWorkspaceRole(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
roleName := req.PathParameter("role")
|
||||
|
||||
role, err := iam.GetWorkspaceRole(workspace, roleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(role)
|
||||
}
|
||||
|
||||
func DescribeWorkspaceUser(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspace, username)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
user, err := iam.GetUserInfo(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.WorkspaceRole = workspaceRole.Annotations[constants.DisplayNameAnnotationKey]
|
||||
|
||||
resp.WriteAsJson(user)
|
||||
}
|
||||
|
||||
func ListDevopsRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
role := req.PathParameter("role")
|
||||
|
||||
rules := iam.GetDevopsRoleSimpleRules(role)
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func InviteUser(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
var user iam.User
|
||||
err := req.ReadEntity(&user)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.InviteUser(workspace, &user)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func RemoveUser(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
|
||||
err := workspaces.RemoveUser(workspace, username)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func ListWorkspaceUsers(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListWorkspaceUsers(workspace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
@@ -2,21 +2,26 @@ 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"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
kserr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
apierr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"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"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type iamHandler struct {
|
||||
@@ -24,29 +29,34 @@ type iamHandler struct {
|
||||
imOperator iam.IdentityManagementInterface
|
||||
}
|
||||
|
||||
func newIAMHandler() *iamHandler {
|
||||
return &iamHandler{}
|
||||
func newIAMHandler(k8sClient k8s.Client, ldapClient ldappool.Client, options iam.Config) *iamHandler {
|
||||
factory := informers.NewInformerFactories(k8sClient.Kubernetes(), k8sClient.KubeSphere(), k8sClient.S2i(), k8sClient.Application())
|
||||
return &iamHandler{
|
||||
amOperator: iam.NewAMOperator(factory.KubernetesSharedInformerFactory()),
|
||||
imOperator: iam.NewIMOperator(ldapClient, options),
|
||||
}
|
||||
}
|
||||
|
||||
// k8s token review
|
||||
// Implement webhook authentication interface
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication
|
||||
func (h *iamHandler) TokenReviewHandler(req *restful.Request, resp *restful.Response) {
|
||||
var tokenReview iamv1alpha2.TokenReview
|
||||
|
||||
err := req.ReadEntity(&tokenReview)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if tokenReview.Spec == nil {
|
||||
api.HandleBadRequest(resp, errors.New("token must not be null"))
|
||||
if err = tokenReview.Validate(); err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
uToken := tokenReview.Spec.Token
|
||||
|
||||
token, err := jwtutil.ValidateToken(uToken)
|
||||
token, err := jwtutil.ValidateToken(tokenReview.Spec.Token)
|
||||
|
||||
if err != nil {
|
||||
failed := iamv1alpha2.TokenReview{APIVersion: tokenReview.APIVersion,
|
||||
@@ -59,18 +69,24 @@ func (h *iamHandler) TokenReviewHandler(req *restful.Request, resp *restful.Resp
|
||||
return
|
||||
}
|
||||
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
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("username not found"))
|
||||
api.HandleBadRequest(resp, errors.New("invalid token"))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.imOperator.DescribeUser(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -92,7 +108,9 @@ func (h *iamHandler) Login(req *restful.Request, resp *restful.Response) {
|
||||
err := req.ReadEntity(&loginRequest)
|
||||
|
||||
if err != nil || loginRequest.Username == "" || loginRequest.Password == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.New("incorrect username or password"))
|
||||
err = errors.New("incorrect username or password")
|
||||
klog.V(4).Infoln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,10 +119,12 @@ func (h *iamHandler) Login(req *restful.Request, resp *restful.Response) {
|
||||
token, err := h.imOperator.Login(loginRequest.Username, loginRequest.Password, ip)
|
||||
|
||||
if err != nil {
|
||||
if serviceError, ok := err.(restful.ServiceError); ok {
|
||||
resp.WriteHeaderAndEntity(serviceError.Code, errors.New(serviceError.Message))
|
||||
if err == iam.AuthRateLimitExceeded {
|
||||
klog.V(4).Infoln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusTooManyRequests, err)
|
||||
return
|
||||
}
|
||||
klog.V(4).Infoln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, err)
|
||||
return
|
||||
}
|
||||
@@ -113,14 +133,16 @@ func (h *iamHandler) Login(req *restful.Request, resp *restful.Response) {
|
||||
}
|
||||
|
||||
func (h *iamHandler) CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
var createRequest iamv1alpha2.UserCreateRequest
|
||||
var createRequest iamv1alpha2.CreateUserRequest
|
||||
err := req.ReadEntity(&createRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := createRequest.Validate(); err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -128,23 +150,223 @@ func (h *iamHandler) CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
created, err := h.imOperator.CreateUser(createRequest.User)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, kserr.Wrap(err))
|
||||
if err == iam.UserAlreadyExists {
|
||||
klog.V(4).Infoln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, err)
|
||||
return
|
||||
}
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.amOperator.CreateClusterRoleBinding(created.Username, createRequest.ClusterRole)
|
||||
err = h.amOperator.CreateClusterRoleBinding(created.Username, createRequest.ClusterRole)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(created)
|
||||
}
|
||||
|
||||
func (h *iamHandler) DeleteUser(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("user")
|
||||
operator := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
if operator == username {
|
||||
err := errors.New("cannot delete yourself")
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleForbidden(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.amOperator.UnBindAllRoles(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.imOperator.DeleteUser(username)
|
||||
|
||||
// TODO release user resources
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(apierr.None)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ModifyUser(request *restful.Request, response *restful.Response) {
|
||||
|
||||
username := request.PathParameter("user")
|
||||
operator := request.HeaderParameter(constants.UserNameHeader)
|
||||
var modifyUserRequest iamv1alpha2.ModifyUserRequest
|
||||
|
||||
err := request.ReadEntity(&modifyUserRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(response, 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)
|
||||
return
|
||||
}
|
||||
|
||||
if err = modifyUserRequest.Validate(); err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(response, err)
|
||||
return
|
||||
}
|
||||
|
||||
// change password by self
|
||||
if operator == modifyUserRequest.Username && modifyUserRequest.Password != "" {
|
||||
|
||||
}
|
||||
|
||||
result, err := h.imOperator.ModifyUser(modifyUserRequest.User)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(response, err)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO modify cluster role
|
||||
|
||||
response.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeUser(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("user")
|
||||
|
||||
user, err := h.imOperator.DescribeUser(username)
|
||||
|
||||
if err != nil {
|
||||
if err == iam.UserNotExists {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO append more user info
|
||||
clusterRole, err := h.amOperator.GetClusterRole(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result := iamv1alpha2.UserDetail{
|
||||
User: user,
|
||||
ClusterRole: clusterRole.Name,
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.imOperator.ListUsers(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListUserRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("user")
|
||||
|
||||
roles, err := h.imOperator.GetUserRoles(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(roles)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.amOperator.ListRoles(namespace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.amOperator.ListClusterRoles(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
role := req.PathParameter("role")
|
||||
namespace := req.PathParameter("namespace")
|
||||
@@ -152,6 +374,7 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response)
|
||||
roleBindings, err := h.amOperator.ListRoleBindings(namespace, role)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -159,12 +382,13 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind {
|
||||
user, err := h.imOperator.GetUserInfo(subject.Name)
|
||||
user, err := h.imOperator.DescribeUser(subject.Name)
|
||||
// skip if user not exist
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -176,152 +400,133 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response)
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListClusterRoles(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListRoles(namespace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
// List users by namespace
|
||||
func (h *iamHandler) ListNamespaceUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
users, err := iam.NamespaceUsers(namespace)
|
||||
roleBindings, err := h.amOperator.ListRoleBindings(namespace, "")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
// sort by time by default
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
return users[i].RoleBindTime.After(*users[j].RoleBindTime)
|
||||
})
|
||||
result := make([]*iam.User, 0)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind {
|
||||
user, err := h.imOperator.DescribeUser(subject.Name)
|
||||
// skip if user not exist
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
result = append(result, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListUserRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("user")
|
||||
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
func (h *iamHandler) ListClusterRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
clusterRole := req.PathParameter("clusterrole")
|
||||
clusterRoleBindings, err := h.amOperator.ListClusterRoleBindings(clusterRole)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, clusterRoles, err := iam.GetUserClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
result := make([]*iam.User, 0)
|
||||
for _, roleBinding := range clusterRoleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind {
|
||||
user, err := h.imOperator.DescribeUser(subject.Name)
|
||||
// skip if user not exist
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
result = append(result, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
roleList := RoleList{}
|
||||
roleList.Roles = roles
|
||||
roleList.ClusterRoles = clusterRoles
|
||||
|
||||
resp.WriteAsJson(roleList)
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) RulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.RoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ClusterRulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.ClusterRoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
rules, err := iam.GetClusterRoleSimpleRules(clusterRoleName)
|
||||
clusterRole := req.PathParameter("clusterrole")
|
||||
rules, err := h.amOperator.GetClusterRoleSimpleRules(clusterRole)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListClusterRoleUsers(clusterRoleName, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteError(http.StatusNotFound, err)
|
||||
} else {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
roleName := req.PathParameter("role")
|
||||
namespace := req.PathParameter("namespace")
|
||||
role := req.PathParameter("role")
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(namespaceName, roleName)
|
||||
rules, err := h.amOperator.GetRoleSimpleRules(namespace, role)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListWorkspaceRoles(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeWorkspaceRole(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListWorkspaceRoleRules(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListWorkspaceUsers(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) InviteUser(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) RemoveUser(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeWorkspaceUser(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -24,104 +24,25 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/iam"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
iam2 "kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const GroupName = "iam.kubesphere.io"
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
|
||||
type UserUpdateRequest struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
Password string `json:"password,omitempty" description:"this is necessary if you need to change your password"`
|
||||
CurrentPassword string `json:"current_password,omitempty" description:"this is necessary if you need to change your password"`
|
||||
ClusterRole string `json:"cluster_role" description:"user's cluster role"`
|
||||
}
|
||||
|
||||
type CreateUserRequest struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang,omitempty" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
Password string `json:"password" description:"password'"`
|
||||
ClusterRole string `json:"cluster_role" description:"user's cluster role"`
|
||||
}
|
||||
|
||||
type UserList struct {
|
||||
Items []struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang,omitempty" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
ClusterRole string `json:"cluster_role" description:"user's cluster role"`
|
||||
CreateTime time.Time `json:"create_time" description:"user creation time"`
|
||||
LastLoginTime time.Time `json:"last_login_time" description:"last login time"`
|
||||
} `json:"items" description:"paging data"`
|
||||
TotalCount int `json:"total_count" description:"total count"`
|
||||
}
|
||||
type NamespacedUser struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang,omitempty" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
Role string `json:"role" description:"user's role in the specified namespace"`
|
||||
RoleBinding string `json:"role_binding" description:"user's role binding name in the specified namespace"`
|
||||
RoleBindTime string `json:"role_bind_time" description:"user's role binding time"`
|
||||
CreateTime time.Time `json:"create_time" description:"user creation time"`
|
||||
LastLoginTime time.Time `json:"last_login_time" description:"last login time"`
|
||||
}
|
||||
|
||||
type ClusterRoleList struct {
|
||||
Items []rbacv1.ClusterRole `json:"items" description:"paging data"`
|
||||
TotalCount int `json:"total_count" description:"total count"`
|
||||
}
|
||||
|
||||
type LoginLog struct {
|
||||
LoginTime string `json:"login_time" description:"last login time"`
|
||||
LoginIP string `json:"login_ip" description:"last login ip"`
|
||||
}
|
||||
|
||||
type RoleList struct {
|
||||
Items []rbacv1.Role `json:"items" description:"paging data"`
|
||||
TotalCount int `json:"total_count" description:"total count"`
|
||||
}
|
||||
|
||||
type InviteUserRequest struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
WorkspaceRole string `json:"workspace_role" description:"user's workspace role'"`
|
||||
}
|
||||
|
||||
type DescribeWorkspaceUserResponse struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
ClusterRole string `json:"cluster_role" description:"user's cluster role"`
|
||||
WorkspaceRole string `json:"workspace_role" description:"user's workspace role"`
|
||||
CreateTime time.Time `json:"create_time" description:"user creation time"`
|
||||
LastLoginTime time.Time `json:"last_login_time" description:"last login time"`
|
||||
}
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client, ldapClient ldappool.Client, options iam.Config) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
|
||||
handler := newIAMHandler()
|
||||
handler := newIAMHandler(k8sClient, ldapClient, options)
|
||||
|
||||
ws.Route(ws.POST("/authenticate").
|
||||
To(handler.TokenReviewHandler).
|
||||
@@ -138,152 +59,132 @@ func addWebService(c *restful.Container) error {
|
||||
ws.Route(ws.POST("/users").
|
||||
To(handler.CreateUser).
|
||||
Doc("Create a user account.").
|
||||
Reads(CreateUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Reads(iamv1alpha2.CreateUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.UserDetail{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}").
|
||||
To(iam.DescribeUser).
|
||||
Doc("Describe the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, iam2.User{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
|
||||
ws.Route(ws.DELETE("/users/{user}").
|
||||
To(iam.DeleteUser).
|
||||
To(handler.DeleteUser).
|
||||
Doc("Delete the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.PUT("/users/{user}").
|
||||
To(iam.UpdateUser).
|
||||
To(handler.ModifyUser).
|
||||
Doc("Update information about the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Reads(UserUpdateRequest{}).
|
||||
Reads(iamv1alpha2.ModifyUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}/logs").
|
||||
To(iam.UserLoginLogs).
|
||||
Doc("Retrieve the \"login logs\" for the specified user.").
|
||||
ws.Route(ws.GET("/users/{user}").
|
||||
To(handler.DescribeUser).
|
||||
Doc("Describe the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, LoginLog{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.UserDetail{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users").
|
||||
To(iam.ListUsers).
|
||||
To(handler.ListUsers).
|
||||
Doc("List all users.").
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.ListUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}/roles").
|
||||
To(iam.ListUserRoles).
|
||||
To(handler.ListUserRoles).
|
||||
Doc("Retrieve all the roles that are assigned to the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, iam.RoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []*rbacv1.Role{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles").
|
||||
To(iam.ListRoles).
|
||||
To(handler.ListRoles).
|
||||
Doc("Retrieve the roles that are assigned to the user in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Returns(http.StatusOK, api.StatusOK, RoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles").
|
||||
To(iam.ListClusterRoles).
|
||||
To(handler.ListClusterRoles).
|
||||
Doc("List all cluster roles.").
|
||||
Returns(http.StatusOK, api.StatusOK, ClusterRoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/users").
|
||||
To(handler.ListRoleUsers).
|
||||
Doc("Retrieve the users that are bound to the role in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Param(ws.PathParameter("role", "role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []NamespacedUser{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iamv1alpha2.ListUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/users").
|
||||
To(iam.ListNamespaceUsers).
|
||||
To(handler.ListNamespaceUsers).
|
||||
Doc("List all users in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Returns(http.StatusOK, api.StatusOK, []NamespacedUser{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iamv1alpha2.ListUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles/{clusterrole}/users").
|
||||
To(iam.ListClusterRoleUsers).
|
||||
To(handler.ListClusterRoleUsers).
|
||||
Doc("List all users that are bound to the specified cluster role.").
|
||||
Param(ws.PathParameter("clusterrole", "cluster role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iamv1alpha2.ListUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles/{clusterrole}/rules").
|
||||
To(iam.ListClusterRoleRules).
|
||||
To(handler.ListClusterRoleRules).
|
||||
Doc("List all policy rules of the specified cluster role.").
|
||||
Param(ws.PathParameter("clusterrole", "cluster role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/rules").
|
||||
To(iam.ListRoleRules).
|
||||
To(handler.ListRoleRules).
|
||||
Doc("List all policy rules of the specified role in the given namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Param(ws.PathParameter("role", "role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/devops/{devops}/roles/{role}/rules").
|
||||
To(iam.ListDevopsRoleRules).
|
||||
Doc("List all policy rules of the specified role in the given devops project.").
|
||||
Param(ws.PathParameter("devops", "devops project ID")).
|
||||
Param(ws.PathParameter("role", "devops role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/rulesmapping/clusterroles").
|
||||
To(iam.ClusterRulesMapping).
|
||||
To(handler.ClusterRulesMapping).
|
||||
Doc("Get the mapping relationships between cluster roles and policy rules.").
|
||||
Returns(http.StatusOK, api.StatusOK, policy.ClusterRoleRuleMapping).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/rulesmapping/roles").
|
||||
To(iam.RulesMapping).
|
||||
To(handler.RulesMapping).
|
||||
Doc("Get the mapping relationships between namespaced roles and policy rules.").
|
||||
Returns(http.StatusOK, api.StatusOK, policy.RoleRuleMapping).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles").
|
||||
To(iam.ListWorkspaceRoles).
|
||||
To(handler.ListWorkspaceRoles).
|
||||
Doc("List all workspace roles.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, api.StatusOK, ClusterRoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}").
|
||||
To(iam.DescribeWorkspaceRole).
|
||||
To(handler.DescribeWorkspaceRole).
|
||||
Doc("Describe the workspace role.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("role", "workspace role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, rbacv1.ClusterRole{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}/rules").
|
||||
To(iam.ListWorkspaceRoleRules).
|
||||
To(handler.ListWorkspaceRoleRules).
|
||||
Doc("List all policy rules of the specified workspace role.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("role", "workspace role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members").
|
||||
To(iam.ListWorkspaceUsers).
|
||||
To(handler.ListWorkspaceUsers).
|
||||
Doc("List all members in the specified workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/members").
|
||||
To(iam.InviteUser).
|
||||
To(handler.InviteUser).
|
||||
Doc("Invite a member to the specified workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Reads(InviteUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.DELETE("/workspaces/{workspace}/members/{member}").
|
||||
To(iam.RemoveUser).
|
||||
To(handler.RemoveUser).
|
||||
Doc("Remove the specified member from the workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{member}").
|
||||
To(iam.DescribeWorkspaceUser).
|
||||
To(handler.DescribeWorkspaceUser).
|
||||
Doc("Describe the specified user in the given workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, DescribeWorkspaceUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
c.Add(ws)
|
||||
return nil
|
||||
|
||||
@@ -13,22 +13,25 @@ import (
|
||||
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/servicemesh/metrics/v1alpha2"
|
||||
tenantv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2"
|
||||
terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
)
|
||||
|
||||
func InstallAPIs(container *restful.Container, client k8s.Client) {
|
||||
func InstallAPIs(container *restful.Container, client k8s.Client, op op.Client, db *mysql.Database) {
|
||||
urlruntime.Must(servicemeshv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(devopsv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(loggingv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(monitoringv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(openpitrixv1.AddToContainer(container))
|
||||
urlruntime.Must(openpitrixv1.AddToContainer(container, client, op))
|
||||
urlruntime.Must(operationsv1alpha2.AddToContainer(container, client))
|
||||
urlruntime.Must(resourcesv1alpha2.AddToContainer(container, client))
|
||||
urlruntime.Must(tenantv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(terminalv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(tenantv1alpha2.AddToContainer(container))
|
||||
urlruntime.Must(tenantv1alpha2.AddToContainer(container, client, db))
|
||||
urlruntime.Must(terminalv1alpha2.AddToContainer(container, client))
|
||||
}
|
||||
|
||||
func InstallAuthorizationAPIs(container *restful.Container) {
|
||||
urlruntime.Must(iamv1alpha2.AddToContainer(container))
|
||||
func InstallAuthorizationAPIs(container *restful.Container, k8sClient k8s.Client, ldapClient ldappool.Client, imOptions iam.Config) {
|
||||
urlruntime.Must(iamv1alpha2.AddToContainer(container, k8sClient, ldapClient, imOptions))
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
@@ -15,7 +16,6 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -43,6 +43,7 @@ func (h *openpitrixHandler) ListApplications(request *restful.Request, response
|
||||
conditions, err := params.ParseConditions(request)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(response, err)
|
||||
return
|
||||
}
|
||||
@@ -52,6 +53,7 @@ func (h *openpitrixHandler) ListApplications(request *restful.Request, response
|
||||
ns, err := h.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(response, err)
|
||||
return
|
||||
}
|
||||
@@ -71,6 +73,7 @@ func (h *openpitrixHandler) ListApplications(request *restful.Request, response
|
||||
result, err := h.openpitrix.ListApplications(conditions, limit, offset, orderBy, reverse)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(response, err)
|
||||
return
|
||||
}
|
||||
@@ -85,17 +88,15 @@ func (h *openpitrixHandler) DescribeApplication(req *restful.Request, resp *rest
|
||||
app, err := h.openpitrix.DescribeApplication(namespace, clusterId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
ns, err := h.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -104,6 +105,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)
|
||||
return
|
||||
}
|
||||
@@ -117,6 +119,7 @@ func (h *openpitrixHandler) CreateApplication(req *restful.Request, resp *restfu
|
||||
var createClusterRequest openpitrix.CreateClusterRequest
|
||||
err := req.ReadEntity(&createClusterRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -126,6 +129,7 @@ func (h *openpitrixHandler) CreateApplication(req *restful.Request, resp *restfu
|
||||
err = h.openpitrix.CreateApplication(namespace, createClusterRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -139,6 +143,7 @@ func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restfu
|
||||
namespace := req.PathParameter("namespace")
|
||||
err := req.ReadEntity(&modifyClusterAttributesRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -146,17 +151,15 @@ func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restfu
|
||||
app, err := h.openpitrix.DescribeApplication(namespace, clusterId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
ns, err := h.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -165,6 +168,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)
|
||||
return
|
||||
}
|
||||
@@ -172,11 +176,8 @@ func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restfu
|
||||
err = h.openpitrix.ModifyApplication(modifyClusterAttributesRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -189,17 +190,15 @@ func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restfu
|
||||
app, err := h.openpitrix.DescribeApplication(namespace, clusterId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
ns, err := h.informers.Core().V1().Namespaces().Lister().Get(namespace)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -208,6 +207,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)
|
||||
return
|
||||
}
|
||||
@@ -215,11 +215,8 @@ func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restfu
|
||||
err = h.openpitrix.DeleteApplication(clusterId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -233,6 +230,7 @@ func (h *openpitrixHandler) GetAppVersionPackage(req *restful.Request, resp *res
|
||||
result, err := h.openpitrix.GetAppVersionPackage(appId, versionId)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -244,6 +242,7 @@ func (h *openpitrixHandler) DoAppAction(req *restful.Request, resp *restful.Resp
|
||||
var doActionRequest openpitrix.ActionRequest
|
||||
err := req.ReadEntity(&doActionRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -253,15 +252,8 @@ func (h *openpitrixHandler) DoAppAction(req *restful.Request, resp *restful.Resp
|
||||
err = h.openpitrix.DoAppAction(appId, &doActionRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -272,6 +264,7 @@ func (h *openpitrixHandler) DoAppVersionAction(req *restful.Request, resp *restf
|
||||
var doActionRequest openpitrix.ActionRequest
|
||||
err := req.ReadEntity(&doActionRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -282,15 +275,8 @@ func (h *openpitrixHandler) DoAppVersionAction(req *restful.Request, resp *restf
|
||||
err = h.openpitrix.DoAppVersionAction(versionId, &doActionRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -307,11 +293,8 @@ func (h *openpitrixHandler) GetAppVersionFiles(req *restful.Request, resp *restf
|
||||
result, err := h.openpitrix.GetAppVersionFiles(versionId, getAppVersionFilesRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -327,6 +310,7 @@ func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *res
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -339,7 +323,8 @@ func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *res
|
||||
result, err := h.openpitrix.ListAppVersionAudits(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -353,6 +338,7 @@ func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Resp
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -360,6 +346,7 @@ func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Resp
|
||||
result, err := h.openpitrix.ListAppVersionReviews(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -376,6 +363,7 @@ func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful.
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -384,6 +372,7 @@ func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful.
|
||||
result, err := h.openpitrix.ListAppVersions(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -393,6 +382,7 @@ func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful.
|
||||
if version, ok := item.(*openpitrix.AppVersion); ok {
|
||||
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)
|
||||
return
|
||||
}
|
||||
@@ -412,6 +402,7 @@ func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Respons
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -419,7 +410,8 @@ func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Respons
|
||||
result, err := h.openpitrix.ListApps(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -429,7 +421,8 @@ func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Respons
|
||||
statuses := "active|used|enabled|stopped|pending|creating|upgrading|updating|rollbacking|stopping|starting|recovering|resizing|scaling|deleting"
|
||||
statisticsResult, err := h.openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{openpitrix.AppId: app.AppId, openpitrix.Status: statuses}}, 0, 0, "", false)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
app.ClusterTotal = &statisticsResult.TotalCount
|
||||
@@ -447,6 +440,7 @@ func (h *openpitrixHandler) ModifyApp(req *restful.Request, resp *restful.Respon
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -454,15 +448,8 @@ func (h *openpitrixHandler) ModifyApp(req *restful.Request, resp *restful.Respon
|
||||
err = h.openpitrix.ModifyApp(appId, &patchAppRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -475,11 +462,8 @@ func (h *openpitrixHandler) DescribeApp(req *restful.Request, resp *restful.Resp
|
||||
result, err := h.openpitrix.DescribeApp(appId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -507,7 +491,8 @@ func (h *openpitrixHandler) CreateApp(req *restful.Request, resp *restful.Respon
|
||||
createAppRequest := &openpitrix.CreateAppRequest{}
|
||||
err := req.ReadEntity(createAppRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -543,6 +528,7 @@ func (h *openpitrixHandler) CreateAppVersion(req *restful.Request, resp *restful
|
||||
var createAppVersionRequest openpitrix.CreateAppVersionRequest
|
||||
err := req.ReadEntity(&createAppVersionRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -565,11 +551,8 @@ func (h *openpitrixHandler) CreateAppVersion(req *restful.Request, resp *restful
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -583,6 +566,7 @@ func (h *openpitrixHandler) ModifyAppVersion(req *restful.Request, resp *restful
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -590,11 +574,8 @@ func (h *openpitrixHandler) ModifyAppVersion(req *restful.Request, resp *restful
|
||||
err = h.openpitrix.ModifyAppVersion(versionId, &patchAppVersionRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -607,11 +588,8 @@ func (h *openpitrixHandler) DeleteAppVersion(req *restful.Request, resp *restful
|
||||
err := h.openpitrix.DeleteAppVersion(versionId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -624,11 +602,8 @@ func (h *openpitrixHandler) DescribeAppVersion(req *restful.Request, resp *restf
|
||||
result, err := h.openpitrix.DescribeAppVersion(versionId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -641,11 +616,8 @@ func (h *openpitrixHandler) DescribeAttachment(req *restful.Request, resp *restf
|
||||
result, err := h.openpitrix.DescribeAttachment(attachmentId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -664,6 +636,7 @@ func (h *openpitrixHandler) CreateCategory(req *restful.Request, resp *restful.R
|
||||
createCategoryRequest := &openpitrix.CreateCategoryRequest{}
|
||||
err := req.ReadEntity(createCategoryRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -671,11 +644,8 @@ func (h *openpitrixHandler) CreateCategory(req *restful.Request, resp *restful.R
|
||||
result, err := h.openpitrix.CreateCategory(createCategoryRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -687,11 +657,8 @@ func (h *openpitrixHandler) DeleteCategory(req *restful.Request, resp *restful.R
|
||||
err := h.openpitrix.DeleteCategory(categoryId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -702,6 +669,7 @@ func (h *openpitrixHandler) ModifyCategory(req *restful.Request, resp *restful.R
|
||||
categoryId := req.PathParameter("category")
|
||||
err := req.ReadEntity(&modifyCategoryRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -709,11 +677,8 @@ func (h *openpitrixHandler) ModifyCategory(req *restful.Request, resp *restful.R
|
||||
err = h.openpitrix.ModifyCategory(categoryId, &modifyCategoryRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -725,11 +690,8 @@ func (h *openpitrixHandler) DescribeCategory(req *restful.Request, resp *restful
|
||||
result, err := h.openpitrix.DescribeCategory(categoryId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -743,6 +705,7 @@ func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.R
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -750,7 +713,8 @@ func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.R
|
||||
result, err := h.openpitrix.ListCategories(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -759,7 +723,8 @@ func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.R
|
||||
if category, ok := item.(*openpitrix.Category); ok {
|
||||
statisticsResult, err := h.openpitrix.ListApps(¶ms.Conditions{Match: map[string]string{"category_id": category.CategoryID, "status": openpitrix.StatusActive, "repo": openpitrix.BuiltinRepoId}}, "", false, 0, 0)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
category.AppTotal = &statisticsResult.TotalCount
|
||||
@@ -774,6 +739,7 @@ func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Respo
|
||||
createRepoRequest := &openpitrix.CreateRepoRequest{}
|
||||
err := req.ReadEntity(createRepoRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -793,11 +759,8 @@ func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Respo
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -809,6 +772,7 @@ func (h *openpitrixHandler) DoRepoAction(req *restful.Request, resp *restful.Res
|
||||
repoId := req.PathParameter("repo")
|
||||
err := req.ReadEntity(repoActionRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -816,11 +780,8 @@ func (h *openpitrixHandler) DoRepoAction(req *restful.Request, resp *restful.Res
|
||||
err = h.openpitrix.DoRepoAction(repoId, repoActionRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -833,11 +794,8 @@ func (h *openpitrixHandler) DeleteRepo(req *restful.Request, resp *restful.Respo
|
||||
err := h.openpitrix.DeleteRepo(repoId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -849,6 +807,7 @@ func (h *openpitrixHandler) ModifyRepo(req *restful.Request, resp *restful.Respo
|
||||
repoId := req.PathParameter("repo")
|
||||
err := req.ReadEntity(&updateRepoRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -856,11 +815,8 @@ func (h *openpitrixHandler) ModifyRepo(req *restful.Request, resp *restful.Respo
|
||||
err = h.openpitrix.ModifyRepo(repoId, &updateRepoRequest)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -873,11 +829,8 @@ func (h *openpitrixHandler) DescribeRepo(req *restful.Request, resp *restful.Res
|
||||
result, err := h.openpitrix.DescribeRepo(repoId)
|
||||
|
||||
if err != nil {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -890,6 +843,7 @@ func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Respon
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -897,7 +851,8 @@ func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Respon
|
||||
result, err := h.openpitrix.ListRepos(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -910,6 +865,7 @@ func (h *openpitrixHandler) ListRepoEvents(req *restful.Request, resp *restful.R
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -917,9 +873,25 @@ func (h *openpitrixHandler) ListRepoEvents(req *restful.Request, resp *restful.R
|
||||
result, err := h.openpitrix.ListRepoEvents(repoId, conditions, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
klog.Errorln(err)
|
||||
handleOpenpitrixError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func handleOpenpitrixError(resp *restful.Response, err error) {
|
||||
if status.Code(err) == codes.NotFound {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
}
|
||||
|
||||
@@ -1,154 +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 v1alpha2
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
devopsv1alpha2 "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (h *tenantHandler) DeleteDevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
|
||||
projectId := req.PathParameter("devops")
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
_, err := h.tenant.GetWorkspace(workspaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.tenant.DeleteDevOpsProject(projectId, username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) CreateDevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
var devops devopsv1alpha2.DevOpsProject
|
||||
|
||||
err := req.ReadEntity(&devops)
|
||||
|
||||
if err != nil {
|
||||
klog.Infof("%+v", err)
|
||||
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp)
|
||||
return
|
||||
}
|
||||
|
||||
klog.Infoln("create workspace", username, workspaceName, devops)
|
||||
project, err := h.tenant.CreateDevOpsProject(username, workspaceName, &devops)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(project)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) GetDevOpsProjectsCountHandler(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
result, err := h.tenant.GetDevOpsProjectsCount(username)
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(struct {
|
||||
Count uint32 `json:"count"`
|
||||
}{Count: result})
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListDevOpsProjectsHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(constants.UserNameHeader)
|
||||
}
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.tenant.ListDevOpsProjects(workspace, username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListDevOpsRules(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
devops := req.PathParameter("devops")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := h.tenant.GetUserDevOpsSimpleRules(username, devops)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorf("%+v", err)
|
||||
errors.ParseSvcErr(err, resp)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListDevopsRules(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
devops := req.PathParameter("devops")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := h.tenant.GetUserDevOpsSimpleRules(username, devops)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
@@ -11,12 +11,15 @@ import (
|
||||
loggingv1alpha2 "kubesphere.io/kubesphere/pkg/api/logging/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/logging"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/models/tenant"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
apierr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -24,24 +27,31 @@ import (
|
||||
|
||||
type tenantHandler struct {
|
||||
tenant tenant.Interface
|
||||
am iam.AccessManagementInterface
|
||||
}
|
||||
|
||||
func newTenantHandler() *tenantHandler {
|
||||
return &tenantHandler{}
|
||||
func newTenantHandler(k8sClient k8s.Client, db *mysql.Database) *tenantHandler {
|
||||
factory := informers.NewInformerFactories(k8sClient.Kubernetes(), k8sClient.KubeSphere(), k8sClient.S2i(), k8sClient.Application())
|
||||
|
||||
return &tenantHandler{
|
||||
tenant: tenant.New(k8sClient.Kubernetes(), factory.KubernetesSharedInformerFactory(), factory.KubeSphereSharedInformerFactory(), db),
|
||||
am: iam.NewAMOperator(factory.KubernetesSharedInformerFactory()),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListWorkspaceRules(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := iam.GetUserWorkspaceSimpleRules(workspace, username)
|
||||
rules, err := h.tenant.GetWorkspaceSimpleRules(workspace, username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Response) {
|
||||
@@ -52,6 +62,7 @@ func (h *tenantHandler) ListWorkspaces(req *restful.Request, resp *restful.Respo
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -180,9 +191,49 @@ func (h *tenantHandler) DeleteNamespace(req *restful.Request, resp *restful.Resp
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
resp.WriteAsJson(apierr.None)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListDevopsProjects(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("workspace")
|
||||
username := req.PathParameter("member")
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(constants.UserNameHeader)
|
||||
}
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
limit, offset := params.ParsePaging(req)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
conditions.Match["workspace"] = workspace
|
||||
|
||||
result, err := h.tenant.ListDevopsProjects(username, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) GetDevOpsProjectsCount(req *restful.Request, resp *restful.Response) {
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
result, err := h.tenant.ListDevopsProjects(username, nil, "", false, 1, 0)
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
resp.WriteEntity(struct {
|
||||
Count int `json:"count"`
|
||||
}{Count: result.TotalCount})
|
||||
}
|
||||
func (h *tenantHandler) DeleteDevopsProject(req *restful.Request, resp *restful.Response) {
|
||||
projectId := req.PathParameter("devops")
|
||||
workspace := req.PathParameter("workspace")
|
||||
@@ -195,21 +246,40 @@ func (h *tenantHandler) DeleteDevopsProject(req *restful.Request, resp *restful.
|
||||
return
|
||||
}
|
||||
|
||||
err = h.tenant.DeleteDevOpsProject(projectId, username)
|
||||
err = h.tenant.DeleteDevOpsProject(username, projectId)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
resp.WriteEntity(apierr.None)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) CreateDevopsProject(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListNamespaceRules(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := iam.GetUserNamespaceSimpleRules(namespace, username)
|
||||
rules, err := h.tenant.GetNamespaceSimpleRules(namespace, username)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *tenantHandler) ListDevopsRules(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
devops := req.PathParameter("devops")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
rules, err := h.tenant.GetUserDevopsSimpleRules(username, devops)
|
||||
|
||||
if err != nil {
|
||||
api.HandleInternalError(resp, err)
|
||||
@@ -247,19 +317,20 @@ func (h *tenantHandler) regenerateLoggingRequest(req *restful.Request) (*restful
|
||||
newUrl := net.FormatURL("http", "127.0.0.1", 80, "/kapis/logging.kubesphere.io/v1alpha2/cluster")
|
||||
values := req.Request.URL.Query()
|
||||
|
||||
clusterRules, err := iam.GetUserClusterRules(username)
|
||||
clusterRoleRules, err := h.am.GetClusterPolicyRules(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasClusterLogAccess := iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}})
|
||||
hasClusterLogAccess := iam.RulesMatchesRequired(clusterRoleRules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}})
|
||||
// if the user is not a cluster admin
|
||||
if !hasClusterLogAccess {
|
||||
queryNamespaces := strings.Split(req.QueryParameter("namespaces"), ",")
|
||||
// then the user can only view logs of namespaces he belongs to
|
||||
namespaces := make([]string, 0)
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
roles, err := h.am.GetRoles("", username)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
|
||||
@@ -32,6 +32,8 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
|
||||
"net/http"
|
||||
)
|
||||
@@ -42,9 +44,9 @@ const (
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
func AddToContainer(c *restful.Container) error {
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client, db *mysql.Database) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
handler := newTenantHandler()
|
||||
handler := newTenantHandler(k8sClient, db)
|
||||
|
||||
ws.Route(ws.GET("/workspaces").
|
||||
To(handler.ListWorkspaces).
|
||||
@@ -103,7 +105,7 @@ func AddToContainer(c *restful.Container) error {
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/devops").
|
||||
To(handler.ListDevOpsProjectsHandler).
|
||||
To(handler.ListDevopsProjects).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.QueryParameter(params.PagingParam, "page").
|
||||
Required(false).
|
||||
@@ -115,7 +117,7 @@ func AddToContainer(c *restful.Container) error {
|
||||
Doc("List devops projects for the current user").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{member}/devops").
|
||||
To(handler.ListDevOpsProjectsHandler).
|
||||
To(handler.ListDevopsProjects).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "workspace member's username")).
|
||||
Param(ws.QueryParameter(params.PagingParam, "page").
|
||||
@@ -129,14 +131,14 @@ func AddToContainer(c *restful.Container) error {
|
||||
Doc("List the devops projects for the workspace member").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.GET("/devopscount").
|
||||
To(handler.GetDevOpsProjectsCountHandler).
|
||||
To(handler.GetDevOpsProjectsCount).
|
||||
Returns(http.StatusOK, api.StatusOK, struct {
|
||||
Count uint32 `json:"count"`
|
||||
}{}).
|
||||
Doc("Get the devops projects count for the member").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.TenantResourcesTag}))
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/devops").
|
||||
To(handler.CreateDevOpsProjectHandler).
|
||||
To(handler.CreateDevopsProject).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("Create a devops project in the specified workspace").
|
||||
Reads(devopsv1alpha2.DevOpsProject{}).
|
||||
|
||||
@@ -21,11 +21,10 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,11 +33,11 @@ const (
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
func AddToContainer(c *restful.Container, client kubernetes.Interface, config *rest.Config) error {
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client) error {
|
||||
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
|
||||
handler := newTerminalHandler(client, config)
|
||||
handler := newTerminalHandler(k8sClient.Kubernetes(), k8sClient.Config())
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/pods/{pod}").
|
||||
To(handler.handleTerminalSession).
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-ldap/ldap"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -38,9 +36,6 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -50,9 +45,21 @@ const (
|
||||
)
|
||||
|
||||
type AccessManagementInterface interface {
|
||||
GetDevopsRoleSimpleRules(role string) []SimpleRule
|
||||
GetClusterRole(username string) (*rbacv1.ClusterRole, error)
|
||||
UnBindAllRoles(username string) error
|
||||
ListRoleBindings(namespace string, role string) ([]*rbacv1.RoleBinding, error)
|
||||
CreateClusterRoleBinding(username string, clusterRole string) error
|
||||
ListRoles(namespace string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error)
|
||||
ListClusterRoles(conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error)
|
||||
ListClusterRoleBindings(clusterRole string) ([]*rbacv1.ClusterRoleBinding, error)
|
||||
GetClusterRoleSimpleRules(clusterRole string) ([]SimpleRule, error)
|
||||
GetRoleSimpleRules(namespace string, role string) ([]SimpleRule, error)
|
||||
GetRoles(namespace, username string) ([]*rbacv1.Role, error)
|
||||
GetClusterPolicyRules(username string) ([]rbacv1.PolicyRule, error)
|
||||
GetPolicyRules(namespace, username string) ([]rbacv1.PolicyRule, error)
|
||||
GetWorkspaceRoleSimpleRules(workspace, roleName string) []SimpleRule
|
||||
GetWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error)
|
||||
GetWorkspaceRoleMap(username string) (map[string]string, error)
|
||||
}
|
||||
|
||||
type amOperator struct {
|
||||
@@ -60,7 +67,31 @@ type amOperator struct {
|
||||
resources resource.ResourceGetter
|
||||
}
|
||||
|
||||
func newAMOperator(informers informers.SharedInformerFactory) AccessManagementInterface {
|
||||
func (am *amOperator) ListClusterRoleBindings(clusterRole string) ([]*rbacv1.ClusterRoleBinding, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (am *amOperator) GetRoles(namespace, username string) ([]*rbacv1.Role, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (am *amOperator) GetClusterPolicyRules(username string) ([]rbacv1.PolicyRule, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (am *amOperator) GetPolicyRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (am *amOperator) GetWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (am *amOperator) UnBindAllRoles(username string) error {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func NewAMOperator(informers informers.SharedInformerFactory) *amOperator {
|
||||
resourceGetter := resource.ResourceGetter{}
|
||||
resourceGetter.Add(v1alpha2.Role, role.NewRoleSearcher(informers))
|
||||
resourceGetter.Add(v1alpha2.ClusterRoles, clusterrole.NewClusterRoleSearcher(informers))
|
||||
@@ -198,7 +229,7 @@ func (am *amOperator) GetUserClusterRoles(username string) (*rbacv1.ClusterRole,
|
||||
return userFacingClusterRole, clusterRoles, nil
|
||||
}
|
||||
|
||||
func (am *amOperator) GetUserClusterRole(username string) (*rbacv1.ClusterRole, error) {
|
||||
func (am *amOperator) GetClusterRole(username string) (*rbacv1.ClusterRole, error) {
|
||||
userFacingClusterRole, _, err := am.GetUserClusterRoles(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -256,15 +287,15 @@ func (am *amOperator) GetWorkspaceRoleBindings(workspace string) ([]*rbacv1.Clus
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (am *amOperator) GetWorkspaceRole(workspace, role string) (*rbacv1.ClusterRole, error) {
|
||||
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
}
|
||||
role = fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
return am.informers.Rbac().V1().ClusterRoles().Lister().Get(role)
|
||||
}
|
||||
//func (am *amOperator) GetWorkspaceRole(workspace, role string) (*rbacv1.ClusterRole, error) {
|
||||
// if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
|
||||
// return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
|
||||
// }
|
||||
// role = fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
|
||||
// return am.informers.Rbac().V1().ClusterRoles().Lister().Get(role)
|
||||
//}
|
||||
|
||||
func (am *amOperator) GetUserWorkspaceRoleMap(username string) (map[string]string, error) {
|
||||
func (am *amOperator) GetWorkspaceRoleMap(username string) (map[string]string, error) {
|
||||
|
||||
clusterRoleBindings, err := am.informers.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
|
||||
|
||||
@@ -286,7 +317,7 @@ func (am *amOperator) GetUserWorkspaceRoleMap(username string) (map[string]strin
|
||||
}
|
||||
|
||||
func (am *amOperator) GetUserWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error) {
|
||||
workspaceRoleMap, err := am.GetUserWorkspaceRoleMap(username)
|
||||
workspaceRoleMap, err := am.GetWorkspaceRoleMap(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -341,55 +372,6 @@ func (am *amOperator) GetClusterRoleBindings(clusterRoleName string) ([]*rbacv1.
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (am *amOperator) ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
roleBindings, err := am.GetClusterRoleBindings(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users := make([]*User, 0)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||
user, err := GetUserInfo(subject.Name)
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// order & reverse
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
if reverse {
|
||||
i, j = j, i
|
||||
}
|
||||
switch orderBy {
|
||||
default:
|
||||
fallthrough
|
||||
case v1alpha2.Name:
|
||||
return strings.Compare(users[i].Username, users[j].Username) <= 0
|
||||
}
|
||||
})
|
||||
|
||||
result := make([]interface{}, 0)
|
||||
|
||||
for i, d := range users {
|
||||
if i >= offset && (limit == -1 || len(result) < limit) {
|
||||
result = append(result, d)
|
||||
}
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: result, TotalCount: len(users)}, nil
|
||||
|
||||
}
|
||||
|
||||
func (am *amOperator) ListRoles(namespace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
return am.resources.ListResources(namespace, v1alpha2.Roles, conditions, orderBy, reverse, limit, offset)
|
||||
}
|
||||
@@ -431,92 +413,6 @@ func (am *amOperator) ListClusterRoles(conditions *params.Conditions, orderBy st
|
||||
return am.resources.ListResources("", v1alpha2.ClusterRoles, conditions, orderBy, reverse, limit, offset)
|
||||
}
|
||||
|
||||
func (am *amOperator) NamespaceUsers(namespaceName string) ([]*User, error) {
|
||||
namespace, err := am.informers.Core().V1().Namespaces().Lister().Get(namespaceName)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
roleBindings, err := am.GetRoleBindings(namespaceName, "")
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users := make([]*User, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
// controlled by ks-controller-manager
|
||||
if roleBinding.Name == NamespaceViewerRoleBindName {
|
||||
continue
|
||||
}
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||
|
||||
// show creator
|
||||
if roleBinding.Name == NamespaceAdminRoleBindName && subject.Name != namespace.Annotations[constants.CreatorAnnotationKey] {
|
||||
continue
|
||||
}
|
||||
|
||||
user, err := GetUserInfo(subject.Name)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.Role = roleBinding.RoleRef.Name
|
||||
user.RoleBindTime = &roleBinding.CreationTimestamp.Time
|
||||
user.RoleBinding = roleBinding.Name
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (am *amOperator) GetUserWorkspaceSimpleRules(workspace, username string) ([]SimpleRule, error) {
|
||||
clusterRules, err := am.GetUserClusterRules(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// cluster-admin
|
||||
if RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"*"},
|
||||
}) {
|
||||
return am.GetWorkspaceRoleSimpleRules(workspace, constants.WorkspaceAdmin), nil
|
||||
}
|
||||
|
||||
workspaceRole, err := am.GetUserWorkspaceRole(workspace, username)
|
||||
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
|
||||
// workspaces-manager
|
||||
if RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"workspaces", "workspaces/*"},
|
||||
}) {
|
||||
return am.GetWorkspaceRoleSimpleRules(workspace, constants.WorkspacesManager), nil
|
||||
}
|
||||
|
||||
return []SimpleRule{}, nil
|
||||
}
|
||||
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return am.GetWorkspaceRoleSimpleRules(workspace, workspaceRole.Annotations[constants.DisplayNameAnnotationKey]), nil
|
||||
}
|
||||
|
||||
func (am *amOperator) GetWorkspaceRoleSimpleRules(workspace, roleName string) []SimpleRule {
|
||||
|
||||
workspaceRules := make([]SimpleRule, 0)
|
||||
@@ -583,20 +479,6 @@ func (am *amOperator) GetUserClusterSimpleRules(username string) ([]SimpleRule,
|
||||
return getClusterSimpleRule(clusterRules), nil
|
||||
}
|
||||
|
||||
func (am *amOperator) GetUserNamespaceSimpleRules(namespace, username string) ([]SimpleRule, error) {
|
||||
clusterRules, err := am.GetUserClusterRules(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules, err := am.GetUserRules(namespace, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules = append(rules, clusterRules...)
|
||||
|
||||
return getSimpleRule(rules), nil
|
||||
}
|
||||
|
||||
// Convert roles to rules
|
||||
func (am *amOperator) GetRoleSimpleRules(namespace string, roleName string) ([]SimpleRule, error) {
|
||||
|
||||
@@ -608,7 +490,7 @@ func (am *amOperator) GetRoleSimpleRules(namespace string, roleName string) ([]S
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return getSimpleRule(role.Rules), nil
|
||||
return ConvertToSimpleRule(role.Rules), nil
|
||||
}
|
||||
|
||||
func getClusterSimpleRule(policyRules []rbacv1.PolicyRule) []SimpleRule {
|
||||
@@ -629,7 +511,7 @@ func getClusterSimpleRule(policyRules []rbacv1.PolicyRule) []SimpleRule {
|
||||
return rules
|
||||
}
|
||||
|
||||
func getSimpleRule(policyRules []rbacv1.PolicyRule) []SimpleRule {
|
||||
func ConvertToSimpleRule(policyRules []rbacv1.PolicyRule) []SimpleRule {
|
||||
simpleRules := make([]SimpleRule, 0)
|
||||
for i := 0; i < len(policy.RoleRuleMapping); i++ {
|
||||
rule := SimpleRule{Name: policy.RoleRuleMapping[i].Name}
|
||||
|
||||
1070
pkg/models/iam/im.go
1070
pkg/models/iam/im.go
File diff suppressed because it is too large
Load Diff
55
pkg/models/iam/im_test.go
Normal file
55
pkg/models/iam/im_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2020 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 iam
|
||||
|
||||
import (
|
||||
"github.com/golang/mock/gomock"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIMOperator(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
ldappool, err := ldap.NewMockClient(&ldap.Options{
|
||||
Host: "192.168.0.7:30389",
|
||||
ManagerDN: "cn=admin,dc=kubesphere,dc=io",
|
||||
ManagerPassword: "admin",
|
||||
UserSearchBase: "ou=Users,dc=kubesphere,dc=io",
|
||||
GroupSearchBase: "ou=Groups,dc=kubesphere,dc=io",
|
||||
InitialCap: 8,
|
||||
MaxCap: 64,
|
||||
}, ctrl, func(client *ldap.MockClient) {
|
||||
client.EXPECT().Search(gomock.Any()).AnyTimes()
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer ldappool.Close()
|
||||
|
||||
im := NewIMOperator(ldappool, Config{})
|
||||
|
||||
err = im.Init()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,16 @@ const (
|
||||
KindTokenReview = "TokenReview"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Lang string `json:"lang,omitempty"`
|
||||
Description string `json:"description"`
|
||||
CreateTime time.Time `json:"create_time"`
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
Name string `json:"name"`
|
||||
Rules []v1.PolicyRule `json:"rules"`
|
||||
@@ -47,15 +57,3 @@ type RoleList struct {
|
||||
ClusterRoles []*v1.ClusterRole `json:"clusterRole" description:"cluster role list"`
|
||||
Roles []*v1.Role `json:"roles" description:"role list"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
adminEmail string
|
||||
adminPassword string
|
||||
authRateLimit string
|
||||
maxAuthFailed int
|
||||
authTimeInterval time.Duration
|
||||
tokenIdleTimeout time.Duration
|
||||
userInitFile string
|
||||
enableMultiLogin bool
|
||||
generateKubeConfig bool
|
||||
}
|
||||
|
||||
@@ -81,7 +81,6 @@ func TestApplicationOperator_CreateApplication(t *testing.T) {
|
||||
defer ctrl.Finish()
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
op := openpitrix.NewMockClient(ctrl)
|
||||
objs := namespacesToRuntimeObjects(test.existNamespaces...)
|
||||
k8s := fake.NewSimpleClientset(objs...)
|
||||
|
||||
@@ -41,6 +41,7 @@ type NamespaceInterface interface {
|
||||
type namespaceSearcher struct {
|
||||
k8s kubernetes.Interface
|
||||
informers k8sinformers.SharedInformerFactory
|
||||
am iam.AccessManagementInterface
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
|
||||
@@ -56,8 +57,8 @@ func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Name
|
||||
return s.k8s.CoreV1().Namespaces().Create(namespace)
|
||||
}
|
||||
|
||||
func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory) NamespaceInterface {
|
||||
return &namespaceSearcher{k8s: k8s, informers: informers}
|
||||
func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory, am iam.AccessManagementInterface) NamespaceInterface {
|
||||
return &namespaceSearcher{k8s: k8s, informers: informers, am: am}
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||
@@ -111,7 +112,7 @@ func (s *namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
|
||||
func (s *namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error) {
|
||||
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
roles, err := s.am.GetRoles("", username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -143,7 +144,7 @@ func containsNamespace(namespaces []*v1.Namespace, namespace *v1.Namespace) bool
|
||||
|
||||
func (s *namespaceSearcher) Search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error) {
|
||||
|
||||
rules, err := iam.GetUserClusterRules(username)
|
||||
rules, err := s.am.GetClusterPolicyRules(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -19,12 +19,16 @@ package tenant
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||
"strconv"
|
||||
@@ -36,14 +40,35 @@ type Interface interface {
|
||||
DescribeWorkspace(username, workspace string) (*v1alpha1.Workspace, error)
|
||||
ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
|
||||
GetWorkspace(workspace string) (*v1alpha1.Workspace, error)
|
||||
DevOpsProjectOperator
|
||||
ListDevopsProjects(username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error)
|
||||
GetWorkspaceSimpleRules(workspace, username string) ([]iam.SimpleRule, error)
|
||||
GetNamespaceSimpleRules(namespace, username string) ([]iam.SimpleRule, error)
|
||||
CountDevOpsProjects(username string) (uint32, error)
|
||||
DeleteDevOpsProject(username, projectId string) error
|
||||
GetUserDevopsSimpleRules(username string, devops string) (interface{}, error)
|
||||
}
|
||||
|
||||
type tenantOperator struct {
|
||||
workspaces WorkspaceInterface
|
||||
namespaces NamespaceInterface
|
||||
DevOpsProjectOperator
|
||||
am iam.AccessManagementInterface
|
||||
devops DevOpsProjectOperator
|
||||
}
|
||||
|
||||
func (t *tenantOperator) CountDevOpsProjects(username string) (uint32, error) {
|
||||
return t.devops.GetDevOpsProjectsCount(username)
|
||||
}
|
||||
|
||||
func (t *tenantOperator) DeleteDevOpsProject(username, projectId string) error {
|
||||
return t.devops.DeleteDevOpsProject(projectId, username)
|
||||
}
|
||||
|
||||
func (t *tenantOperator) GetUserDevopsSimpleRules(username string, projectId string) (interface{}, error) {
|
||||
return t.devops.GetUserDevOpsSimpleRules(username, projectId)
|
||||
}
|
||||
|
||||
func (t *tenantOperator) ListDevopsProjects(username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error) {
|
||||
return t.devops.ListDevOpsProjects(conditions.Match["workspace"], username, conditions, orderBy, reverse, limit, offset)
|
||||
}
|
||||
|
||||
func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
|
||||
@@ -51,9 +76,11 @@ func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
|
||||
}
|
||||
|
||||
func New(client kubernetes.Interface, informers k8sinformers.SharedInformerFactory, ksinformers ksinformers.SharedInformerFactory, db *mysql.Database) Interface {
|
||||
amOperator := iam.NewAMOperator(informers)
|
||||
return &tenantOperator{
|
||||
workspaces: newWorkspaceOperator(client, informers, ksinformers, db),
|
||||
namespaces: newNamespaceOperator(client, informers),
|
||||
workspaces: newWorkspaceOperator(client, informers, ksinformers, amOperator, db),
|
||||
namespaces: newNamespaceOperator(client, informers, amOperator),
|
||||
am: amOperator,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,17 +122,69 @@ func (t *tenantOperator) ListWorkspaces(username string, conditions *params.Cond
|
||||
return &models.PageableResponse{Items: result, TotalCount: len(workspaces)}, nil
|
||||
}
|
||||
|
||||
func (t *tenantOperator) GetWorkspaceSimpleRules(workspace, username string) ([]iam.SimpleRule, error) {
|
||||
clusterRules, err := t.am.GetClusterPolicyRules(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// cluster-admin
|
||||
if iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"*"},
|
||||
}) {
|
||||
return t.am.GetWorkspaceRoleSimpleRules(workspace, constants.WorkspaceAdmin), nil
|
||||
}
|
||||
|
||||
workspaceRole, err := t.am.GetWorkspaceRole(workspace, username)
|
||||
|
||||
// workspaces-manager
|
||||
if iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"workspaces", "workspaces/*"},
|
||||
}) {
|
||||
return t.am.GetWorkspaceRoleSimpleRules(workspace, constants.WorkspacesManager), nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return []iam.SimpleRule{}, nil
|
||||
}
|
||||
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return t.am.GetWorkspaceRoleSimpleRules(workspace, workspaceRole.Annotations[constants.DisplayNameAnnotationKey]), nil
|
||||
}
|
||||
|
||||
func (t *tenantOperator) GetNamespaceSimpleRules(namespace, username string) ([]iam.SimpleRule, error) {
|
||||
clusterRules, err := t.am.GetClusterPolicyRules(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules, err := t.am.GetPolicyRules(namespace, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules = append(rules, clusterRules...)
|
||||
|
||||
return iam.ConvertToSimpleRule(rules), nil
|
||||
}
|
||||
|
||||
func (t *tenantOperator) appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1.Workspace {
|
||||
workspace = workspace.DeepCopy()
|
||||
if workspace.Annotations == nil {
|
||||
workspace.Annotations = make(map[string]string)
|
||||
}
|
||||
ns, err := t.ListNamespaces(username, ¶ms.Conditions{Match: map[string]string{constants.WorkspaceLabelKey: workspace.Name}}, "", false, 1, 0)
|
||||
if err == nil {
|
||||
|
||||
if ns, err := t.ListNamespaces(username, ¶ms.Conditions{Match: map[string]string{constants.WorkspaceLabelKey: workspace.Name}}, "", false, 1, 0); err == nil {
|
||||
workspace.Annotations["kubesphere.io/namespace-count"] = strconv.Itoa(ns.TotalCount)
|
||||
}
|
||||
devops, err := t.ListDevOpsProjects(workspace.Name, username, ¶ms.Conditions{}, "", false, 1, 0)
|
||||
if err == nil {
|
||||
|
||||
if devops, err := t.ListDevopsProjects(username, ¶ms.Conditions{Match: map[string]string{"workspace": workspace.Name}}, "", false, 1, 0); err == nil {
|
||||
workspace.Annotations["kubesphere.io/devops-count"] = strconv.Itoa(devops.TotalCount)
|
||||
}
|
||||
|
||||
@@ -135,7 +214,3 @@ func (t *tenantOperator) ListNamespaces(username string, conditions *params.Cond
|
||||
|
||||
return &models.PageableResponse{Items: result, TotalCount: len(namespaces)}, nil
|
||||
}
|
||||
|
||||
func (t *tenantOperator) GetWorkspace(workspace string) (*v1alpha1.Workspace, error) {
|
||||
return t.workspaces.GetWorkspace(workspace)
|
||||
}
|
||||
|
||||
@@ -46,13 +46,18 @@ import (
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type InWorkspaceUser struct {
|
||||
*iam.User
|
||||
WorkspaceRole string `json:"workspaceRole"`
|
||||
}
|
||||
|
||||
type WorkspaceInterface interface {
|
||||
GetWorkspace(workspace string) (*v1alpha1.Workspace, error)
|
||||
SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error)
|
||||
ListNamespaces(workspace string) ([]*core.Namespace, error)
|
||||
DeleteNamespace(workspace, namespace string) error
|
||||
RemoveUser(user, workspace string) error
|
||||
AddUser(workspace string, user *iam.User) error
|
||||
AddUser(workspace string, user *InWorkspaceUser) error
|
||||
CountDevopsProjectsInWorkspace(workspace string) (int, error)
|
||||
CountUsersInWorkspace(workspace string) (int, error)
|
||||
CountOrgRoles() (int, error)
|
||||
@@ -64,17 +69,19 @@ type workspaceOperator struct {
|
||||
client kubernetes.Interface
|
||||
informers informers.SharedInformerFactory
|
||||
ksInformers externalversions.SharedInformerFactory
|
||||
am iam.AccessManagementInterface
|
||||
|
||||
// TODO: use db interface instead of mysql client
|
||||
// we can refactor this after rewrite devops using crd
|
||||
db *mysql.Database
|
||||
}
|
||||
|
||||
func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, db *mysql.Database) WorkspaceInterface {
|
||||
func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, am iam.AccessManagementInterface, db *mysql.Database) WorkspaceInterface {
|
||||
return &workspaceOperator{
|
||||
client: client,
|
||||
informers: informers,
|
||||
ksInformers: ksinformers,
|
||||
am: am,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
@@ -104,7 +111,7 @@ func (w *workspaceOperator) DeleteNamespace(workspace string, namespace string)
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) RemoveUser(workspace string, username string) error {
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspace, username)
|
||||
workspaceRole, err := w.am.GetWorkspaceRole(workspace, username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -117,9 +124,9 @@ func (w *workspaceOperator) RemoveUser(workspace string, username string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) AddUser(workspaceName string, user *iam.User) error {
|
||||
func (w *workspaceOperator) AddUser(workspaceName string, user *InWorkspaceUser) error {
|
||||
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspaceName, user.Username)
|
||||
workspaceRole, err := w.am.GetWorkspaceRole(workspaceName, user.Username)
|
||||
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
klog.Errorf("get workspace role failed: %+v", err)
|
||||
@@ -215,7 +222,7 @@ func (w *workspaceOperator) CountDevopsProjectsInWorkspace(workspaceName string)
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) CountUsersInWorkspace(workspace string) (int, error) {
|
||||
count, err := iam.WorkspaceUsersTotalCount(workspace)
|
||||
count, err := w.CountUsersInWorkspace(workspace)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -285,7 +292,7 @@ func (*workspaceOperator) compare(a, b *v1alpha1.Workspace, orderBy string) bool
|
||||
}
|
||||
|
||||
func (w *workspaceOperator) SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error) {
|
||||
rules, err := iam.GetUserClusterRules(username)
|
||||
rules, err := w.am.GetClusterPolicyRules(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -299,7 +306,7 @@ func (w *workspaceOperator) SearchWorkspace(username string, conditions *params.
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
workspaceRoles, err := iam.GetUserWorkspaceRoleMap(username)
|
||||
workspaceRoles, err := w.am.GetWorkspaceRoleMap(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -186,10 +186,10 @@ func newConfig() *Config {
|
||||
SonarQubeOptions: sonarqube.NewSonarQubeOptions(),
|
||||
KubernetesOptions: k8s.NewKubernetesOptions(),
|
||||
ServiceMeshOptions: servicemesh.NewServiceMeshOptions(),
|
||||
LdapOptions: ldap.NewLdapOptions(),
|
||||
LdapOptions: ldap.NewOptions(),
|
||||
RedisOptions: cache.NewRedisOptions(),
|
||||
S3Options: s3.NewS3Options(),
|
||||
OpenPitrixOptions: openpitrix.NewOpenPitrixOptions(),
|
||||
OpenPitrixOptions: openpitrix.NewOptions(),
|
||||
MonitoringOptions: prometheus.NewPrometheusOptions(),
|
||||
KubeSphereOptions: kubesphere.NewKubeSphereOptions(),
|
||||
AlertingOptions: alerting.NewAlertingOptions(),
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
@@ -28,24 +27,16 @@ type Error struct {
|
||||
|
||||
var None = Error{Message: "success"}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
func (e Error) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func Wrap(err error) Error {
|
||||
func Wrap(err error) error {
|
||||
return Error{Message: err.Error()}
|
||||
}
|
||||
|
||||
func New(message string) Error {
|
||||
return Error{Message: message}
|
||||
}
|
||||
|
||||
func ParseSvcErr(err error, resp *restful.Response) {
|
||||
if svcErr, ok := err.(restful.ServiceError); ok {
|
||||
resp.WriteServiceError(svcErr.Code, svcErr)
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, Wrap(err))
|
||||
}
|
||||
func New(format string, args ...interface{}) error {
|
||||
return Error{Message: fmt.Sprintf(format, args...)}
|
||||
}
|
||||
|
||||
func GetServiceErrorCode(err error) int {
|
||||
|
||||
@@ -38,11 +38,11 @@ func NewClientSetOptions() *ClientSetOptions {
|
||||
mySQLOptions: mysql.NewMySQLOptions(),
|
||||
redisOptions: cache.NewRedisOptions(),
|
||||
kubernetesOptions: k8s.NewKubernetesOptions(),
|
||||
ldapOptions: ldap.NewLdapOptions(),
|
||||
ldapOptions: ldap.NewOptions(),
|
||||
devopsOptions: jenkins.NewDevopsOptions(),
|
||||
sonarqubeOptions: sonarqube.NewSonarQubeOptions(),
|
||||
s3Options: s3.NewS3Options(),
|
||||
openPitrixOptions: openpitrix.NewOpenPitrixOptions(),
|
||||
openPitrixOptions: openpitrix.NewOptions(),
|
||||
prometheusOptions: prometheus.NewPrometheusOptions(),
|
||||
kubesphereOptions: kubesphere.NewKubeSphereOptions(),
|
||||
elasticSearhOptions: esclient.NewElasticSearchOptions(),
|
||||
@@ -114,7 +114,7 @@ type ClientSet struct {
|
||||
mySQLClient *mysql.Client
|
||||
|
||||
k8sClient k8s.Client
|
||||
ldapClient *ldap.Client
|
||||
ldapClient ldap.Client
|
||||
devopsClient *jenkins.Client
|
||||
sonarQubeClient *sonarqube.Client
|
||||
redisClient cache.Interface
|
||||
@@ -242,7 +242,7 @@ func (cs *ClientSet) SonarQube() (*sonarqube.Client, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *ClientSet) Ldap() (*ldap.Client, error) {
|
||||
func (cs *ClientSet) Ldap() (ldap.Client, error) {
|
||||
var err error
|
||||
|
||||
if cs.csoptions.ldapOptions == nil || cs.csoptions.ldapOptions.Host == "" {
|
||||
@@ -256,7 +256,7 @@ func (cs *ClientSet) Ldap() (*ldap.Client, error) {
|
||||
defer mutex.Unlock()
|
||||
|
||||
if cs.ldapClient == nil {
|
||||
cs.ldapClient, err = ldap.NewLdapClient(cs.csoptions.ldapOptions, cs.stopCh)
|
||||
cs.ldapClient, err = ldap.NewClient(cs.csoptions.ldapOptions, cs.stopCh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -311,7 +311,7 @@ func (cs *ClientSet) OpenPitrix() (openpitrix.Client, error) {
|
||||
if cs.openpitrixClient != nil {
|
||||
return cs.openpitrixClient, nil
|
||||
} else {
|
||||
cs.openpitrixClient, err = openpitrix.NewOpenPitrixClient(cs.csoptions.openPitrixOptions)
|
||||
cs.openpitrixClient, err = openpitrix.NewClient(cs.csoptions.openPitrixOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ type channelPool struct {
|
||||
// PoolFactory is a function to create new connections.
|
||||
type PoolFactory func(string) (ldap.Client, error)
|
||||
|
||||
// NewChannelPool returns a new pool based on buffered channels with an initial
|
||||
// newChannelPool returns a new pool based on buffered channels with an initial
|
||||
// capacity and maximum capacity. Factory is used when initial capacity is
|
||||
// greater than zero to fill the pool. A zero initialCap doesn't fill the Pool
|
||||
// until a new Get() is called. During a Get(), If there is no new connection
|
||||
@@ -36,7 +36,7 @@ type PoolFactory func(string) (ldap.Client, error)
|
||||
// of the call is one of those passed, most likely you want to set this to something
|
||||
// like
|
||||
// []uint8{ldap.LDAPResultTimeLimitExceeded, ldap.ErrorNetwork}
|
||||
func NewChannelPool(initialCap, maxCap int, name string, factory PoolFactory, closeAt []uint16) (Pool, error) {
|
||||
func newChannelPool(initialCap, maxCap int, name string, factory PoolFactory, closeAt []uint16) (Pool, error) {
|
||||
if initialCap < 0 || maxCap <= 0 || initialCap > maxCap {
|
||||
return nil, errors.New("invalid capacity settings")
|
||||
}
|
||||
@@ -85,7 +85,7 @@ func (c *channelPool) Get() (*PoolConn, error) {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
|
||||
// wrap our connections with our ldap.PoolClient implementation (wrapConn
|
||||
// wrap our connections with our ldap.Client implementation (wrapConn
|
||||
// method) that puts the connection back to the pool if it's closed.
|
||||
select {
|
||||
case conn := <-conns:
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/go-ldap/ldap"
|
||||
)
|
||||
|
||||
// PoolConn implements PoolClient to override the Close() method
|
||||
// PoolConn implements Client to override the Close() method
|
||||
type PoolConn struct {
|
||||
Conn ldap.Client
|
||||
c *channelPool
|
||||
|
||||
@@ -20,11 +20,13 @@ package ldap
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-ldap/ldap"
|
||||
"github.com/golang/mock/gomock"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
NewConn() (ldap.Client, error)
|
||||
Close()
|
||||
GroupSearchBase() string
|
||||
UserSearchBase() string
|
||||
}
|
||||
@@ -35,8 +37,8 @@ type poolClient struct {
|
||||
}
|
||||
|
||||
// panic if cannot connect to ldap service
|
||||
func NewLdapClient(options *Options, stopCh <-chan struct{}) (Client, error) {
|
||||
pool, err := NewChannelPool(8, 64, "kubesphere", func(s string) (ldap.Client, error) {
|
||||
func NewClient(options *Options, stopCh <-chan struct{}) (Client, error) {
|
||||
pool, err := newChannelPool(options.InitialCap, options.MaxCap, options.PoolName, func(s string) (ldap.Client, error) {
|
||||
conn, err := ldap.Dial("tcp", options.Host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -46,7 +48,6 @@ func NewLdapClient(options *Options, stopCh <-chan struct{}) (Client, error) {
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
pool.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -57,13 +58,16 @@ func NewLdapClient(options *Options, stopCh <-chan struct{}) (Client, error) {
|
||||
|
||||
go func() {
|
||||
<-stopCh
|
||||
if client.pool != nil {
|
||||
client.pool.Close()
|
||||
}
|
||||
client.Close()
|
||||
}()
|
||||
|
||||
return client, nil
|
||||
}
|
||||
func (l *poolClient) Close() {
|
||||
if l.pool != nil {
|
||||
l.pool.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (l *poolClient) NewConn() (ldap.Client, error) {
|
||||
if l.pool == nil {
|
||||
@@ -81,7 +85,7 @@ func (l *poolClient) NewConn() (ldap.Client, error) {
|
||||
err = conn.Bind(l.options.ManagerDN, l.options.ManagerPassword)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
klog.Error(err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
@@ -94,3 +98,25 @@ func (l *poolClient) GroupSearchBase() string {
|
||||
func (l *poolClient) UserSearchBase() string {
|
||||
return l.options.UserSearchBase
|
||||
}
|
||||
|
||||
func NewMockClient(options *Options, ctrl *gomock.Controller, setup func(client *MockClient)) (Client, error) {
|
||||
pool, err := newChannelPool(options.InitialCap, options.MaxCap, options.PoolName, func(s string) (ldap.Client, error) {
|
||||
conn := newMockClient(ctrl)
|
||||
conn.EXPECT().Bind(gomock.Any(), gomock.Any()).AnyTimes()
|
||||
conn.EXPECT().Close().AnyTimes()
|
||||
setup(conn)
|
||||
return conn, nil
|
||||
}, []uint16{ldap.LDAPResultAdminLimitExceeded, ldap.ErrorNetwork})
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := &poolClient{
|
||||
pool: pool,
|
||||
options: options,
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
231
pkg/simple/client/ldap/mock.go
Normal file
231
pkg/simple/client/ldap/mock.go
Normal file
@@ -0,0 +1,231 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/go-ldap/ldap (interfaces: Client)
|
||||
|
||||
// Package ldap is a generated GoMock package.
|
||||
package ldap
|
||||
|
||||
import (
|
||||
tls "crypto/tls"
|
||||
ldap "github.com/go-ldap/ldap"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
)
|
||||
|
||||
// MockClient is a mock of Client interface
|
||||
type MockClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockClientMockRecorder
|
||||
}
|
||||
|
||||
// MockClientMockRecorder is the mock recorder for MockClient
|
||||
type MockClientMockRecorder struct {
|
||||
mock *MockClient
|
||||
}
|
||||
|
||||
// newMockClient creates a new mock instance
|
||||
func newMockClient(ctrl *gomock.Controller) *MockClient {
|
||||
mock := &MockClient{ctrl: ctrl}
|
||||
mock.recorder = &MockClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockClient) EXPECT() *MockClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Add mocks base method
|
||||
func (m *MockClient) Add(arg0 *ldap.AddRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Add", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Add indicates an expected call of Add
|
||||
func (mr *MockClientMockRecorder) Add(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockClient)(nil).Add), arg0)
|
||||
}
|
||||
|
||||
// Bind mocks base method
|
||||
func (m *MockClient) Bind(arg0, arg1 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Bind", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Bind indicates an expected call of Bind
|
||||
func (mr *MockClientMockRecorder) Bind(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bind", reflect.TypeOf((*MockClient)(nil).Bind), arg0, arg1)
|
||||
}
|
||||
|
||||
// Close mocks base method
|
||||
func (m *MockClient) Close() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Close")
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close
|
||||
func (mr *MockClientMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockClient)(nil).Close))
|
||||
}
|
||||
|
||||
// Compare mocks base method
|
||||
func (m *MockClient) Compare(arg0, arg1, arg2 string) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Compare", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Compare indicates an expected call of Compare
|
||||
func (mr *MockClientMockRecorder) Compare(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Compare", reflect.TypeOf((*MockClient)(nil).Compare), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Del mocks base method
|
||||
func (m *MockClient) Del(arg0 *ldap.DelRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Del", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Del indicates an expected call of Del
|
||||
func (mr *MockClientMockRecorder) Del(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Del", reflect.TypeOf((*MockClient)(nil).Del), arg0)
|
||||
}
|
||||
|
||||
// Modify mocks base method
|
||||
func (m *MockClient) Modify(arg0 *ldap.ModifyRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Modify", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// Modify indicates an expected call of Modify
|
||||
func (mr *MockClientMockRecorder) Modify(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Modify", reflect.TypeOf((*MockClient)(nil).Modify), arg0)
|
||||
}
|
||||
|
||||
// ModifyDN mocks base method
|
||||
func (m *MockClient) ModifyDN(arg0 *ldap.ModifyDNRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ModifyDN", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ModifyDN indicates an expected call of ModifyDN
|
||||
func (mr *MockClientMockRecorder) ModifyDN(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyDN", reflect.TypeOf((*MockClient)(nil).ModifyDN), arg0)
|
||||
}
|
||||
|
||||
// PasswordModify mocks base method
|
||||
func (m *MockClient) PasswordModify(arg0 *ldap.PasswordModifyRequest) (*ldap.PasswordModifyResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PasswordModify", arg0)
|
||||
ret0, _ := ret[0].(*ldap.PasswordModifyResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// PasswordModify indicates an expected call of PasswordModify
|
||||
func (mr *MockClientMockRecorder) PasswordModify(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordModify", reflect.TypeOf((*MockClient)(nil).PasswordModify), arg0)
|
||||
}
|
||||
|
||||
// Search mocks base method
|
||||
func (m *MockClient) Search(arg0 *ldap.SearchRequest) (*ldap.SearchResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Search", arg0)
|
||||
ret0, _ := ret[0].(*ldap.SearchResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Search indicates an expected call of Search
|
||||
func (mr *MockClientMockRecorder) Search(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Search", reflect.TypeOf((*MockClient)(nil).Search), arg0)
|
||||
}
|
||||
|
||||
// SearchWithPaging mocks base method
|
||||
func (m *MockClient) SearchWithPaging(arg0 *ldap.SearchRequest, arg1 uint32) (*ldap.SearchResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SearchWithPaging", arg0, arg1)
|
||||
ret0, _ := ret[0].(*ldap.SearchResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SearchWithPaging indicates an expected call of SearchWithPaging
|
||||
func (mr *MockClientMockRecorder) SearchWithPaging(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchWithPaging", reflect.TypeOf((*MockClient)(nil).SearchWithPaging), arg0, arg1)
|
||||
}
|
||||
|
||||
// SetTimeout mocks base method
|
||||
func (m *MockClient) SetTimeout(arg0 time.Duration) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetTimeout", arg0)
|
||||
}
|
||||
|
||||
// SetTimeout indicates an expected call of SetTimeout
|
||||
func (mr *MockClientMockRecorder) SetTimeout(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTimeout", reflect.TypeOf((*MockClient)(nil).SetTimeout), arg0)
|
||||
}
|
||||
|
||||
// SimpleBind mocks base method
|
||||
func (m *MockClient) SimpleBind(arg0 *ldap.SimpleBindRequest) (*ldap.SimpleBindResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SimpleBind", arg0)
|
||||
ret0, _ := ret[0].(*ldap.SimpleBindResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SimpleBind indicates an expected call of SimpleBind
|
||||
func (mr *MockClientMockRecorder) SimpleBind(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SimpleBind", reflect.TypeOf((*MockClient)(nil).SimpleBind), arg0)
|
||||
}
|
||||
|
||||
// Start mocks base method
|
||||
func (m *MockClient) Start() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Start")
|
||||
}
|
||||
|
||||
// Start indicates an expected call of Start
|
||||
func (mr *MockClientMockRecorder) Start() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockClient)(nil).Start))
|
||||
}
|
||||
|
||||
// StartTLS mocks base method
|
||||
func (m *MockClient) StartTLS(arg0 *tls.Config) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StartTLS", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// StartTLS indicates an expected call of StartTLS
|
||||
func (mr *MockClientMockRecorder) StartTLS(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartTLS", reflect.TypeOf((*MockClient)(nil).StartTLS), arg0)
|
||||
}
|
||||
@@ -11,11 +11,14 @@ type Options struct {
|
||||
ManagerPassword string `json:"managerPassword,omitempty" yaml:"managerPassword"`
|
||||
UserSearchBase string `json:"userSearchBase,omitempty" yaml:"userSearchBase"`
|
||||
GroupSearchBase string `json:"groupSearchBase,omitempty" yaml:"groupSearchBase"`
|
||||
InitialCap int `json:"initialCap,omitempty" yaml:"initialCap"`
|
||||
MaxCap int `json:"maxCap,omitempty" yaml:"maxCap"`
|
||||
PoolName string `json:"poolName,omitempty" yaml:"poolName"`
|
||||
}
|
||||
|
||||
// NewLdapOptions return a default option
|
||||
// NewOptions return a default option
|
||||
// which host field point to nowhere.
|
||||
func NewLdapOptions() *Options {
|
||||
func NewOptions() *Options {
|
||||
return &Options{
|
||||
Host: "",
|
||||
ManagerDN: "cn=admin,dc=example,dc=org",
|
||||
@@ -25,7 +28,7 @@ func NewLdapOptions() *Options {
|
||||
}
|
||||
|
||||
func (l *Options) Validate() []error {
|
||||
errors := []error{}
|
||||
var errors []error
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ func newAppManagerClient(endpoint string) (pb.AppManagerClient, error) {
|
||||
return pb.NewAppManagerClient(conn), nil
|
||||
}
|
||||
|
||||
func NewOpenPitrixClient(options *Options) (Client, error) {
|
||||
func NewClient(options *Options) (Client, error) {
|
||||
|
||||
runtimeMangerClient, err := newRuntimeManagerClient(options.RuntimeManagerEndpoint)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ type Options struct {
|
||||
RepoIndexerEndpoint string `json:"repoIndexerEndpoint,omitempty" yaml:"repoIndexerEndpoint,omitempty"`
|
||||
}
|
||||
|
||||
func NewOpenPitrixOptions() *Options {
|
||||
func NewOptions() *Options {
|
||||
return &Options{}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,19 +20,26 @@ package jwtutil
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"os"
|
||||
)
|
||||
|
||||
const secretEnv = "JWT_SECRET"
|
||||
|
||||
var secret []byte
|
||||
var secretKey []byte
|
||||
|
||||
func Setup(key string) {
|
||||
secret = []byte(key)
|
||||
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(secret)
|
||||
token, err := uToken.SignedString(secretKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -41,7 +48,7 @@ func MustSigned(claims jwt.MapClaims) string {
|
||||
|
||||
func provideKey(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok {
|
||||
return secret, nil
|
||||
return secretKey, nil
|
||||
} else {
|
||||
return nil, fmt.Errorf("expect token signed with HMAC but got %v", token.Header["alg"])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user