sfUser equivalent in Symfony 2 - symfony

What is the sfUser equivalent in Symfony 2?
sfUser allowed getting user session attributes using getAttribute() method.
Is Symfony\Component\Security\Core\User\User its equivalent? But it doesn't have getAttribute() method in it.

To get session attributes, get the session service from the container. This example is in a controller, where the session is available via a helper method:
public function fooAction()
{
$session = $this->getRequest()->getSession();
// Setting
$session->set("foo", "bar");
// Retrieving
$foo = $session->get("foo");
}
See the documentation for details. You can also retrieve the session explicitly from the container should you need it, via $container->get("session");
If you need the User object, you can get it via:
public function fooAction()
{
// Get user from security token (assumes logged in/token present)
$user = $this->get("security.context")->getToken()->getUser();
}
Again, see the documentation for further details.

Related

Hash user password without User instance in symfony

As it can be read in the official documentation, the current procedure to manually hash a password in the Symfony framework, is the following:
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
public function register(UserPasswordEncoderInterface $encoder)
{
// whatever *your* User object is
$user = new App\Entity\User();
$plainPassword = 'ryanpass';
$encoded = $encoder->encodePassword($user, $plainPassword);
$user->setPassword($encoded);
}
The encodePassword method requires an User instance to be passed as its first argument. The User instance must therefore pre-exist when the method is called: this means that a 'User' must be instantiated without a valid hashed password. I'd like the password to be provided as a constructor argument instead, so that an User entity is in a valid state when it is created.
Is there an alternative way of hashing the password using Symfony?
Update for Symfony 5 and later. The Encoder stuff was renamed to Hasher. The answer still works but just replace EncoderFactoryInterface with PasswordHasherFactoryInterface and change your variable names to hasher.
The UserPasswordEncoder uses what is known as an EncoderFactory to determine the exact password encoder for a given type of user. Adjust your code to:
public function register(EncoderFactoryInterface $encoderFactory)
{
$passwordEncoder = $encoderFactory->getEncoder(User::class);
$hashedPassword = $passwordEncoder->encodePassword($plainPassword,null);
And that should work as desired. Notice that getEncoder can take either a class instance or a class name.
Also note the need to explicitly send null for the salt. For some reason, some of the Symfony encoder classes do not have default values for salt yet.

Api-Platform: using PUT for creating resources

I would like to use the PUT method for creating resources. They are identified by an UUID, and since it is possible to create UUIDs on the client side, I would like to enable the following behaviour:
on PUT /api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 if this resource exists, update it
on PUT /api/myresource/4dc6efae-1edd-4f46-b2fe-f00c968fd881 if this resource does not exist, create it
It's possible to achieve this by implementing an ItemDataProviderInterface / RestrictedDataProviderInterface.
However, my resource is actually a subresource, so let's say I want to create a new Book which references an existing Author.
My constructor looks like this:
/**
* Book constructor
*/
public function __construct(Author $author, string $uuid) {
$this->author = $author;
$this->id = $uuid;
}
But I don't know how to access the Author entity (provided in the request body) from my BookItemProvider.
Any ideas?
In API Platform many things that should occur on item creation is based on the kind of request it is. It would be complicated to change.
Here are 2 possibilities to make what you want.
First, you may consider to do a custom route and use your own logic. If you do it you will probably be happy to know that using the option _api_resource_class on your custom route will enable some listeners of APIPlaform and avoid you some work.
The second solution, if you need global behavior for example, is to override API Platform. Your main problem for this is the ReadListener of ApiPlatform that will throw an exception if it can't found your resource. This code may not work but here is the idea of how to override this behavior:
class CustomReadListener
{
private $decoratedListener;
public function __construct($decoratedListener)
{
$this->decoratedListener = $decoratedListener;
}
public function onKernelRequest(GetResponseEvent $event)
{
try {
$this->decoratedListener->onKernelRequest($event);
} catch (NotFoundHttpException $e) {
// Don't forget to throw the exception if the http method isn't PUT
// else you're gonna break the 404 errors
$request = $event->getRequest();
if (Request::METHOD_PUT !== $request->getMethod()) {
throw $e;
}
// 2 solutions here:
// 1st is doing nothing except add the id inside request data
// so the deserializer listener will be able to build your object
// 2nd is to build the object, here is a possible implementation
// The resource class is stored in this property
$resourceClass = $request->attributes->get('_api_resource_class');
// You may want to use a factory? Do your magic.
$request->attributes->set('data', new $resourceClass());
}
}
}
And you need to specify a configuration to declare your class as service decorator:
services:
CustomReadListener:
decorate: api_platform.listener.request.read
arguments:
- "#CustomReadListener.inner"
Hope it helps. :)
More information:
Information about event dispatcher and kernel events: http://symfony.com/doc/current/components/event_dispatcher.html
ApiPlatform custom operation: https://api-platform.com/docs/core/operations#creating-custom-operations-and-controllers
Symfony service decoration: https://symfony.com/doc/current/service_container/service_decoration.html

ASP.NET MVC How does AuthorizeAttribute support checking Roles?

In my controllers, I have code like [Authorize(Roles = "Administrators")] annotated above some actions, and I want to know how AuthorizeAttribute uses the Roles parameter (the implementation of the checking mechanism). My goal is to create an extension of this class, called PrivilegeAttribute for example, so that I can annotate actions like [Privilege(Privileges = "read")]. In this class, I would check if the Role of the user has at least one of the privileges in this custom filter (read in this example). I have already created the association between roles and privileges in the code and in the database, and what I want help with is checking whether the role is associated to the privilege.
I tried seeing if that information is there in HttpContextBase.User.Identity but I couldn't find it.
Thank you.
If you don't need your own custom attribute and could live with using someone else attribute, than I would suggest to use the package Thinktecture.IdentityModel.Owin.ResourceAuthorization.Mvc as described here
Blog Post by Dominick Baier
and here
Git Hub Sample Code for the Package
so it basically works like this:
you put an attribute over your action like this:
[ResourceAuthorize("View", "Customer")]
The first argument is the name of the Action to check, the second one is the name of the attribute.
Then you derive from ResourceAuthorizationManager in your code and override the CheckAccessAssync Method
public class MyAuthorization : ResourceAuthorizationManager
{
public override Task<bool> CheckAccessAsync(ResourceAuthorizationContext context)
{
var resource = context.Resource.First().Value;
var action = context.Action.First().Value;
// getting the roles that are connected to that resource and action
// from the db. Context could of course be injected into the
// constructor of the class. In my code I assume that the table
// thank links roles, resources and actions is called Roles ToActions
using(var db = MyContext())
var roles = db.RolesToActions // Use your table name here
.Where(r => r.Resource == resource && r.Action == action).ToList();
foreach(var role in roles)
{
if(context.Principal.IsInRole(role.Name)
{
return Ok();
}
}
return Nok();
}
}
}
So I hope this helps. If you prefer to implement your own attribute however, than the source code from the ResourceAuthorization GitHub Repository should be a good starting point

How to destroy session in symfony 2.6?

I tried doing this:
$session->remove();
Also this:
$session->clear();
But it gives following error:
Call to a member function clear() on a non-object
invalidate()
Clears all session data and regenerates session ID. Do not use session_destroy().
This actually does what you want.
Source & more info:
http://symfony.com/doc/current/components/http_foundation/sessions.html
Also such things are easy to check by simply review the source.
For this case you should check Session or SessionInterface source:
http://api.symfony.com/2.6/Symfony/Component/HttpFoundation/Session/SessionInterface.html
http://api.symfony.com/2.6/Symfony/Component/HttpFoundation/Session/Session.html
Edit.
Of course this method belongs to Session class so you have to access Session object first in your controller.
So we go to:
http://symfony.com/doc/current/book/controller.html#managing-the-session
and we see how to do that:
public function indexAction(Request $request)
{
$session = $request->getSession();
$session->invalidate(); //here we can now clear the session.
}

Symfony/DRY - check if user is granted in every action

I'm using this code to check if a user is granted in my Symfony application :
$securityContext = $this->container->get('security.context');
if($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED') ){
$user = $this->get('security.context')->getToken()->getUser()->getId();
} else {
return $this->render('IelCategoryBundle:Category:home.html.twig');
}
I have to ckeck this in almost every CRUD action that I'm writing (edit, delete, ...).
I feel not DRY at all (no play on words ;-)). Is there a better way to check this in many actions ?
JMSSecurityExtraBundle provides the #Secure annotation which eases checking for a certain user-role before invoking a controller/service method.
use JMS\SecurityExtraBundle\Annotation as SecurityExtra;
/** #SecurityExtra\Secure(roles="IS_AUTHENTICATED_REMEMBERED") */
public function yourAction()
{
// ...
}
Your best bet would be to rely on Kernel event listeners: http://symfony.com/doc/current/cookbook/service_container/event_listener.html.
Implement your listener as a service and then you could set $this->user to desired value if isGranted results TRUE. Later on, you could easily retrieve the value within the controller using:
$myServiceListener->getUser();
On the other hand, if check fails you could easily redirect user to your home.html.twig.

Resources