2

Important note: This is PHP (5.3+). PHP is stateless and everything you do dies when the request is over unless saved to a persistent storage, but if the answer provided gives me pseudo-code, I'd also be happy. Also, I can't use routing. I need something that deals solely with objects and parts of them.

My system right now can register a module and set its usage permissions, e.g: who can access this module's functionality based on a pre-defined set of rules, but generally, most of the time we'll just be looking for whether the requester is an user or an administrator.

Thing is though, I realized this late that there's a potentially big problem: if I register a module as admin-level, the permissions are then set at the moment that module initializes, there's virtually no way for my user-level modules, or really anyone without proper permissions to interact with them, even if these unprivileged parties have a real reason for it, as such, a few points up until now:

Point 1: Well, maybe if an u-level module has to interact with an a-level, then that a-level really shouldn't be an a-level module. As it stands right now, when the user logs in and the modules are loaded, this is how it looks: enter image description here

The user can't even find the module, because it's not there. The system decided, based on his credentials & additional checks to not even instantiate the module.

Resolve: Create a new hierarchy where my modules now are open for everyone but have sub-modules or partitions and if one of them deviates from the inherited parent-module's permissions, you have to write that by hand, it'd look like this:

enter image description here

Now, the big module has no permissions set, but the sub-modules do and they're being checked every single time the user accesses them.

This seems to solve the issue, but only at a surface level because it lands me back to the issue of me having to check every time I access a resource:

enter image description here

Point 2: I can maybe skip all of this if I just store, in my database, whatever an a-level module decides it's necessary to let others know about.

Resolve:

I came up with "data residuums". Basically, if the user-level module is interested in the output of the admin-level modules, that admin-level module can spit out "registries" of data that it updates whenever it has to and whoever is interested in these can just check them. This way, it's ensured that, no matter what happens, I can still access the admin-level module's data if I need, but I won't be able to interact with its inner-workings. I'll be able to see (some) of them, but this way, I can ensure that low-privileged users can't suddenly make admin-level changes on my site:

enter image description here

So, the a-level module does its things and at the end of it all, it saves that output to storage that anyone interested in can access.

But this means that I can't really call everything that I'd want because once the a-level module is done running its internals, it's over.

This also means that I'd need my a-level modules to run first, just to ensure that the u-level modules actually have data to work with. This is incompatible with what I currently have.

I was thinking that, even if I believe PHP doesn't allow it, maybe "attach credentials" to every important call that's made:

enter image description here

But then again, this still requires me to do a check on every call.

I guess, really, I'm looking for a way to establish identity and it being handled automatically when making calls.


I know this is already extremely long, but an example would be an a-level module that deals with generating suggestions based on the application's ever-changing state with possibly sensitive data, let's call this SuggestionsModule. Now, if I allow everyone to have access to SuggestionsModule\Register\addSuggestion, I give everyone the possibility to add suggestions, **unless I add a check for this exactly addSuggestion and here the problem becomes even worse: at times, these sub-module's functions will have checks on their own. What if a sub-module is fine to load for user-level, then I hit a function that's very sensitive? I have to write a check and this is what I'm trying to avoid - pollution.

  • Few questions. Why making checks in every call is a problem? Are you concerned about performance issues? How often is user-module calling admin-module? Have you considered an auth-module to implement the policies so that user-module and admin-module only have to ask to this one? A sort of OAuth, where 2 parties collaborate through a 3rd one. – Laiv May 22 at 6:36
  • @Laiv While I did say I want to avoid all checks, the only problem with it is that it litters the code and performance: Imagine if I asked a module about some output for every post there is on my page: it'd be 50 checks that are unecessary. It can happen once, or a lot of times. Yes, but that wouldn't work, the authentication still has to deal with modules that are destined for admin, but SOME of it, the user can access. – coolpasta May 22 at 11:05
1

What you need is a separation between mechanism and policy.

You should have model modules that interacts with your data storage and implements business rules. Then these are wrapped with as many modules that implements permissions checks as you needed.

As you're using PHP, an additional risk exist that you need to take into account to make sure that user can't directly access the mechanism modules. You'd need to put them outside your web directory or write htaccess rules to prevent their access.

  • But there is no way to avoid all these checks? It simply feels atrocious to have so many checks. – coolpasta May 22 at 11:07
  • Your permission checks should only be kept in the policy modules, the mechanism module should just assume that the user has permission to perform the call if it gets called. If you have a set of common checks that you always need to do on every request, you'll need to route all your requests to a common authorisation module. If you can't write an htaccess to do this, you can require 'internal/authz.php'; at the top of all your files. The output of the authz module should be a data structure that details the privileges of the user or to reject the request. – Lie Ryan May 22 at 12:02
  • With a stateless system like HTTP, yes, you'll have to redo your checks with every request. If you have an expensive check, you can use PHP's SESSION mechanism or a signed cookie to cache some of the checks. – Lie Ryan May 22 at 12:12
  • That sounds about what I need to do but can you provide a bit of code, even if pseudo? I don't know where to begin. I don't have routing and this is WordPress if it helps you in any way. – coolpasta May 22 at 13:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.