File diff suppressed because it is too large
Load Diff
@@ -1,54 +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 "sync"
|
||||
|
||||
type Counter struct {
|
||||
value int
|
||||
m *sync.Mutex
|
||||
}
|
||||
|
||||
func NewCounter(value int) Counter {
|
||||
c := Counter{}
|
||||
c.m = &sync.Mutex{}
|
||||
c.Set(value)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Counter) Set(value int) {
|
||||
c.m.Lock()
|
||||
c.value = value
|
||||
c.m.Unlock()
|
||||
}
|
||||
|
||||
func (c *Counter) Add(value int) {
|
||||
c.m.Lock()
|
||||
c.value += value
|
||||
c.m.Unlock()
|
||||
}
|
||||
|
||||
func (c *Counter) Sub(value int) {
|
||||
c.m.Lock()
|
||||
c.value -= value
|
||||
c.m.Unlock()
|
||||
}
|
||||
|
||||
func (c *Counter) Get() int {
|
||||
return c.value
|
||||
}
|
||||
@@ -1,188 +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"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
)
|
||||
|
||||
const ClusterRoleKind = "ClusterRole"
|
||||
|
||||
// Get user list based on workspace role
|
||||
func WorkspaceRoleUsers(workspace string, roleName string) ([]models.User, error) {
|
||||
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
|
||||
workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
names := make([]string, 0)
|
||||
|
||||
for _, subject := range workspaceRoleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind {
|
||||
names = append(names, subject.Name)
|
||||
}
|
||||
}
|
||||
|
||||
users, err := GetUsers(names)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(users); i++ {
|
||||
users[i].WorkspaceRole = roleName
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUsers(names []string) ([]models.User, error) {
|
||||
var users []models.User
|
||||
|
||||
if names == nil || len(names) == 0 {
|
||||
return make([]models.User, 0), nil
|
||||
}
|
||||
|
||||
conn, err := ldap.Client()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
user, err := UserDetail(name, conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, *user)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUser(name string) (*models.User, error) {
|
||||
|
||||
conn, err := ldap.Client()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, err := UserDetail(name, conn)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespace bool, namespaces []string, err error) {
|
||||
|
||||
clusterRoles, err := GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
clusterRules := make([]v1.PolicyRule, 0)
|
||||
for _, role := range clusterRoles {
|
||||
clusterRules = append(clusterRules, role.Rules...)
|
||||
}
|
||||
|
||||
if requiredRule.Size() == 0 {
|
||||
if RulesMatchesRequired(clusterRules, v1.PolicyRule{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
}) {
|
||||
return true, nil, nil
|
||||
}
|
||||
} else {
|
||||
|
||||
if RulesMatchesRequired(clusterRules, requiredRule) {
|
||||
return true, nil, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
roles, err := GetRoles("", username)
|
||||
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
rulesMapping := make(map[string][]v1.PolicyRule, 0)
|
||||
|
||||
for _, role := range roles {
|
||||
rules := rulesMapping[role.Namespace]
|
||||
if rules == nil {
|
||||
rules = make([]v1.PolicyRule, 0)
|
||||
}
|
||||
rules = append(rules, role.Rules...)
|
||||
rulesMapping[role.Namespace] = rules
|
||||
}
|
||||
|
||||
namespaces = make([]string, 0)
|
||||
|
||||
for namespace, rules := range rulesMapping {
|
||||
if requiredRule.Size() == 0 || RulesMatchesRequired(rules, requiredRule) {
|
||||
namespaces = append(namespaces, namespace)
|
||||
}
|
||||
}
|
||||
|
||||
return false, namespaces, nil
|
||||
}
|
||||
|
||||
func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) {
|
||||
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users := make([]string, 0)
|
||||
|
||||
for _, s := range clusterRoleBinding.Subjects {
|
||||
if s.Kind == v1.UserKind && !slice.ContainsString(users, s.Name, nil) {
|
||||
users = append(users, s.Name)
|
||||
}
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
||||
for _, rule := range rules {
|
||||
if ruleMatchesRequired(rule, required) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -22,9 +22,12 @@ import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/redis"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -38,11 +41,10 @@ import (
|
||||
ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
jwtutils "kubesphere.io/kubesphere/pkg/utils/jwt"
|
||||
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
|
||||
)
|
||||
|
||||
var (
|
||||
counter Counter
|
||||
adminEmail string
|
||||
adminPassword string
|
||||
tokenExpireTime time.Duration
|
||||
@@ -82,7 +84,7 @@ func checkAndCreateDefaultGroup(conn ldap.Client) error {
|
||||
nil,
|
||||
)
|
||||
|
||||
groups, err := conn.Search(groupSearchRequest)
|
||||
_, err := conn.Search(groupSearchRequest)
|
||||
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
err = createGroupsBaseDN(conn)
|
||||
@@ -95,14 +97,6 @@ func checkAndCreateDefaultGroup(conn ldap.Client) error {
|
||||
return fmt.Errorf("iam database init failed: %s\n", err)
|
||||
}
|
||||
|
||||
if groups == nil || len(groups.Entries) == 0 {
|
||||
_, err = CreateGroup(models.Group{Path: constants.SystemWorkspace, Name: constants.SystemWorkspace, Creator: constants.AdminUserName, Description: "system workspace"})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("system-workspace create failed: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -130,13 +124,10 @@ func checkAndCreateDefaultUser(conn ldap.Client) error {
|
||||
}
|
||||
|
||||
if users == nil || len(users.Entries) == 0 {
|
||||
counter = NewCounter(0)
|
||||
err := CreateUser(models.User{Username: constants.AdminUserName, Email: adminEmail, Password: adminPassword, Description: "Administrator account that was always created by default."})
|
||||
_, err := CreateUser(&models.User{Username: constants.AdminUserName, Email: adminEmail, Password: adminPassword, Description: "Administrator account that was always created by default."})
|
||||
if err != nil {
|
||||
return fmt.Errorf("admin create failed: %s\n", err)
|
||||
}
|
||||
} else {
|
||||
counter = NewCounter(len(users.Entries))
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -164,12 +155,12 @@ func createGroupsBaseDN(conn ldap.Client) error {
|
||||
}
|
||||
|
||||
// User login
|
||||
func Login(username string, password string, ip string) (string, error) {
|
||||
func Login(username string, password string, ip string) (*models.Token, error) {
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
@@ -185,11 +176,11 @@ func Login(username string, password string, ip string) (string, error) {
|
||||
result, err := conn.Search(userSearchRequest)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(result.Entries) != 1 {
|
||||
return "", ldap.NewError(ldap.LDAPResultInvalidCredentials, errors.New("incorrect password"))
|
||||
return nil, ldap.NewError(ldap.LDAPResultInvalidCredentials, errors.New("incorrect password"))
|
||||
}
|
||||
|
||||
uid := result.Entries[0].GetAttributeValue("uid")
|
||||
@@ -200,7 +191,7 @@ func Login(username string, password string, ip string) (string, error) {
|
||||
err = conn.Bind(dn, password)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claims := jwt.MapClaims{}
|
||||
@@ -209,13 +200,11 @@ func Login(username string, password string, ip string) (string, error) {
|
||||
claims["username"] = uid
|
||||
claims["email"] = email
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
|
||||
uToken, _ := token.SignedString(jwtutils.Secret)
|
||||
token := jwtutil.MustSigned(claims)
|
||||
|
||||
loginLog(uid, ip)
|
||||
|
||||
return uToken, nil
|
||||
return &models.Token{Token: token}, nil
|
||||
}
|
||||
|
||||
func loginLog(uid, ip string) {
|
||||
@@ -226,99 +215,6 @@ func loginLog(uid, ip string) {
|
||||
}
|
||||
}
|
||||
|
||||
func UserList(limit int, offset int) (int, []models.User, error) {
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
users := make([]models.User, 0)
|
||||
|
||||
pageControl := ldap.NewControlPaging(1000)
|
||||
|
||||
entries := make([]*ldap.Entry, 0)
|
||||
|
||||
cursor := 0
|
||||
l1:
|
||||
for {
|
||||
|
||||
userSearchRequest := ldap.NewSearchRequest(
|
||||
ldapclient.UserSearchBase,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=inetOrgPerson))",
|
||||
[]string{"uid", "mail", "description"},
|
||||
[]ldap.Control{pageControl},
|
||||
)
|
||||
|
||||
response, err := conn.Search(userSearchRequest)
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
for _, entry := range response.Entries {
|
||||
cursor++
|
||||
if cursor > offset {
|
||||
if len(entries) < limit {
|
||||
entries = append(entries, entry)
|
||||
} else {
|
||||
break l1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updatedControl := ldap.FindControl(response.Controls, ldap.ControlTypePaging)
|
||||
if ctrl, ok := updatedControl.(*ldap.ControlPaging); ctrl != nil && ok && len(ctrl.Cookie) != 0 {
|
||||
pageControl.SetCookie(ctrl.Cookie)
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
redisClient := redis.Client()
|
||||
|
||||
for _, v := range entries {
|
||||
|
||||
uid := v.GetAttributeValue("uid")
|
||||
email := v.GetAttributeValue("mail")
|
||||
description := v.GetAttributeValue("description")
|
||||
user := models.User{Username: uid, Email: email, Description: description}
|
||||
|
||||
avatar, err := redisClient.HMGet("kubesphere:users:avatar", uid).Result()
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if len(avatar) > 0 {
|
||||
if url, ok := avatar[0].(string); ok {
|
||||
user.AvatarUrl = url
|
||||
}
|
||||
}
|
||||
|
||||
lastLogin, err := redisClient.LRange(fmt.Sprintf("kubesphere:users:%s:login-log", uid), -1, -1).Result()
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if len(lastLogin) > 0 {
|
||||
user.LastLoginTime = strings.Split(lastLogin[0], ",")[0]
|
||||
}
|
||||
|
||||
user.ClusterRules = make([]models.SimpleRule, 0)
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
return counter.Get(), users, nil
|
||||
}
|
||||
|
||||
func LoginLog(username string) ([]string, error) {
|
||||
redisClient := redis.Client()
|
||||
|
||||
@@ -331,48 +227,77 @@ func LoginLog(username string) ([]string, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func Search(keyword string, limit int, offset int) (int, []models.User, error) {
|
||||
func ListUsersByName(names []string) (*models.PageableResponse, error) {
|
||||
users := make([]*models.User, 0)
|
||||
|
||||
for _, name := range names {
|
||||
if !k8sutil.ContainsUser(users, name) {
|
||||
user, err := DescribeUser(name)
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, u := range users {
|
||||
items = append(items, u)
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: len(items)}, nil
|
||||
}
|
||||
|
||||
func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
users := make([]models.User, 0)
|
||||
|
||||
pageControl := ldap.NewControlPaging(80)
|
||||
|
||||
entries := make([]*ldap.Entry, 0)
|
||||
users := make([]models.User, 0)
|
||||
|
||||
filter := "(&(objectClass=inetOrgPerson))"
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=*%s*)(mail=*%s*)(description=*%s*)))", keyword, keyword, keyword)
|
||||
}
|
||||
|
||||
cursor := 0
|
||||
l1:
|
||||
for {
|
||||
userSearchRequest := ldap.NewSearchRequest(
|
||||
ldapclient.UserSearchBase,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=*%s*)(mail=*%s*)(description=*%s*)))", keyword, keyword, keyword),
|
||||
[]string{"uid", "mail", "description"},
|
||||
filter,
|
||||
[]string{"uid", "mail", "description", "preferredLanguage", "createTimestamp"},
|
||||
[]ldap.Control{pageControl},
|
||||
)
|
||||
|
||||
response, err := conn.Search(userSearchRequest)
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, entry := range response.Entries {
|
||||
cursor++
|
||||
if cursor > offset {
|
||||
if len(entries) < limit {
|
||||
entries = append(entries, entry)
|
||||
} else {
|
||||
break l1
|
||||
}
|
||||
}
|
||||
|
||||
uid := entry.GetAttributeValue("uid")
|
||||
email := entry.GetAttributeValue("mail")
|
||||
description := entry.GetAttributeValue("description")
|
||||
lang := entry.GetAttributeValue("preferredLanguage")
|
||||
createTimestamp, _ := time.Parse("20060102150405Z", entry.GetAttributeValue("createTimestamp"))
|
||||
|
||||
user := models.User{Username: uid, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
updatedControl := ldap.FindControl(response.Controls, ldap.ControlTypePaging)
|
||||
@@ -384,52 +309,104 @@ l1:
|
||||
break
|
||||
}
|
||||
|
||||
redisClient := redis.Client()
|
||||
|
||||
for _, v := range entries {
|
||||
|
||||
uid := v.GetAttributeValue("uid")
|
||||
email := v.GetAttributeValue("mail")
|
||||
description := v.GetAttributeValue("description")
|
||||
user := models.User{Username: uid, Email: email, Description: description}
|
||||
|
||||
avatar, err := redisClient.HMGet("kubesphere:users:avatar", uid).Result()
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
switch orderBy {
|
||||
case "username":
|
||||
fallthrough
|
||||
case "createTime":
|
||||
return users[i].CreateTime.Before(users[j].CreateTime)
|
||||
default:
|
||||
return strings.Compare(users[i].Username, users[j].Username) <= 0
|
||||
}
|
||||
})
|
||||
|
||||
if len(avatar) > 0 {
|
||||
if url, ok := avatar[0].(string); ok {
|
||||
user.AvatarUrl = url
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for i, user := range users {
|
||||
|
||||
if i >= offset && len(items) < limit {
|
||||
|
||||
avatar, err := getAvatar(user.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.AvatarUrl = avatar
|
||||
|
||||
lastLoginTime, err := getLastLoginTime(user.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user.LastLoginTime = lastLoginTime
|
||||
|
||||
clusterRole, err := GetUserClusterRole(user.Username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.ClusterRole = clusterRole.Name
|
||||
|
||||
items = append(items, user)
|
||||
}
|
||||
|
||||
lastLogin, err := redisClient.LRange(fmt.Sprintf("kubesphere:users:%s:login-log", uid), -1, -1).Result()
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if len(lastLogin) > 0 {
|
||||
user.LastLoginTime = strings.Split(lastLogin[0], ",")[0]
|
||||
}
|
||||
|
||||
user.ClusterRules = make([]models.SimpleRule, 0)
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
return counter.Get(), users, nil
|
||||
return &models.PageableResponse{Items: items, TotalCount: len(users)}, nil
|
||||
}
|
||||
|
||||
func UserDetail(username string, conn ldap.Client) (*models.User, error) {
|
||||
func DescribeUser(username string) (*models.User, error) {
|
||||
|
||||
user, err := GetUserInfo(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groups, err := GetUserGroups(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.Groups = groups
|
||||
|
||||
avatar, err := getAvatar(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.AvatarUrl = avatar
|
||||
|
||||
lastLoginTime, err := getLastLoginTime(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user.LastLoginTime = lastLoginTime
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// Get user info only included email description & lang
|
||||
func GetUserInfo(username string) (*models.User, error) {
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userSearchRequest := ldap.NewSearchRequest(
|
||||
ldapclient.UserSearchBase,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass=inetOrgPerson)(uid=%s))", username),
|
||||
[]string{"mail", "description", "preferredLanguage"},
|
||||
[]string{"mail", "description", "preferredLanguage", "createTimestamp"},
|
||||
nil,
|
||||
)
|
||||
|
||||
@@ -446,7 +423,20 @@ func UserDetail(username string, conn ldap.Client) (*models.User, error) {
|
||||
email := result.Entries[0].GetAttributeValue("mail")
|
||||
description := result.Entries[0].GetAttributeValue("description")
|
||||
lang := result.Entries[0].GetAttributeValue("preferredLanguage")
|
||||
user := models.User{Username: username, Email: email, Description: description, Lang: lang}
|
||||
createTimestamp, _ := time.Parse("20060102150405Z", result.Entries[0].GetAttributeValue("createTimestamp"))
|
||||
user := &models.User{Username: username, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func GetUserGroups(username string) ([]string, error) {
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
groupSearchRequest := ldap.NewSearchRequest(
|
||||
ldapclient.GroupSearchBase,
|
||||
@@ -456,11 +446,10 @@ func UserDetail(username string, conn ldap.Client) (*models.User, error) {
|
||||
nil,
|
||||
)
|
||||
|
||||
result, err = conn.Search(groupSearchRequest)
|
||||
result, err := conn.Search(groupSearchRequest)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
|
||||
groups := make([]string, 0)
|
||||
@@ -470,41 +459,47 @@ func UserDetail(username string, conn ldap.Client) (*models.User, error) {
|
||||
groups = append(groups, groupName)
|
||||
}
|
||||
|
||||
user.Groups = groups
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
redisClient := redis.Client()
|
||||
|
||||
avatar, err := redisClient.HMGet("kubesphere:users:avatar", username).Result()
|
||||
func getLastLoginTime(username string) (string, error) {
|
||||
lastLogin, err := redis.Client().LRange(fmt.Sprintf("kubesphere:users:%s:login-log", username), -1, -1).Result()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(lastLogin) > 0 {
|
||||
return strings.Split(lastLogin[0], ",")[0], nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func setAvatar(username, avatar string) error {
|
||||
_, err := redis.Client().HMSet("kubesphere:users:avatar", map[string]interface{}{"username": avatar}).Result()
|
||||
return err
|
||||
}
|
||||
|
||||
func getAvatar(username string) (string, error) {
|
||||
|
||||
avatar, err := redis.Client().HMGet("kubesphere:users:avatar", username).Result()
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(avatar) > 0 {
|
||||
if url, ok := avatar[0].(string); ok {
|
||||
user.AvatarUrl = url
|
||||
return url, nil
|
||||
}
|
||||
}
|
||||
|
||||
user.Status = 0
|
||||
|
||||
lastLogin, err := redisClient.LRange(fmt.Sprintf("kubesphere:users:%s:login-log", username), -1, -1).Result()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(lastLogin) > 0 {
|
||||
user.LastLoginTime = strings.Split(lastLogin[0], ",")[0]
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func DeleteUser(username string) error {
|
||||
|
||||
// bind root DN
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -521,13 +516,7 @@ func DeleteUser(username string) error {
|
||||
|
||||
err = deleteRoleBindings(username)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
counter.Sub(1)
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func deleteRoleBindings(username string) error {
|
||||
@@ -539,7 +528,7 @@ func deleteRoleBindings(username string) error {
|
||||
}
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
|
||||
roleBinding = roleBinding.DeepCopy()
|
||||
length1 := len(roleBinding.Subjects)
|
||||
|
||||
for index, subject := range roleBinding.Subjects {
|
||||
@@ -571,6 +560,7 @@ func deleteRoleBindings(username string) error {
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
|
||||
for _, clusterRoleBinding := range clusterRoleBindings {
|
||||
clusterRoleBinding = clusterRoleBinding.DeepCopy()
|
||||
length1 := len(clusterRoleBinding.Subjects)
|
||||
|
||||
for index, subject := range clusterRoleBinding.Subjects {
|
||||
@@ -637,7 +627,7 @@ func UserCreateCheck(check string) (exist bool, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func CreateUser(user models.User) error {
|
||||
func CreateUser(user *models.User) (*models.User, error) {
|
||||
user.Username = strings.TrimSpace(user.Username)
|
||||
user.Email = strings.TrimSpace(user.Email)
|
||||
user.Password = strings.TrimSpace(user.Password)
|
||||
@@ -646,7 +636,7 @@ func CreateUser(user models.User) error {
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
@@ -662,17 +652,17 @@ func CreateUser(user models.User) error {
|
||||
result, err := conn.Search(userSearchRequest)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(result.Entries) > 0 {
|
||||
return ldap.NewError(ldap.LDAPResultEntryAlreadyExists, fmt.Errorf("username or email already exists"))
|
||||
return nil, ldap.NewError(ldap.LDAPResultEntryAlreadyExists, fmt.Errorf("username or email already exists"))
|
||||
}
|
||||
|
||||
maxUid, err := getMaxUid(conn)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxUid += 1
|
||||
@@ -688,7 +678,7 @@ func CreateUser(user models.User) error {
|
||||
userCreateRequest.Attribute("mail", []string{user.Email}) // RFC1274: RFC822 Mailbox
|
||||
userCreateRequest.Attribute("userPassword", []string{user.Password}) // RFC4519/2307: password of user
|
||||
if user.Lang != "" {
|
||||
userCreateRequest.Attribute("preferredLanguage", []string{user.Lang}) // RFC4519/2307: password of user
|
||||
userCreateRequest.Attribute("preferredLanguage", []string{user.Lang})
|
||||
}
|
||||
if user.Description != "" {
|
||||
userCreateRequest.Attribute("description", []string{user.Description}) // RFC4519: descriptive information
|
||||
@@ -697,16 +687,22 @@ func CreateUser(user models.User) error {
|
||||
err = conn.Add(userCreateRequest)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
counter.Add(1)
|
||||
if user.AvatarUrl != "" {
|
||||
setAvatar(user.Username, user.AvatarUrl)
|
||||
}
|
||||
|
||||
if user.ClusterRole != "" {
|
||||
CreateClusterRoleBinding(user.Username, user.ClusterRole)
|
||||
err := CreateClusterRoleBinding(user.Username, user.ClusterRole)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return DescribeUser(user.Username)
|
||||
}
|
||||
|
||||
func getMaxUid(conn ldap.Client) (int, error) {
|
||||
@@ -768,11 +764,12 @@ func getMaxGid(conn ldap.Client) (int, error) {
|
||||
return maxGid, nil
|
||||
}
|
||||
|
||||
func UpdateUser(user models.User) error {
|
||||
func UpdateUser(user *models.User) (*models.User, error) {
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
@@ -794,19 +791,27 @@ func UpdateUser(user models.User) error {
|
||||
userModifyRequest.Replace("userPassword", []string{user.Password})
|
||||
}
|
||||
|
||||
if user.AvatarUrl != "" {
|
||||
err = setAvatar(user.Username, user.AvatarUrl)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = conn.Modify(userModifyRequest)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = CreateClusterRoleBinding(user.Username, user.ClusterRole)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nil
|
||||
return DescribeUser(user.Username)
|
||||
}
|
||||
func DeleteGroup(path string) error {
|
||||
|
||||
@@ -829,13 +834,14 @@ func DeleteGroup(path string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateGroup(group models.Group) (*models.Group, error) {
|
||||
func CreateGroup(group *models.Group) (*models.Group, error) {
|
||||
|
||||
// bind root DN
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
maxGid, err := getMaxGid(conn)
|
||||
@@ -861,7 +867,9 @@ func CreateGroup(group models.Group) (*models.Group, error) {
|
||||
groupCreateRequest.Attribute("description", []string{group.Description})
|
||||
}
|
||||
|
||||
groupCreateRequest.Attribute("memberUid", []string{group.Creator})
|
||||
if group.Members != nil {
|
||||
groupCreateRequest.Attribute("memberUid", group.Members)
|
||||
}
|
||||
|
||||
err = conn.Add(groupCreateRequest)
|
||||
|
||||
@@ -871,18 +879,7 @@ func CreateGroup(group models.Group) (*models.Group, error) {
|
||||
|
||||
group.Gid = strconv.Itoa(maxGid)
|
||||
|
||||
group.CreateTime = time.Now().UTC().Format("2006-01-02T15:04:05Z")
|
||||
|
||||
redisClient := redis.Client()
|
||||
|
||||
if err := redisClient.HMSet("kubesphere:groups:create-time", map[string]interface{}{group.Name: group.CreateTime}).Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := redisClient.HMSet("kubesphere:groups:creator", map[string]interface{}{group.Name: group.Creator}).Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &group, nil
|
||||
return DescribeGroup(group.Path)
|
||||
}
|
||||
|
||||
func UpdateGroup(group *models.Group) (*models.Group, error) {
|
||||
@@ -894,7 +891,7 @@ func UpdateGroup(group *models.Group) (*models.Group, error) {
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
old, err := GroupDetail(group.Path, conn)
|
||||
old, err := DescribeGroup(group.Path)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1027,34 +1024,22 @@ func ChildList(path string) ([]models.Group, error) {
|
||||
|
||||
group.ChildGroups = childGroups
|
||||
|
||||
redisClient := redis.Client()
|
||||
|
||||
createTime, _ := redisClient.HMGet("kubesphere:groups:create-time", group.Name).Result()
|
||||
|
||||
if len(createTime) > 0 {
|
||||
if t, ok := createTime[0].(string); ok {
|
||||
group.CreateTime = t
|
||||
}
|
||||
}
|
||||
|
||||
creator, _ := redisClient.HMGet("kubesphere:groups:creator", group.Name).Result()
|
||||
|
||||
if len(creator) > 0 {
|
||||
if t, ok := creator[0].(string); ok {
|
||||
group.Creator = t
|
||||
}
|
||||
}
|
||||
|
||||
groups = append(groups, group)
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func GroupDetail(path string, conn ldap.Client) (*models.Group, error) {
|
||||
func DescribeGroup(path string) (*models.Group, error) {
|
||||
|
||||
searchBase, cn := splitPath(path)
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
groupSearchRequest := ldap.NewSearchRequest(searchBase,
|
||||
ldap.ScopeSingleLevel, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass=posixGroup)(cn=%s))", cn),
|
||||
@@ -1083,24 +1068,76 @@ func GroupDetail(path string, conn ldap.Client) (*models.Group, error) {
|
||||
|
||||
group.ChildGroups = childGroups
|
||||
|
||||
redisClient := redis.Client()
|
||||
|
||||
createTime, _ := redisClient.HMGet("kubesphere:groups:create-time", group.Name).Result()
|
||||
|
||||
if len(createTime) > 0 {
|
||||
if t, ok := createTime[0].(string); ok {
|
||||
group.CreateTime = t
|
||||
}
|
||||
}
|
||||
|
||||
creator, _ := redisClient.HMGet("kubesphere:groups:creator", group.Name).Result()
|
||||
|
||||
if len(creator) > 0 {
|
||||
if t, ok := creator[0].(string); ok {
|
||||
group.Creator = t
|
||||
}
|
||||
}
|
||||
|
||||
return &group, nil
|
||||
|
||||
}
|
||||
|
||||
func WorkspaceUsersTotalCount(workspace string) (int, error) {
|
||||
workspaceRoleBindings, err := GetWorkspaceRoleBindings(workspace)
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
users := make([]string, 0)
|
||||
|
||||
for _, roleBinding := range workspaceRoleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||
users = append(users, subject.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return len(users), nil
|
||||
}
|
||||
|
||||
func ListWorkspaceUsers(workspace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
|
||||
workspaceRoleBindings, err := GetWorkspaceRoleBindings(workspace)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
|
||||
for _, roleBinding := range workspaceRoleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||
user, err := DescribeUser(subject.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefix := fmt.Sprintf("workspace:%s:", workspace)
|
||||
user.WorkspaceRole = fmt.Sprintf("workspace-%s", strings.TrimPrefix(roleBinding.Name, prefix))
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// order & reverse
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
switch orderBy {
|
||||
default:
|
||||
fallthrough
|
||||
case "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
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package policy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
@@ -55,292 +56,25 @@ func init() {
|
||||
}
|
||||
|
||||
var (
|
||||
WorkspaceRoleRuleMapping = []models.Rule{
|
||||
{
|
||||
Name: "workspaces",
|
||||
Actions: []models.Action{
|
||||
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces"},
|
||||
}, {
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"jenkins.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}, {
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"devops.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{Name: "members",
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"patch", "update"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "devops",
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/devops"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/devops"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/devops"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/devops"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "projects",
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "organizations",
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"workspaces/organizations"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"workspaces/organizations"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"workspaces/organizations"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"workspaces/organizations"},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
Name: "roles",
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/roles"},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ClusterRoleRuleMapping = []models.Rule{
|
||||
{Name: "workspaces",
|
||||
Actions: []models.Action{
|
||||
{
|
||||
Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"workspaces"},
|
||||
Resources: []string{"monitoring/*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"quota", "status", "monitoring", "persistentvolumeclaims"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"resources"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces", "workspaces/*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"namespaces"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"", "apps", "extensions", "batch"},
|
||||
Resources: []string{"serviceaccounts", "limitranges", "deployments", "configmaps", "secrets", "jobs", "cronjobs", "persistentvolumeclaims", "statefulsets", "daemonsets", "ingresses", "services", "pods/*", "pods", "events", "deployments/scale"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"rolebindings", "roles"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"members"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"router"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"jenkins.kubesphere.io", "devops.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
APIGroups: []string{"tenant.kubesphere.io"},
|
||||
Resources: []string{"workspaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"tenant.kubesphere.io"},
|
||||
Resources: []string{"workspaces"},
|
||||
},
|
||||
},
|
||||
@@ -349,7 +83,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
APIGroups: []string{"tenant.kubesphere.io", "monitoring.kubesphere.io"},
|
||||
Resources: []string{"workspaces", "workspaces/*"},
|
||||
},
|
||||
{
|
||||
@@ -359,7 +93,7 @@ var (
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"", "apps", "extensions", "batch"},
|
||||
APIGroups: []string{"", "apps", "extensions", "batch", "resources.kubesphere.io"},
|
||||
Resources: []string{"serviceaccounts", "limitranges", "deployments", "configmaps", "secrets", "jobs", "cronjobs", "persistentvolumeclaims", "statefulsets", "daemonsets", "ingresses", "services", "pods/*", "pods", "events", "deployments/scale"},
|
||||
},
|
||||
{
|
||||
@@ -367,16 +101,6 @@ var (
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"rolebindings", "roles"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"members"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"router"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"jenkins.kubesphere.io", "devops.kubesphere.io"},
|
||||
@@ -391,9 +115,13 @@ var (
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"monitoring", "health", "monitoring/*"},
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"monitoring.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}, {
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"health"},
|
||||
}},
|
||||
},
|
||||
},
|
||||
@@ -405,14 +133,14 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "watch", "list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users", "users/*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"clusterrules"},
|
||||
ResourceNames: []string{"mapping"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"rulesmapping"},
|
||||
ResourceNames: []string{"clusterroles"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "watch", "list"},
|
||||
@@ -425,12 +153,12 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create", "get", "list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"clusterrules"},
|
||||
ResourceNames: []string{"mapping"},
|
||||
},
|
||||
@@ -445,7 +173,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list", "update", "patch"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
{
|
||||
@@ -459,8 +187,8 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete", "deletecollection"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"accounts"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -483,8 +211,8 @@ var (
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"clusterroles/*"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"clusterroles", "clusterroles/*"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -527,15 +255,9 @@ var (
|
||||
APIGroups: []string{"storage.k8s.io"},
|
||||
Resources: []string{"storageclasses"},
|
||||
}, {
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"storage-classes"},
|
||||
Resources: []string{"resources"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"storage/*"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"storageclasses", "storageclasses/*"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -578,15 +300,13 @@ var (
|
||||
Resources: []string{"nodes", "events"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"nodes"},
|
||||
Resources: []string{"resources", "monitoring", "monitoring/*"},
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"nodes", "nodes/*"},
|
||||
}, {
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"pods"},
|
||||
Resources: []string{"resources"},
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"monitoring.kubesphere.io"},
|
||||
Resources: []string{"nodes"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -669,14 +389,9 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"list", "get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"components", "components/*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"list", "get"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"pods"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -726,12 +441,12 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io", "resources.kubesphere.io"},
|
||||
Resources: []string{"rolebindings"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
},
|
||||
@@ -772,15 +487,9 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io", "resources.kubesphere.io"},
|
||||
Resources: []string{"roles"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"roles"},
|
||||
Resources: []string{"resources"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
@@ -819,7 +528,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"apps", "extensions"},
|
||||
APIGroups: []string{"apps", "extensions", "resources.kubesphere.io"},
|
||||
Resources: []string{"deployments", "deployments/scale"},
|
||||
},
|
||||
{
|
||||
@@ -875,7 +584,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"apps"},
|
||||
APIGroups: []string{"apps", "resources.kubesphere.io"},
|
||||
Resources: []string{"statefulsets"},
|
||||
},
|
||||
{
|
||||
@@ -929,7 +638,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"apps", "extensions"},
|
||||
APIGroups: []string{"apps", "extensions", "resources.kubesphere.io"},
|
||||
Resources: []string{"daemonsets"},
|
||||
},
|
||||
{
|
||||
@@ -974,8 +683,17 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"pod/shell"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"pod/terminal"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"pods"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -997,7 +715,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"list", "get"},
|
||||
APIGroups: []string{""},
|
||||
APIGroups: []string{"", "resources.kubesphere.io"},
|
||||
Resources: []string{"services"},
|
||||
},
|
||||
},
|
||||
@@ -1039,7 +757,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"router"},
|
||||
},
|
||||
},
|
||||
@@ -1048,7 +766,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"router"},
|
||||
},
|
||||
},
|
||||
@@ -1057,7 +775,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"router"},
|
||||
},
|
||||
},
|
||||
@@ -1066,7 +784,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"router"},
|
||||
},
|
||||
},
|
||||
@@ -1081,7 +799,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"extensions"},
|
||||
APIGroups: []string{"extensions", "resources.kubesphere.io"},
|
||||
Resources: []string{"ingresses"},
|
||||
},
|
||||
},
|
||||
@@ -1121,7 +839,7 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
APIGroups: []string{"", "resources.kubesphere.io"},
|
||||
Resources: []string{"persistentvolumeclaims"},
|
||||
},
|
||||
},
|
||||
@@ -1160,10 +878,9 @@ var (
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"applications"},
|
||||
Resources: []string{"resources"},
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"applications"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
@@ -1203,7 +920,7 @@ var (
|
||||
{Name: "view", Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"view", "list"},
|
||||
APIGroups: []string{"batch"},
|
||||
APIGroups: []string{"batch", "resources.kubesphere.io"},
|
||||
Resources: []string{"jobs"},
|
||||
},
|
||||
}},
|
||||
@@ -1236,7 +953,7 @@ var (
|
||||
{Name: "view", Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"view", "list"},
|
||||
APIGroups: []string{"batch"},
|
||||
APIGroups: []string{"batch", "resources.kubesphere.io"},
|
||||
Resources: []string{"cronjobs"},
|
||||
},
|
||||
}},
|
||||
@@ -1269,7 +986,7 @@ var (
|
||||
{Name: "view", Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"view", "list"},
|
||||
APIGroups: []string{""},
|
||||
APIGroups: []string{"", "resources.kubesphere.io"},
|
||||
Resources: []string{"secrets"},
|
||||
},
|
||||
}},
|
||||
@@ -1302,7 +1019,7 @@ var (
|
||||
{Name: "view", Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"view", "list"},
|
||||
APIGroups: []string{""},
|
||||
APIGroups: []string{"", "resources.kubesphere.io"},
|
||||
Resources: []string{"configmaps"},
|
||||
},
|
||||
}},
|
||||
@@ -1331,3 +1048,16 @@ var (
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func GetClusterAction(module, action string) (models.Action, error) {
|
||||
for _, rule := range ClusterRoleRuleMapping {
|
||||
if rule.Name == module {
|
||||
for _, act := range rule.Actions {
|
||||
if act.Name == action {
|
||||
return act, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return models.Action{}, fmt.Errorf("not found")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user