Symfony2 Circular reference in my routing.dev.yml - php

I am trying to build a login and registration forms and processes in my project, but I am getting the circular reference error for some reason. The registration works fine. The problem is when I am building a login form. I am using the tutorial from here:
http://symfony.com/doc/current/cookbook/security/form_login_setup.html.
When I add this the project still works:
firewalls:
default:
anonymous: ~
http_basic: ~
form_login:
login_path: /login_user
check_path: /login_check
But when I make the routes in the controller I get the error:
<?php
// src/AppBundle/Controller/SecurityController.php
// ...
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
class SecurityController extends Controller
{
/**
* #Route("/login_user", name="login_route")
*/
public function loginAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render(
'Frontend/navbar.html.twig',
array(
// last username entered by the user
'last_username' => $lastUsername,
'error' => $error,
)
);
}
/**
* #Route("/login_check", name="login_check")
*/
public function loginCheckAction()
{
// this controller will not be executed,
// as the route is handled by the Security system
}
}
This is my routing.dev.yml:
_wdt:
resource: "#WebProfilerBundle/Resources/config/routing/wdt.xml"
prefix: /_wdt
_profiler:
resource: "#WebProfilerBundle/Resources/config/routing/profiler.xml"
prefix: /_profiler
_configurator:
resource: "#SensioDistributionBundle/Resources/config/routing/webconfigurator.xml"
prefix: /_configurator
_errors:
resource: "#TwigBundle/Resources/config/routing/errors.xml"
prefix: /_error
_main:
resource: routing.yml
What can be the problem here?

Related

User doesn't logout properly in Symfony2

I'm trying to logout an user (session) when the Logout link is clicked. It seems to work when I pressed the Logout, but if I change the path, the user still alive and I don't know why.
Here's my Controller:
/**
* #Route("/logout", name="logout")
*/
public function logoutAction(Request $request)
{
$helper = $this->get('security.authentication_utils');
$this->container->get('security.token_storage')->setToken(null);
$this->get('session')->set('id', null);
$request->getSession()->invalidate();
$this->get('security.token_storage')->setToken(null);
return $this->render(
'login.html.twig',
array(
'last_username' => null,
'error' => null,
)
);
}
Here's my security.yml:
security:
# ...
main:
anonymous: ~
guard:
authenticators:
- app.form_login_authenticator
logout:
path: logout
target: logout
invalidate_session: true
Here's the routing.yml:
app:
resource: '#AppBundle/Controller/'
logout:
path: /logout
Remove the logoutAction and check if it works. This action is provided by Symfony itself. You should only set logout path in security.yml what you did.

Symfony 3 FOSUserBundle redirect to login after submiting edit profile

Here is my problem, im working with FOSUserBundle and Symfony 3, i've created a UserBundle that inherits FOSUserBundle so i can override some of it's parts when needed, for project's needs i've created two firewalls, one for the backend and the second for the frontend part, everything worked fine until i tried to edit the current logged user's profile(username and email), when i use var_dump($this->getUser()) while loading the editing form i get all of the current user's data but after submiting i get var_dump($this->getUser()) = null and get redirected to login form.
This is the security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
admin:
pattern: /admin(.*)
form_login:
provider: fos_userbundle
login_path: /admin/login
check_path: /admin/login_check
csrf_token_generator: security.csrf.token_manager
default_target_path: /admin/
always_use_default_target_path: true
logout:
path: /admin/logout
target: /admin/login
anonymous: true
main:
pattern: ^/
form_login:
provider: fos_userbundle
login_path: /login
check_path: /login_check
csrf_token_generator: security.csrf.token_manager
default_target_path: /
always_use_default_target_path: true
# if you are using Symfony < 2.8, use the following config instead:
# csrf_provider: form.csrf_provider
logout:
path: /logout
target: /login
anonymous: true
access_control:
- { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login_check$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
The routes for the admin(backend) part in routing.yml:
admin_login:
path: /admin/login
defaults: { _controller: FOSUserBundle:Security:login }
admin_check:
path: /admin/login_check
defaults: { _controller: FOSUserBundle:Security:check }
admin_logout:
path: /admin/logout
defaults: { _controller: FOSUserBundle:Security:logout }
admin_profile_show:
path: /admin/profile/show
defaults: { _controller: FOSUserBundle:Profile:show }
admin_profile_edit:
path: /admin/profile/edit
defaults: { _controller: FOSUserBundle:Profile:edit }
admin_profile_change_password:
path: /admin/profile/changePassword
defaults: { _controller: FOSUserBundle:ChangePassword:changePassword }
And this is the editAction in my ProfileController.php that can be accessed via the route admin_profile_edit in the routing file above, that action overrides the one in FOSUserBundle
// UserBundle/Controller/ProfileController.php
public function editAction(Request $request)
{
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
/** #var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
$dispatcher = $this->get('event_dispatcher');
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_INITIALIZE, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
/** #var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->get('fos_user.profile.form.factory');
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_profile_show');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::PROFILE_EDIT_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
$requestAttributes = $this->container->get('request_stack')->getCurrentrequest()->attributes;
if ($requestAttributes->get('_route') == 'admin_profile_edit') {
$template = sprintf('UserBundle:Profile:user_admin_edit.html.twig');
} else {
$template = sprintf('FOSUserBundle:Profile:edit.html.twig');
}
return $this->render($template, array(
'form' => $form->createView()
));
}
Now when loading the editing form everything works fine and the current user data show perfectly if i use var_dump($this->getUser()), but after submiting the form the same var_dump is null and im redirected to the login form.
I don't know if im missing somthing or doing it wrong, because i've already did the same thing with another project in Symfony 2.8 and it worked perfectly without any problems.
I hope that i've provided the max informations for my problem.
Thank you for your help.
Extend base Action(login), and add custom logic with redirect;
See Link:
This redirects using a 301 return code to the client:
$this->redirect(
$this->generateUrl(
'person_in_need_view',
array('id' => $id)
)
);
This redirects internally:
$this->forward(
'person_in_need_view',
array('id' => $id)
)
The solution is to change the form action from fos_user_profile_edit to admin_profile_edit, the route that loaded the edit form was admin_profile_edit for the backend users, but i've forgot to change it in my form action that's why after submitting the user wasn't reconized anymore because it was redirected to the fos_user_profile_edit editAction that is supposed to work in the frontend part.

No property defined for entity for resource owner

So i'm trying to use the HWI-OAuthBundle and FoS-UserBundle in order to enable users to connect from our schools credentials. So I applied what was said in the docs and configured the custom resource owner.
When i try to login, i'm correctly redirected to the schools OAuth service where i login & authorize the client to access my profile but then i have this error message :
No property defined for entity for resource owner 'myecp'.
I tried several solutions I found on internet, none of them works for me.
Here is my code :
config.yml
#HWIOAuthBundle
hwi_oauth:
connect:
account_connector: my.myecp.user_provider
firewall_names: [secured_area]
fosub:
username_iterations: 30
properties:
myecp: myecp_id
resource_owners:
myecp:
type: oauth2
client_id: "%myecp_client_id%"
client_secret: "%myecp_secret%"
access_token_url: https://my.ecp.fr/oauth/v2/token
authorization_url: https://my.ecp.fr/oauth/v2/auth
infos_url: https://my.ecp.fr/api/v1/members/me
user_response_class: HWI\Bundle\OAuthBundle\OAuth\Response\PathUserResponse
paths:
identifier: id
nickname: login
realname: [first_name, last_name]
mail: mail
options:
csrf: true
#FOSUserBundle
fos_user:
db_driver: orm
firewall_name: main
user_class: AppBundle\Entity\Personnes
from_email:
address: "%mailer_user%"
sender_name: "%mailer_user%"
#Services
services:
my.myecp.user_provider:
class: AppBundle\Security\Core\User\FOSUBPersonnesProvider
arguments: ['#fos_user.user_manager', { myecp: myecp_id }]
security.yml :
# To get started with security, check out the documentation:
# http://symfony.com/doc/current/security.html
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
# http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers:
fos_userbundle:
id: fos_user.user_provider.username
# in_memory:
# memory: ~
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
anonymous: ~
oauth:
resource_owners:
myecp: "/login/check"
login_path: /login
use_forward: false
failure_path: /login
oauth_user_provider:
service: my.oauth_aware.user_provider.service
main:
# anonymous: ~
# activate different ways to authenticate
# http_basic: ~
# http://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
# form_login: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
services.yml:
services:
# service_name:
# class: AppBundle\Directory\ClassName
# arguments: ["#another_service_name", "plain_value", "%parameter_name%"]
my.oauth_aware.user_provider.service:
class: HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider
arguments:
- '#fos_user.user_manager'
- ['pass properties as array']
routing.yml:
app:
resource: "#AppBundle/Controller/"
type: annotation
hwi_oauth_redirect:
resource: "#HWIOAuthBundle/Resources/config/routing/redirect.xml"
prefix: /connect
hwi_oauth_connect:
resource: "#HWIOAuthBundle/Resources/config/routing/connect.xml"
prefix: /connect
hwi_oauth_login:
resource: "#HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /login
fos_user:
resource: "#FOSUserBundle/Resources/config/routing/all.xml"
myecp_login:
path: /login/check
logout:
path: /logout
FOSUBPersonnesProvider.php
class FOSUBPersonnesProvider extends BaseFOSUBProvider
{
/**
* {#inheritDoc}
*/
public function connect(UserInterface $user, UserResponseInterface $response)
{
// get property from provider configuration by provider name
// , it will return `myecp_id` in that case (see service definition below)
$property = $this->getProperty($response);
$username = $response->getUsername(); // get the unique user identifier
//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
$existingUser = $this->userManager->findUserBy(array($property => $username));
if (null !== $existingUser) {
$existingUser->$setter_id(null);
$existingUser->$setter_token(null);
$this->userManager->updateUser($existingUser);
}
$user->$setter_id($username);
$user->$setter_token($response->getAccessToken());
$this->userManager->updateUser($user);
}
/**
* {#inheritdoc}
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$userId = $response->getUsername();
$user = $this->userManager->findUserBy(array('myecpId' => $userId));
// if null just create new user and set it properties
if (null === $user) {
$first_name = $response->getFirstName();
$last_name = $response->getLastName();
$email = $response->getEmail();
$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->setPrenom($first_name);
$user->setNom($last_name);
$user->setMail($email);
$user->$setter_id($userId);
$user->$setter_token($response->getAccessToken());
$this->userManager->updateUser($user);
return $user;
}
// else update access token of existing user
$user = parent::loadUserByOAuthUserResponse($response);
$serviceName = $response->getResourceOwner()->getName();
$setter = 'set' . ucfirst($serviceName) . 'AccessToken';
$user->$setter($response->getAccessToken());//update access token
return $user;
}
}
Thanks for your help !
First change in file services.yml line where You pass argument for user.provider.
For example change last line, below is my working example for google.
my.custom.user_provider:
class: YOURBUNDLENAME\Security\Core\MyFOSUBUserProvider
arguments:
- '#fos_user.user_manager'
- arguments: **[ #fos_user.user_manager, { google: googleID }** ]
Next change $property to name of User entity property name ( myecp ?? ) . In my exmaple its googleID. $property is in FOSUBPersonnesProvider.php below connect() method.
My User.php entity looks like:
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="google_id", type="string", nullable=true)
*/
private $googleID;
I hope this will help you
I solved this problem.
Because here passing arguments as array:
arguments: ['#fos_user.user_manager', { myecp: myecp_id }] //In Service
Change to :
arguments: ['#fos_user.user_manager', myecp: myecp_id ]
When send second parameter in FOSUserProvider merging array HERE
Then ERROR message showing HERE
protected function getProperty(UserResponseInterface $response)
{
$resourceOwnerName = $response->getResourceOwner()->getName();
if (!isset($this->properties[$resourceOwnerName])) {
throw new \RuntimeException(sprintf("No property defined for entity for resource owner '%s'.", $resourceOwnerName));
}
return $this->properties[$resourceOwnerName];
}
If you are using Facebook:
arguments: ['#fos_user.user_manager', facebook: facebook ]
If you are using amazon:
arguments: ['#fos_user.user_manager', amazon: amazon ]
If you are using Odnoklassniki:
arguments: ['#fos_user.user_manager', odnoklassniki: odnoklassniki ]
If you are using github:
arguments: ['#fos_user.user_manager', github: github ]
If you are using google:
arguments: ['#fos_user.user_manager', google: google ]

Symfony2 SecurityController error

I'm new in symfony and I'm following the login form tutorial(https://symfony.com/doc/2.8/cookbook/security/form_login_setup.html) but I get the following error:
Uncaught PHP Exception LogicException: "The controller must return a response (null given). Did you forget to add a return statement somewhere in your controller?" at /var/www/html/app/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php line 157
Context: { "exception": "Object(LogicException)" }
I use the same SecurityController:
class SecurityController extends Controller{
* #Route("/admin", name="login")
public function loginAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render(
'security/login.html.twig',
array(
// last username entered by the user
'last_username' => $lastUsername,
'error' => $error,
)
);
}
/**
* #Route("/login_check", name="login_check")
*/
public function loginCheckAction()
{
// this controller will not be executed,
// as the route is handled by the Security system
}
security.yml
# To get started with security, check out the documentation:
http://symfony.com/doc/current/book/security.html
security:
# http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
providers:
app_users:
ldap:
service: app.ldap
base_dn: DC=corp, DC=int
search_dn: null
search_password: null
filter: (uid={username})
default_roles: ROLE_USER
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
# activate different ways to authenticate
# http_basic: ~
# http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate
# form_login: ~
# http://symfony.com/doc/current/cookbook/security/form_login_setup.html
secure:
provider: app_users
form_login_ldap:
service: app.ldap
dn_string: "uid={username},ou=Users,dc=corp,dc=int"
check_path: login_check
login_path: admin
logout: true
In your security.yml, try to replace
check_path: login_check
by
check_path: /login_check
And make your method like this :
/**
* #Route("/login_check", name="login_check")
*/
public function loginCheckAction()
{
throw new \RuntimeException('You must configure the check path to be handled by the firewall using form_login in your security firewall configuration.');
}

symfony2 No redirect on restricted areas

I have my security file configured as follows:
security:
...
pattern: ^/[members|admin]
form_login:
check_path: /members/auth
login_path: /public/login
failure_forward: false
failure_path: null
logout:
path: /public/logout
target: /
Currently if I access the members url without authenticating it redirects me to /public/login but I dont want it to redirect. I'm mainly responding with json on my controllers so I just want to show a warning on the restricted url such as {"error": "Access denied"}. If I take out the login_path: /public/login code it redirects to a default url /login. How do I do to stop it from redirecting?
You need to create a Listener and then trigger your response. My solution is based on - https://gist.github.com/xanf/1015146
Listener Code --
namespace Your\NameSpace\Bundle\Listener;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
class AjaxAuthenticationListener
{
/**
* Handles security related exceptions.
*
* #param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance
*/
public function onCoreException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
$request = $event->getRequest();
if ($request->isXmlHttpRequest()) {
if ($exception instanceof AuthenticationException || $exception instanceof AccessDeniedException || $exception instanceof AuthenticationCredentialsNotFoundException) {
$responseData = array('status' => 401, 'msg' => 'User Not Authenticated');
$response = new JsonResponse();
$response->setData($responseData);
$response->setStatusCode($responseData['status']);
$event->setResponse($response);
}
}
}
}
You need to create a service for the listener --
e_ent_int_baems.ajaxauthlistener:
class: Your\NameSpace\Bundle\Listener\AjaxAuthenticationListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onCoreException, priority: 1000 }
You can do like I did:
in security.yml
firewalls:
administrators:
pattern: ^/
form_login:
check_path: _security_check
login_path: _security_login
logout: true
security: true
anonymous: true
access_denied_url: access_denied
in routing.yml
access_denied:
path: /error403
defaults :
_controller: FrameworkBundle:Template:template
template: 'DpUserBundle:Static:error403.html.twig'
simply add to firewall section *access_denied_url* param
See this page for the full security.yml configuration reference. Also, this is an even better reference with explanations of each key.
I'd suggest creating your own listener class to handle returning JSON when a User needs to login. Example: https://gist.github.com/1015146

Categories