Software Questions
Software Questions

Reputation: 81

Authorization Service -- returning a list of authorized resources

What is the recommended way of retrieving a list of all Resources that a User has access to?

In many examples I've seen, Authorization is placed into a separate service -- often one that exposes a method similar to isAuthorized(), which can be used for individual queries ("Is the User authorized to use Resource ABC?") as well as bulk queries ("Is the User authorized to use any of the following list of resources?").

While the authorization-logic exists in the Authorization Service, the enforcement of the authorization policies is kept within the application itself (e.g., business-logic layer for actually implementing access to the resource, based on the result from the Authorization service; or the presentation layer to show/hide individual options based on the result from the Authorization Service, etc.).

What is the preferred way of doing this if, for example, my Data Access layer has potentially billions of "resources" that it could return? Does my business-logic layer query all that data (passing all of it over the network), and then forward that giant list on to the Authorization Service (again over the network), only to get a giant list of "ALLOW/DENY" sent back to the business logic? Obviously that doesn't sound quite right.

Is this a case where we can't have a "clean" separation of data-access, authorization-logic, and business-logic? Should I instead ask my Data-Access layer to only return to me a list of all Resources that the User has access to, which could end up being implemented as a simple database join, but would then require that some of the logic for determining who has access to what resources under what conditions (i.e., the authorization policies) be embedded in the data-access code, and therefore those policies would be spread through-out my code base (e.g., some authorization logic would be in my Data-Access Layer, some would be in my Authorization Layer, etc.)?

Maybe performance trumps a "clean" architecture, but is there a better way of doing this?

Upvotes: 8

Views: 926

Answers (3)

oopexpert
oopexpert

Reputation: 755

Authentication is better to be externalized. Authorization often is too application dependent to externalize. It may work for little systems. But for big systems you will encounter scaling problems as you already expect.

Another thing is returning huge datasets. It seems to me, that this is better placed in reporting. So separate first process modules from reporting modules, that have different requirements because in a business process you need focussed data and in reporting mass data and abstraction.

Authorization is NOT a layer. It's an aspect. An application may not work without a layer if you do not replace it at least with a proper mock. But if you remove aspects you should not have a problem to run the application. Maybe your program will not log anything or you will be able to see more data than you are allowed to see but it will still work.

So should Authorization be externalized from the application domain? No. Should it be separated from the business logic? Yes. The proper mechanism: Aspects (AspectJ, Proxy-Pattern, Template-Class-Pattern). This is my general suggestion.

My special suggestion for "huge data" in business processes is: Try to partition your domain model properly to have little focussed data (Subject "Usability" or "User experience"). Then return to my general suggestion.

If you have to deal with huge amount of data in business processes: Use the last point of "Make It Work Make It Right Make It Fast". Think about it as an optimization for special data requests, that are or are expected to be slow. In this case use special sql queries, pre-loading, caching etc. The DAO-Layer may be the proper location, an caching aspect or an optimization aspect for the DAO-Layer that overrides "working slow"-implementations with alternative implementations that are fast.

The suggestions I made refer to normal business use cases. I am not talking about big data or reporting. As I mentioned these sectors have different requirements.

Upvotes: 1

djna
djna

Reputation: 55907

I have an embryonic idea, not based on any practical experience but at first sight it's plausible.

Why do we have an Authorization service? My claim is that we have some features of that service because our data source is not doing a complete job. If we were using only an RDBMS database as the source of our data then the database could police major categories of authorisation. We can work against Views and grant privileges to access those Views and hence protect Tables and Columns as we wish. There then remains the set of rules of this kind

Salary information for an employee can be shown to a). the employee, b). their manager and second line manager, c). members of the HR remuneration team.

I believe that such authorisation rules have business semantics, and are best implemented by an authorisation service and the expression of that service is in terms of business objects:

 can This employee see That employee's salary?

It is not expressed in terms of tables, rows and columns but at a coarser, business-meaninful granularity. Implementing this requires building a data model that expresses the authorisation rules, and strictly speaking this is business logic, we just choose to refactor to the authorisation service to encapsulate the implementation.

Contrast this with the fine-grained Entity authorisation, expressed in terms of Views, Tables and Columns. My claim is that this properly belongs in the Data Source and if our data source cannot or does not implement it, then we need to implement it in our Data Access layer. The DAOs "know" which views/tables they use and presumably also know the id on behalf of whom the request is being run and so decide whether access is permitted.

Speaking loosely: DAO has the SQL so knows the entities, so can decide. (Yes there may not be SQL for some back ends, but the DAO is the object that understands what is being retrieved.) It could be enriched with a method to list which of its access methods are permitted for a given user.

 CustomerDAO.whatIsAuthorised("joeCoder") => READ, QUERY

 CustomerDAO.whatIsAuthorised("phb") => READ, QUERY, UPDATE

Upvotes: 0

J. Ed
J. Ed

Reputation: 6742

I don't have a definitive answer to your question, but I may be able to offer some pointers-

  • you asked

    Does my business-logic layer query all that data , and then forward that giant list on to the Authorization Service, only to get a giant list of "ALLOW/DENY" sent back to the business logic?

Well, that doesn't really seem like a likely scenario to me. Can you think of a situation where you would want to present all the available records to a user? Isn't it more reasonable that you'd want to further filter those records (i.e by type, date etc..), and probably you'd also want to page them so that the user would get a bite-size result set.

  • Add that to the fact that most likely you'd only be passing records' identifiers to and from your service, you may find that this approach is doable for you.

  • Also note that having your authorization logic as a 'service' doesn't necessarily mean that it has to reside on a different machine; you can implement it as a separate logical module, and still have it run on the same machine (possibly on the same process as your application, if you want to), thus avoiding the network traffic issue.

  • your observation that implementing authorization as part of data access can be tricky is correct. However, there are some infrastructure tools that help you with that. For example- oracle's virtual private database, (n)hibernate filters and I'm sure there are others.

Again, these aren't complete answers, but they may lead you towards a solution that will work for you.
I'd suggest you google 'authorization framework+ [your favorite programming language]'; I'm sure someone's already done it before :)

Upvotes: 0

Related Questions