Help: Security per record - is it possible to make optimal solution ?
HS

HS @_hs_

About: software developer doing some architecture

Location:
Göteborg, Sweden
Joined:
Jul 26, 2018

Help: Security per record - is it possible to make optimal solution ?

Publish Date: May 6 '20
2 7

So I have a case where data structure looks more like a graph so lets say (object)->(another one)->(yes, antoher)->(even more). And this is stored in graph DB but there's "piled" data which is stored in different engine as pile of things referenced by some filed to vertex/node in graph one.

My problem is that I need security "user per object" where each user can have different access rights, and no role will help in this case as most of the users have different access rights even when they work at same position. So this is what I would call access grant per record or per object.

Now if someone has access to particular object he automatically has access to parent objects. But for example lets say I have (A)->(B) and (A)->(C). If I can access B I should be able to get A but not necessarily C.

I do plan to integrate something like HashiCorp Consul or if there's another similar thing which is easy to use but I don't think this can help at all. I also do have SSO but as any other it mainly relies on roles and such.

BTW, system is multi tenant so adding a new record to a specific user should be visible only for that particular client users, and Admin should decide who get's to see what.

So couple of ways to do it:

  1. Have enormous amount of custom queries which filter out data - slow, hard to maintain and possible to leak data when new features are added or changes are introduced.
  2. Middleware that handles access per object only - also slow due to a lot of network calls like Client -> load balancer -> API -> DB -> API -> middleware -> DB of the middleware -> middleware -> API -> load balancer -> Client. This could be used with some form of in memory cache which would speed up thing to some extent.
  3. Have in-memory filter where each record stored and modified by admin has it's access towards each user cached - extra expensive to have huge amounts of RAM for such a cache
  4. Have SSO deal with it through roles - now I have no idea how would I automate adding roles for each new object inserted to the system, and why would I have so much roles. Users have single access for SSO, so the actual roles would have to spill all over place as there's things like user from one tenant can be added to access some of the data of another tenant...

Anyone have ideas on how to deal with this in optimal way? I really do need help, maybe some software for this I didn't know exits or using SSO or Consul properly somehow for this?

Comments 7 total

  • HS
    HSMay 6, 2020

    Thanks a lot for the answer. I do have a problem where this is actually a requirement and people will be spending a lot of time managing access control through out the system.

    I remembered one real world example on small scale. Let's say you have a building and it has floors and rooms on it. Now you wan't some users to access some rooms. But not all. So if you give user access to room 2001 on floor 2, it means that user has to have access to a building because he cannot access floor unless he access room. But on the other hand he doesn't have to have access to floor 1, he can use elevator directly to floor 2, and have a key or a card for specific room.

    Now my problem in comparison to example would be I have customers owning thousands of buildings. And I have a lot of customers. And some of them want to offer access to users belonging to a different client BUT only for SPECIFIC buildings :D

    I tried to push something which most people hate me for and that is "tell clients this cannot work good and let's have access per parent". I'm not sure will it work (will sales accept the suggestion and will clients agree on it as reasonable approach) but if so I still need to have access per building and you if you have 1 user with access to buildings A,B,C another one can have access to C,D and third one to B,D,N,L,M. So I would have to do all permutations of it to make roles or have role per object in database which still brings me to I need access control inside of my own graph database and roles don't help at all as in this case it's much easier to have users have access to different parts.

    Your example sounds interesting but I have no idea where to start with it so I'll start searching for "data source identifiers" and check if something pops up.

    Again, thanks a lot for the answer.

  • Tony Metzidis
    Tony MetzidisMay 7, 2020

    Sounds just like a filesystem. put the objects on disk, protect them with ACLs (eg chmod)

    • HS
      HSMay 7, 2020

      Good point, however I need it in DB for many other things. But I could investigate on how to "mimic" this approach. Had stuff on file storage previously but searching was not so optimal and projections were hard, although it was cloud storage so no ACL was possible without having users as part of the cloud provider user system which was not an option at that point.

  • HS
    HSMay 7, 2020

    I'm actually working towards it. Thanks. Also the thing with this one was performance concern, where I have additional call to access management API, or even if I kind of "monolith it" I still need that extra call to filter out data not allowed for specific users. I'll look into options for my framework and how not to redesign whole architecture because of this but still maintain some performance. Anyways I think it's safe to say I'm using Neo4j sa graph db and Spring (for now) as framework so there might be a way. Just not here yet.

    But more importantly I value your answer as it gave me some encouragement that there's just no way around "user per resource" as it's a requirement, but it might be not that bad as I think.

    Just want to share latest experiment in Cypher

    RETURN EXISTS((s)-[*0..]->()<-[:HAS_ACCESS]-()<-[:HAS_ROLE*0..1]-(u))
    

    So this would work for both User having direct access to a certain object or Role having access to it. It's also relying on a fact that only parents point to children not the other way around. So if I have two options:
    (SuperParent)->(Parent)->(Child)->(Edge)
    (SuperParent)->(Parent2)->(Child2)
    where User - has access -> child2 but Role -> has access -> child 1
    I can get true for

    MATCH (c:Child) WHERE c.name = 'Child' OR c.name = 'Child2'
    MATCH (u:User {name: "user1"})
    RETURN EXISTS((s)-[*0..]->()<-[:HAS_ACCESS]-()<-[:HAS_ROLE*0..1]-(u))
    

    so it either uses Role if it can or ignores it. And it's quite fast to my surprise, however it's just a sample cypher on sample DB. But also I can ask for Super parent in same query and get true. But it does go through Role as it's using most of the relationships or it might be that role access relationship was made first so it hits it first.

    So I discovered that I can have optional relationships and mandatory ones in query with Neo4j. Might write post about this one as I find it interesting what can you do with cypher regardless of what I use in the project.

Add comment