Jump to content

Appreciate critique of my proposed access control strategy


NotionCommotion

Recommended Posts

I think I am close on how I should implement access control, however, considering that I am making up much of the approach myself, I expect that there are some flaws in my approach and would appreciate a reality check.

Use Case and User Requirements

The application is a content management system which allows capital project users to request content from vendors for a specific project, vendor users provide the content, and facility operation users to utilize the content upon project completion.  Note that multiple content records will always remain associated with one project.

Capital project users and facility operation users both belong to the tenant (owner) organization.  Vendor users belong to a vendor organization which has a many-to-one relationship to tenant owner.  As such, I have a AbstractUser which is extended using CTI by TenantUser and VendorUser.

Allowed permissions per user type are:

  • Vendor users can:
    • Read the organization they belong to (the vendor company) and read/update their own profile.
    • View projects and perform CRUD operations on project content based on the project, user, specification, and whether they own/uploaded the original content.
  • Tenant normal users can:
    • Read the organization they belong to (the tenant/owner company) and read/update their own profile.
    • Manage a given resource type (i.e. all vendors) when allowed by admin.
    • Manage a specific resource (i.e. Acme Pipe and Fittings Company) when allowed by admin.
    • Read everything except for projects and content contained within projects unless the projects have been made available to them.
    • View projects and perform CRUD operations on project content based on the project, user, specification, and whether they own/uploaded the original content.
  • Tenant admin users can:
    • Do everything a normal user can plus manage resources.
    • Assign permission to a normal tenant user to manage all resources of a given type (i.e. allow them to manage all vendors).
    • Assign permission to a normal tenant user to manage a specific resources (i.e. allow them to manage Acme Pipe and Fittings Company).

The utilized access control strategy should also promote:

  • a simple and intuitive ux which reflects the way normal people think without requiring large amounts of script to maintain.
  • consistency among projects yet allow flexibility by having new projects be prepopulated with a clone of the tenant wide default permissions prototype.

Proposed Implementation

It seems like role based access control provides the most intuitive for most needs, however, as far as I could tell, will not allow all functionality and my intent is to use multiple strategies.

To implement RBAC, I will:

  • Create action roles such as ROLE_VIEW_VENDOR and ROLE_MANAGE_VENDOR, ROLE_VIEW_PROJECT and ROLE_MANAGE_PROJECT, ROLE_VIEW_ASSET and ROLE_MANAGE_ASSET, etc.
  • Create user roles such as:
    • ROLE_USER which is any authenticated user and can only view/edit their own profile.
    • ROLE_VENDOR_USER which uses hierarchy to extend ROLE_USER.
    • ROLE_TENANT_USER which uses hierarchy to extend ROLE_USER, ROLE_VIEW_VENDOR, ROLE_VIEW_ASSET, etc
    • ROLE_ADMIN_USER which uses hierarchy to extend ROLE_TENANT_USER, ROLE_MANAGE_VENDOR, ROLE_MANAGE_PROJECT, ROLE_MANAGE_ASSET, ROLE_MANAGE_USER, etc.

Then to allow a tenant user to manage a given resource type (i.e. all vendors) when allowed by, ROLE_MANAGE_VENDOR can be added to the user's role array.

For the remaining functionality, I will need to join the user to the resource, and I refer to this intersecting entity as "ResourceMember".

Then to allow a tenant user to manage a specific resource (i.e. Acme Pipe and Fittings Company) when allowed by admin, ROLE_MANAGE_VENDOR can be added to ResourceMember user roles property.  Or maybe since ResourceMember joins a single resource thus we already know it is a vendor resource, could just add role ROLE_MANAGE.

The CRUD operations on project content gets more complicated.  My plan for this is a quasi Unix file permissions where each project is analogous to a directory and content added to the project is analogous to a file.  The project holds the tenant and vendor user required permission settings needed to create, read, update, etc content, and each could be "other" (any authenticated user), "owner" (they uploaded it and admin hasn't reassigned), and "restrict".  If "restrict" and they do not belong to the membership group (i.e. joined by resource_member), they are denied, but if they do, a similar check is performed using resource required permissions for that specific user stored in ResourceMember and its restrict will be final.  Note that the ERD below shows these permissions as integers but they represent permissions such as 0755 (but no execution of course!).  I don't plan on allowing the project (container) to have an owner so create/owner doesn't really make sense but the others seem to.

When creating a new project, the project permissions and project-member permissions for both a tenant and vendor user will be cloned from the tenant's default prototypes and stored in the project, and when adding a member, the appropriate copy of the project-member permission stored in the project will be cloned and stored in the membership entity.

One other detail.  User roles and additional group member entity roles are stored in a JSON array, and I might have performance issues when performing a GET collection request.  I thought that some DB's might be able to handle this, but am suspect, and instead will have some duplicating read flags persisted in the DB which will be used to dynamically create the appropriate SQL without needing to hydrate the entities.

Up to now, I am just asking whether my approach is viable or not and if so whether you have any recommendations, advice, caution, etc, however, do have a specific question.

Up above, I said "I will need to join the user to the resource".  No issue with the user but not so with the resource side.  My current approach is to join another table which has a one-to-one relationship to the resource (see below schema).  One thing I liked about this approach is doesn't pollute my resources with permission prototypes, owner, redundant read flags, and other properties just used for access control.  Don't like how it uses CTI which I think I overuse.  Also, just noticed that the resource (i.e. Project) has the access control primary key and not the other way around and should fix this.

Possible changes to my other table approach are:

  1. Have a separate junction table for Project, Vendor, Asset, etc.  Doesn't seem as "SQL proper" and just have some gut feel I will later run into issues.
  2. Not use a FK constraint but use the resource class and its PK as the identifier.  I've always shied away from this approach and have the same guy feel concern, but maybe applicable.
    1. If option 1 (separate junction tables) or option 2 (no FKs) are used, think that I should locate the access control properties in the resource (project) and get rid of the extra tables?
  3. Use super/sub SQL schema so that Project, Vendor, Asset, etc all share a single PK.  Makes the join easy and no gut feel concern about issues, but definitely way more difficult to later add some resource, and will also complicate adding a resource which is already using CTI (like User).

I am on uncharted territory and typically when so in the past, never ended well and I needed to later do differently.

image.thumb.png.a6e17facb42901f71f73c3e5c7476439.png

Link to comment
Share on other sites

1 hour ago, gizmola said:

What do you mean CTI?

Was thinking "class table inheritance" which is my understanding just using super/subtype SQL to help enforce inheritance on the DB level.

PS. Sorry, after posting this question, started thinking it wasn't appropriate.  Thing is programming it totally not my day job but only my hope to quit my day job and do something else, and the only people I know that know programming are here.

Link to comment
Share on other sites

In most relational design parlance you call this "subtype" or "subtyping" and refer to the base table as a "supertype".  There is a symbol that ERD tools use for this type of relationship, as shown in this article:  https://learndatamodeling.com/blog/supertype-and-subtype/

It's the half circle connector they show.  Ultimately, it resolves in the same way you resolved it for those tables, but my initial take on what you are doing is:

  • Not sure why tenant_user and vendor_user both have tenant_id and public_id.  If there are a bunch more specific attributes only pertinent to the type, then that's where they would go.  Right now I don't see the value of the subtype tables at all.
  • You have a bunch of attributes that smell like repeating groups
    • tenant_default_permission
    • vendor_default_permission
      • or
    • tenant_read_permission
    • vendor_read_permission

I would return to the question of "Is there an entirely generic ACL structure that can do what i need?"  Obviously there is, because people have used generic ACL/security systems for years to support complicated business security concepts.  I don't really buy into your "reinvent the wheel" approach.  

The other thing that is notoriously problematic, is when you have a mixture of static permissions and row level permissions.  It means that you can't do a single query without baking that into everything you do.  Some years ago I worked for a startup that implemented a full social media system, not unlike facebook, but with more sophisticated access control and permissions of things.  The primary insight for me, was that "entity groups" was the mechanism that facilitated and solved a lot of problems.   By having groups that related users and organizations to each other, and groups to each other, every piece of content or digital asset could be controlled by belonging to one or more groups.  Rather than a single person entity owning a file, a group owned the file, with the original creator being the only member of the "owner" group.  Through the creation of different groups with separate "group type" it was always possible to join to content and determine if that should be in a relational result or not.  

This is just an aside, but it's what I thought about when seeing how you are attempting to solve a few different problems.  "Do I have access to this feature or function?" is one problem that ACL is built for. What content should I see based on my place within an organization or department, is another problem.  ACL's are not well suited to the 2nd problem, and it looks to me like you are trying to solve both problems with a hybrid/relational structure, and that's jamming a square peg into a round hole if it's too much of one thing or another.

Link to comment
Share on other sites

12 hours ago, gizmola said:

In most relational design parlance you call this "subtype" or "subtyping" and refer to the base table as a "supertype".  There is a symbol that ERD tools use for this type of relationship, as shown in this article:  https://learndatamodeling.com/blog/supertype-and-subtype/

It's the half circle connector they show.  Ultimately, it resolves in the same way you resolved it for those tables...

Thank you gizmola,  While the subtyping is somewhat of a different topic,  would like your thoughts and will reply with two separate responses.

I use this approach all the time and it seems like others rarely if at all do.  Either I know more than everyone else in the world or there is something I don't know which makes this model less necessary.  Humm, which one is it...

Let's use your example from learndatamodeling.  Why would I use this model?

  1. It looks pretty with all the common data in the employee table.  I don't think there is any normalization rule to go this way.  Agree?  If so, not a good reason.
  2. I have one or more other tables that need to reference employee.  Yes, very often.  Sure, I could have two joins to both full time and hourly employee, but that is more complicated from both a SQL perspective (can't use non-null, require triggers to check) and PHP perspective (no AbstractEmployee to type declare), and is also less performant (will require unions instead of joins) and less flexible.

I keep on hearing favor composition over inheritance, and while I finally understand and agree that it should be used in many cases, don't see the value for modelling entities such as this one.

Is there a better way to handle requirements such as this?

Or maybe it is a common design pattern and I just think I am the only one using it?

image.png.24a6d6fb1b02d4cacaee729a103d085b.png

 

Some of my attempts searching for this holy grail.

 

 

 

 

 

 

 

 

 

 

 

Edited by NotionCommotion
Link to comment
Share on other sites

9 hours ago, gizmola said:

I don't really buy into your "reinvent the wheel" approach.

I completely agree!

Most of the time, I am controlling "what content should I see based on my place within an organization or department".

For a couple edge cases, however, I need to control whether "I have access to this feature or function".

I don't really understand attribute based access control, however, based on my recent research, looks like the first need is best handled by using RBAC (role based) and the second is best handled by using ACL.  Agree?  If so, then I will need to use two models.

Also, I am using Symfony which really focuses on RBAC, and while they have an ACL bundle, they recommend not using it (and it also doesn't appear to support changing the required resource permission).

There is also Laminas's ACL component which you previously brought to my attention and I have since spent some time investigating.  I was very interesting, had some great features, and was highly decoupled, however, I kind of concluded that it was overkill.  Maybe not?

High level requirements and proposed solutions are:

  • Normal role access control.
    • Use Symfony's normal approach (which happens to be voters)
  • Ability to give regular users additional permissions on a per resource basis.
    • While not a must have feature, it is pretty simple since the required permission of the resource doesn't change.  If this was the only one-off, I would likely just use a resource/user junction table to store extra roles and call it good, but have the next one...
  • Ability to define both the required permission to perform some action on a given resource as well as the authority of each user for that specific resource.
    • Unfortunately, this is an important requirement.  Are you thinking that Laminas's ACL component would be well suited to meet this need?  If so, would like to discuss more.
13 hours ago, gizmola said:

The primary insight for me, was that "entity groups" was the mechanism that facilitated and solved a lot of problems.   By having groups that related users and organizations to each other, and groups to each other, every piece of content or digital asset could be controlled by belonging to one or more groups.  Rather than a single person entity owning a file, a group owned the file, with the original creator being the only member of the "owner" group.  Through the creation of different groups with separate "group type" it was always possible to join to content and determine if that should be in a relational result or not.  

 I haven't yet gotten through the details, but also felt that groups were the key.  Sometimes called them groups and other times called them memberships.  For my use case, I don't think I need multiple groups but just one group per project.  If more requirements are later added, maybe then more groups, but oh well.  If project contains content, all the content in some projects needs to be available to all and for other projects only is available to some, how do you think your groups approach would work?

PS.  Would you agree that Unix file permissions and ACL are both examples of Discretionary Access Control?  https://ebrary.net/26657/computer_science/access_control_strategies says they are and just want to make sure I should believe them.

The remained of my reply is really to respond to your other comments.  I will completely take and appreciate any critique you offer, however, I am not necessarily asking for it.

9 hours ago, gizmola said:
  • Not sure why tenant_user and vendor_user both have tenant_id and public_id.  If there are a bunch more specific attributes only pertinent to the type, then that's where they would go.  Right now I don't see the value of the subtype tables at all.

public_id is an identifier ID which is unique per entity type for a given tenant, and is just used so I don't have to expose the DB PK or use a UUID or anything.  I actually think my homegrown solution is pretty clean, however, I am always concerned when I need to use a homegrown solution for what seems to be a common need.

tenant_user belongs to tenant and is joined by tenant_id.  vendor_user belongs to vendor, is joined by vendor_id, and vendor belongs to tenant and is joined by tenant_id.  As such, I really don't need tenant_id in vendur_user, but I wish to keep content completely isolated between tenants, and ended up adding tenant_id to every entity except (for a few common entities which are not owned by a tenant).

9 hours ago, gizmola said:
  • You have a bunch of attributes that smell like repeating groups
    • tenant_default_permission
    • vendor_default_permission
      • or
    • tenant_read_permission
    • vendor_read_permission

tenant/vendor_default_permission is like unix permission 0755 and represents my Permission class.  I didn't show tenant but if I did, you would see similar, and they act as prototypes until they get to their final home.  I copy them from tenant to project_access_control so that the project_access_control version could be changed without changing the tenant version, and then again copy it to project_member for the same reason.

tenant/vendor_read_permission represents my PermissionEnum class, and several bits in tenant/vendor_default_permission hold the same content which I know is a big SQL no-no.  It is just used so I can do queries without indexing concern when using bitwise operators in the where clause, and is on my list of things to maybe change.

class Permission
{
    private const
    READ    =   0b00000011,
    CREATE  =   0b00001100,
    MODIFY  =   0b00110000,
    COWORKER=   0b01000000,
    OWNER   =   0b10000000
    ;

    public function __construct(
        private PermissionEnum $read,
        private PermissionEnum $create,
        private PermissionEnum $modify,
        private bool $restrictToOwner,
        private bool $coworkers,
    )
    {
    }

    public static function create(int $value): self
    {
        return new self(
            PermissionEnum::from($value&self::READ),
            PermissionEnum::from($value&self::CREATE  >> 2),
            PermissionEnum::from($value&self::MODIFY  >> 4),
            boolval($value&self::COWORKER),
            boolval($value&self::OWNER),
        );
    }
    
    // other methods...

    public function getValue(): int
    {
        $rs = $this->read->value | $this->create->value << 2 | $this->modify->value << 4;
        $rs = $this->coworkers?$rs|self::COWORKER:$rs & (~ self::COWORKER);
        $rs = $this->restrictToOwner?$rs|self::OWNER:$rs & (~ self::OWNER);
        return $rs;
    }
}

 

enum PermissionEnum: int
{
    private const MAP = [
        'public'    => 0b00,
        'owner'     => 0b01,
        'restrict'  => 0b10,
        'override'  => 0b11   //Not sure what this should be used for.
    ];
    case public     = 0b00;
    case owner      = 0b01;
    case restrict   = 0b10;
    case override   = 0b11;  //Not sure what this should be used for.
}

 

Link to comment
Share on other sites

From what I interpret from your first reply, here is what I think could be helpful.

Relational databases have no concept of inheritance/super/sublcasses.  So when you have OOP code that clearly benefits from inheritance, and you are persisting data in a relational database, you are left with 3 choices:

  • Put all the attributes in one table/set of tables even though there will be a handful of attributes that are only relevant for a subtype.  The more subtypes you have, the more of these irrelevant attributes, and to compound this, you have to name them all in some way
  • Create a full set of separate table(s) for each type
  • Use the supertype/subtype model
    • There is nothing special in SQL that makes this relational design pattern work.
      • You have a type field in the supertype that indicates which subtype of user this is
      • The relationship between supertype and subtype is 1-1, and thus the subtype has the same primary key as the supertype.  
    • This is what is described in the article
    • It is what your model implemented with supertype user, and subytpes (vendor_user, tenant_user) -- typed by user.type value/field
    • You or your ORM need enhanced capabilities beyond the basic one-to-many, many-to-one, etc built ins.  You will have in essence some switch statement type logic in your model to handle the subtypes

I won't talk about the first 2 options, other than in comparison of some benefits that supertype/subtype can have.

 

A typical requirement would be in storing contact methods for a user.  Let's say that you have these contact methods:  (phone, email, address) and each of these can exist as multiple types (home, work, mobile, cell) and perhaps you will have a primary designation.  A lot more about this problem is covered by an implementation of the "party pattern", by which I refer specifically to a relational structure.

Another common requirement would be in relating users together in some way.  An example is a hierarchy for Company -> Department -> Employee.  Just to simplify, let's say you implement this with a many to many resolution of employee to employee, typically with a "relationshipType"  attribute to give context to the values.  Just for simplicity, I'll provide these relationship types ("parent of", "spouse of").

Here is where the benefits start to add up.

  • You create these tables and code that lets you add (for an employee) one or more addresses, one or more emails, one or more phone numbers.
    • This code works for all subtypes.  You are not duplicating database structure.  Your query capabilities are more rich (I have this phone number, who/what is it for?)  You query one table for that, vs, if you have tables for each subtype, you have to query the phone number table for each type of employee.
    • You can relate subtypes together again using one relational structure.  

Following this, and looking at the party pattern, if you step back from employee, and instead make the supertype "entity" where an entity can be any of (a person, a user, a company, a department, a subsidiary, a customer etc.)  you get more and more flexibility with your structure, and you still have a way to map between your classes and your relational store.  You are still going to use composition and Dependency Injection etc. but you also have a nucleus of tables that support your data persistence requirements and you will be reusing more code and structure.  

Now in terms of Laravel and Symfony, both ORM's have capabilities that support the supertype/subtype relationship.  You may or may not find those facilities useful, or better yet, performant to an acceptable level for you, but they exist and can be used.   

Yes this is a common pattern used by data architects.  It's not found much in garden variety systems, although to be fair those type of systems either don't have complex requirements or the people designing the database aren't experienced with relational database design in general.  

So to conclude, you have already got a model that uses this pattern, in the case of your user table and subtypes.  I assume that the reason you were doing that is that you'd already concluded there were benefits in terms of attaching things like security, which will require relating security to users across types.

 

 

Link to comment
Share on other sites

As for your 2nd post, there is a lot of material that you are close to, and I am not, which makes it hard for me to really see the forest through the trees.  I don't see Roles/ACL being different things.  A role is just a convenient way to group up sets of permissions. This makes it simple and easy to give people sets of access.     All security schemes tend to boil down to the same thing:

  • For an effective user
    • The system has something to secure.  That "thing" needs an identifier, so your code can bridge between the abstract idea of "I want to secure one or more features, functions" and a way of representing those things in your code.
    • Once you start to group those individual things together, a role is simply a parent grouper for a set of permissions
    • By giving a "user" one or more roles, you give them the access appropriate for the role(s) you want them to have

There is nothing more or less than that involved.   It also points out that roles are more than just a relational concept, but can also have meaning that can short cut granular permissions.  In some cases (Symfony 5/6 for example) which you mentioned, there really aren't any granular permissions.  You have roles (and again a user can have one or more roles) and you use roles specifically in controllers or methods.  The problem of user authentication is intrinsically separated and solved for you, but after a user has been authenticated, you use roles in various ways to write whatever security code you might need.

To handle more complicated scenarios like the ones you brought up in your use case, you utilize voters.  Custom voters basically let you write the type of complicated access code you might have that involves row level access to things.  Their documentation covers scenarios for a blog/forum system like: 

  • For a post
    • If I'm the owner I can see it
    • If I have the "admin" role I can see it
    • If It's public anyone can see it

Since you already mentioned you are using some portions of symfony, then I would highly recommend looking through the security documentation, and paying special attention to the "Access Control" and discussion of voters and custom voters.  It also has an event system, which lets you write hooks for specific security events that can be very useful in dealing with many scenarios (login, logout, user changes password, unsuccessful login attempts etc.)

From what I understand of what your requirements are, there isn't anything that can't be done with a higher degree of simplicity and elegance, using the current symfony security scheme.  The voters give you a way of handling the things that pure roles can't.  The main exercise for you would be to devise a role system that matches what you require.  Keep in mind that with this sort of system, you don't want or need something like "read", "write" etc, because you are going to secure those individual routes or class methods.  You won't have an abstract token to represent those ideas, and one could argue that trying to use a file system oriented access scheme isn't appropriate to data anyways, so trying to borrow those concepts isn't a good juxtaposition.

Link to comment
Share on other sites

Thanks again gizmola,

What I heard is when I have OOP code that clearly benefits from inheritance and am persisting in a relational database, I should not be ashamed of using the supertype/subtype model.  Guess it paid off asking the same question over and over again until I got the answer I wanted!  By the way, can't claim credit myself and it was Rudy years ago who set me in this direction.

I also heard the party model mentioned.  benanamen recommended this approach a few months back.  Didn't make the connection until now, but this appears to be a model which has super/sub types at its core.

Link to comment
Share on other sites

18 hours ago, NotionCommotion said:

 

I also heard the party model mentioned.  benanamen recommended this approach a few months back.  Didn't make the connection until now, but this appears to be a model which has super/sub types at its core.

 

The Party model is a relational database design pattern.  It deals in a robust and fully relational way with how to represent organizations/companies/people and contacts.  It's a very specific way of representing those things in a relational database.  It also happens to use supertype/subtype for reasons that hopefully will be apparent.

Most of what I was talking about was the inherent problem with matching a relational database (which is based on set theory) to an object oriented code base (with interfaces, inheritance and composition) is that they are just entirely different paradigms.

This article does an excellent job walking you through the pattern and providing some concrete examples.  Just be careful not to conflate the author's use of roles, which is specific to solving the "organizational and team" relationships he wants to represent.  While those could be used by a system for security, that's not the point of how they were used in his later examples.  

  

Link to comment
Share on other sites

Thanks for the Party model link.  I will definitely spend some time going over it as well as its predecessor Bill of Materials.

On 4/13/2022 at 2:36 PM, gizmola said:

From what I understand of what your requirements are, there isn't anything that can't be done with a higher degree of simplicity and elegance, using the current symfony security scheme.  The voters give you a way of handling the things that pure roles can't.  The main exercise for you would be to devise a role system that matches what you require.

AFAIK roles dictate the user's job title (ROLE_ADMIN , ROLE_HR_MANAGER) and can also be used slightly differently by dictating some capability of the job title (ROLE_CAN_FIRE_PEOPLE) and grant permission by resource type but not per resource.  For my requirements, I would need to create individual roles for every project (ROLE_CAN_VIEW_PROJECT_123, etc) which doesn't sound right.

I agree that voters give me an easy and consistent way to hook and handling things, but don't dictate how they are handled and leave that to me.  They will give me some attribute string (could be an action such as view/edit or whatever I want), the resource, and user (actually token) which is great, but I will still need other information like whether a given user can view content in a given project, and therefor would need "something" similar to the original schema I showed.  No?

On 4/13/2022 at 2:36 PM, gizmola said:

The system has something to secure.  That "thing" needs an identifier, so your code can bridge between the abstract idea of "I want to secure one or more features, functions" and a way of representing those things in your code.

So, in order to grant permission by  individual resources, I need an identifier.  Just realized I had project.access_control_id referencing project_access_control.id and project_access_control.resource_id referencing project.id which would identify, but don't think it is the right way.  I also had project_access_control.resource_id reference project.id which will also identify, however, don't know whether I like my use of subtyping and extending abstract_access_control by project_access_control (and asset_access_control and vendor_access_control).

So, maybe a third way to identify the thing?  The following represents how the Symfony ACL bundle does it.  Not sure whether their exact schema will work for me but sure they are doing things that I haven't thought of.  I like how it is less coupled to my domain, but at the same time don't like how it is less coupled to my domain (no FKs acl_object_identifier to naics_code.id, etc, acl_sercurity_identifiers to user.id).  Not sure why they don't have a FK between acl_classes.id and acl_object_identifier.class_id.  My confusion is how I would expose security settings to an admin user.  The admin user will have some role ROLE_MANAGE_ACL so no problem there but will need to perform some queries to show all resources that user 123 has been given permission and all users that have permission to act on resource 321.  Normally this is done with FK's and joins but I don't have them and instead have tables which include the names of the resources and users.  Maybe not possible?

image.thumb.png.184e9c4ac56a5016ea31be22fcaa29dd.png

Edited by NotionCommotion
Link to comment
Share on other sites

Quote

So, in order to grant permission by  individual resources, I need an identifier.  Just realized I had project.access_control_id referencing project_access_control.id and project_access_control.resource_id referencing project.id which would identify, but don't think it is the right way.  I also had project_access_control.resource_id reference project.id which will also identify, however, don't know whether I like my use of subtyping and extending abstract_access_control by project_access_control (and asset_access_control and vendor_access_control).

No, because you are adding your security check code to the function or method you are securing.

The voter is a place where you can add the code that would do the row level checking you need -- so for example, determining if someone is a project member.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.