Merge pull request #3073 from RolandMa1986/feat-group-api
feat: group auth, add group & groupbinding api
This commit is contained in:
@@ -34,6 +34,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/query"
|
||||
apirequest "kubesphere.io/kubesphere/pkg/apiserver/request"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/group"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/im"
|
||||
servererr "kubesphere.io/kubesphere/pkg/server/errors"
|
||||
)
|
||||
@@ -41,13 +42,15 @@ import (
|
||||
type iamHandler struct {
|
||||
am am.AccessManagementInterface
|
||||
im im.IdentityManagementInterface
|
||||
group group.GroupOperator
|
||||
authorizer authorizer.Authorizer
|
||||
}
|
||||
|
||||
func newIAMHandler(im im.IdentityManagementInterface, am am.AccessManagementInterface, options *authoptions.AuthenticationOptions) *iamHandler {
|
||||
func newIAMHandler(im im.IdentityManagementInterface, am am.AccessManagementInterface, group group.GroupOperator, options *authoptions.AuthenticationOptions) *iamHandler {
|
||||
return &iamHandler{
|
||||
am: am,
|
||||
im: im,
|
||||
group: group,
|
||||
authorizer: authorizerfactory.NewRBACAuthorizer(am),
|
||||
}
|
||||
}
|
||||
@@ -57,6 +60,11 @@ type Member struct {
|
||||
RoleRef string `json:"roleRef"`
|
||||
}
|
||||
|
||||
type GroupMember struct {
|
||||
UserName string `json:"userName"`
|
||||
GroupName string `json:"groupName"`
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeUser(request *restful.Request, response *restful.Response) {
|
||||
username := request.PathParameter("user")
|
||||
|
||||
@@ -1315,3 +1323,223 @@ func handleError(request *restful.Request, response *restful.Response, err error
|
||||
api.HandleInternalError(response, request, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListWorkspaceGroups(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
queryParam := query.ParseQueryParameter(request)
|
||||
result, err := h.group.ListGroups(workspaceName, queryParam)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) CreateGroup(request *restful.Request, response *restful.Response) {
|
||||
workspace := request.PathParameter("workspace")
|
||||
var group iamv1alpha2.Group
|
||||
|
||||
err := request.ReadEntity(&group)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
created, err := h.group.CreateGroup(workspace, &group)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
return
|
||||
}
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(created)
|
||||
}
|
||||
|
||||
func (h *iamHandler) DescribeGroup(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
groupName := request.PathParameter("group")
|
||||
ns, err := h.group.DescribeGroup(workspaceName, groupName)
|
||||
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(ns)
|
||||
}
|
||||
|
||||
func (h *iamHandler) DeleteGroup(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
groupName := request.PathParameter("group")
|
||||
|
||||
err := h.group.DeleteGroup(workspaceName, groupName)
|
||||
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(servererr.None)
|
||||
}
|
||||
|
||||
func (h *iamHandler) UpdateGroup(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
groupName := request.PathParameter("group")
|
||||
|
||||
var group iamv1alpha2.Group
|
||||
err := request.ReadEntity(&group)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
if groupName != group.Name {
|
||||
err := fmt.Errorf("the name of the object (%s) does not match the name on the URL (%s)", group.Name, groupName)
|
||||
klog.Errorf("%+v", err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
updated, err := h.group.UpdateGroup(workspaceName, &group)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
return
|
||||
}
|
||||
if errors.IsBadRequest(err) {
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(updated)
|
||||
}
|
||||
|
||||
func (h *iamHandler) PatchGroup(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
groupName := request.PathParameter("group")
|
||||
|
||||
var group iamv1alpha2.Group
|
||||
err := request.ReadEntity(&group)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
group.Name = groupName
|
||||
|
||||
patched, err := h.group.PatchGroup(workspaceName, &group)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
return
|
||||
}
|
||||
if errors.IsBadRequest(err) {
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(patched)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListGroupBindings(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
groupName := request.PathParameter("group")
|
||||
queryParam := query.ParseQueryParameter(request)
|
||||
result, err := h.group.ListGroupBindings(workspaceName, groupName, queryParam)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(result)
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListGroupsRoleBinding(request *restful.Request, response *restful.Response) {
|
||||
//todo
|
||||
}
|
||||
|
||||
func (h *iamHandler) ListGroupsWorkspaceRoleBinding(request *restful.Request, response *restful.Response) {
|
||||
//todo
|
||||
}
|
||||
|
||||
func (h *iamHandler) CreateGroupBinding(request *restful.Request, response *restful.Response) {
|
||||
|
||||
workspace := request.PathParameter("workspace")
|
||||
|
||||
var members []GroupMember
|
||||
err := request.ReadEntity(&members)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
api.HandleBadRequest(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range members {
|
||||
err := h.group.CreateGroupBinding(workspace, item.GroupName, item.UserName)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
handleError(request, response, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
response.WriteEntity(members)
|
||||
}
|
||||
|
||||
func (h *iamHandler) DeleteGroupBinding(request *restful.Request, response *restful.Response) {
|
||||
workspaceName := request.PathParameter("workspace")
|
||||
name := request.PathParameter("groupbinding")
|
||||
|
||||
err := h.group.DeleteGroupBinding(workspaceName, name)
|
||||
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
api.HandleNotFound(response, request, err)
|
||||
return
|
||||
}
|
||||
api.HandleInternalError(response, request, err)
|
||||
return
|
||||
}
|
||||
|
||||
response.WriteEntity(servererr.None)
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@ limitations under the License.
|
||||
package v1alpha2
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
restfulspec "github.com/emicklei/go-restful-openapi"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/api"
|
||||
@@ -28,9 +30,9 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/am"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/group"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam/im"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -39,9 +41,9 @@ const (
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha2"}
|
||||
|
||||
func AddToContainer(container *restful.Container, im im.IdentityManagementInterface, am am.AccessManagementInterface, options *authoptions.AuthenticationOptions) error {
|
||||
func AddToContainer(container *restful.Container, im im.IdentityManagementInterface, am am.AccessManagementInterface, group group.GroupOperator, options *authoptions.AuthenticationOptions) error {
|
||||
ws := runtime.NewWebService(GroupVersion)
|
||||
handler := newIAMHandler(im, am, options)
|
||||
handler := newIAMHandler(im, am, group, options)
|
||||
|
||||
// users
|
||||
ws.Route(ws.POST("/users").
|
||||
@@ -476,6 +478,86 @@ func AddToContainer(container *restful.Container, im im.IdentityManagementInterf
|
||||
Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{rbacv1.Role{}}}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.DevOpsProjectRoleTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/groups").
|
||||
To(handler.ListWorkspaceGroups).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Returns(http.StatusOK, api.StatusOK, api.ListResult{}).
|
||||
Doc("List groups of the specified workspace.").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/groups/{group}").
|
||||
To(handler.DescribeGroup).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("group", "group name")).
|
||||
Doc("Retrieve group details.").
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.Group{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.DELETE("/workspaces/{workspace}/groups/{group}").
|
||||
To(handler.DeleteGroup).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("group", "group name")).
|
||||
Doc("Delete group.").
|
||||
Returns(http.StatusOK, api.StatusOK, errors.None).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/groups").
|
||||
To(handler.CreateGroup).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("Create Group").
|
||||
Reads(iamv1alpha2.Group{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.Group{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.PUT("/workspaces/{workspace}/groups/{group}/").
|
||||
To(handler.UpdateGroup).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("group", "group name")).
|
||||
Doc("Update Group").
|
||||
Reads(iamv1alpha2.Group{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.Group{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/groups/{group}/groupbindings").
|
||||
To(handler.ListGroupBindings).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("group", "group name")).
|
||||
Doc("Retrieve group's members in the workspace.").
|
||||
Returns(http.StatusOK, api.StatusOK, api.ListResult{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/groups/{group}/rolebindings").
|
||||
To(handler.ListGroupsRoleBinding).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("group", "group name")).
|
||||
Doc("Retrieve group's rolebindings of all projects in the workspace.").
|
||||
Returns(http.StatusOK, api.StatusOK, api.ListResult{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.GET("/workspaces/{workspace}/groups/{group}/workspacerolebinding").
|
||||
To(handler.ListGroupsWorkspaceRoleBinding).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("group", "group name")).
|
||||
Doc("Retrieve group's workspacerolebindings of the workspace.").
|
||||
Returns(http.StatusOK, api.StatusOK, api.ListResult{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.DELETE("/workspaces/{workspace}/groupbindings/{groupbinding}").
|
||||
To(handler.DeleteGroupBinding).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Param(ws.PathParameter("groupbinding", "groupbinding name")).
|
||||
Doc("Delete GroupBinding to remove user from the group.").
|
||||
Returns(http.StatusOK, api.StatusOK, errors.None).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
ws.Route(ws.POST("/workspaces/{workspace}/groupbindings").
|
||||
To(handler.CreateGroupBinding).
|
||||
Param(ws.PathParameter("workspace", "workspace name")).
|
||||
Doc("Create GroupBinding to add a user to the group").
|
||||
Reads([]GroupMember{}).
|
||||
Returns(http.StatusOK, api.StatusOK, iamv1alpha2.GroupBinding{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.GroupTag}))
|
||||
|
||||
container.Add(ws)
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user