We are trying to use FOSUserBundle and HWIOAuthBundle together in the way like it's described there https://gist.github.com/danvbe/4476697
The only difference is that we are using mongodb. This error is fired:
User provider "wf\UserBundle\Document\FOSUBUserProvider" must implement "Symfony\Component\Security\Core\User\UserProviderInterface"
the FOSUBUserProvider is picked from this sample (the src is below). Is not it supposed that HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider implements Symfony\Component\Security\Core\User\UserProviderInterface ?
<?php
namespace wf\UserBundle\Document;
use Symfony\Component\Security\Core\User\UserInterface;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseFOSUBUserProvider;
class FOSUBUserProvider extends BaseFOSUBUserProvider
{
/**
* {#inheritDoc}
*/
public function connect(UserInterface $user, UserResponseInterface $response)
{
$property = $this->getProperty($response);
$username = $response->getUsername();
//on connect - get the access token and the user ID
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
//we "disconnect" previously connected users
if (null !== $previousUser = $this->userManager->findUserBy(array($property => $username))) {
$previousUser->$setter_id(null);
$previousUser->$setter_token(null);
$this->userManager->updateUser($previousUser);
}
//we connect current user
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
$this->userManager->updateUser($user);
}
/**
* {#inheritdoc}
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$username = $response->getUsername();
$user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
//when the user is registrating
if (null === $user) {
$service = $response->getResourceOwner()->getName();
$setter = 'set'.ucfirst($service);
$setter_id = $setter.'Id';
$setter_token = $setter.'AccessToken';
// create new user here
$user = $this->userManager->createUser();
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
//I have set all requested data with the user's username
//modify here with relevant data
$user->setUsername($username);
$user->setEmail($username);
$user->setPassword($username);
$user->setEnabled(true);
$this->userManager->updateUser($user);
return $user;
}
//if user exists - go with the HWIOAuth way
$user = parent::loadUserByOAuthUserResponse($response);
$serviceName = $response->getResourceOwner()->getName();
$setter = 'set' . ucfirst($serviceName) . 'AccessToken';
//update access token
$user->$setter($response->getAccessToken());
return $user;
}
}
FOSUBUserProvider implements AccountConnectorInterface and OAuthAwareUserProviderInterface which are both interfaces so it not possible that they implement UserProviderInterface.
Checking docs in hwioauthbundle I found that OAuthUserProvider is the class that implements UserProviderInterface.
https://github.com/hwi/HWIOAuthBundle/blob/master/Security/Core/User/OAuthUserProvider.php
Using
providers:
fos_userbundle:
id: fos_user.user_manager
in 'security.yml' instead of (custom)
providers:
wf_hwi_provider:
id: wf_user.fos_user_provider
does it
Related
I am building a Slim Framework 4 Api Application, with Eloquent.
public/index.php
$capsule = new \Illuminate\Database\Capsule\Manager;
$capsule->addConnection($dbconfig);
$capsule->setAsGlobal();
$capsule->bootEloquent();
$app->add(new RequestUser()); // for calling middleware that adds user
Middlware
class RequestUser
{
public function __invoke(Request $request, RequestHandler $handler): Response
{
....................
$user = User::where('emailid', $email)->first();
$request = $request->withAttribute('user', $user);
$request = $request->withAttribute('token', (string) $exploded_authorization[1]);
return $handler->handle($request);
}
}
Controller
use Psr\Http\Message\ServerRequestInterface as Request;
public function create(Request $request, Response $response, $args)
{
$user = $request->getAttribute('user'); // gives me the request user information
}
Model
<?php
namespace App\Models\TableModel;
use Illuminate\Database\Eloquent\Model;
use DateTime;
use Psr\Http\Message\ServerRequestInterface as Request;
class Details extends Model
{
protected $table = 'my_table';
protected $primaryKey = 'Id';
public $timestamps = false;
protected $fillable = [];
protected $hidden = [];
protected $casts = [
];
protected $appends = ['can_edit', 'can_delete'];
public function getCanEditAttribute(){
$now = date('Y-m-d H:i:s');
return $this->Start_Date >= $now;
}
public function getCanDeleteAttribute(){
//request contains the user information from the middleware? How to access here
return
}
}
I want to access the $request in my Model so that i could get the user information, who is trying to access on CanDelete.
You got the wrong kind of middleware, it needs to be a routing middleware and binded to route or route group directly, not $app->add
How to use session for retrieving data during redirect? I am getting the error message: "exception 'Symfony\Component\Form\Exception\AlreadySubmittedException' with message 'You cannot change the data of a submitted form."
C:\Bitnami\wampstack-5.5.30-0\sym_prog\proj3_27\src\MeetingBundle\Controller\UserController.php
/**
* Creates a new User entity.
*
* #Route("/new", name="user_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$user = new User();
$form = $this->createForm(new UserType(), $user);
$form->handleRequest($request);
$session = $this->getRequest()->getSession();
$form->setData(unserialize($session->get('userFilter')));
if ( $form->isSubmitted() && $form->isValid() ) {
$session->set( 'userFilter', serialize($form->getData()) );
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_edit', array('id' => $user->getId()));
}
return $this->render('MeetingBundle::user/new.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
} // public function newAction(Request $request)
C:\Bitnami\wampstack-5.5.30-0\sym_prog\proj3_27\src\MeetingBundle\EventListener\ExceptionListener.php
<?php
namespace MeetingBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Router;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
//every time the Kernel throws the kernel.exception event, the function onKernelException() is called.
/* also must create service :
meeting.exception_listener:
class: MeetingBundle\EventListener\ExceptionListener
arguments: [#templating, #kernel, #router]
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
*/
class ExceptionListener
{
protected $templating;
protected $kernel;
protected $router;
public function __construct( EngineInterface $templating, $kernel, Router $router)
{
$this->templating = $templating;
$this->kernel = $kernel;
$this->router = $router;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
$request=$event->getRequest();
$referer = $event->getRequest()->headers->get('referer');
$msg="";
$excStr=$exception->__toString(); // returns string finally!
$bdup=strpos( $excStr , 'Integrity constraint violation: 1062 Duplicate entry' );
if($bdup) {
$msg=" This username is already taken. Choose another username. ";
}
if(strlen($msg)!=0) {
// flash messsages are displayed in layout.html
$request->getSession()
->getFlashBag()
->add('Error', $msg);
}
$response = new RedirectResponse($referer); // redirect to the error page
if ($exception instanceof HttpExceptionInterface) {
$response->setStatusCode($exception->getStatusCode());
$response->headers->replace($exception->getHeaders());
} else {
$response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
}
$event->setResponse($response);
}
}
I'm working on a API. To give User Access - for example by smartphone - I need to login users by rest.
Is there an existing module available? Actually, I'm using fosUserBundle. Maybe there is a possibility to get those two bundle work together?
The Users which will login by rest are already existing as "normal" fos users.
It would be grest if you could gomme some links, tips or hints cause I'm searching and searching and searching and for the reason that I am new in symfony it's not that easy :):)
rgrds
I use FOSUserBundle for login since a smartphone by the API.
APIBundle/Controller/UserController.php (the default route is /api)
/**
* #Post("/user/login")
* #Template(engine="serializer")
*/
public function loginAction()
{
$request = $this->get('request');
$username = $request->request->get('username');
$password = $request->request->get('password');
return $this->container->get('myproject_user.user_service')
->login($username, $password);
}
in this method, I call a personal service who manage the user's functions. (UserHandler.php)
UserBundle/Handler/UserHandler.php
class UserHandler implements UserHandlerInterface
{
private $om;
private $entityClass;
private $repository;
private $container;
private $manager;
public function __construct(ObjectManager $om, Container $container, $entityClass)
{
$this->om = $om;
$this->entityClass = $entityClass;
$this->repository = $this->om->getRepository($this->entityClass);
$this->container = $container;
$this->manager = $this->container->get('fos_user.user_manager');
}
public function login($username, $password)
{
$jsonErrorCreator = $this->container->get('myproject_api.create_error_json');
$code = 0;
// check the arguments here.
$user = $this->manager->findUserByUsername($username);
if($user === null) $user = $this->manager->findUserByEmail($username);
if($user === null)
{
$code = 224;
return ($jsonErrorCreator->createErrorJson($code, $username));
}
// check the user password
if($this->checkUserPassword($user, $password) === false)
{
$code = 225;
return ($jsonErrorCreator->createErrorJson($code, null));
}
// log the user
$this->loginUser($user);
$jsonCreator = $this->container->get('myproject_api.create_json');
$response = $jsonCreator->createJson(array('success'=>true, 'user'=>$user));
return $response;
}
protected function loginUser(User $user)
{
$security = $this->container->get('security.context');
$providerKey = $this->container->getParameter('fos_user.firewall_name');
$roles = $user->getRoles();
$token = new UsernamePasswordToken($user, null, $providerKey, $roles);
$security->setToken($token);
}
protected function checkUserPassword(User $user, $password)
{
$factory = $this->container->get('security.encoder_factory');
$encoder = $factory->getEncoder($user);
if(!$encoder)
return false;
return $encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt());
}
}
UserBundle/Handler/UserHandlerInterface.php
Interface UserHandlerInterface
{
public function login($username, $password);
}
Don't forget to declare your service !
UserBundle/Resources/config/services.yml
myproject_user.user_service:
class: %myproject_user.user_handler.class%
arguments: [ #doctrine.orm.entity_manager, #service_container, %fos_user.model.user.class%]
You can now login with your smartphone at the adresse api/user/login
I think I got the solution:
http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html
This seems pretty nice to me and paired with Guras inputit should work as well.
I have a bugs, actually it is error this is notice but still, I would like to fix it;
When I am try to access pages with null role, it is showing this messages:
Notice: Trying to get property of non-object in C:\Zend\Apache2\htdocs\hotelrwanda\application\plugin\AccessCheck.php on line 18
How can get it fixed here is my script:
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$resource = $request->getControllerName();
$action = $request->getActionName();
$identity = $this->_auth->getStorage()->read();
$role = $identity->role;
if(!$this->_acl->isAllowed($role, $resource, $action)){
$request->setControllerName('users')
->setActionName('login');
}
}
Line: 18 is this line :$role = $identity->role;
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$resource = $request->getControllerName();
$action = $request->getActionName();
$role = 'guest'; //your default role
if(Zend_Auth::getInstance()->hasIdentity())
{
$role = Zend_Auth::getInstance()->getIdentity()->role;
}
if(!$this->_acl->isAllowed($role, $resource, $action)){
$request->setControllerName('users')
->setActionName('login');
}
}
Here 'guest' is acting as default role . You can name it anything you like but make sure to add this role in your acl and give permission to this role accordingly .
I have a Federico_Plugin_Acl that extends Zend_Controller_Plugin_Abstract which looks like this:
class Federico_Plugin_Acl extends Zend_Controller_Plugin_Abstract {
private $_acl = null;
private $_auth = null;
const DEFAULT_ROLE = 'guest';
public function __construct($auth) {
$this->_auth = $auth;
$this->_acl = new Zend_Acl();
$this->_acl->addRole(new Zend_Acl_Role(self::DEFAULT_ROLE));
$this->_acl->addRole(new Zend_Acl_Role('user'), self::DEFAULT_ROLE);
$this->_acl->addRole(new Zend_Acl_Role('admin'), 'user');
$this->_acl->addResource(new Zend_Acl_Resource('index'));
$this->_acl->addResource(new Zend_Acl_Resource('users'));
$this->_acl->addResource(new Zend_Acl_Resource('about'));
$this->_acl->addResource(new Zend_Acl_Resource('gisele'));
$this->_acl->addResource(new Zend_Acl_Resource('admin'));
$this->_acl->allow('guest', 'index');
$this->_acl->allow('guest', 'about');
$this->_acl->deny('guest', 'gisele');
$this->_acl->deny('guest', 'users');
$this->_acl->allow('user', 'users', array('index'));
$this->_acl->allow('admin', 'users');
$this->_acl->allow('admin', 'gisele');
}
public function preDispatch(Zend_Controller_Request_Abstract $request) {
if ($this->_auth->hasIdentity()) {
$role = $this->_auth->getStorage()->read()->role;
} else {
$role = self::DEFAULT_ROLE;
}
$action = $request->getActionName();
$controller = $request->getControllerName();
if ($this->_acl->has($controller)) {
if (!$this->_acl->isAllowed($role, $controller, $action)) {
$request->setActionName('login');
$request->setControllerName('index');
}
}
}
}
And this method is in my bootstrap to make use of this class:
protected function _initNavigation()
{
$this->_auth = Zend_Auth::getInstance();
$this->_acl = new Federico_Plugin_Acl($this->_auth);
$this->bootstrap('view');
$view = $this->getResource('view');
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml','nav');
$navigation = new Zend_Navigation($config);
$roleAuth = $this->_auth->getIdentity();
if(null == $roleAuth)
$role = 'guest';
else
$role = $roleAuth->role;
$view->navigation($navigation)->setAcl($this->_acl)->setRole($role);
}
With these configurations set like that, I get the following error:
Catchable fatal error: Argument 1 passed to Zend_View_Helper_Navigation_HelperAbstract::setAcl() must be an instance of Zend_Acl, instance of Federico_Plugin_Acl given, called in /home/fiodorovich/public_html/gisele/application/Bootstrap.php on line 118 and defined in /home/fiodorovich/library/ZendFramework/library/Zend/View/Helper/Navigation/HelperAbstract.php on line 333
Call Stack
Which is to be expected since Federico_Plugin_Acl is an instance of Zend_Controller_Plugin_Abstract...Still, if I extend Zend_Acl instead I get this error:
Fatal error: Zend_Acl_Role_Registry_Exception: Role 'guest' not found in /home/fiodorovich/library/ZendFramework/library/Zend/View/Helper/Navigation/HelperAbstract.php on line 522
So...I've been trying for a while to get this thing solved,... but don't seem to get this to work properly...Any ideas on what I'm missing here?
Zend_Controller_Plugin_Abstract and Zend_Acl are completelly different things. What you want to do is get the ACL object out of your plugin (which is now in private section) and pass it over to
$view->navigation($navigation)->setAcl(<here>);