crusttech / crust-server

Apache License 2.0
87 stars 21 forks source link

Refactor rules to accept interface instead of string for resource #78

Closed darh closed 5 years ago

darh commented 5 years ago

Simplify rules.Resource struct and refactor all fucs that accept it

titpetric commented 5 years ago

I'm gonna look at the API's (internal checkAccess) if we can drop the .String() and just use resource.

I have to git blame the resource struct, I remember only needing three things there - ID of the record (uint64), Name (channel, module,...), and Scope (crm, messaging,...). This gives us a globally unique resource ID (the fmt.Stringer interface provides it), which is %s:%s:%d, so there's definitely one field off here...

titpetric commented 5 years ago

Ok, researched a bit:

return fmt.Sprintf("%s:%s:%d", r.Service, r.Scope, r.ID)
// Resource returns a system resource ID for this type
func (r *Organisation) Resource() rules.Resource {
    resource := rules.Resource{
        Service: "system",
        Scope:   "organisation",
    }
    if r != nil {
        resource.ID = r.ID
        resource.Name = r.Name
    }
    return resource
}

Name was added to hold a readable name of the resource that's being managed. That way the user would know, that they are managing something like Facebook and not system:organisation:%1. I don't see that we can drop any fields from here. If we don't need that, then I suggest:

  1. Drop Name,
  2. Rename Scope into Kind

@darh thoughts and additions re: simplify rules.Resource?

darh commented 5 years ago

Our initial assumptions regarding permission changed in the last couple of weeks and with that, a lot of code is now redundant (see #96)

I would go as far as removing rules.Resource and replacing it with a string type. Rationale behind this is:

const organisationResource = "system:organisation:"

func (r Organisation) Resource() string {
  return organisationResource + r.ID
}

Why not ptr? Because if we're always talking about a specific resource here and as such, it is always an instance with a valid ID/identifier.

For 1st level we can go with this:

type System struct {}
const systemResource = "system"
func (System) Resource() string {
  return systemResource
} 

and so on...


Re: renaming: I would ditch the Scope term because we do not use it anywhere. Even the proposed Kind is not an appropirate choice -- we use it for something else. It is simply a resource.


darh commented 5 years ago

let me extend that one a bit...

// pseudo, untested code

type (
    Resource string
)

const delimiter = ':'

func (r *Resource) AppendID(ID uint64) {
    if !r.Final() {
        // I'm ok with that as I'm ok with "index out of range" panics
        panic("can not append ID to non-final resource " + r.String())
    }

    *r = Resource(r.String() + strconv.FormatUint(ID, 10))
}

func (r Resource) String() string {
    return string(r)
}

// + func that replaces ID with asterisk for the needs of resource.Check 

func (r Resource) Final() bool {
    return len(r) > 0 && r[len(r)-1] != resDelimiter
}

Then, constants under different services:

const SystemResource = Resource("system")
const MessagingResource = Resource("messaging")

// under channel
const ChannelResource = Resource("messaging:channel:")

// under compose
const ModuleResource = Resource("compose:module:")

And finally, how channels use these resources

func (c *Channel) Resource () Resource {
    return ChannelResource.AppendID(c.ID)
}
titpetric commented 5 years ago

I think we have to go a few steps backwards:

I think we need to do:

1) pass Resource instead of String higher up in app-specific check functions to the internal apis, 2) rely on Resource methods to provide the Resource ID or wildcards (drop strings pkg and delimiter implementations outside of Resource) 3) consider dropping Name if we don't need it for the front-end anymore. If we only need the ResourceID for the front-end, update the marshalling function to only produce the ID output as string

darh commented 5 years ago

Agreed on Resource string and typed resources (const SystemResource = Resource("system") ).

titpetric commented 5 years ago

Implemented