I have a domain model structure laid out in GORM like:
User -< Company -< Product
These are mapped to RESTFUL routes similar to:
/company/1
/company/1/product/6
The currently logged in user is available in controllers as user.
Given this ownership structure, I want to ensure:
a user can't access company they don't own
and can't access products that are not associated with companies they own.
Is there a general, declarative approach to handling this Spring (or in Grails)? The obvious approach of:
if (product.company.user != user) throw new Exception()
...in an application controller seems brittle, especially as the object hierarchy expands.
Related
I'm exploring the Spring framework, and in particular I am working on a Cinema Management Application that will be connected to a React.JS SPA (Single Page Application).
The problem is the following. On my database I do have three different tables representing three different types of users, namely Admin, Customer, and Cinema_Employee.
For each type of user, I created a #RestController with a list of RequestMethods that a particular user is able to perform:
"/admin"
"/customer"
"/employee"
What I am trying to achieve now, it's to secure each endpoint offering three different login pages that will handle the authentication the respective type of user.
How can I set up three AuthenticationManager that handle different Authentication objects within a SecurityConfig class given these requirements, and most importantly, how can I override the Authorisation mindful that each user once has logged in, will have access only to the respective endpoint?
I looked carefully at other examples online, and most of them are radical different, following a pattern where the database has another additional 'Authorities' table aside the 'user' one that stores the credential. In my case this solution cannot be applied, not only because the whole design would become redundant, but also because the name of the table where the application will perform the authentication check against, explicitly imply the authorisation that a given user has inside the system.
Your design sounds strange to me.
A user should have a role, e.g. Admin, Customer, Employee and based on the user's role he gets access to methods or not. Have a look at role based access control concepts. For Spring Security there is for example this tutorial:
https://www.baeldung.com/role-and-privilege-for-spring-security-registration
Model in MVC is said to contain any business logic.
If that is true, then, I think authentication is the role of model.
"Your manager can change employee's salary, but you employee can't change your salary." is business logic. So, employee model should contain authentication logic that checks whether who is messaging to them is manager or not.
However, authentication logic is often handled by controller.
Why isn't authentication logic in Model?
I think you are confusing Authentication and Authorization. Authentication (identifying the user) is often handled by the controller, but what that user does (like your example) is authorization, and is usually much more deeply embedded into business logic. Most models will have some form of "User" which will have a set of permissions which are passed down into the business logic layers.
You can see this thread where this is discussed (ad nauseam, and with quite a bit of snark)
I was wondering if session handling like authentication and signing in is best handled by the User Model (assuming a user model refers to a user) and has attributes such as email and password. Or should session handling be held by another model?
What exactly is the best way to do this - I have code pretty much strewn partially in controllers in function files and want to refactor my code to adhere more to MVC principles. My project is based on the Zend Framework.
In MVC concept, the model represents the business part of your application.
Manage authentication, saving, deleting, activating of an user are business issues.
So it makes sense to create a method authenticate, save, delete, activate directly in your user model.
So in your user model, it is preferable to implement static methods as
public static function authenticate ($ username, $ password)
{
$authService = $this-> getServiceLocator()->get('Zend\Authentication\AuthenticationService');
$adapter = $authService->getAdapter();
$adapter->setIdentityValue($username);
$adapter->setCredentialValue($password);
$authResult = $authService->authenticate();
return $authResult->isValid();
}
And in your controller, you can directly do:
User/Entity/User::authenticate($username, $password);
I view authentication and session management as application-level concerns.
One general criterion I often apply is this: "Could I use my models in another app (perhaps a commandline app) or another website?
For example, in your circumstance, I would view a User model as representing a user. That user exists irrespective of whether or not he is actually visiting and/or logging in/out of your website. He could be referenced in a commandline app (Ex: a cron job that sends email to all users on their birthday; a reporting utility that counts all users that have incomplete profiles); etc. As such, I would keep authentication session management at the controller-level or perhaps one level down in a service level.
But as in most things, YMMV.
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?
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.
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.
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).
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.
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.
From my personal experience with MVC frameworks I would say:
Model is an object that is representing database table it should be
pure and should not contain any additional logic.
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.
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.
I'll use Rails as an example. The authorization library, pundit, places authorization firmly within the "model" domain - this is enforced through their helper methods.
Suppose you have a ShoppingBag model. You might want to create a ShoppingBag
class ShoppingBagController
def create
authorize ShoppingBag.new, current_user
end
end
It works really well if you have a 1-1 mapping between a model and a controller. But what if you need a second controller on the same model? Now you're stuck!
class DiscountedShoppingBagController
def create
authorize ShoppingBag.new, current_user # does not work for us. we want a slightly different authorization, on the same model.
end
end
It's for that reason I dislike pundit, and CanCanCan. Authorization at the controller level, for me, is ideal. Doing so on the model level limits me too much, without any commensurate gain.
I'm looking at creating my first ASP.NET MVC application using MVC3.
The project template I used included some models for registering users, logging in and updating a forgotten password.
I want users to be authenticated against my own data store (probably using Entity Framework) and using google OAuth.
I assumed that I'd want a User model class that contained a few standard properties and some business logic which handled the "local" authentication and the OAuth call but the project template has confused me.
Should I be creating multiple view-models for different actions like Login, Register, etc and then using the controller to instantiate and invoke my model to perform the business logic or should I use my User model for all the different actions?
Thanks
Ben
Should I be creating multiple
view-models for different actions like
Login, Register, etc and then using
the controller to instantiate and
invoke my model to perform the
business logic or should I use my User
model for all the different actions?
View model per view. That's the rule. There might even be 2 view models per view (one for rendering data in the GET and one for receiving data from the view in the POST action). Don't be shy in creating view models. You definitely shouldn't be using a User model for all different actions, that would be catastrophic. The model should be used by your service layer. A User model will be manipulated by this layer, and never passed to a view.
You may also checkout AutoMapper for mapping between your model classes and view models. It's a great tool and comes in handy especially when the number of view models start to increase.