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.
Related
I'm developing a fairly standard web application with Wicket, Spring & Hibernate. I've been using wicket-auth-roles and spring-security to authenticate users, and now want to add more fine grained authorizations to my applications.
In my applications users are members of groups, and groups have access to a subset of Hibernate objects that I use as wicket IModel objects. As such the decision whether or not a user may view certain page does not depend on the page path, but on the page model. (Most implementations of authorization for Wicket I've seen either grant access to a url or restrict it; they do not perform any checks on the model object.)
At present I've implemented this restriction as a custom IAuthorizationStrategy like this:
#Override
public boolean isActionAuthorized(final Component component, final Action action) {
if (!(component instanceof GenePage))
// We only check access to the GenePage for now
return true;
// Figure out from component what Gene the user is trying to view
Gene gene = (Gene) component.getDefaultModelObject();
User user = MySession.get().getUserModel().getObject();
return geneDAO.hasAccess(user, gene);
}
The problem with this implementation is that it fully composes the page and only in Page#onConfigure throws an uncaught UnauthorizedActionException. So far I've been unable to catch this exception, so it's logged as a problem even though it's part of the normal program flow. Fully composing the page also triggers a few actions in my page constructor and Page#onInitialize that I would only like to run if the user may actually view the Page.
Can anyone recommend me a better approach to restrict page access based on whether users have access to the Model object?
Solutions that tie in anywhere along the stack using Hibernate, Spring, Spring Security, Wicket and/or Wicket-Auth-Roles would be preferred. I know there are other wicket auth-integrations out there, so if you feel those could help in this instance, please let me know!
I feel that you expect a weird behaviour. This authz mechanism is designed to protect against Insecure Direct Object Reference Vulnerabilities. So you should not use it as a "part of the normal program flow". If you have kind of valid use cases then such kind of "hasAccess" failures should be handled somehow differently as valid behaviour, you should use some other mechanism, probably something custom built, as in most cases it will be very specific to your application.
Experts,
what's the recommended way to pass the user id (system internal id of the user used to query for the user info) between controllers in a codeigniter app?
I'm considering the following options:
1. Use the CI session id to query the database for the user id in every controller. That way I don't have to place the user id in the session which is a security concern. But this option means an extra db query in every controller
2. Store the user id directly in the session so I have it readily available to query for user info.
What do you think?
From my understanding of MVC you're not normally supposed to talk directly between two controllers. However in this case I would use the session. As far as security goes there are plenty of extensions to codeigniter dealing with authentication such as TankAuth and WolfAuth including many others that you might look into if that is your concern. In this case however I'd say using the session to store a user id is perfectly fine as long as you're not storing sensitive data along with it.
You can read up on CodeIgniter sessions here: http://ellislab.com/codeigniter/user_guide/libraries/sessions.html
There is a great authentication library Ion Auth. Check it out
http://benedmunds.com/ion_auth/
Suppose my module accepts a username and password and returns true or false to indicate success or failure. Would this be more a model or a controller?
It really doesn't need to exist in a controller. It could be in a class library if needed. You would need to have a Controller Action / View that eventually prompts a user for their credentials, but the logic of authenticating does not need to exist in the Controller Action.
The username, password and success indicator would be part of the Model,
the model would be made visible to the client in the View,
the model would be processed by the Controller.
Authentication is a service - structure from model layer, which utilizes both domain object and data storage structure (usually data mappers). As minimum, it has to interact with User domain objects and both persistent storage (like SQL) and cookies. It also might require data exchange with session.
Also, when controller sends user login details to model layer, it should not receive any replay. That part should be handles by the current View, which requests the user-state from model layer.
P.S. I hope you are not one of the people who refer to IE as "the internet" and ASP.NET MVC framework as "the MVC".
it will be an action from a controller.
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 am building an ASP.NET MVC3 app using Forms Authentication and I'd like to log out all existing sessions for a user when that user logs in. I'm trying to prevent multiple people at different workstations from logging in and working under the same account.
Is there a standard way of handling this? Logging out the existing session is easy, but I haven't come across a way to check for other sessions by the same account and log them out.
I have a few ideas on how to hack this, but I'm curious if there's an established method for this using IIS or the FormsAuthentication API.
Because of the statelessness of the web, you can't "log out" a session until they make their next request (for instance, session might be maintained in a cookie, which can't be written on the client outside of the context of a request-response interaction).
There is still a solution, which assumes you are using session state, and preferably you have a common base controller for all of your controllers requiring "Authentication".
Upon successful login, generate a token (a guid perhaps) and store that with the session. Also write this to a application-wide store (database or application context for instance) keyed by the userid.
In the Base Controller (or otherwise you'd have to create an action filter) check the token in session against the token registered for the userid in the application-wide store. If they don't match, log out the user using the standard SignOut() call.
You could use the Membership.IsOnline property which is based on LastActivityDate:
A user is considered online if the
current date and time minus the
UserIsOnlineTimeWindow property value
is earlier than the LastActivityDate
for the user.