Skip to content

Commit

Permalink
Merge pull request #848 from jlandowner/ui-user-urlparam
Browse files Browse the repository at this point in the history
  • Loading branch information
oruharo authored Jul 2, 2024
2 parents 9616c63 + 8420cda commit e142e61
Show file tree
Hide file tree
Showing 48 changed files with 2,144 additions and 736 deletions.
5 changes: 4 additions & 1 deletion internal/cmd/user/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,5 +256,8 @@ func (o *GetOption) ListUsersByKubeClient(ctx context.Context) ([]*dashv1alpha1.
if err != nil {
return nil, err
}
return apiconv.C2D_Users(users, apiconv.WithUserRaw(ptr.To(o.OutputFormat == "yaml"))), nil
if o.OutputFormat == "yaml" {
return apiconv.C2D_Users(users, apiconv.WithUserRaw()), nil
}
return apiconv.C2D_Users(users), nil
}
2 changes: 0 additions & 2 deletions internal/cmd/user/update_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ type UpdateRoleOption struct {
Roles []string
PrivilegedRole bool
Force bool

userAddons []*dashv1alpha1.UserAddon
}

func UpdateRoleCmd(cmd *cobra.Command, cliOpt *cli.RootOptions) *cobra.Command {
Expand Down
10 changes: 8 additions & 2 deletions internal/cmd/workspace/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,10 @@ func (o *GetOption) listWorkspacesByKubeClient(ctx context.Context, userName str
if err != nil {
return nil, err
}
return apiconv.C2D_Workspaces(workspaces, apiconv.WithWorkspaceRaw(ptr.To(o.OutputFormat == "yaml"))), nil
if o.OutputFormat == "yaml" {
return apiconv.C2D_Workspaces(workspaces, apiconv.WithWorkspaceRaw()), nil
}
return apiconv.C2D_Workspaces(workspaces), nil
}

func (o *GetOption) listUsersByKubeClient(ctx context.Context) ([]*dashv1alpha1.User, error) {
Expand All @@ -270,5 +273,8 @@ func (o *GetOption) listUsersByKubeClient(ctx context.Context) ([]*dashv1alpha1.
if err != nil {
return nil, err
}
return apiconv.C2D_Users(users, apiconv.WithUserRaw(ptr.To(o.OutputFormat == "yaml"))), nil
if o.OutputFormat == "yaml" {
return apiconv.C2D_Users(users, apiconv.WithUserRaw()), nil
}
return apiconv.C2D_Users(users), nil
}
10 changes: 5 additions & 5 deletions internal/dashboard/auth_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ func validateCallerHasAdmin(callerGroupRoleMap map[string]string) error {
return errors.New("not admin")
}

func validateCallerHasAdminForAllRoles(tryRoleNames []string) func(map[string]string) error {
func validateCallerHasAdminForAllRoles(tryRoles []cosmov1alpha1.UserRole) func(map[string]string) error {
return func(callerGroupRoleMap map[string]string) error {
for _, r := range tryRoleNames {
tryAccessGroup, _ := (cosmov1alpha1.UserRole{Name: r}).GetGroupAndRole()
for _, r := range tryRoles {
tryAccessGroup, _ := r.GetGroupAndRole()
callerRoleForTriedGroup := callerGroupRoleMap[tryAccessGroup]

// Deny if caller does not have administrative privilege for tried group.
Expand All @@ -220,9 +220,9 @@ func validateCallerHasAdminForAllRoles(tryRoleNames []string) func(map[string]st
}
}

func validateCallerHasAdminForAtLeastOneRole(tryRoleNames []cosmov1alpha1.UserRole) func(map[string]string) error {
func validateCallerHasAdminForAtLeastOneRole(tryRoles []cosmov1alpha1.UserRole) func(map[string]string) error {
return func(callerGroupRoleMap map[string]string) error {
for _, r := range tryRoleNames {
for _, r := range tryRoles {
tryAccessGroup, _ := r.GetGroupAndRole()
callerRoleForTriedGroup := callerGroupRoleMap[tryAccessGroup]

Expand Down
3 changes: 2 additions & 1 deletion internal/dashboard/auth_middleware_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

cosmov1alpha1 "github.com/cosmo-workspace/cosmo/api/v1alpha1"
"github.com/cosmo-workspace/cosmo/pkg/apiconv"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -233,7 +234,7 @@ func Test_validateCallerHasAdminForAllRoles(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := validateCallerHasAdminForAllRoles(tt.args.tryRoleNames)
f := validateCallerHasAdminForAllRoles(apiconv.S2C_UserRoles(tt.args.tryRoleNames))
if err := f(tt.args.callerGroupRoleMap); (err != nil) != tt.wantErr {
t.Errorf("validateCallerHasAdminForAllRoles() error = %v, wantErr %v", err, tt.wantErr)
}
Expand Down
48 changes: 40 additions & 8 deletions internal/dashboard/user_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

connect_go "github.com/bufbuild/connect-go"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"

cosmov1alpha1 "github.com/cosmo-workspace/cosmo/api/v1alpha1"
"github.com/cosmo-workspace/cosmo/pkg/apiconv"
Expand All @@ -28,7 +29,7 @@ func (s *Server) CreateUser(ctx context.Context, req *connect_go.Request[dashv1a
log.Debug().Info("request", "req", req)

// group-admin user can create users which have only the their groups
if err := adminAuthentication(ctx, validateCallerHasAdminForAllRoles(req.Msg.Roles)); err != nil {
if err := adminAuthentication(ctx, validateCallerHasAdminForAllRoles(apiconv.S2C_UserRoles(req.Msg.Roles))); err != nil {
return nil, ErrResponse(log, err)
}

Expand Down Expand Up @@ -80,8 +81,11 @@ func (s *Server) GetUsers(ctx context.Context, req *connect_go.Request[dashv1alp
return nil, ErrResponse(log, err)
}

res := &dashv1alpha1.GetUsersResponse{
Items: apiconv.C2D_Users(users, apiconv.WithUserRaw(req.Msg.WithRaw)),
res := &dashv1alpha1.GetUsersResponse{}
if req.Msg.WithRaw != nil && *req.Msg.WithRaw {
res.Items = apiconv.C2D_Users(users, apiconv.WithUserRaw())
} else {
res.Items = apiconv.C2D_Users(users)
}
if len(res.Items) == 0 {
res.Message = "No items found"
Expand All @@ -94,16 +98,36 @@ func (s *Server) GetUser(ctx context.Context, req *connect_go.Request[dashv1alph
log.Debug().Info("request", "req", req)

if err := userAuthentication(ctx, req.Msg.UserName); err != nil {
return nil, ErrResponse(log, err)
if err := adminAuthentication(ctx, passAllAdmin); err != nil {
return nil, ErrResponse(log, err)
}
}

user, err := s.Klient.GetUser(ctx, req.Msg.UserName)
if err != nil {
return nil, ErrResponse(log, err)
}

res := &dashv1alpha1.GetUserResponse{
User: apiconv.C2D_User(*user, apiconv.WithUserRaw(req.Msg.WithRaw)),
res := &dashv1alpha1.GetUserResponse{}
if req.Msg.WithRaw != nil && *req.Msg.WithRaw {
addons := make([]cosmov1alpha1.InstanceObject, len(user.Status.Addons))
for i, v := range user.Status.Addons {
var inst cosmov1alpha1.InstanceObject
if v.Kind == "Instance" {
inst = &cosmov1alpha1.Instance{}
} else {
inst = &cosmov1alpha1.ClusterInstance{}
}
err := s.Klient.Get(ctx, types.NamespacedName{Name: v.Name, Namespace: v.Namespace}, inst)
if err != nil {
log.Error(err, "failed to get addon", "name", v.Name, "namespace", v.Namespace)
continue
}
addons[i] = inst
}
res.User = apiconv.C2D_User(*user, apiconv.WithUserRaw(), apiconv.WithAddonsRaw(addons))
} else {
res.User = apiconv.C2D_User(*user)
}

return connect_go.NewResponse(res), nil
Expand All @@ -114,7 +138,15 @@ func (s *Server) GetEvents(ctx context.Context, req *connect_go.Request[dashv1al
log.Debug().Info("request", "req", req)

if err := userAuthentication(ctx, req.Msg.UserName); err != nil {
return nil, ErrResponse(log, err)
targetUser, err := s.Klient.GetUser(ctx, req.Msg.UserName)
if err != nil {
return nil, ErrResponse(log, err)
}

// group-admin user can get workspaces of users which have only the their groups
if err := adminAuthentication(ctx, validateCallerHasAdminForAtLeastOneRole(targetUser.Spec.Roles)); err != nil {
return nil, ErrResponse(log, err)
}
}

events, err := s.Klient.ListEvents(ctx, cosmov1alpha1.UserNamespace(req.Msg.UserName))
Expand All @@ -141,7 +173,7 @@ func (s *Server) DeleteUser(ctx context.Context, req *connect_go.Request[dashv1a
}

// group-admin user can delete users which have only the their groups
if err := adminAuthentication(ctx, validateCallerHasAdminForAllRoles(apiconv.C2S_UserRole(targetUser.Spec.Roles))); err != nil {
if err := adminAuthentication(ctx, validateCallerHasAdminForAllRoles(targetUser.Spec.Roles)); err != nil {
return nil, ErrResponse(log, err)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/dashboard/user_sub_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (s *Server) UpdateUserRole(ctx context.Context, req *connect_go.Request[das

// group-admin can attach or detach only group-roles
changingRoles := diff(apiconv.C2S_UserRole(currentUser.Spec.Roles), req.Msg.Roles)
if err := adminAuthentication(ctx, validateCallerHasAdminForAllRoles(changingRoles)); err != nil {
if err := adminAuthentication(ctx, validateCallerHasAdminForAllRoles(apiconv.S2C_UserRoles(changingRoles))); err != nil {
return nil, ErrResponse(log, err)
}

Expand Down
68 changes: 59 additions & 9 deletions internal/dashboard/workspace_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

connect_go "github.com/bufbuild/connect-go"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"

cosmov1alpha1 "github.com/cosmo-workspace/cosmo/api/v1alpha1"
"github.com/cosmo-workspace/cosmo/pkg/apiconv"
Expand All @@ -30,7 +31,15 @@ func (s *Server) CreateWorkspace(ctx context.Context, req *connect_go.Request[da
log.Debug().Info("request", "req", req)

if err := userAuthentication(ctx, req.Msg.UserName); err != nil {
return nil, ErrResponse(log, err)
targetUser, err := s.Klient.GetUser(ctx, req.Msg.UserName)
if err != nil {
return nil, ErrResponse(log, err)
}

// group-admin user can delete users which have only the their groups
if err := adminAuthentication(ctx, validateCallerHasAdminForAllRoles(targetUser.Spec.Roles)); err != nil {
return nil, ErrResponse(log, err)
}
}

m := req.Msg
Expand All @@ -52,7 +61,15 @@ func (s *Server) GetWorkspaces(ctx context.Context, req *connect_go.Request[dash
log.Debug().Info("request", "req", req)

if err := userAuthentication(ctx, req.Msg.UserName); err != nil {
return nil, ErrResponse(log, err)
targetUser, err := s.Klient.GetUser(ctx, req.Msg.UserName)
if err != nil {
return nil, ErrResponse(log, err)
}

// group-admin user can get workspaces of users which have only the their groups
if err := adminAuthentication(ctx, validateCallerHasAdminForAtLeastOneRole(targetUser.Spec.Roles)); err != nil {
return nil, ErrResponse(log, err)
}
}

wss, err := s.Klient.ListWorkspacesByUserName(ctx, req.Msg.UserName, func(opt *kosmo.ListWorkspacesOptions) {
Expand All @@ -62,8 +79,11 @@ func (s *Server) GetWorkspaces(ctx context.Context, req *connect_go.Request[dash
return nil, ErrResponse(log, err)
}

res := &dashv1alpha1.GetWorkspacesResponse{
Items: apiconv.C2D_Workspaces(wss, apiconv.WithWorkspaceRaw(req.Msg.WithRaw)),
res := &dashv1alpha1.GetWorkspacesResponse{}
if req.Msg.WithRaw != nil && *req.Msg.WithRaw {
res.Items = apiconv.C2D_Workspaces(wss, apiconv.WithWorkspaceRaw())
} else {
res.Items = apiconv.C2D_Workspaces(wss)
}
if len(res.Items) == 0 {
res.Message = "No items found"
Expand All @@ -76,16 +96,30 @@ func (s *Server) GetWorkspace(ctx context.Context, req *connect_go.Request[dashv
log.Debug().Info("request", "req", req)

if err := s.sharedWorkspaceAuthorization(ctx, req.Msg.WsName, req.Msg.UserName, false); err != nil {
return nil, ErrResponse(log, err)
targetUser, err := s.Klient.GetUser(ctx, req.Msg.UserName)
if err != nil {
return nil, ErrResponse(log, err)
}

// group-admin user can get workspaces of users which have only the their groups
if err := adminAuthentication(ctx, validateCallerHasAdminForAtLeastOneRole(targetUser.Spec.Roles)); err != nil {
return nil, ErrResponse(log, err)
}
}

ws, err := s.Klient.GetWorkspaceByUserName(ctx, req.Msg.WsName, req.Msg.UserName)
if err != nil {
return nil, ErrResponse(log, err)
}

res := &dashv1alpha1.GetWorkspaceResponse{
Workspace: apiconv.C2D_Workspace(*ws, apiconv.WithWorkspaceRaw(req.Msg.WithRaw)),
res := &dashv1alpha1.GetWorkspaceResponse{}
if req.Msg.WithRaw != nil && *req.Msg.WithRaw {
var inst cosmov1alpha1.Instance
s.Klient.Get(ctx, types.NamespacedName{Name: ws.Status.Instance.Name, Namespace: ws.Status.Instance.Namespace}, &inst)
res.Workspace = apiconv.C2D_Workspace(*ws, apiconv.WithWorkspaceRaw(), apiconv.WithWorkspaceInstanceRaw(&inst))

} else {
res.Workspace = apiconv.C2D_Workspace(*ws)
}

return connect_go.NewResponse(res), nil
Expand All @@ -96,7 +130,15 @@ func (s *Server) DeleteWorkspace(ctx context.Context, req *connect_go.Request[da
log.Debug().Info("request", "req", req)

if err := userAuthentication(ctx, req.Msg.UserName); err != nil {
return nil, ErrResponse(log, err)
targetUser, err := s.Klient.GetUser(ctx, req.Msg.UserName)
if err != nil {
return nil, ErrResponse(log, err)
}

// group-admin user can delete users which have only the their groups
if err := adminAuthentication(ctx, validateCallerHasAdminForAllRoles(targetUser.Spec.Roles)); err != nil {
return nil, ErrResponse(log, err)
}
}

ws, err := s.Klient.DeleteWorkspace(ctx, req.Msg.WsName, req.Msg.UserName)
Expand All @@ -117,7 +159,15 @@ func (s *Server) UpdateWorkspace(ctx context.Context, req *connect_go.Request[da
log.Debug().Info("request", "req", req)

if err := s.sharedWorkspaceAuthorization(ctx, req.Msg.WsName, req.Msg.UserName, true); err != nil {
return nil, ErrResponse(log, err)
targetUser, err := s.Klient.GetUser(ctx, req.Msg.UserName)
if err != nil {
return nil, ErrResponse(log, err)
}

// group-admin user can delete users which have only the their groups
if err := adminAuthentication(ctx, validateCallerHasAdminForAtLeastOneRole(targetUser.Spec.Roles)); err != nil {
return nil, ErrResponse(log, err)
}
}

ws, err := s.Klient.UpdateWorkspace(ctx, req.Msg.WsName, req.Msg.UserName, kosmo.UpdateWorkspaceOpts{
Expand Down
18 changes: 15 additions & 3 deletions pkg/apiconv/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package apiconv
import (
"fmt"
"regexp"
"slices"
"sort"
"strings"
"time"
Expand All @@ -17,10 +18,21 @@ import (

type UserConvertOptions func(c *cosmov1alpha1.User, d *dashv1alpha1.User)

func WithUserRaw(withRaw *bool) func(c *cosmov1alpha1.User, d *dashv1alpha1.User) {
func WithUserRaw() func(c *cosmov1alpha1.User, d *dashv1alpha1.User) {
return func(c *cosmov1alpha1.User, d *dashv1alpha1.User) {
if withRaw != nil && *withRaw {
d.Raw = ToYAML(c)
d.Raw = ToYAML(c)
}
}

func WithAddonsRaw(addons []cosmov1alpha1.InstanceObject) func(c *cosmov1alpha1.User, d *dashv1alpha1.User) {
return func(c *cosmov1alpha1.User, d *dashv1alpha1.User) {
for _, addon := range addons {
index := slices.IndexFunc(c.Spec.Addons, func(a cosmov1alpha1.UserAddon) bool {
return a.Template.Name == addon.GetSpec().Template.Name
})
if index > -1 {
d.Addons[index].Raw = ToYAML(addon)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/apiconv/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func TestC2D_User(t *testing.T) {
},
},
opts: []UserConvertOptions{
WithUserRaw(ptr.To(true)),
WithUserRaw(),
},
},
want: &dashv1alpha1.User{
Expand Down
12 changes: 8 additions & 4 deletions pkg/apiconv/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ import (

type WorkspaceConvertOptions func(c *cosmov1alpha1.Workspace, d *dashv1alpha1.Workspace)

func WithWorkspaceRaw(withRaw *bool) func(c *cosmov1alpha1.Workspace, d *dashv1alpha1.Workspace) {
func WithWorkspaceRaw() func(c *cosmov1alpha1.Workspace, d *dashv1alpha1.Workspace) {
return func(c *cosmov1alpha1.Workspace, d *dashv1alpha1.Workspace) {
if withRaw != nil && *withRaw {
d.Raw = ToYAML(c)
}
d.Raw = ToYAML(c)
}
}

func WithWorkspaceInstanceRaw(inst *cosmov1alpha1.Instance) func(c *cosmov1alpha1.Workspace, d *dashv1alpha1.Workspace) {
return func(c *cosmov1alpha1.Workspace, d *dashv1alpha1.Workspace) {
d.RawInstance = ToYAML(inst)
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/apiconv/workspace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ func TestC2D_Workspace(t *testing.T) {
},
},
opts: []WorkspaceConvertOptions{
WithWorkspaceRaw(ptr.To(true)),
WithWorkspaceRaw(),
},
},
want: &dashv1alpha1.Workspace{
Expand Down
Loading

0 comments on commit e142e61

Please sign in to comment.