@@ -20,42 +20,22 @@ package iam
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/rbac/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
)
|
||||
|
||||
type roleList struct {
|
||||
ClusterRoles []*v1.ClusterRole `json:"clusterRoles" protobuf:"bytes,2,rep,name=clusterRoles"`
|
||||
ClusterRoles []*v1.ClusterRole `json:"clusterRole" protobuf:"bytes,2,rep,name=clusterRoles"`
|
||||
Roles []*v1.Role `json:"roles" protobuf:"bytes,2,rep,name=roles"`
|
||||
}
|
||||
|
||||
func RoleRules(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
roleName := req.PathParameter("role")
|
||||
|
||||
role, err := iam.GetRole(namespace, roleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules([]*v1.Role{role}, namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules[namespace])
|
||||
}
|
||||
|
||||
func RoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
func ListRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
roleName := req.PathParameter("role")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
@@ -69,7 +49,53 @@ func RoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func NamespaceUsers(req *restful.Request, resp *restful.Response) {
|
||||
func 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 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 ListNamespaceUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
@@ -80,25 +106,26 @@ func NamespaceUsers(req *restful.Request, resp *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
// sort by time by default
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
return users[i].Username < users[j].Username
|
||||
return users[i].RoleBindTime.After(*users[j].RoleBindTime)
|
||||
})
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
func UserRoles(req *restful.Request, resp *restful.Response) {
|
||||
func ListUserRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("username")
|
||||
|
||||
roles, err := iam.GetRoles(username, "")
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
_, clusterRoles, err := iam.GetUserClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
@@ -112,79 +139,62 @@ func UserRoles(req *restful.Request, resp *restful.Response) {
|
||||
resp.WriteAsJson(roleList)
|
||||
}
|
||||
|
||||
func NamespaceRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := iam.GetRoles(username, namespace)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, clusterRole := range clusterRoles {
|
||||
role := new(v1.Role)
|
||||
role.Name = clusterRole.Name
|
||||
role.Labels = clusterRole.Labels
|
||||
role.Namespace = namespace
|
||||
role.Annotations = clusterRole.Annotations
|
||||
role.Kind = "Role"
|
||||
role.Rules = clusterRole.Rules
|
||||
roles = append(roles, role)
|
||||
}
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(roles, namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules[namespace])
|
||||
}
|
||||
|
||||
func RulesMappingHandler(req *restful.Request, resp *restful.Response) {
|
||||
func RulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.RoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ClusterRulesMappingHandler(req *restful.Request, resp *restful.Response) {
|
||||
func ClusterRulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.ClusterRoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ClusterRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
func ListClusterRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
clusterRole, err := iam.GetClusterRole(clusterRoleName)
|
||||
rules, err := iam.GetClusterRoleSimpleRules(clusterRoleName)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
rules, err := iam.GetClusterRoleSimpleRules([]*v1.ClusterRole{clusterRole})
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func 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.WriteError(http.StatusInternalServerError, err)
|
||||
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)
|
||||
}
|
||||
|
||||
func ListRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
roleName := req.PathParameter("role")
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(namespaceName, roleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func ClusterRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
|
||||
users, err := iam.ClusterRoleUsers(clusterRoleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
|
||||
@@ -18,17 +18,14 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"kubesphere.io/kubesphere/pkg/utils/iputil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
|
||||
"net/http"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/utils"
|
||||
jwtutils "kubesphere.io/kubesphere/pkg/utils/jwt"
|
||||
)
|
||||
|
||||
type Spec struct {
|
||||
@@ -63,11 +60,11 @@ func LoginHandler(req *restful.Request, resp *restful.Response) {
|
||||
err := req.ReadEntity(&loginRequest)
|
||||
|
||||
if err != nil || loginRequest.Username == "" || loginRequest.Password == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.Wrap(fmt.Errorf("incorrect username or password")))
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.New("incorrect username or password"))
|
||||
return
|
||||
}
|
||||
|
||||
ip := utils.RemoteIp(req.Request)
|
||||
ip := iputil.RemoteIp(req.Request)
|
||||
|
||||
token, err := iam.Login(loginRequest.Username, loginRequest.Password, ip)
|
||||
|
||||
@@ -76,7 +73,7 @@ func LoginHandler(req *restful.Request, resp *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(models.Token{Token: token})
|
||||
resp.WriteAsJson(token)
|
||||
}
|
||||
|
||||
// k8s token review
|
||||
@@ -91,13 +88,13 @@ func TokenReviewHandler(req *restful.Request, resp *restful.Response) {
|
||||
}
|
||||
|
||||
if tokenReview.Spec == nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("token must not be null")))
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New("token must not be null"))
|
||||
return
|
||||
}
|
||||
|
||||
uToken := tokenReview.Spec.Token
|
||||
|
||||
token, err := jwtutils.ValidateToken(uToken)
|
||||
token, err := jwtutil.ValidateToken(uToken)
|
||||
|
||||
if err != nil {
|
||||
failed := TokenReview{APIVersion: APIVersion,
|
||||
@@ -112,24 +109,29 @@ func TokenReviewHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
|
||||
username := claims["username"].(string)
|
||||
username, ok := claims["username"].(string)
|
||||
|
||||
conn, err := ldap.Client()
|
||||
if !ok {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New("username not found"))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := iam.GetUserInfo(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
user, err := iam.UserDetail(username, conn)
|
||||
groups, err := iam.GetUserGroups(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.Groups = groups
|
||||
|
||||
success := TokenReview{APIVersion: APIVersion,
|
||||
Kind: KindTokenReview,
|
||||
Status: &Status{
|
||||
|
||||
@@ -19,7 +19,6 @@ package iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -33,8 +32,6 @@ import (
|
||||
)
|
||||
|
||||
func CreateGroup(req *restful.Request, resp *restful.Response) {
|
||||
//var json map[string]interface{}
|
||||
|
||||
var group models.Group
|
||||
|
||||
err := req.ReadEntity(&group)
|
||||
@@ -45,19 +42,18 @@ func CreateGroup(req *restful.Request, resp *restful.Response) {
|
||||
}
|
||||
|
||||
if !regexp.MustCompile("[a-z0-9]([-a-z0-9]*[a-z0-9])?").MatchString(group.Name) {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, fmt.Errorf("incalid group name %s", group))
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(fmt.Sprintf("incalid group name %s", group)))
|
||||
return
|
||||
}
|
||||
|
||||
if group.Creator == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, fmt.Errorf("creator should not be null"))
|
||||
return
|
||||
}
|
||||
|
||||
created, err := iam.CreateGroup(group)
|
||||
created, err := iam.CreateGroup(&group)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -75,6 +71,10 @@ func DeleteGroup(req *restful.Request, resp *restful.Response) {
|
||||
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
|
||||
}
|
||||
@@ -106,23 +106,18 @@ func UpdateGroup(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
}
|
||||
|
||||
func GroupDetail(req *restful.Request, resp *restful.Response) {
|
||||
func DescribeGroup(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
path := req.PathParameter("path")
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
group, err := iam.DescribeGroup(path)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
group, err := iam.GroupDetail(path, conn)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -130,20 +125,11 @@ func GroupDetail(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
}
|
||||
|
||||
func GroupUsers(req *restful.Request, resp *restful.Response) {
|
||||
func ListGroupUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
path := req.PathParameter("path")
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
group, err := iam.GroupDetail(path, conn)
|
||||
group, err := iam.DescribeGroup(path)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
@@ -156,10 +142,10 @@ func GroupUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
for i := 0; i < len(group.Members); i++ {
|
||||
name := group.Members[i]
|
||||
user, err := iam.UserDetail(name, conn)
|
||||
user, err := iam.DescribeUser(name)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, 32) {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
group.Members = append(group.Members[:i], group.Members[i+1:]...)
|
||||
i--
|
||||
modify = true
|
||||
@@ -170,25 +156,6 @@ func GroupUsers(req *restful.Request, resp *restful.Response) {
|
||||
}
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(clusterRoles); i++ {
|
||||
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
user.ClusterRole = clusterRoles[i].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if group.Path == group.Name {
|
||||
workspaceRole := iam.GetWorkspaceRole(clusterRoles, group.Name)
|
||||
user.WorkspaceRole = workspaceRole
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
@@ -200,18 +167,7 @@ func GroupUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
}
|
||||
|
||||
func CountHandler(req *restful.Request, resp *restful.Response) {
|
||||
count, err := iam.CountChild("")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(map[string]int{"total_count": count})
|
||||
}
|
||||
|
||||
func RootGroupList(req *restful.Request, resp *restful.Response) {
|
||||
func ListGroups(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
array := req.QueryParameter("path")
|
||||
|
||||
@@ -229,18 +185,9 @@ func RootGroupList(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
groups := make([]*models.Group, 0)
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
for _, v := range paths {
|
||||
path := strings.TrimSpace(v)
|
||||
group, err := iam.GroupDetail(path, conn)
|
||||
group, err := iam.DescribeGroup(path)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
|
||||
@@ -19,9 +19,9 @@ package iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -63,7 +62,7 @@ func CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
err = iam.CreateUser(user)
|
||||
created, err := iam.CreateUser(&user)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
@@ -74,7 +73,7 @@ func CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
resp.WriteAsJson(created)
|
||||
}
|
||||
|
||||
func DeleteUser(req *restful.Request, resp *restful.Response) {
|
||||
@@ -100,7 +99,7 @@ func DeleteUser(req *restful.Request, resp *restful.Response) {
|
||||
func UpdateUser(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
usernameInPath := req.PathParameter("name")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
usernameInHeader := req.HeaderParameter(constants.UserNameHeader)
|
||||
var user models.User
|
||||
|
||||
err := req.ReadEntity(&user)
|
||||
@@ -125,22 +124,23 @@ func UpdateUser(req *restful.Request, resp *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
if username == user.Username && user.Password != "" {
|
||||
_, err = iam.Login(username, user.CurrentPassword, "")
|
||||
// change password by self
|
||||
if usernameInHeader == user.Username && user.Password != "" {
|
||||
_, err = iam.Login(usernameInHeader, user.CurrentPassword, "")
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("incorrect current password")))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = iam.UpdateUser(user)
|
||||
result, err := iam.UpdateUser(&user)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func UserLoginLog(req *restful.Request, resp *restful.Response) {
|
||||
@@ -167,20 +167,11 @@ func UserLoginLog(req *restful.Request, resp *restful.Response) {
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func CurrentUserDetail(req *restful.Request, resp *restful.Response) {
|
||||
func DescribeUser(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
username := req.PathParameter("username")
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
user, err := iam.UserDetail(username, conn)
|
||||
user, err := iam.DescribeUser(username)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
@@ -191,186 +182,81 @@ func CurrentUserDetail(req *restful.Request, resp *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
clusterRole, err := iam.GetUserClusterRole(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRules, err := iam.GetClusterRoleSimpleRules(clusterRoles)
|
||||
user.ClusterRole = clusterRole.Name
|
||||
|
||||
clusterRules, err := iam.GetUserClusterSimpleRules(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(clusterRoles); i++ {
|
||||
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
user.ClusterRole = clusterRoles[i].Name
|
||||
break
|
||||
}
|
||||
result := struct {
|
||||
*models.User
|
||||
ClusterRules []models.SimpleRule `json:"cluster_rules"`
|
||||
}{
|
||||
User: user,
|
||||
ClusterRules: clusterRules,
|
||||
}
|
||||
|
||||
user.ClusterRules = clusterRules
|
||||
|
||||
resp.WriteAsJson(user)
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func NamespacesListHandler(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("name")
|
||||
func Precheck(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
namespaces, err := iam.GetNamespaces(username)
|
||||
check := req.QueryParameter("check")
|
||||
|
||||
exist, err := iam.UserCreateCheck(check)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(namespaces)
|
||||
resp.WriteAsJson(map[string]bool{"exist": exist})
|
||||
}
|
||||
|
||||
func UserDetail(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("name")
|
||||
usernameFromHeader := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
if username == usernameFromHeader {
|
||||
CurrentUserDetail(req, resp)
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
user, err := iam.UserDetail(username, conn)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
clusterRules, err := iam.GetClusterRoleSimpleRules(clusterRoles)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
workspaceRoles := iam.GetWorkspaceRoles(clusterRoles)
|
||||
|
||||
for i := 0; i < len(clusterRoles); i++ {
|
||||
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
user.ClusterRole = clusterRoles[i].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
user.ClusterRules = clusterRules
|
||||
|
||||
user.WorkspaceRoles = workspaceRoles
|
||||
|
||||
resp.WriteAsJson(user)
|
||||
}
|
||||
|
||||
func UserList(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
limit, err := strconv.Atoi(req.QueryParameter("limit"))
|
||||
if err != nil {
|
||||
limit = 65535
|
||||
}
|
||||
offset, err := strconv.Atoi(req.QueryParameter("offset"))
|
||||
if err != nil {
|
||||
offset = 0
|
||||
}
|
||||
func ListUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
if check := req.QueryParameter("check"); check != "" {
|
||||
exist, err := iam.UserCreateCheck(check)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(map[string]bool{"exist": exist})
|
||||
Precheck(req, resp)
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
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)
|
||||
names := params.ParseArray(req.QueryParameter(params.NameParam))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if len(names) > 0 {
|
||||
users, err := iam.ListUsersByName(names)
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
if query := req.QueryParameter("name"); query != "" {
|
||||
names := strings.Split(query, ",")
|
||||
users := make([]*models.User, 0)
|
||||
for _, name := range names {
|
||||
user, err := iam.UserDetail(name, conn)
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, 32) {
|
||||
continue
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
users = append(users, user)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
return
|
||||
}
|
||||
|
||||
var total int
|
||||
var users []models.User
|
||||
|
||||
if query := req.QueryParameter("search"); query != "" {
|
||||
total, users, err = iam.Search(query, limit, offset)
|
||||
} else if query := req.QueryParameter("keyword"); query != "" {
|
||||
total, users, err = iam.Search(query, limit, offset)
|
||||
} else {
|
||||
total, users, err = iam.UserList(limit, offset)
|
||||
}
|
||||
users, err := iam.ListUsers(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(users); i++ {
|
||||
clusterRoles, err := iam.GetClusterRoles(users[i].Username)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
for j := 0; j < len(clusterRoles); j++ {
|
||||
if clusterRoles[j].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
users[i].ClusterRole = clusterRoles[j].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, u := range users {
|
||||
items = append(items, u)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(models.PageableResponse{Items: items, TotalCount: total})
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
18
pkg/apiserver/iam/types.go
Normal file
18
pkg/apiserver/iam/types.go
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
|
||||
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
|
||||
@@ -18,698 +18,155 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-ldap/ldap"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
sliceutils "kubesphere.io/kubesphere/pkg/utils"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const UserNameHeader = "X-Token-Username"
|
||||
func ListWorkspaceRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
func WorkspaceRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
name := req.PathParameter("name")
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := workspaces.Roles(workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(roles)
|
||||
}
|
||||
|
||||
func WorkspaceMemberDetail(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.PathParameter("member")
|
||||
|
||||
user, err := iam.GetUser(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespaces, err := workspaces.Namespaces(workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.WorkspaceRole = user.WorkspaceRoles[workspace]
|
||||
|
||||
roles := make(map[string]string)
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
if role := user.Roles[namespace.Name]; role != "" {
|
||||
roles[namespace.Name] = role
|
||||
}
|
||||
}
|
||||
|
||||
user.Roles = roles
|
||||
user.Rules = nil
|
||||
user.WorkspaceRules = nil
|
||||
user.WorkspaceRoles = nil
|
||||
user.ClusterRules = nil
|
||||
resp.WriteAsJson(user)
|
||||
}
|
||||
|
||||
func WorkspaceMemberInvite(req *restful.Request, resp *restful.Response) {
|
||||
var users []models.UserInvite
|
||||
workspace := req.PathParameter("name")
|
||||
err := req.ReadEntity(&users)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.Invite(workspace, users)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func WorkspaceMemberRemove(req *restful.Request, resp *restful.Response) {
|
||||
query := req.QueryParameter("name")
|
||||
workspace := req.PathParameter("name")
|
||||
|
||||
names := strings.Split(query, ",")
|
||||
|
||||
err := workspaces.RemoveMembers(workspace, names)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
exist, err := workspaces.NamespaceExistCheck(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(map[string]bool{"exist": exist})
|
||||
}
|
||||
|
||||
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
workspace := req.PathParameter("name")
|
||||
|
||||
err := workspaces.DeleteNamespace(workspace, namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
|
||||
devops := req.PathParameter("id")
|
||||
workspace := req.PathParameter("name")
|
||||
force := req.QueryParameter("force")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
err := workspaces.UnBindDevopsProject(workspace, devops)
|
||||
|
||||
if err != nil && force != "true" {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.DeleteDevopsProject(username, devops)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
|
||||
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
var devops models.DevopsProject
|
||||
|
||||
err := req.ReadEntity(&devops)
|
||||
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
|
||||
}
|
||||
|
||||
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
|
||||
result, err := iam.ListWorkspaceRoles(workspace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(project)
|
||||
|
||||
resp.WriteAsJson(result.Items)
|
||||
}
|
||||
|
||||
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
func ListWorkspaceRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
role := req.PathParameter("role")
|
||||
|
||||
namespace := &v1.Namespace{}
|
||||
|
||||
err := req.ReadEntity(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if namespace.Annotations == nil {
|
||||
namespace.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
namespace.Annotations["creator"] = username
|
||||
namespace.Annotations["workspace"] = workspace
|
||||
|
||||
if namespace.Labels == nil {
|
||||
namespace.Labels = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
namespace.Labels["kubesphere.io/workspace"] = workspace
|
||||
|
||||
namespace, err = workspaces.CreateNamespace(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(namespace)
|
||||
}
|
||||
|
||||
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.PathParameter("username")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(UserNameHeader)
|
||||
}
|
||||
|
||||
limit := 65535
|
||||
offset := 0
|
||||
orderBy := "createTime"
|
||||
reverse := true
|
||||
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
page, _ := strconv.Atoi(groups[2])
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
|
||||
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
|
||||
orderBy = groups[1]
|
||||
reverse = false
|
||||
}
|
||||
|
||||
if q := req.QueryParameter("reverse"); q != "" {
|
||||
b, err := strconv.ParseBool(q)
|
||||
if err == nil {
|
||||
reverse = b
|
||||
}
|
||||
}
|
||||
|
||||
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := models.PageableResponse{}
|
||||
result.TotalCount = total
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, n := range devOpsProjects {
|
||||
result.Items = append(result.Items, n)
|
||||
}
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
var workspace models.Workspace
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
err := req.ReadEntity(&workspace)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
|
||||
return
|
||||
}
|
||||
|
||||
workspace.Path = workspace.Name
|
||||
workspace.Members = nil
|
||||
|
||||
if workspace.Admin != "" {
|
||||
workspace.Creator = workspace.Admin
|
||||
} else {
|
||||
workspace.Creator = username
|
||||
}
|
||||
|
||||
created, err := workspaces.Create(&workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(created)
|
||||
|
||||
}
|
||||
|
||||
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
|
||||
name := req.PathParameter("name")
|
||||
|
||||
if name == "" || strings.Contains(name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
|
||||
return
|
||||
}
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = workspaces.Delete(workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(errors.None)
|
||||
}
|
||||
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
|
||||
var workspace models.Workspace
|
||||
name := req.PathParameter("name")
|
||||
err := req.ReadEntity(&workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if name != workspace.Name {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("the name of workspace (%s) does not match the name on the URL (%s)", workspace.Name, name)))
|
||||
return
|
||||
}
|
||||
|
||||
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
|
||||
return
|
||||
}
|
||||
|
||||
workspace.Path = workspace.Name
|
||||
|
||||
workspace.Members = nil
|
||||
|
||||
edited, err := workspaces.Edit(&workspace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(edited)
|
||||
}
|
||||
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
name := req.PathParameter("name")
|
||||
|
||||
workspace, err := workspaces.Detail(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(workspace)
|
||||
}
|
||||
|
||||
// List all workspaces for the current user
|
||||
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
|
||||
keyword := req.QueryParameter("keyword")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
sort.Slice(ws, func(i, j int) bool {
|
||||
t1, err := ws[i].GetCreateTime()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
t2, err := ws[j].GetCreateTime()
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
return t1.After(t2)
|
||||
})
|
||||
|
||||
resp.WriteAsJson(ws)
|
||||
}
|
||||
|
||||
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
|
||||
withMetrics, err := strconv.ParseBool(req.QueryParameter("metrics"))
|
||||
|
||||
if err != nil {
|
||||
withMetrics = false
|
||||
}
|
||||
|
||||
username := req.PathParameter("username")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
if username == "" {
|
||||
username = req.HeaderParameter(UserNameHeader)
|
||||
}
|
||||
limit := 65535
|
||||
offset := 0
|
||||
orderBy := "createTime"
|
||||
reverse := true
|
||||
|
||||
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
|
||||
limit, _ = strconv.Atoi(groups[1])
|
||||
page, _ := strconv.Atoi(groups[2])
|
||||
if page < 0 {
|
||||
page = 1
|
||||
}
|
||||
offset = (page - 1) * limit
|
||||
}
|
||||
|
||||
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
|
||||
orderBy = groups[1]
|
||||
reverse = false
|
||||
}
|
||||
|
||||
if q := req.QueryParameter("reverse"); q != "" {
|
||||
b, err := strconv.ParseBool(q)
|
||||
if err == nil {
|
||||
reverse = b
|
||||
}
|
||||
}
|
||||
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
|
||||
total, namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username, keyword, orderBy, reverse, limit, offset)
|
||||
|
||||
if withMetrics {
|
||||
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result := models.PageableResponse{}
|
||||
result.TotalCount = total
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, n := range namespaces {
|
||||
result.Items = append(result.Items, n)
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func DevopsRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
//workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
devopsName := req.PathParameter("devops")
|
||||
|
||||
var rules []models.SimpleRule
|
||||
|
||||
role, err := iam.GetDevopsRole(devopsName, username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
switch role {
|
||||
case "developer":
|
||||
rules = []models.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "devops", Actions: []string{"view"}},
|
||||
}
|
||||
break
|
||||
case "owner":
|
||||
rules = []models.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
{Name: "devops", Actions: []string{"edit", "view", "delete"}},
|
||||
}
|
||||
break
|
||||
case "maintainer":
|
||||
rules = []models.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
|
||||
{Name: "devops", Actions: []string{"view"}},
|
||||
}
|
||||
break
|
||||
case "reporter":
|
||||
fallthrough
|
||||
default:
|
||||
rules = []models.SimpleRule{
|
||||
{Name: "pipelines", Actions: []string{"view"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "devops", Actions: []string{"view"}},
|
||||
}
|
||||
break
|
||||
}
|
||||
rules := iam.GetWorkspaceRoleSimpleRules(workspace, role)
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func NamespacesRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
//workspaceName := req.PathParameter("workspace")
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
roles, err := iam.GetRoles(username, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, clusterRole := range clusterRoles {
|
||||
role := new(rbac.Role)
|
||||
role.Name = clusterRole.Name
|
||||
role.Labels = clusterRole.Labels
|
||||
role.Namespace = namespaceName
|
||||
role.Annotations = clusterRole.Annotations
|
||||
role.Kind = "Role"
|
||||
role.Rules = clusterRole.Rules
|
||||
roles = append(roles, role)
|
||||
}
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(roles, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if rules[namespaceName] == nil {
|
||||
resp.WriteAsJson(make([]models.SimpleRule, 0))
|
||||
} else {
|
||||
resp.WriteAsJson(rules[namespaceName])
|
||||
}
|
||||
}
|
||||
|
||||
func WorkspaceRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
func DescribeWorkspaceRole(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
roleName := req.PathParameter("role")
|
||||
|
||||
username := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
role, err := iam.GetWorkspaceRole(workspace, roleName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
rules := iam.GetWorkspaceSimpleRules(clusterRoles, workspace)
|
||||
|
||||
if rules[workspace] != nil {
|
||||
resp.WriteAsJson(rules[workspace])
|
||||
} else if rules["*"] != nil {
|
||||
resp.WriteAsJson(rules["*"])
|
||||
} else {
|
||||
resp.WriteAsJson(make([]models.SimpleRule, 0))
|
||||
}
|
||||
resp.WriteAsJson(role)
|
||||
}
|
||||
|
||||
func WorkspaceMemberList(req *restful.Request, resp *restful.Response) {
|
||||
func DescribeWorkspaceUser(req *restful.Request, resp *restful.Response) {
|
||||
workspace := req.PathParameter("workspace")
|
||||
limit, err := strconv.Atoi(req.QueryParameter("limit"))
|
||||
username := req.PathParameter("username")
|
||||
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspace, username)
|
||||
|
||||
if err != nil {
|
||||
limit = 500
|
||||
}
|
||||
offset, err := strconv.Atoi(req.QueryParameter("offset"))
|
||||
if err != nil {
|
||||
offset = 0
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
user, err := iam.DescribeUser(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
user.WorkspaceRole = workspaceRole.Labels[constants.DisplayNameLabelKey]
|
||||
|
||||
group, err := iam.GroupDetail(workspace, conn)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
keyword := ""
|
||||
|
||||
if query := req.QueryParameter("keyword"); query != "" {
|
||||
keyword = query
|
||||
}
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
|
||||
total := len(group.Members)
|
||||
|
||||
members := sliceutils.RemoveString(group.Members, func(item string) bool {
|
||||
return keyword != "" && !strings.Contains(item, keyword)
|
||||
})
|
||||
|
||||
for i := 0; i < len(members); i++ {
|
||||
username := members[i]
|
||||
|
||||
if i < offset {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(users) == limit {
|
||||
break
|
||||
}
|
||||
|
||||
user, err := iam.UserDetail(username, conn)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
group.Members = sliceutils.RemoveString(group.Members, func(item string) bool {
|
||||
return item == username
|
||||
})
|
||||
continue
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
for i := 0; i < len(clusterRoles); i++ {
|
||||
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
|
||||
user.ClusterRole = clusterRoles[i].Name
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if group.Path == group.Name {
|
||||
|
||||
workspaceRole := iam.GetWorkspaceRole(clusterRoles, group.Name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
user.WorkspaceRole = workspaceRole
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
if total > len(group.Members) {
|
||||
go iam.UpdateGroup(group)
|
||||
}
|
||||
if req.QueryParameter("limit") != "" {
|
||||
resp.WriteAsJson(map[string]interface{}{"items": users, "total_count": len(members)})
|
||||
} else {
|
||||
resp.WriteAsJson(users)
|
||||
}
|
||||
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 models.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")
|
||||
var user models.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 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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user