Skip to content

Commit

Permalink
add endpoint to discover the resource a role is assigned to
Browse files Browse the repository at this point in the history
  • Loading branch information
mikemrm committed Jul 24, 2023
1 parent 511dda9 commit 82e0bd6
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 0 deletions.
28 changes: 28 additions & 0 deletions internal/api/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,31 @@ func (r *Router) roleDelete(c echo.Context) error {

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

func (r *Router) roleGetResource(c echo.Context) error {
roleIDStr := c.Param("role_id")

ctx, span := tracer.Start(c.Request().Context(), "api.roleGetResource", trace.WithAttributes(attribute.String("id", roleIDStr)))
defer span.End()

roleResourceID, err := gidx.Parse(roleIDStr)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "error getting resource").SetInternal(err)
}

roleResource, err := r.engine.NewResourceFromID(roleResourceID)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "error getting resource").SetInternal(err)
}

resource, err := r.engine.GetRoleResource(ctx, roleResource, "")
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "error getting resource").SetInternal(err)
}

resp := resourceResponse{
ID: resource.ID,
}

return c.JSON(http.StatusOK, resp)
}
1 change: 1 addition & 0 deletions internal/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func (r *Router) Routes(rg *echo.Group) {
v1.GET("/relationships/to/:id", r.relationshipListTo)
v1.GET("/roles/:role_id", r.roleGet)
v1.DELETE("/roles/:id", r.roleDelete)
v1.GET("/roles/:role_id/resource", r.roleGetResource)
v1.POST("/roles/:role_id/assignments", r.assignmentCreate)
v1.DELETE("/roles/:role_id/assignments", r.assignmentDelete)
v1.GET("/roles/:role_id/assignments", r.assignmentsList)
Expand Down
4 changes: 4 additions & 0 deletions internal/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ type roleResponse struct {
Actions []string `json:"actions"`
}

type resourceResponse struct {
ID gidx.PrefixedID `json:"id"`
}

type deleteRoleResponse struct {
Success bool `json:"success"`
}
Expand Down
5 changes: 5 additions & 0 deletions internal/query/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ func (e *Engine) GetRole(ctx context.Context, roleResource types.Resource, query
return types.Role{}, nil
}

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

// ListAssignments returns nothing but satisfies the Engine interface.
func (e *Engine) ListAssignments(ctx context.Context, role types.Role, queryToken string) ([]types.Resource, error) {
return nil, nil
Expand Down
31 changes: 31 additions & 0 deletions internal/query/relations.go
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,37 @@ func (e *engine) GetRole(ctx context.Context, roleResource types.Resource, query
return types.Role{}, ErrRoleNotFound
}

// GetRoleResource gets the role's assigned resource.
func (e *engine) GetRoleResource(ctx context.Context, roleResource types.Resource, queryToken string) (types.Resource, error) {
var (
resActions map[types.Resource][]string
err error
)

for _, resType := range e.schemaRoleables {
resActions, err = e.listRoleResourceActions(ctx, roleResource, resType.Name, queryToken)
if err != nil {
return types.Resource{}, err
}

// roles are only ever created for a single resource, so we can break after the first one is found.
if len(resActions) != 0 {
break
}
}

if len(resActions) > 1 {
e.logger.Warnw("role is assigned to more than one resource", "role.id", roleResource.ID.String())
}

// returns the first resources actions.
for resource := range resActions {
return resource, nil
}

return types.Resource{}, ErrRoleNotFound
}

// DeleteRole removes all role actions from the assigned resource.
func (e *engine) DeleteRole(ctx context.Context, roleResource types.Resource, queryToken string) (string, error) {
var (
Expand Down
1 change: 1 addition & 0 deletions internal/query/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Engine interface {
CreateRelationships(ctx context.Context, rels []types.Relationship) (string, error)
CreateRole(ctx context.Context, res types.Resource, actions []string) (types.Role, string, error)
GetRole(ctx context.Context, roleResource types.Resource, queryToken string) (types.Role, error)
GetRoleResource(ctx context.Context, roleResource types.Resource, queryToken string) (types.Resource, error)
ListAssignments(ctx context.Context, role types.Role, queryToken string) ([]types.Resource, error)
ListRelationshipsFrom(ctx context.Context, resource types.Resource, queryToken string) ([]types.Relationship, error)
ListRelationshipsTo(ctx context.Context, resource types.Resource, queryToken string) ([]types.Relationship, error)
Expand Down

0 comments on commit 82e0bd6

Please sign in to comment.