The Security component
Marie Minasyan
20.06.2013
The security component:
# app/config/security.yml
security:
firewalls:
secured_area:
pattern: ^/
anonymous: ~
http_basic:
realm: "Secured Demo Area"
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
providers:
in_memory:
memory:
users:
ryan: { password: ryanpass, roles: 'ROLE_USER' }
admin: { password: kitten, roles: 'ROLE_ADMIN' }
encoders:
Symfony\Component\Security\Core\User\User: plaintext
Each user is assigned a set of roles, each resource requires one or more roles.
If the user has the required roles, access is granted. Otherwise access is denied.
Role names begin with 'ROLE_...'
Role inheritance:
# app/config/security.yml
security:
#...
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
Authenticating is done by the firewall
=> configured using a map of all secured areas of the application
=> the map contains a request matcher and a collection of listeners
kernel.request
AuthenticationException
,
For each incoming request:
Options:
path
ip
or ips
host
methods
requires_channel
# app/config/security.yml
security:
#...
access_control:
- { path: ^/admin, roles: ROLE_USER, ip: 127.0.0.1 }
- { path: ^/admin, roles: ROLE_USER_HOST, host: symfony.com }
- { path: ^/admin, roles: ROLE_USER_METHOD, methods: [POST, PUT] }
- { path: ^/admin, roles: ROLE_USER}
- { path: ^/cart, roles: ROLE_USER, requires_channel: https}
/admin/users 127.0.0.1 example.com GET => rule #1
/admin/user 127.0.0.1 symfony.com GET => rule #1
/admin/user 168.0.0.1 symfony.com GET => rule #2
/admin/user 168.0.0.1 symfony.com POST => rule #2
/admin/user 168.0.0.1 example.com POST => rule #3
/admin/user 168.0.0.1 example.com GET => rule #4
Controllers:
/**
* @Secure(roles="ROLE_ADMIN")
**/
public function helloAction($name) { }
public function helloAction($name)
{
if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) {
throw new AccessDeniedException();
}
}
{% if is_granted('ROLE_ADMIN') %}
<a href="...">Edit</a>
{% endif %}
Users can come from anywhere - a configuration file, a database table, a web service, or anything else.
Most common : from DB using Doctrine 2
# app/config/security.yml
security
providers:
main:
entity: { class: Acme\UserBundle\Entity\User, property: username }
// src/Acme/UserBundle/Entity/User.php
namespace Acme\UserBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* @ORM\Entity
*/
class User implements UserInterface
{
/**
* @ORM\Column(type="string", length=255)
*/
protected $username;
}
Example with a web service:
# app/config/security.yml
security
providers:
users:
id: user.provider
<service id="user.provider" class="Acme\UserBundle\Entity\Manager\UserManager">
<argument type="service" id="service_container"/>
</service>
UserProviderInterface -
retrieves and refreshes users
AbstractToken
- represents the user authentication data present in the request
AbstractAuthenticationListener
- fielding requests to the firewall and calling the authentication
provider
AuthenticationProviderInterface
- verifies theToken
SecurityFactoryInterface
- ties them all togetherCreate a new provider (declared first) that chains several providers together :
# app/config/security.yml
security:
providers:
chain_provider:
chain:
providers: [in_memory, user_db]
in_memory:
memory:
users:
foo: { password: test }
user_db:
entity: { class: Acme\UserBundle\Entity\User, property: username }
# app/config/security.yml
security:
firewalls:
secured_area:
# ...
provider: user_db
http_basic:
realm: "Secured Demo Area"
provider: in_memory
form_login: ~
# app/config/security.yml
security:
# ...
encoders:
Symfony\Component\Security\Core\User\User:
algorithm: sha1
iterations: 1
encode_as_base64: false
Acme\UserBundle\Entity\User: sha512
$factory = $this->get('security.encoder_factory');
$user = new Acme\UserBundle\Entity\User();
$encoder = $factory->getEncoder($user);
$password = $encoder->encodePassword('ryanpass', $user->getSalt());
$user->setPassword($password);