21

Typically, I place authorization decisions in my server side controllers. These have been RESTful endpoints recently, but I think the same stands for MVC type architectures. For the sake of argument assume that it's role based authorisation. A protected method will be annotated or make checks and return 403s if necessary.

Now, given that authorisation is in fact a business rule - "only administrators can list X" for example, I'm thinking they should be pushed down a layer. When a controller asks the business layer to perform the operation, the service or business layer informs the controller it's not authorised.

Is this a reasonable approach? Are there disadvantages to this?

I'm loathe to have an AuthorisationService that essentially holds a bunch of static procedural coded rules to do this but maybe it makes sense to keep all access logic in one place. Is it a cross cutting concern that should be kept separate?

So I'm asking if anyone has done this and how they achieved it in a clean way or if there are any good resources I could read. I'm using Java fwiw but this is a language agnostic question.

I've checked out the related questions on here and they're very thin on the ground and answers. For example: Validation and Authorisation in Domain Models and Carrying that through a Service Layer to MVC

I'm reading the spring security docs which make some good arguments for it being a cross cutting concern, but I'm worried it's just the "spring way" and would like wider perspectives. It also ties your application to a specific framework.

  • 1
    Status 403 is wrong for authorisation problems. Use 401. – gnasher729 Oct 31 '15 at 20:43
  • @gnasher729 I think that's backwards. 401 means authentication has failed or is not provided, 403 means you don't have access rights: stackoverflow.com/questions/3297048/… – JimmyJames May 31 at 15:51
  • @JimmyJames, there's another school of thought that you should just use only one of them for all authentication and authorization failures since it doesn't let automated tools infer business logic as easily. There's some leeway. – Berin Loritsch May 31 at 18:00
  • 1
    @BerinLoritsch Sorry, are you saying that the idea is to make it harder to understand if it's an authentication or authorization issue? The RFC seems pretty clear but states you can use 404 instead of 403 if you don't want to expose too much info. Is there a reference you can provide for the argument for using a 401 instead of 403? – JimmyJames May 31 at 18:13
  • @JimmyJames, Yes. This thought process comes from security professionals, not developers. And I've also seen your recommendation of 404 to completely hide the information to hide that the resource even exists. – Berin Loritsch May 31 at 19:27
8

Its good practice to expose only the options a user is authorized for.

This forces authorization to be a cross cutting concern. The "View" needs to know what a user is allowed to do before it can build options and menus for display.

The back end should not trust the front end to make security decisions so must check authorization itself.

There may be business rules that effect authorization depending on data e.g. "Only users with a balance over $5000 can invoke a foreign currency transfer" or "Only a user located at Head Office can view these accounts". So some authorization logic is required within the the business logic.

There are also Technical authorizations to consider - who is allowed to view the logs, who can backup/restore the database etc.

So in the end every component in your may have some specific security and/or authorization requirements, in practice its almost impossible to wrap this up into a separate "authorization layer".

7

I think it's absolutely reasonable approach to engrain authorization in your Service layer. You need to protect your service from performing unauthorized activities(especially data-modifications). Your Service layer could resides in one library, and being used by different Presentation layers(you could have different UI-applications, that use the same Service layer). And you can't rely on the fact that specific Presentation layers perform necessary validation. This is especially important if you will decide afterwards to move your Service layer to the separate process(e.g. following SOA approach).

Now about how to achieve this in a "clean way". I don't like the idea of littering business logic with authorization checks, so some specific implementation of aspect-oriented-programming-approach could help: it could be decorating service methods with special attributes or using dynamic proxies with interceptions.

And importantly, I need to admit that in very simple projects, may be, you could live without separated validations, just to simplify your life. But it's important do not miss the moment when "simple project" began to become "complex project".

7

I like pushing authorization checks down as low as they can go! (But no further!)

You're still free to write automated authorization tests against layers "above" this. And some rules may only be applicable or make sense in higher layers like your service layer (CanView/CanSerialize?). But, I generally think the safest authorization strategy is also "DRY-est" strategy: Keep authorization as low as possible, in the most "common" or "shared" code as you can (without over-complicating the auth rules).

Think about the alternative. If your authorization rules are tested and enforced only in the service layer, leaving your poor domain objects to bend to the wills of a moody service objects, you'll often be required to enforce each individual rule more than once, in multiple objects and multiple places in each object, and in more complicated code.

Furthermore, when your analytics team hires a consulting firm to write reporting services using your domain objects, you don't want to have to trust those developers! (Or whatever. You build additional services or calls over the same objects for any reason.) You won't want to crack open the big book of business rules and hope to enforce those rules properly again; you want your domain to already know them and enforce them.

  • @Shoe If I understand your concern -- that's sort of the point. If only an "admin" has permission, per the business rules, to create a Widget, the same rule applies everywhere. (So don't risk letting anyone ignore it!) If the rule doesn't apply everywhere, it's not really a rule about Widgets and only Widgets.. Push rules down as far as they (the individual rule(s)) can go; but, not as far as "rules" can go ... I feel like I'm not stating the distinction well. But, there's supposed to be distinction there. – svidgen Jul 2 '18 at 20:07
  • In my experience, authorization rules are often part of the business rules. As such, "as far down as they can go" is often my domain layer. But, I suspect that where your rules "should" fall is just a consequence of your domain, the nature of the rules, and how the business talks about them. – svidgen Jul 2 '18 at 20:17

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.