Skip to content

Commit

Permalink
add rolebinding storage
Browse files Browse the repository at this point in the history
Signed-off-by: Bailin He <[email protected]>
  • Loading branch information
bailinhe committed Apr 26, 2024
1 parent c7b2205 commit 91f0956
Show file tree
Hide file tree
Showing 16 changed files with 1,078 additions and 135 deletions.
2 changes: 1 addition & 1 deletion cmd/createrole.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func createRole(ctx context.Context, cfg *config.AppConfig) {
logger.Fatalw("error creating role resource", "error", err)
}

rb, err := engine.CreateRoleBinding(ctx, resource, roleres, rbsubj)
rb, err := engine.CreateRoleBinding(ctx, subjectResource, resource, roleres, rbsubj)
if err != nil {
logger.Fatalw("error creating role binding", "error", err)
}
Expand Down
116 changes: 63 additions & 53 deletions internal/api/rolebindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"fmt"
"net/http"
"time"

"github.com/labstack/echo/v4"
"go.infratographer.com/x/gidx"
Expand Down Expand Up @@ -52,13 +53,13 @@ func (r *Router) roleBindingCreate(c echo.Context) error {
return r.errorResponse("error creating resource", err)
}

subjectResource, err := r.currentSubject(c)
actor, err := r.currentSubject(c)
if err != nil {
return err
}

// permissions on role binding actions, similar to roles v1, are granted on the resources
if err := r.checkActionWithResponse(ctx, subjectResource, string(iapl.RoleBindingActionCreate), resource); err != nil {
if err := r.checkActionWithResponse(ctx, actor, string(iapl.RoleBindingActionCreate), resource); err != nil {
return err
}

Expand Down Expand Up @@ -86,20 +87,26 @@ func (r *Router) roleBindingCreate(c echo.Context) error {
}
}

rb, err := r.engine.CreateRoleBinding(ctx, resource, roleResource, subjects)
rb, err := r.engine.CreateRoleBinding(ctx, actor, resource, roleResource, subjects)
if err != nil {
return r.errorResponse("error creating role-binding", err)
}

return c.JSON(
http.StatusOK,
roleBindingResponse{
ID: rb.ID,
Subjects: resourceToSubject(rb.Subjects),
ID: rb.ID,
ResourceID: rb.ResourceID,
Subjects: resourceToSubject(rb.Subjects),
Role: roleBindingResponseRole{
ID: rb.Role.ID,
Name: rb.Role.Name,
},

CreatedBy: rb.CreatedBy,
UpdatedBy: rb.UpdatedBy,
CreatedAt: rb.CreatedAt.Format(time.RFC3339),
UpdatedAt: rb.UpdatedAt.Format(time.RFC3339),
},
)
}
Expand Down Expand Up @@ -160,20 +167,25 @@ func (r *Router) roleBindingsList(c echo.Context) error {

for i, rb := range rbs {
resp.Data[i] = roleBindingResponse{
ID: rb.ID,
Subjects: resourceToSubject(rb.Subjects),
ID: rb.ID,
ResourceID: rb.ResourceID,
Subjects: resourceToSubject(rb.Subjects),
Role: roleBindingResponseRole{
ID: rb.Role.ID,
Name: rb.Role.Name,
},

CreatedBy: rb.CreatedBy,
UpdatedBy: rb.UpdatedBy,
CreatedAt: rb.CreatedAt.Format(time.RFC3339),
UpdatedAt: rb.UpdatedAt.Format(time.RFC3339),
}
}

return c.JSON(http.StatusOK, resp)
}

func (r *Router) roleBindingsDelete(c echo.Context) error {
resID := c.Param("id")
rbID := c.Param("rb_id")

ctx, span := tracer.Start(
Expand All @@ -182,17 +194,6 @@ func (r *Router) roleBindingsDelete(c echo.Context) error {
)
defer span.End()

// resource
resourceID, err := gidx.Parse(resID)
if err != nil {
return r.errorResponse("error parsing resource ID", fmt.Errorf("%w: %s", ErrInvalidID, err.Error()))
}

resource, err := r.engine.NewResourceFromID(resourceID)
if err != nil {
return r.errorResponse("error creating resource", err)
}

// role-binding
rolebindingID, err := gidx.Parse(rbID)
if err != nil {
Expand All @@ -209,12 +210,18 @@ func (r *Router) roleBindingsDelete(c echo.Context) error {
return err
}

// resource
resource, err := r.engine.GetRoleBindingResource(ctx, rbRes)
if err != nil {
return r.errorResponse("error getting role-binding owner resource", err)
}

// permissions on role binding actions, similar to roles v1, are granted on the resources
if err := r.checkActionWithResponse(ctx, actor, string(iapl.RoleBindingActionDelete), resource); err != nil {
return err
}

if err := r.engine.DeleteRoleBinding(ctx, rbRes, resource); err != nil {
if err := r.engine.DeleteRoleBinding(ctx, rbRes); err != nil {
return r.errorResponse("error updating role-binding", err)
}

Expand All @@ -224,7 +231,6 @@ func (r *Router) roleBindingsDelete(c echo.Context) error {
}

func (r *Router) roleBindingGet(c echo.Context) error {
resID := c.Param("id")
rbID := c.Param("rb_id")

ctx, span := tracer.Start(
Expand All @@ -233,17 +239,6 @@ func (r *Router) roleBindingGet(c echo.Context) error {
)
defer span.End()

// resource
resourceID, err := gidx.Parse(resID)
if err != nil {
return r.errorResponse("error parsing resource ID", fmt.Errorf("%w: %s", ErrInvalidID, err.Error()))
}

resource, err := r.engine.NewResourceFromID(resourceID)
if err != nil {
return r.errorResponse("error creating resource", err)
}

// role-binding
rolebindingID, err := gidx.Parse(rbID)
if err != nil {
Expand All @@ -260,50 +255,52 @@ func (r *Router) roleBindingGet(c echo.Context) error {
return err
}

// permissions on role binding actions, similar to roles v1, are granted on the resources
if err := r.checkActionWithResponse(ctx, actor, string(iapl.RoleBindingActionGet), resource); err != nil {
return err
}

rb, err := r.engine.GetRoleBinding(ctx, rbRes)
if err != nil {
return r.errorResponse("error getting role-binding", err)
}

// permissions on role binding actions, similar to roles v1, are granted on the resources
// since the rolebinding is returning the resource ID that it belongs to, we
// will use this resource ID to check the permissions
resource, err := r.engine.NewResourceFromID(rb.ResourceID)
if err != nil {
return r.errorResponse("error creating resource", err)
}

if err := r.checkActionWithResponse(ctx, actor, string(iapl.RoleBindingActionGet), resource); err != nil {
return err
}

return c.JSON(
http.StatusOK,
roleBindingResponse{
ID: rb.ID,
Subjects: resourceToSubject(rb.Subjects),
ID: rb.ID,
ResourceID: rb.ResourceID,
Subjects: resourceToSubject(rb.Subjects),
Role: roleBindingResponseRole{
ID: rb.Role.ID,
Name: rb.Role.Name,
},

CreatedBy: rb.CreatedBy,
UpdatedBy: rb.UpdatedBy,
CreatedAt: rb.CreatedAt.Format(time.RFC3339),
UpdatedAt: rb.UpdatedAt.Format(time.RFC3339),
},
)
}

func (r *Router) roleBindingUpdate(c echo.Context) error {
resID := c.Param("id")
rbID := c.Param("rb_id")

ctx, span := tracer.Start(
c.Request().Context(), "api.roleBindingUpdate",
trace.WithAttributes(attribute.String("id", resID)),
trace.WithAttributes(attribute.String("rolebinding_id", rbID)),
)
defer span.End()

// resource
resourceID, err := gidx.Parse(resID)
if err != nil {
return r.errorResponse("error parsing resource ID", fmt.Errorf("%w: %s", ErrInvalidID, err.Error()))
}

resource, err := r.engine.NewResourceFromID(resourceID)
if err != nil {
return r.errorResponse("error creating resource", err)
}

// role-binding
rolebindingID, err := gidx.Parse(rbID)
Expand All @@ -321,6 +318,12 @@ func (r *Router) roleBindingUpdate(c echo.Context) error {
return err
}

// resource
resource, err := r.engine.GetRoleBindingResource(ctx, rbRes)
if err != nil {
return r.errorResponse("error getting role-binding owner resource", err)
}

// permissions on role binding actions, similar to roles v1, are granted on the resources
if err := r.checkActionWithResponse(ctx, actor, string(iapl.RoleBindingActionUpdate), resource); err != nil {
return err
Expand All @@ -347,20 +350,27 @@ func (r *Router) roleBindingUpdate(c echo.Context) error {
}
}

rb, err := r.engine.UpdateRoleBinding(ctx, rbRes, subjects)
rb, err := r.engine.UpdateRoleBinding(ctx, actor, rbRes, subjects)
if err != nil {
return r.errorResponse("error updating role-binding", err)
}

return c.JSON(
http.StatusOK,
roleBindingResponse{
ID: rb.ID,
Subjects: resourceToSubject(rb.Subjects),
ID: rb.ID,
ResourceID: rb.ResourceID,
Subjects: resourceToSubject(rb.Subjects),

Role: roleBindingResponseRole{
ID: rb.Role.ID,
Name: rb.Role.Name,
},

CreatedBy: rb.CreatedBy,
UpdatedBy: rb.UpdatedBy,
CreatedAt: rb.CreatedAt.Format(time.RFC3339),
UpdatedAt: rb.UpdatedAt.Format(time.RFC3339),
},
)
}
12 changes: 9 additions & 3 deletions internal/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,15 @@ type rolebindingUpdateRequest struct {
}

type roleBindingResponse struct {
ID gidx.PrefixedID `json:"id"`
Role roleBindingResponseRole `json:"role"`
Subjects []roleBindingSubject `json:"subjects"`
ID gidx.PrefixedID `json:"id"`
ResourceID gidx.PrefixedID `json:"resource_id"`
Role roleBindingResponseRole `json:"role"`
Subjects []roleBindingSubject `json:"subjects"`

CreatedBy gidx.PrefixedID `json:"created_by"`
UpdatedBy gidx.PrefixedID `json:"updated_by"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}

type listRoleBindingsResponse struct {
Expand Down
11 changes: 8 additions & 3 deletions internal/query/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func (e *Engine) SubjectHasPermission(context.Context, types.Resource, string, t
}

// CreateRoleBinding returns nothing but satisfies the Engine interface.
func (e *Engine) CreateRoleBinding(context.Context, types.Resource, types.Resource, []types.RoleBindingSubject) (types.RoleBinding, error) {
func (e *Engine) CreateRoleBinding(context.Context, types.Resource, types.Resource, types.Resource, []types.RoleBindingSubject) (types.RoleBinding, error) {
return types.RoleBinding{}, nil
}

Expand All @@ -219,15 +219,20 @@ func (e *Engine) GetRoleBinding(context.Context, types.Resource) (types.RoleBind
}

// DeleteRoleBinding returns nothing but satisfies the Engine interface.
func (e *Engine) DeleteRoleBinding(context.Context, types.Resource, types.Resource) error {
func (e *Engine) DeleteRoleBinding(context.Context, types.Resource) error {
return nil
}

// UpdateRoleBinding returns nothing but satisfies the Engine interface.
func (e *Engine) UpdateRoleBinding(context.Context, types.Resource, []types.RoleBindingSubject) (types.RoleBinding, error) {
func (e *Engine) UpdateRoleBinding(context.Context, types.Resource, types.Resource, []types.RoleBindingSubject) (types.RoleBinding, error) {
return types.RoleBinding{}, nil
}

// GetRoleBindingResource returns nothing but satisfies the Engine interface.
func (e *Engine) GetRoleBindingResource(context.Context, types.Resource) (types.Resource, error) {
return types.Resource{}, nil
}

// AllActions returns nothing but satisfies the Engine interface.
func (e *Engine) AllActions() []string {
return nil
Expand Down
Loading

0 comments on commit 91f0956

Please sign in to comment.