I have a User object that, upon successful authentication, is tucked into the session (sans security info) for easy recall and for determining whether we have an authenticated user or anonymous session. There are several paths by which the user can alter some or all of his or her information and I'd like to keep that session value up to date. The obvious answer is to update the value in the afterSave() callback, but that, of course, violates MVC.
Is there another way of capturing every change in one place so that I don't have to drop session writes all over the place? I can't think of anything, nor have I been able to find any other ideas. Am I the only person trying to do something like this?
Thanks.
Final Solution: I marked neilcrookes' response as the answer, frankly, because there doesn't seem to be the better way. Since this way violates my OCD senses, though, I took a slightly different path. I decided to have my User::authenticate() method return the authenticated user object to the caller so it can do whatever it wants with it. One of the things that the callers "want" to do is to drop that value in the session. It's redundancy, but it's very, very limited. In my mind, that felt better than accessing the session from the model (though it's certainly a damned if you do, damned if you don't scenario).
//in users controller
if ($this->User->save()) {
$this->Auth->login($this->User->read());
$this->Session->setFlash[.. etc]
And for the record, I do not agree with the answer of neilcrooks, but I will refrain from feeding the troll.
Some might disagree but I'd screw MVC, do it in Model::afterSave() and use $_SESSION - test for the session before writing to it, in case it's not started for example you are saving against the model in a shell or something.
MVC is a general pattern - a guideline, you can bang your head against it trying to figure out how to achieve something that doesn't quite fit, or just do it another way and move onto to something more important.
Bring on the flames.
after save
Use Like this
$this->Session->write('Auth.User.mmid', $kinde['Kindle']['id']);
You should be able to just use AppController to create the necessary callback(s) that keep your session data up to date. So, for instance, you could have your User model afterSave() set a property called changed to true. Then in your AppController->afterFilter() you check that property and update the session data as necessary.
Alternatively, you could write a component through which to update your user info and also your session data. Then any controller that needs to change user info just needs to include that component.
There's no need to write redundant code or break MVC.
Related
Javascript admitted newbie and hacker here, so I suspect this question is very ignorant and a learning experience.
I'm essentially converting an old Apex/Visualforce page to LWC. The Apex code employs Database.setSavepoint() and Database.rollback() and I have no idea how something similar would be accomplished in LWC, or even if it needs to be.
Google provides nothing, and I know it's not done through #wire and #AuraEnabled.
The main pain point of migrating VF apex controllers ("regular ones", oldschool, which were working with massive hidden html field for "viewstate" and weren't using #remoteaction to be a bit more mobile-friendly) to Aura/LWC server-side controllers is the static keyword next to the method definition. You don't have "viewstate" of whole controller passed to the method magically, you need to explicitly pass the params the method needs. From LWC/Aura or (re)query them. It's bit like everything was marked transient if you know what this keyword does.
savepoint and rollback have to happen in one transaction anyway (1 interation, 1 button click). User triggered something and it either succeeds or fails. You can't save the game ;) and 3 interactions later go "gotcha, rollback". The state was written to database, the ship has sailed. And savepoints can't be serialised (you can't grab the variable, pass it to VF/Aura/LWC client-side and later back to the server). If you're passing something back - it means the transaction is almost over and they wouldn't be needed anyway.
So there are no technical problems with it. The question is what is your business logic doing with the rollbacks. Is it some funky "validate before save"? Some way to try firing all validation rules, triggers etc and see what explodes"?
LWC shouldn't care and you should be able to pass the result of this operation back nicely. It's a good question whether you still need this functionality but it's biz question, not technical.
In my old cakephp 2.x Applications, the password hash was hidden by '*' when I retrieved the data from the User Model. I am not a hundret percent shure, but I think this was done automaticly by Cake.
Now testing Cakephp3.0, I am surprised finding the complete hash when retrieving data from the User Model.
I got a few questions concerning this password-hash-hiding:
Am I right with my opinion this was a function in cakephp2?
Does anyone know, why this function was not implemented in Cakephp3 and why?
If I am wrong by assuming this was included in cake, where is the place to implement this functionality in cake2 and cake3?
Thank you very much for your help.
Am I right with my opinion this was a function in cakephp2?
Yes, in Cake 2.x this is part ot the Debugger, the data itself however is not being touched, just some of the content is being masked when outputting the data.
Does anyone know, why this function was not implemented in Cakephp3 and why?
It is still implemented, but it has been moved. The whole point of this masking thingy was to avoid accidental exposure of datasource credentials (mainly in error messages/pages), it never really had something to do with possible user model data, this is just a side effect for data that happens to use keys like password.
So in 3.x this functionality has been moved to \Cake\Database\Connection::__debugInfo()
https://github.com/cakephp/cakephp/pull/4542
This ensures that you'll still end up with masked credentials when for example debugging connection objects, being it explicitly, or implicitly on error pages, while it doesn't obstruct debugging other data anymore.
[...], where is the place to implement this functionality in [...] cake3?
This highly depends on your use case, if you'd for example wanted to have it masked in debug output, then you could implement it in an overriden __debugInfo() method in your user entity class, similar to how the Connection class is doing it.
https://github.com/cakephp/cakephp/blob/3.0.11/src/Database/Connection.php#L702
Of course this would only work for entities, not for non-hydrated data (array data).
How are folks generally handling the whitelisting of foreign key values? Let's ignore the use case of an associated user record which brings an additional set of issues and stick to a fairly benign scenario: A Task belongs to a Project. When I create the task, I want to create it with its project_id value, but I don't want that value to be editable. The property is passed by a hidden field in the shared form.
I know I could just unset that property in the controller before calling save() in the edit action, but I was wondering whether anyone had a better solution. I've used/tried several, but all are laborious or less "universal" than I'd like.
Does anyone have a solution that they really like to solve this particular problem?
Thanks.
I handle this manually as well. The process is something like this.
Load object and show the edit screen to the user.
When user submits, take the primary ID and load the object again. Check ownership.
Have a whitelist of user editable fields, loop through those keys and populate your new object, leave everything else alone.
Save.
You could move this into some kind of before save hook or behavior I would say. But this seems the best practice with the RoR feature (we all know what happened in GitHub)
I'm knocking together a demo app based upon Nancy.Demo.Authentication.Forms.
I'm implementing Claims and UserName in my UserIdentity:IUserIdentity class and, as per the demo, I've got a UserModel with UserName.
In the SecureModule class, I can see that the Context.CurrentUser can be used to see who it is that's logged on, but as per the interface, this only supplies the username and the claims. If I then need to get more data (say messages for the logged on user) for a view model, all I can see to use as a filter for a db query is the username, which feels, well, weird. I'd much rather be using the uniqueIdentifier of the user.
I think what I'm trying to get to the bottom of, if it is better to add the extra fields to my IUserIdentity implementation, or to the UserModel? And where to populate these?
Not sure my question is that clear (It's not clear in my head!), but some general basic architecture advice would go down a treat.
Sorry for the delayed reply.. bit hectic at the moment :)
The IUserIdentity is the minimum interface required to use Nancy's built in authentication helpers, you can implement that and add as much additional information as you like to your class; it's similar to the standard .net IPrincipal. If you do add your own info you'll obviously have to cast to your implementation type to access the additional fields. We could add a CurrentUser method to stop you having to do that, but it seems a little redundant.
You can stop reading here if you like, or you can read on if you're interested in how forms auth works..
FormsAuth uses an implementation of IUsernameMapper (which is probably named wrong now) to convert between the Guid user identifier that's stored in the client cookie and the actual user (the IUserIdentity). It's worth noting that this GUID needs to be mapped to the user/id somewhere, but it's not intended to be your database primary key, it is merely a layer of indirection between your (probably predictable) user id/names and the "token" stored on the client. Although the cookies are encrypted and HMACd (depending on your configuration), if someone does manage to crack open and reconstruct the auth cookie they would have to guess someone else's GUID in order to impersonate them, rather than changing a username (to "admin" or something smilar), or an id (to 1 for the first user).
Hope that makes sense :)
I just realized when doing basic CakePHP stuff, that there is quite bad security issue, which many don't necessarily notice. I'll just take this basic function that I think many users use while doing CakePHP driven apps.
function edit() {
if(!empty($this->data)) {
if($this->User->save($this->data)) {
}
}
}
Lets assume user has privileges to use this action. This action could be editing user information, which may have like city and number and ofcourse username. Lets assume that we want to have a form that allows us to edit just the city and number but not the username. Well what if someone just inserts that username field into that form with firebug for example? Then submits the form. Now the edit would just grab all the post information, including the username field and its value and edit them straight away. So you can change your username in this case even though there werent a field for it.
This can go even further, if someone would use saveAll(), which allows you to validate and save multiple models in one shot. If you could guess from form fields the models to use, you could easily go to other models and tables aswell and alter those information.
Now that you understand my concerns, my question is what would be the best or atleast near the best method to avoid this?
I know I could just grab the data I want from $this->data to other variable and then pass that to the save or saveAll, but because there are many forms and ajax requests, that would be quite a lot of work. But is it the only way to go or are there better ways?
Should I make or is there a behavior which could stop this? Like checking what variables some action in some controller can get from post?
After couple of days research I found that this is not really a "security hole", but rather beginners mistake.
There are two ways avoiding this type of form tampering: Security component ( http://book.cakephp.org/view/1296/Security-Component ) which automatically gets CSRF and form tampering protection by creating one-time hashes for form fields.
The other way is to give the third parameter to save() function. The save actually gets 3 parameters: data, validate, fieldlist. The fieldlist parameter acts like whitelist of fields that are allowed to be saved.
I first reported this problem as a bug to cakephp which it then wasn't but this euromark guy replied to me that he had done nice documenting about the actual problem and how to do secure saves and I really think it was quite good reading. So if you have the same problems, please see this page: http://www.dereuromark.de/2010/09/21/saving-model-data-and-security/