I am trying to make a standard login authenticated from the database in symfony2.
I have followed the docs here:
http://symfony.com/doc/current/book/security.html
and here:
http://symfony.com/doc/current/cookbook/security/entity_provider.html
My security File:
security:
encoders:
Acme\UserBundle\Entity\User:
algorithm: sha1
encode_as_base64: false
iterations: 1
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH ]
providers:
administrators:
entity: { class: RWLoginBundle:User, property: username }
firewalls:
secured_area:
pattern: ^/
anonymous: ~
form_login: ~
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
My routing file:
login:
pattern: /
defaults: { _controller: RWLoginBundle:Default:login }
login_check:
pattern: /login_check
but when I enter the user and password I get the error:
Fatal error: Call to undefined method RW\LoginBundle\Entity\User::findOneBy() in /var/www/rw/vendor/symfony/symfony/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php on line 55
my login page has been made according to the docs with the form and there is a redirect input there which goes to a url that does exist.
Has anybody come across anything like this before?
Edit: added entity below
namespace RW\LoginBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* RW\LoginBundle\Entity\User
*
* #ORM\Table(name="users")
* #ORM\Entity(repositoryClass="RW\LoginBundle\Entity\User")
*/
class User implements UserInterface, \Serializable
Related
Authenticated: No appears in the Symfony2 dev toolbar after a successful login.
In my success handler I can access $token->getRoles() and see the role objects assigned to the user so it appears to be serializing okay.
So I'm not sure why it's not authenticating.
Here is my security.yml:
security:
encoders:
FixedApp\Model\User:
algorithm: sha1
encode_as_base64: false
iterations: 1
role_hierarchy:
ROLE_ADMIN: [ROLE_USER, ROLE_LIMITED_ADMIN]
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
administrators:
entity: { class: FixedApp\Model\User, property: username }
firewalls:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
login:
pattern: ^/$
security: false
secured_area:
pattern: ^/
form_login:
check_path: fixed_app_authentication_login
login_path: fixed_app_homepage
username_parameter: form[username]
password_parameter: form[password]
default_target_path: fixed_app_hub_homepage
always_use_default_target_path: true
success_handler: security.authentication.success_handler
logout:
path: fixed_app_authentication_logout
target: fixed_app_homepage
access_control:
- { path: ^/log-in$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /users/edit, roles: ROLE_ADMIN }
It not authenticating is a problem, because when I go to /users/edit as an admin it says Access Denied. So I need to figure out what is going on here. Any ideas would be most appreciated.
I saw a number of other people online with this same problem but I've never seen a solution put anywhere before - so hopefully this helps someone.
In UserRole.php class I was missing this function:
/**
* #see RoleInterface
*/
public function getRole()
{
return $this->role;
}
And secondly, in User.php class I made it implement EquatableInterface:
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
...
class User implements AdvancedUserInterface, EquatableInterface, \Serializable
{
...
public function isEqualTo(UserInterface $user)
{
if ($this->getId() == $user->getId())
{
return true;
}
else
{
return false;
}
}
And then it started working. The Symfony toolbar button went green, it says Authenticated: Yes and it lists all the roles for that user.
I am using the FOSUserBundle and am successfully creating users in my database. However, I'm trying to log users in and only have ROLE_ADMIN users access /admin by following the Symfony security walk-through.
However, even without having figured out logging users in, when I try to access localhost/app_dev.php/admin I am able to access it as the "Anon" user. Below are my security.yml and controller files:
app/config/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:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/admin/, role: ROLE_ADMIN }
src/AppBundle/Controller/DefaultController.php
class DefaultController extends Controller
{
/**
* #Route("/admin", name="admin")
*/
public function AdminAction(Request $request)
{
return $this->render('default/admin.html.twig', array(
'title' => 'Welcome Admin!!'
));
}
}
I'm not familiar with FOSUserBundle however your access_control entry is for the path /admin/ - note the trailing slash whereas your example localhost/app_dev.php/admin doesn't. If you remove that from your access_control entry or change your routes then this should work as expected.
E.g.
access_control:
- { path: ^/admin, role: ROLE_ADMIN }
I'm trying to restrict users from going to anything within /admin/ and if they attempt to then they will be redirected to /login.
At the moment I can get to the login page which is using a traditional login form and if I submit it I get an error returned saying 'Bad Credentials', therefore the /login_check seems to be working correctly. However, if I go to /admin/ or /admin/foo it doesn't redirect to /login. Instead it says 'No route found for GET /admin/'.
My security.yml file is:
jms_security_extra:
secure_all_services: false
expressions: true
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN:
ROLE_SUPER_ADMIN:
providers:
administrators:
entity: { class: XXXBundle:AdminUser, property: email }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin_area:
pattern: ^/admin
form_login:
login_path: /login
check_path: /admin/login_check
#anonymous: ~
#http_basic:
# realm: "Secured Demo Area"
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
My routing.yml file is:
login:
pattern: /login
defaults: { _controller: XXXBundleSecurity:login }
login_check:
pattern: /admin/login_check
/admin/XXX routes are unneccessary. If you have set
pattern: ^/admin
/admin/XXX should be redirected to /login.
more details see http://symfony.com/doc/2.0/book/security.html#using-a-traditional-login-form
It seems you're missing both routes you're trying to access. Try to add this to your routing.yml:
admin:
resource: "#XXXBundle/Controller/Admin.php"
type: annotation
prefix: /admin
I like Routes using Annotations very much so I used that in this example.
Then in your Admin.php you can use something like:
// XXXBundle/Controller/Admin.php
namespace XXXBundle/Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
class AdminController extends Controller
{
/**
* #Route("/", name="admin_index")
*/
public function indexAction(Request $request)
{
// Code goes here
}
/**
* #Route("/foo ", name="admin_foo")
*/
public function fooAction(Request $request)
{
// Code goes here
}
}
I have a project with / put behind a firewall. However, I want one of my controllers to be "insecure", e.g display its contents regardless of authentication. But whatever I do, the bundle stays secure.
My current approach is:
security.yml:
jms_security_extra:
secure_all_services: true
expressions: true
security:
encoders:
BrokernetGroup\Platea\SecurityBundle\Entity\User:
id: brokernet_group_platea_security.crypt_encoder
role_hierarchy:
providers:
db_users:
entity:
class: BrokernetGroup\Platea\SecurityBundle\Entity\User
property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login.html$
security: false
protected_area:
pattern: ^/
form_login:
check_path: /login-check.do
login_path: /login.html
logout:
path: /logout.do
target: /
access_control:
Controller skeleton:
<?php
namespace BrokernetGroup\Platea\InfoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use JMS\SecurityExtraBundle\Annotation as SE;
/**
* Description of InfoController
*
* #author Gergely Polonkai
*
* #SE\PreAuthorize("permitAll")
*/
class InfoController
{
/**
* #Route("/", name="BrokernetGroupPlateaInfo_homepage", hostnamePattern="{hostname}", requirements={"hostname" = "%www_hostnames%"})
* #Template
*/
public function homepageAction()
{
return array();
}
}
add anonymous: ~ below the protected_area: in your security.yml file for enabling anonymous token
I've written my own password encoder which implements the PasswordEncoderInterface:
class BCryptPasswordEncoder implements PasswordEncoderInterface {
protected $encoder;
public function __construct(BCryptEncoder $encoder) {
$this->encoder = $encoder;
}
public function encodePassword($raw, $salt) {
return $this->encoder->encodeString($raw, $salt);
}
public function isPasswordValid($encoded, $raw, $salt) {
return $this->encoder->encodeString($raw, $salt) == $encoded;
}
}
The encoder is registered as a service with the id bcrypt.password.encoder. But I don't know, how to tell symfony to user it.
Currently the app/config/security.yml looks like this:
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
neo4j:
id: security.user.provider.neo4j
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
secured_area:
provider: neo4j
pattern: ^/.*
form_login:
check_path: /login_check
login_path: /login
logout:
path: /logout
target: /
anonymous: ~
access_control:
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/.*, role: ROLE_ADMIN }
Btw I'm not using any doctrine entities.
Edit: Symfony\Component\Security\Core\User\User is my UserObject. I modified the security.yml a bit:
encoders:
Symfony\Component\Security\Core\User\User:
id: bcrypt.password.encoder
which results in a fatal error:
Catchable Fatal Error: Argument 1 passed to EMC3\Bundle\UserBundle\Neo4jUserProvider::__construct() must be an instance of EMC3\Bundle\UserBundle\UserManager, instance of EMC3\Bundle\UserBundle\BCryptEncoder given, called in /var/www/emc3/app/cache/dev/appDevDebugProjectContainer.php on line 227 and defined in /var/www/emc3/src/EMC3/Bundle/UserBundle/Neo4jUserProvider.php line 29
Which doesn't make any sense for me.
Starting from Symfony 2.2, BCrypt is natively supported, so you can configure it easily as such:
security:
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: bcrypt
cost: 7
You may want to adjust the cost upwards if you have a fast enough server though.
As of November 2011, before Symfony 2.2, this is not directly supported.
Instead of reinventing the wheel, I suggest you to use the Blowfish Password Encoder bundle I wrote (ElnurBlowfishPasswordEncoderBundle), which solves the same problem. Or, at least, you can see how it's implemented.
If you're using Symfony 2.2 or later, see Seldaek's answer for configuration instructions.
Your encoders section should look like this:
encoders:
Acme\UserBundle\Entity\User:
id: bcrypt.password.encoder
where Acme\UserBundle is your vendor and bundle namespace, of course.
For reference, a complete example security config can be found here.
EDIT: The way the encoder factory works (source code here, relevant lines start on line 33) is that in your config, you have given the framework a class, and an encoder to use for the class. It's Doctrine-independent, so just provide the fully-qualified class name of your user object in the config instead of a "user entity," and when your password is encoded, Symfony will know how to handle it.