I was looking and looking a bit too long time for a solution for my problem and I can hardly find anything focused on the topic which bothers me.
Namely: Do you have any idea if user login can be processed inside symfony2 without using a form login? To be more precise, I mean let's say something like this:
$this->authenticationManager->login($user->getUsername(), $user->getPassword());
For now I have two ideas to do what I want to do but a bit differently:
Take advantage of AJAX and send arequest via POST to loginAction with it (unfortunately this is not going to work if JavaScript would have been disabled)
In symfony's docs I found an option post_only: true which when I set to false lets me access loginAction wih GET method so simple redirect would have done the job here.
nevertheless I would prefer the solution I'm searching for.
BTW: Can you tell me how to generate csrf token if I needed it to successfully submit login data?
You can manually set the authentification token:
// Inside an action, for example. You already need an user.
$providerKey = 'main'; // your firewall name
$token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
$this->container->get('security.context')->setToken($token);
Found here.
Related
I'm in searching of the best way of removing business logic from controller and correct usage of model(and maybe services).
Some details below.
Actually, my project is more complicated, but as example I will use Simple Blog application.
I have created my application (Simple Blog) in next steps:
created bundle
generated entities(Topic, Post, Comment)
generated controller for each entity, using doctrine:generate:crud
installed FOSUserBundle and generated User entity
So, I have all needed methods and forms in my controllers. But now I have some troubles:
Admin need to be able see all topics and posts, when simple User can only see
topic and posts where he is owner.
Currently there are indexAction, that return findAll common for any user. As solution, I can check in action, if ROLE_USER or ADMIN and return find result for each condition. But this variant keep some logic at action.
I also can generate action for each role, but what happened if roles amount will increase?
What is the best way to solve this problem with result for each role?
I need to edit some parameters before saving.
For example, I have some scheduler, where I create date in some steps, using features of DateTime.
Before saving I need to do some calculations with date.
I can do it in controller using service or simple $request->params edit.
What is the best way to edit some $request parameters before saving?
My questions I have marked with bold.
Thanks a lot for any help!
What I would do is to create a query which fetches the topics. Afterwards I would have a method argument which specifies if the query should select only the topics for a certain user or all topics. Something like this should do the work in your TopicRepository:
public function findTopics($userId = false)
{
$query = $this->createQueryBuilder('topic');
if($userId) {
$query->join('topic.user', 'user')
->where('user.id = :user_id')
->setParameter(':user_id', $userId)
;
}
return $query->getQuery()->getResult();
}
So, whenever you need to get the topics only by a user, you would pass a $userId to the method and it would return the results only for that user. In your controller you'd have something similar to this code (Symfony 2.6+):
$authorizationChecker = $this->get('security.authorization_checker');
if($authorizationChecker->isGranted('ROLE_ADMIN')){
$results = $this->get('doctrine.orm.entity_manager')->getRepository('TopicRepository')->findTopics();
} else {
$results = $this->get('doctrine.orm.entity_manager')->getRepository('TopicRepository')->findTopics($this->getUser()->getId());
}
You can try using Doctrine Events and create a PreUpdate depending on your case. See the documentation for more information. If you have a TopicFormType, you could also try the form events.
You are not supposed to "edit" a $request, which is why you can't directly do that. You can, however, retrieve a value, save it as a $variable and then do whatever you want with it. You can always create a new Request if you really need it. Could you be more specific what you want to do here and why is this necessary?
I'm building a application with Symfony 2.6.5. I have built my own User Provider following this and this.
My User class implements AdvancedUserInterface and EquatableInterface.
isEqualTo returns false if either password, username or isEnabled has changed.
I serialize id, username, password, isEnabled and a few custom properties.
It all works pretty good. Except for the following:
I can login (without RememberMe), everything looks good. I've verified that refreshUser() in my user provider is called on every request as is isEqual() in user.
If I directly change the username in the database and hit refresh, I'm not logged out. My view displays the user name and that changes to the new value from the database. Likewise I am not logged out if I manually change the password hash in the database. I have verified that isEqualTo() returns false and $this->setAuthenticated(false) happens in AbstractToken.
It does logout on the next refresh if I change isEnabled to false.
Either I'm doing something wrong, the documentation here is wrong, I'm misinterpreting it or there is a bug in Symfony.
It's not a big deal. The fact that isEnabled gives me a way to log someone out is good but I'd like to understand this better.
Thanks
EDIT: I just discovered that I'm not the only one seeing this.
https://github.com/symfony/symfony/issues/13870
I probably should have looked there first.
I have come to the conclusion that this is a documentation issue rather than a bug. Explanation at the bottom of https://github.com/symfony/symfony/issues/13870 and a new issue for the docs at https://github.com/symfony/symfony-docs/issues/5419
I am wondering how I add user impersonation on mvc identity 2.0, I seen some people using this:
FormsAuthentication.SignOut();
FormsAuthentication.SetAuthCookie(user.UserName, false);
This wont work for me it wont even sign out I use :
AuthenticationManager.SignOut()
So how do I go along doing this I have admin panel what lists users, I get the userId or userName, what exactly do I have to do? I have never used Claims so I dont understand it much I wont need to revert back to user they can just logout for now.
Here is the solution for anyone who else is having this issue - :
var user = _db.AspNetUsers.Single(a => a.Id == id);
var impersonatedUser = UserManager.FindByName(user.Email);
var impersonatedIdentity = UserManager.CreateIdentity(impersonatedUser, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = false }, impersonatedIdentity);
Thanks for this question as it helped me find a number of solutions including yours and #trailmax. After some thought I went about this a different way, as I just needed to change some of the Claims to do the impersonation. I call this semi-impersonation, as it just changes a few things rather than totally change the user.
Like trailmax I have written a blog post on my approach with all the code. Below I have summarised how it works.
I add a session cookie with the impersonation information I needed to change in the current user to allow them to access information belonging to another user. I my case I had a key to some data.
I then use the new MVC's 5 AuthenticationFilter OnAuthentication method to a) look for the impersonation cookie. If it found it then it changed the Claims in the current ClaimsPrincipal, which the filter would then propagate through the application.
Coming out of impersonation mode was achieved by deleting the cookie, which you do by setting its expire date to a date prior to now.
The benefits are much more control over the level of access, but it won't work in all cases. In my article I compare my approach with #trailmax's approach to bring out the benefits of each implementation.
I'm making a module to allow users to update single fields on in this case, their user entity.
The code below is an example of the method I have initially been using to get it working and test other elements of the module
global $user;
$account = user_load($user->uid);
$edit = (array) $account;
$edit['field_lastname']['und'][0]['value'] = 'test';
user_save($account, $edit);
However this bypasses any field validation defined elsewhere in Drupal. I don't want to reproduce any validation written elsewhere - it's not the Drupal way!
My question is: Is there a function in Drupal 7 that can be called to update the value of a single field. I imagine such a function would clear the appropriate caches, invoke the fields validation etc.
I am aware the solution will be totally different to my current user object based one. I just can't for the life of me find the appropriate function in the API. I wander whether the fact I am looking for a save function alone is the problem - and that there are some other necessary steps that come before.
Any help gratefully appreciated.
Check out the drupal_form_submit function. It lets you submit forms from code. In this case, you could use it to the user edit form, which would then fire the appropriate validation.
The documentation reads:
Helper function for authentication
modules. Either login in or registers
the current user, based on username.
Either way, the global $user object is
populated based on $name.
It seems to me that this function does not actually perform a login (it does not trigger the user_hook with op=login. It does not call user_external_login or even user_authenticate_finalize.
Am I interpreting it wrong?
I looked through the code, and it doesn't invoke hook_user() op = 'login'. You can do that in your own module though.
Look at user_module_invoke() to do this.
It does log the user in.
Last lines in code,
// Log user in.
$form_state['uid'] = $account->uid;
user_login_submit(array(), $form_state);
, seems to say that, in spite of submitting a wrong password.
System seems to create a user (named like that name provided in the login form) and save locally whichever wrong password provided (which will be, then, the "right" password).
If you do not take further action, then, it will not even care about an external authentication source and the real onwer of that name will not be able to log in later...
Scary, uh?