Jump to content

Ascertain access


KillGorack
 Share

Go to solution Solved by KillGorack,

Recommended Posts

Need some pointers.

User (usr), Application (app), and Permission (acs) tables.

Need an SQL to ascertain access levels for read, modify, and admin..

A record in asc is NOT guaranteed!

in the app table for example if ap_read = 1  then we need not a record in acs to read whatever is there. If however it was 0 we would need a record in asc with read = 1 for that app/usr combo

I currently open and query these three separately, and it works, but there has to be a more elegant way.

not EXACTLY normalized.. I guess. I hope the question is descriptive enough.

tbl_strctr.PNG.284d55a5a1758ce1bc0fe0107a9a6008.PNG

Link to comment
Share on other sites

If it makes understanding it easier, here's my current solution..

          $sql = "SELECT 
              acs_read AS `read`,
              acs_modify AS `modify`,
              acs_administer AS `admin`
          FROM
              acs
          WHERE
              acs.acs_usr = :usr AND acs.acs_app = :app
          UNION SELECT 
              ap_read AS `read`,
              ap_modify AS `modify`,
              ap_administer AS `admin`
          FROM
              app
          WHERE
              app.ID = :app 
          UNION SELECT 
              acs_administer AS `read`,
              acs_administer AS `modify`,
              acs_administer AS `admin`
          FROM
              acs
          WHERE
              acs.acs_usr = :usr AND acs.acs_app = 3";
          $vars = array('app' => $kernel['app']['ID'], 'usr' => $kernel['ses']['usr']['ID']);
          $bits = $this->pdo->fetchdata($sql, 2, $vars);

          $row = array(
            'read' => max(array_column($bits, 'read')),
            'modify' => max(array_column($bits, 'modify')),
            'admin' => max(array_column($bits, 'admin')),
          );

The weird part at the end where I point to app 3; Three is the permissions app. If you have the admin bit set at one there for a user.. you have access to everything..

 

Link to comment
Share on other sites

It's not clear at all how/what you are trying to secure.   

Why do you have a separate app for "admin" purposes which requires a relation through acs?  What is the purpose of admin then?

   

Link to comment
Share on other sites

Posted (edited)
1 hour ago, gizmola said:

It's not clear at all how/what you are trying to secure.   

Why do you have a separate app for "admin" purposes which requires a relation through acs?  What is the purpose of admin then?

   

I don't have a separate app for admin purposes. Admin is just a bit boolean variable that will let a user do administrative functions in an app.

  • Read; read stuff
  • modify; modify stuff like record editing / deleting
  • admin; administrative functions like changing how data is presented to users.

These are just bits boolean variables..

Edited by KillGorack
Link to comment
Share on other sites

  • Solution

It's kinda ugly but this works

SELECT
  GREATEST(
    COALESCE((SELECT acs.acs_read FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),
    COALESCE((SELECT app.ap_read FROM app WHERE app.ID = :app), 0),
    COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)
  ) AS `read`,
  GREATEST(
    COALESCE((SELECT acs.acs_modify FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),
    COALESCE((SELECT app.ap_modify FROM app WHERE app.ID = :app), 0),
    COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)
  ) AS `modify`,
  GREATEST(
    COALESCE((SELECT acs.acs_modify FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),
    COALESCE((SELECT app.ap_modify FROM app WHERE app.ID = :app), 0),
    COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)
  ) AS `admin`
from acs
WHERE acs.acs_usr = :usr

 

Link to comment
Share on other sites

select 
    coalesce(acs.acs_read, app.ap_read) as read,
    coalesce(acs.acs_modify, app.ap_modify) as modify,
    coalesce(acs.acs_administer, app.ap_administer) as administer
from app 
left join acs on acs.acs_app=app.ID and acs.acs_usr=$user
where
    app.ID=$app

This will give you the value in acs if it exists.  If no row exists it will fall back to the value in app.

If a row in acs exists with ap_read=0, then the user would be denied read even if ap_read=1.  If that's not what you want you will need to adjust things.

Edited by kicken
Link to comment
Share on other sites

14 hours ago, KillGorack said:

It's kinda ugly but this works

SELECT
  GREATEST(
    COALESCE((SELECT acs.acs_read FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),
    COALESCE((SELECT app.ap_read FROM app WHERE app.ID = :app), 0),
    COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)
  ) AS `read`,
  GREATEST(
    COALESCE((SELECT acs.acs_modify FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),
    COALESCE((SELECT app.ap_modify FROM app WHERE app.ID = :app), 0),
    COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)
  ) AS `modify`,
  GREATEST(
    COALESCE((SELECT acs.acs_modify FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),
    COALESCE((SELECT app.ap_modify FROM app WHERE app.ID = :app), 0),
    COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)
  ) AS `admin`
from acs
WHERE acs.acs_usr = :usr

 

Typo fixing this for future reference.. apologies!

 

SELECT

            GREATEST(

              COALESCE((SELECT acs.acs_read FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),

              COALESCE((SELECT app.ap_read FROM app WHERE app.ID = :app), 0),

              COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)

            ) AS `read`,

            GREATEST(

              COALESCE((SELECT acs.acs_modify FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),

              COALESCE((SELECT app.ap_modify FROM app WHERE app.ID = :app), 0),

              COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)

            ) AS `modify`,

            GREATEST(

              COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = :app), 0),

              COALESCE((SELECT app.ap_administer FROM app WHERE app.ID = :app), 0),

              COALESCE((SELECT acs.acs_administer FROM acs WHERE acs.acs_usr = :usr AND acs.acs_app = 3), 0)

            ) AS `admin`

from acs

WHERE acs.acs_usr = :usr

Link to comment
Share on other sites

I think you missed the point of my question.   You have a field named "acs_admininister in ACS and you have a field named "ap_administer" in app.  Then to top it all off, you state that you have magical app # 3, that you will also query all the time.

Why?  If a user is a "superadmin" who can just do everything, then why don't you just have a column in User named "is_super_admin"?  As it is now, you repeatedly and inefficiently are doing a query against a table that will hardly ever change for no reason.

As for an app, what is the purpose of ap_administer vs. a user with acs_administer?  Why do you have both columns?  

You have several major relational design mistakes, the most obvious being repeating groups.  You have employed repeating groups in both the ACS and the App table, which makes trying to optimize anything pretty much of a lost cause.  But you also have a design that does almost nothing for security, because you don't have anything that represents a feature to be secured.  I was hoping you might see the problem?  Yes you have a bunch of items that are another "repeating group" in app, although it is impossible to tell if any of those represent "features", but even if they did/do, there is nothing database driven that anyone can use to determine in even a semi-sophisticated way, whether or not someone should have access to do something in your system.

There is no granularization possible.  If I have "modify" does that mean I can add/edit/delete all my data?  What about other data?  Is there some data I should be able to add/edit, but other data I shouldn't be able to?  Maybe some things I should delete but other things I shouldn't be able to?  

You don't have a sql optimization problem, you have a database design problem.  You have an inept database design for security purposes, and you can combine and reduce the number of queries (which might save you a few hundred milliseconds), but that doesn't really change much internally from a database efficiency standpoint, and what is worse is that your security scheme does almost nothing useful, and doesn't make sense.   The code you build upon it, is not going to be valuable, maintainable or extensible. 

I know this is blunt, but I think the best value I could bring to you here, is to just be brutally honest.  

Here is an adequate normalized multi-system ACL schema.  It tries to maximize reuse across applications by having the main string keys (role name, access_name) in tables so that those standard names can be reused, which makes this look a little more complicated than it actually is.  The important things are that an app_access record is something to be secured for an app.  

 

simple_multi_system_acl.png

 

These get grouped up at app setup by role.  So you configure all the accesses a non-authenticated user should be able to do see/do.  Then all the things a normal user should be able to see/do.  In normal operation functions are simple:

- Users get one or more roles assigned to them, based on whatever logic you desire.

-You query the database for a user user ->role(s) ->app->accesses

-You have simple unit testable function for access that only needs 3 things:

  • app_id, user_id, access_name.name

Let's imagine that function was named userCanDo($appId, $userId, $accessName).

Your only "magical" access would be a bypass based on someone having a "SUPERADMIN" role, which just needs a "IS_SUPER_ADMIN" access for an app.  Access would boil down to something simple like:

 

if (userCanDo($appId, $userId, 'IS_SUPER_ADMIN') || userCanDo($appId, $userId, 'THING_TO_DO')) {
   // Proceed
} else {
   // Show Access Error
}

 

I don't expect you to adopt this system, but at very least you should be comparing the functionality, simplicity and configurability it provides, to what you are doing, and noticing the significant differences as well as missing pieces in yours.  

Link to comment
Share on other sites

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.

 Share

×
×
  • 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.