code refactor (#1786)
* implement LDAP mock client Signed-off-by: hongming <talonwan@yunify.com> * update Signed-off-by: hongming <talonwan@yunify.com> * update Signed-off-by: hongming <talonwan@yunify.com> * resolve conflict Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
@@ -2,21 +2,26 @@ package v1alpha2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-ldap/ldap"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
kserr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
|
||||
apierr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"kubesphere.io/kubesphere/pkg/utils/iputil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type iamHandler struct {
|
||||
@@ -24,29 +29,34 @@ type iamHandler struct {
|
||||
imOperator iam.IdentityManagementInterface
|
||||
}
|
||||
|
||||
func newIAMHandler() *iamHandler {
|
||||
return &iamHandler{}
|
||||
func newIAMHandler(k8sClient k8s.Client, ldapClient ldappool.Client, options iam.Config) *iamHandler {
|
||||
factory := informers.NewInformerFactories(k8sClient.Kubernetes(), k8sClient.KubeSphere(), k8sClient.S2i(), k8sClient.Application())
|
||||
return &iamHandler{
|
||||
amOperator: iam.NewAMOperator(factory.KubernetesSharedInformerFactory()),
|
||||
imOperator: iam.NewIMOperator(ldapClient, options),
|
||||
}
|
||||
}
|
||||
|
||||
// k8s token review
|
||||
// Implement webhook authentication interface
|
||||
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#webhook-token-authentication
|
||||
func (h *iamHandler) TokenReviewHandler(req *restful.Request, resp *restful.Response) {
|
||||
var tokenReview iamv1alpha2.TokenReview
|
||||
|
||||
err := req.ReadEntity(&tokenReview)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if tokenReview.Spec == nil {
|
||||
api.HandleBadRequest(resp, errors.New("token must not be null"))
|
||||
if err = tokenReview.Validate(); err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
uToken := tokenReview.Spec.Token
|
||||
|
||||
token, err := jwtutil.ValidateToken(uToken)
|
||||
token, err := jwtutil.ValidateToken(tokenReview.Spec.Token)
|
||||
|
||||
if err != nil {
|
||||
failed := iamv1alpha2.TokenReview{APIVersion: tokenReview.APIVersion,
|
||||
@@ -59,18 +69,24 @@ func (h *iamHandler) TokenReviewHandler(req *restful.Request, resp *restful.Resp
|
||||
return
|
||||
}
|
||||
|
||||
claims := token.Claims.(jwt.MapClaims)
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
|
||||
if !ok {
|
||||
api.HandleBadRequest(resp, errors.New("invalid token"))
|
||||
return
|
||||
}
|
||||
|
||||
username, ok := claims["username"].(string)
|
||||
|
||||
if !ok {
|
||||
api.HandleBadRequest(resp, errors.New("username not found"))
|
||||
api.HandleBadRequest(resp, errors.New("invalid token"))
|
||||
return
|
||||
}
|
||||
|
||||
user, err := h.imOperator.DescribeUser(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -92,7 +108,9 @@ func (h *iamHandler) Login(req *restful.Request, resp *restful.Response) {
|
||||
err := req.ReadEntity(&loginRequest)
|
||||
|
||||
if err != nil || loginRequest.Username == "" || loginRequest.Password == "" {
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.New("incorrect username or password"))
|
||||
err = errors.New("incorrect username or password")
|
||||
klog.V(4).Infoln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,10 +119,12 @@ func (h *iamHandler) Login(req *restful.Request, resp *restful.Response) {
|
||||
token, err := h.imOperator.Login(loginRequest.Username, loginRequest.Password, ip)
|
||||
|
||||
if err != nil {
|
||||
if serviceError, ok := err.(restful.ServiceError); ok {
|
||||
resp.WriteHeaderAndEntity(serviceError.Code, errors.New(serviceError.Message))
|
||||
if err == iam.AuthRateLimitExceeded {
|
||||
klog.V(4).Infoln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusTooManyRequests, err)
|
||||
return
|
||||
}
|
||||
klog.V(4).Infoln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusUnauthorized, err)
|
||||
return
|
||||
}
|
||||
@@ -113,14 +133,16 @@ func (h *iamHandler) Login(req *restful.Request, resp *restful.Response) {
|
||||
}
|
||||
|
||||
func (h *iamHandler) CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
var createRequest iamv1alpha2.UserCreateRequest
|
||||
var createRequest iamv1alpha2.CreateUserRequest
|
||||
err := req.ReadEntity(&createRequest)
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := createRequest.Validate(); err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -128,23 +150,223 @@ func (h *iamHandler) CreateUser(req *restful.Request, resp *restful.Response) {
|
||||
created, err := h.imOperator.CreateUser(createRequest.User)
|
||||
|
||||
if err != nil {
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, kserr.Wrap(err))
|
||||
if err == iam.UserAlreadyExists {
|
||||
klog.V(4).Infoln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusConflict, err)
|
||||
return
|
||||
}
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.amOperator.CreateClusterRoleBinding(created.Username, createRequest.ClusterRole)
|
||||
err = h.amOperator.CreateClusterRoleBinding(created.Username, createRequest.ClusterRole)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(created)
|
||||
}
|
||||
|
||||
func (h *iamHandler) DeleteUser(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("user")
|
||||
operator := req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
if operator == username {
|
||||
err := errors.New("cannot delete yourself")
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleForbidden(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := h.amOperator.UnBindAllRoles(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = h.imOperator.DeleteUser(username)
|
||||
|
||||
// TODO release user resources
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(apierr.None)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ModifyUser(request *restful.Request, response *restful.Response) {
|
||||
|
||||
username := request.PathParameter("user")
|
||||
operator := request.HeaderParameter(constants.UserNameHeader)
|
||||
var modifyUserRequest iamv1alpha2.ModifyUserRequest
|
||||
|
||||
err := request.ReadEntity(&modifyUserRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(response, err)
|
||||
return
|
||||
}
|
||||
|
||||
if username != modifyUserRequest.Username {
|
||||
err = fmt.Errorf("the name of user (%s) does not match the name on the URL (%s)", modifyUserRequest.Username, username)
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(response, err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = modifyUserRequest.Validate(); err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(response, err)
|
||||
return
|
||||
}
|
||||
|
||||
// change password by self
|
||||
if operator == modifyUserRequest.Username && modifyUserRequest.Password != "" {
|
||||
|
||||
}
|
||||
|
||||
result, err := h.imOperator.ModifyUser(modifyUserRequest.User)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(response, err)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO modify cluster role
|
||||
|
||||
response.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeUser(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("user")
|
||||
|
||||
user, err := h.imOperator.DescribeUser(username)
|
||||
|
||||
if err != nil {
|
||||
if err == iam.UserNotExists {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleNotFound(resp, err)
|
||||
return
|
||||
}
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO append more user info
|
||||
clusterRole, err := h.amOperator.GetClusterRole(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result := iamv1alpha2.UserDetail{
|
||||
User: user,
|
||||
ClusterRole: clusterRole.Name,
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.imOperator.ListUsers(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListUserRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("user")
|
||||
|
||||
roles, err := h.imOperator.GetUserRoles(username)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(roles)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.amOperator.ListRoles(namespace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req)
|
||||
orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, v1alpha2.CreateTime)
|
||||
reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, true)
|
||||
conditions, err := params.ParseConditions(req)
|
||||
|
||||
if err != nil {
|
||||
klog.V(4).Infoln(err)
|
||||
api.HandleBadRequest(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := h.amOperator.ListClusterRoles(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
role := req.PathParameter("role")
|
||||
namespace := req.PathParameter("namespace")
|
||||
@@ -152,6 +374,7 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response)
|
||||
roleBindings, err := h.amOperator.ListRoleBindings(namespace, role)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -159,12 +382,13 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind {
|
||||
user, err := h.imOperator.GetUserInfo(subject.Name)
|
||||
user, err := h.imOperator.DescribeUser(subject.Name)
|
||||
// skip if user not exist
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
@@ -176,152 +400,133 @@ func (h *iamHandler) ListRoleUsers(req *restful.Request, resp *restful.Response)
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoles(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListClusterRoles(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoles(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListRoles(namespace, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
// List users by namespace
|
||||
func (h *iamHandler) ListNamespaceUsers(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
users, err := iam.NamespaceUsers(namespace)
|
||||
roleBindings, err := h.amOperator.ListRoleBindings(namespace, "")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
// sort by time by default
|
||||
sort.Slice(users, func(i, j int) bool {
|
||||
return users[i].RoleBindTime.After(*users[j].RoleBindTime)
|
||||
})
|
||||
result := make([]*iam.User, 0)
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind {
|
||||
user, err := h.imOperator.DescribeUser(subject.Name)
|
||||
// skip if user not exist
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
result = append(result, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteAsJson(users)
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListUserRoles(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("user")
|
||||
|
||||
roles, err := iam.GetUserRoles("", username)
|
||||
func (h *iamHandler) ListClusterRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
clusterRole := req.PathParameter("clusterrole")
|
||||
clusterRoleBindings, err := h.amOperator.ListClusterRoleBindings(clusterRole)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, clusterRoles, err := iam.GetUserClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
result := make([]*iam.User, 0)
|
||||
for _, roleBinding := range clusterRoleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == rbacv1.UserKind {
|
||||
user, err := h.imOperator.DescribeUser(subject.Name)
|
||||
// skip if user not exist
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
result = append(result, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
roleList := RoleList{}
|
||||
roleList.Roles = roles
|
||||
roleList.ClusterRoles = clusterRoles
|
||||
|
||||
resp.WriteAsJson(roleList)
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) RulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.RoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ClusterRulesMapping(req *restful.Request, resp *restful.Response) {
|
||||
rules := policy.ClusterRoleRuleMapping
|
||||
resp.WriteAsJson(rules)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
rules, err := iam.GetClusterRoleSimpleRules(clusterRoleName)
|
||||
clusterRole := req.PathParameter("clusterrole")
|
||||
rules, err := h.amOperator.GetClusterRoleSimpleRules(clusterRole)
|
||||
if err != nil {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
resp.WriteAsJson(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListClusterRoleUsers(req *restful.Request, resp *restful.Response) {
|
||||
clusterRoleName := req.PathParameter("clusterrole")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := iam.ListClusterRoleUsers(clusterRoleName, conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteError(http.StatusNotFound, err)
|
||||
} else {
|
||||
resp.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListRoleRules(req *restful.Request, resp *restful.Response) {
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
roleName := req.PathParameter("role")
|
||||
namespace := req.PathParameter("namespace")
|
||||
role := req.PathParameter("role")
|
||||
|
||||
rules, err := iam.GetRoleSimpleRules(namespaceName, roleName)
|
||||
rules, err := h.amOperator.GetRoleSimpleRules(namespace, role)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
klog.Errorln(err)
|
||||
api.HandleInternalError(resp, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(rules)
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListWorkspaceRoles(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeWorkspaceRole(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListWorkspaceRoleRules(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListWorkspaceUsers(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) InviteUser(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) RemoveUser(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeWorkspaceUser(request *restful.Request, response *restful.Response) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -24,104 +24,25 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
iamv1alpha2 "kubesphere.io/kubesphere/pkg/api/iam/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/iam"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
iam2 "kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/policy"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
ldappool "kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const GroupName = "iam.kubesphere.io"
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
|
||||
type UserUpdateRequest struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
Password string `json:"password,omitempty" description:"this is necessary if you need to change your password"`
|
||||
CurrentPassword string `json:"current_password,omitempty" description:"this is necessary if you need to change your password"`
|
||||
ClusterRole string `json:"cluster_role" description:"user's cluster role"`
|
||||
}
|
||||
|
||||
type CreateUserRequest struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang,omitempty" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
Password string `json:"password" description:"password'"`
|
||||
ClusterRole string `json:"cluster_role" description:"user's cluster role"`
|
||||
}
|
||||
|
||||
type UserList struct {
|
||||
Items []struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang,omitempty" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
ClusterRole string `json:"cluster_role" description:"user's cluster role"`
|
||||
CreateTime time.Time `json:"create_time" description:"user creation time"`
|
||||
LastLoginTime time.Time `json:"last_login_time" description:"last login time"`
|
||||
} `json:"items" description:"paging data"`
|
||||
TotalCount int `json:"total_count" description:"total count"`
|
||||
}
|
||||
type NamespacedUser struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang,omitempty" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
Role string `json:"role" description:"user's role in the specified namespace"`
|
||||
RoleBinding string `json:"role_binding" description:"user's role binding name in the specified namespace"`
|
||||
RoleBindTime string `json:"role_bind_time" description:"user's role binding time"`
|
||||
CreateTime time.Time `json:"create_time" description:"user creation time"`
|
||||
LastLoginTime time.Time `json:"last_login_time" description:"last login time"`
|
||||
}
|
||||
|
||||
type ClusterRoleList struct {
|
||||
Items []rbacv1.ClusterRole `json:"items" description:"paging data"`
|
||||
TotalCount int `json:"total_count" description:"total count"`
|
||||
}
|
||||
|
||||
type LoginLog struct {
|
||||
LoginTime string `json:"login_time" description:"last login time"`
|
||||
LoginIP string `json:"login_ip" description:"last login ip"`
|
||||
}
|
||||
|
||||
type RoleList struct {
|
||||
Items []rbacv1.Role `json:"items" description:"paging data"`
|
||||
TotalCount int `json:"total_count" description:"total count"`
|
||||
}
|
||||
|
||||
type InviteUserRequest struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
WorkspaceRole string `json:"workspace_role" description:"user's workspace role'"`
|
||||
}
|
||||
|
||||
type DescribeWorkspaceUserResponse struct {
|
||||
Username string `json:"username" description:"username"`
|
||||
Email string `json:"email" description:"email address"`
|
||||
Lang string `json:"lang" description:"user's language setting, default is zh-CN"`
|
||||
Description string `json:"description" description:"user's description"`
|
||||
ClusterRole string `json:"cluster_role" description:"user's cluster role"`
|
||||
WorkspaceRole string `json:"workspace_role" description:"user's workspace role"`
|
||||
CreateTime time.Time `json:"create_time" description:"user creation time"`
|
||||
LastLoginTime time.Time `json:"last_login_time" description:"last login time"`
|
||||
}
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
func AddToContainer(c *restful.Container, k8sClient k8s.Client, ldapClient ldappool.Client, options iam.Config) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
|
||||
handler := newIAMHandler()
|
||||
handler := newIAMHandler(k8sClient, ldapClient, options)
|
||||
|
||||
ws.Route(ws.POST("/authenticate").
|
||||
To(handler.TokenReviewHandler).
|
||||
@@ -138,152 +59,132 @@ func addWebService(c *restful.Container) error {
|
||||
ws.Route(ws.POST("/users").
|
||||
To(handler.CreateUser).
|
||||
Doc("Create a user account.").
|
||||
Reads(CreateUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Reads(iamv1alpha2.CreateUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.UserDetail{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}").
|
||||
To(iam.DescribeUser).
|
||||
Doc("Describe the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, iam2.User{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
|
||||
ws.Route(ws.DELETE("/users/{user}").
|
||||
To(iam.DeleteUser).
|
||||
To(handler.DeleteUser).
|
||||
Doc("Delete the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.PUT("/users/{user}").
|
||||
To(iam.UpdateUser).
|
||||
To(handler.ModifyUser).
|
||||
Doc("Update information about the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Reads(UserUpdateRequest{}).
|
||||
Reads(iamv1alpha2.ModifyUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}/logs").
|
||||
To(iam.UserLoginLogs).
|
||||
Doc("Retrieve the \"login logs\" for the specified user.").
|
||||
ws.Route(ws.GET("/users/{user}").
|
||||
To(handler.DescribeUser).
|
||||
Doc("Describe the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, LoginLog{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.UserDetail{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users").
|
||||
To(iam.ListUsers).
|
||||
To(handler.ListUsers).
|
||||
Doc("List all users.").
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.ListUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.IdentityManagementTag}))
|
||||
ws.Route(ws.GET("/users/{user}/roles").
|
||||
To(iam.ListUserRoles).
|
||||
To(handler.ListUserRoles).
|
||||
Doc("Retrieve all the roles that are assigned to the specified user.").
|
||||
Param(ws.PathParameter("user", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, iam.RoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []*rbacv1.Role{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles").
|
||||
To(iam.ListRoles).
|
||||
To(handler.ListRoles).
|
||||
Doc("Retrieve the roles that are assigned to the user in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Returns(http.StatusOK, api.StatusOK, RoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles").
|
||||
To(iam.ListClusterRoles).
|
||||
To(handler.ListClusterRoles).
|
||||
Doc("List all cluster roles.").
|
||||
Returns(http.StatusOK, api.StatusOK, ClusterRoleList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/users").
|
||||
To(handler.ListRoleUsers).
|
||||
Doc("Retrieve the users that are bound to the role in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Param(ws.PathParameter("role", "role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []NamespacedUser{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iamv1alpha2.ListUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/users").
|
||||
To(iam.ListNamespaceUsers).
|
||||
To(handler.ListNamespaceUsers).
|
||||
Doc("List all users in the specified namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Returns(http.StatusOK, api.StatusOK, []NamespacedUser{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iamv1alpha2.ListUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles/{clusterrole}/users").
|
||||
To(iam.ListClusterRoleUsers).
|
||||
To(handler.ListClusterRoleUsers).
|
||||
Doc("List all users that are bound to the specified cluster role.").
|
||||
Param(ws.PathParameter("clusterrole", "cluster role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iamv1alpha2.ListUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/clusterroles/{clusterrole}/rules").
|
||||
To(iam.ListClusterRoleRules).
|
||||
To(handler.ListClusterRoleRules).
|
||||
Doc("List all policy rules of the specified cluster role.").
|
||||
Param(ws.PathParameter("clusterrole", "cluster role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{role}/rules").
|
||||
To(iam.ListRoleRules).
|
||||
To(handler.ListRoleRules).
|
||||
Doc("List all policy rules of the specified role in the given namespace.").
|
||||
Param(ws.PathParameter("namespace", "kubernetes namespace")).
|
||||
Param(ws.PathParameter("role", "role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/devops/{devops}/roles/{role}/rules").
|
||||
To(iam.ListDevopsRoleRules).
|
||||
Doc("List all policy rules of the specified role in the given devops project.").
|
||||
Param(ws.PathParameter("devops", "devops project ID")).
|
||||
Param(ws.PathParameter("role", "devops role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/rulesmapping/clusterroles").
|
||||
To(iam.ClusterRulesMapping).
|
||||
To(handler.ClusterRulesMapping).
|
||||
Doc("Get the mapping relationships between cluster roles and policy rules.").
|
||||
Returns(http.StatusOK, api.StatusOK, policy.ClusterRoleRuleMapping).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/rulesmapping/roles").
|
||||
To(iam.RulesMapping).
|
||||
To(handler.RulesMapping).
|
||||
Doc("Get the mapping relationships between namespaced roles and policy rules.").
|
||||
Returns(http.StatusOK, api.StatusOK, policy.RoleRuleMapping).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles").
|
||||
To(iam.ListWorkspaceRoles).
|
||||
To(handler.ListWorkspaceRoles).
|
||||
Doc("List all workspace roles.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, api.StatusOK, ClusterRoleList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}").
|
||||
To(iam.DescribeWorkspaceRole).
|
||||
To(handler.DescribeWorkspaceRole).
|
||||
Doc("Describe the workspace role.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("role", "workspace role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, rbacv1.ClusterRole{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/roles/{role}/rules").
|
||||
To(iam.ListWorkspaceRoleRules).
|
||||
To(handler.ListWorkspaceRoleRules).
|
||||
Doc("List all policy rules of the specified workspace role.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("role", "workspace role name")).
|
||||
Returns(http.StatusOK, api.StatusOK, []iam2.SimpleRule{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members").
|
||||
To(iam.ListWorkspaceUsers).
|
||||
To(handler.ListWorkspaceUsers).
|
||||
Doc("List all members in the specified workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, api.StatusOK, UserList{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/members").
|
||||
To(iam.InviteUser).
|
||||
To(handler.InviteUser).
|
||||
Doc("Invite a member to the specified workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Reads(InviteUserRequest{}).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.DELETE("/workspaces/{workspace}/members/{member}").
|
||||
To(iam.RemoveUser).
|
||||
To(handler.RemoveUser).
|
||||
Doc("Remove the specified member from the workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, errors.Error{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{member}").
|
||||
To(iam.DescribeWorkspaceUser).
|
||||
To(handler.DescribeWorkspaceUser).
|
||||
Doc("Describe the specified user in the given workspace.").
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("member", "username")).
|
||||
Returns(http.StatusOK, api.StatusOK, DescribeWorkspaceUserResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AccessManagementTag}))
|
||||
c.Add(ws)
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user