29

I'm writing a web application with some ACL requirements: a user can make changes to some items, some items may be editable by several users, administrator can edit anything and a manager can edit everything within her organization etc.

I'm using the Play! framework, and by the looks of the Secure module, it seems that the place to put authorization concerns is in the Controllers. However, it seems to me that the authorization issues are part of the business logic, and therefore should be in the model. Furthermore, I'm starting to see duplicated logic in the controllers that I need to refactor out.

On the other hand, adding authorization to the model means that I'd have to have some way of getting the current user from within the model, which doesn't seem right. Alternatively, I could add a "current_user" parameter to every model method, but that seems even worse.

So what is the common practice? Can/should I put authorization code in the model, or keep it in the controller?

itsadok
  • 27,343
  • 27
  • 120
  • 167

6 Answers6

17

I think this is a grey area. One could argue that the user access is part of the mapping between the HTTP world and the Object-Oriented world. This is what the controller is intended for (hence the heavy use of statics), to transform the incoming request, ready to process the business rules on the domain model.

I would suggest that the controller logic is absolutely the right place for controlling the access to the model, especially as this is managed largely at an annotation level, and the authentication is abstracted off to a Security class.

Codemwnci
  • 51,224
  • 10
  • 90
  • 127
  • 4
    In my opinion, I think it is absolutely right, however, it is a grey area and therefore open to interpretation. So, it depends on whether you agree with my interpretation or not :o) – Codemwnci Sep 01 '11 at 14:39
11

Authorization should neither be part of controller or domain model.

Instead it should be in the service layer.

Controller should just act as dispatcher and delegate between HTTP and application service. It's the application service where the orchestration takes place. This is the best place for placing authorization.

Suppose user A is authorized to access data from domain X, but not authorized for even a read access for data from domain Y. If authorization is placed in the controller, then user A gets authorized in the controller X, and via the service calls can access data from domain Y, which is not what we expected.

Since domain models communicate with each other on service layer, hence it best to place the authorization on the same level.

user3802960
  • 123
  • 1
  • 4
  • So, If there is a logic that super admin has access to all resource and whereas admin has access to some, where does this logic sits: controller ( given such logic can be handled with policy based authorization which in turn uses httpcontext. and i don't want httpcontext to be used in service.), service or domain model – arjun Jul 17 '19 at 03:53
  • another side effect to this, controllers might not be the only entry point to your service, what if I suddenly want gRPC endpoint & 1 gRPC endpoint will map everything to services, same thing with websockets, controller should only transform request into domain objects, once it's passed inside, service takes care of everything, that way you can upgrade your endpoint later should you need to. –  Nov 11 '20 at 09:05
9

In most cases, the security should be one (or more) layer above the Model. Security is a domain on it's own, restricting access to a lower level layer.

I don't think the security should be done at the controller level.

In my opinion, this should look like that:

View -> Controller -> Security -> Model

The security layer could be a façade or a proxy over the model, protecting access, but be transparent to the controller.

However, if the views are to be modified depending on the access rights of the user, some checks might have to happen at the controller level (like setting the value of a CanEdit boolean property on the ViewModel).

Martin
  • 5,539
  • 4
  • 26
  • 46
  • You are mixing up security and authorization. Security concerns have to be dealt with on every layer of the application - see: defense in depth. The question is "where does authorization belong to?", not security. – Francois Bourgeois Feb 07 '13 at 14:20
1

I am at this stage and intending to handle this in the following way:

  • No form validation by JS, instead via HTTPS ajax

  • An Ajax php class

  • Form data sent to a model as its data for concrete validation for
    common type such as email and password (likely assoc array validation will be reused by other classes so this is definately a model area).

  • if no error a lookup in a User table for the credentials email /
    password credentials passed to a Controller with the authentication
    type such as login / signup / password reset

  • the controller then produces the required output view or sets user logged in session etc

This is based in Laravel but I have my own library as want it independent of laravel and just loosely based for this vital requirement.

The point being that the Model looks up the required credentials as data, then sends to the Controller as it does not care how it should be processed. I think this is the only way to make this area a definitive responsibility between each of the components.

Datadimension
  • 963
  • 1
  • 8
  • 22
1

I personally really like the way the Play! Secure module handles this (the tutorial is ever-helpful here). If you don't mind using the @Before annotation, it's pretty painless.

andronikus
  • 3,893
  • 1
  • 23
  • 44
0

From my personal experience with MVC frameworks I would say:

  1. Model is an object that is representing database table it should be pure and should not contain any additional logic.
  2. Controller is the place where are made the decisions and other custom logic, so the authorization should be in the controller. It could be designed some hook that can check if the user is authorized or not in all needed places so you wont have a code repetition DRY.

  3. The best way to give permission to user if you are using a typical REST architecture is to make a token , save it in the databse and on client side and verify this token on every request. If you are using web browser app you can use server-side sessions for authorization ( Its much more easier).

So my propose is to keep the authorization logic in the Controller.

tima_t
  • 9
  • 1
  • So, If there is a logic that super admin has access to all resource and whereas admin has access to some, where does this logic sits: controller ( authorization), service or domain model – arjun Jul 17 '19 at 03:51