love and loss: a symfony security play
DESCRIPTION
The security component tackles the complex problems of authentication and authorization by spreading concerns across a number of single responsibility objects. This is a flexible design, but difficult for beginners to navigate. This presentation will bring the security component to life for us all to understand! Join us to see some of your favorite members of the Symfony community perform the security component in a series of scenes, interspliced with some technical descriptions of what's going on.TRANSCRIPT
Love & LossA Symfony Security Play
brewcycleportland.com
@kriswallsmith
assetic
Buzz
Spork
“…the current implementation of the Security Component is … not easily accessible”
http://www.testically.org/2011/03/14/why-i-gave-up-on-the-symfony2-security-component/
“I would rather see Symfony2 postponed again or the Security Component removed …
I don’t think it is even near of being usable to the community outside the core.”
http://www.testically.org/2011/03/14/why-i-gave-up-on-the-symfony2-security-component/
“The past few days I have really be struggling with the Symfony2 security component. It is the most complex component of
Symfony2 if you ask me!”
http://blog.vandenbrand.org/2012/06/19/symfony2-authentication-provider-authenticate-against-webservice/
“(I’m) wondering if I should just work around rather than work with the framework”
https://groups.google.com/forum/#!msg/symfony2/AZpgbEk4Src/73P99zOmq2YJ
Enhance yourPHPfun!
http://curiouscomedy.org
HttpKernel
kernel.exception
kernel.request kernel.terminatekernel.controller kernel.view kernel.response
kernel.request kernel.controller kernel.view kernel.response kernel.terminate
kernel.exception
HttpKernel
kernel.request kernel.controller kernel.view kernel.response kernel.terminate
kernel.exception
HttpKernel
HttpKernelGet the response and get out
kernel.request
Routeretc…
Firewall
FirewallJust another listener
class YesFirewall{ public function handle($event) { // always say yes }}
use Symfony\Component\HttpFoundation\Response;
class NoFirewall{ public function handle($event) { // always say no $event->setResponse( new Response('go away', 401) ); }}
use Symfony\Component\HttpFoundation\Response;
class PickyFirewall{ public function handle($event) { $request = $event->getRequest(); $user = $request->headers->get('PHP_AUTH_USER');
// only names that start with "Q" if ('Q' == $user[0]) return;
$event->setResponse(new Response('go away', 401)); }}
Security ListenersThe firewall’s henchmen
Firewall
Listeners
kernel.request
class Firewall{ public $listeners = array();
public function handle($event) { foreach ($this->listeners as $listener) { $listener->handle($event);
if ($event->hasResponse()) return; } }}
class YesListener{ public function handle($event) { // always say yes }}
use Symfony\Component\HttpFoundation\Response;
class NoListener{ public function handle($event) { // always say no $event->setResponse( new Response('go away', 401) ); }}
use Symfony\Component\HttpFoundation\Response;
class PickyListener{ public function handle($event) { $request = $event->getRequest(); $user = $request->headers->get('PHP_AUTH_USER');
// only names that start with "Q" if ('Q' == $user[0]) return;
$event->setResponse(new Response('go away', 401)); }}
AuthenticationAre you who you say you are?
AuthorizationAre you allowed to ____?
TokensThe Language of Security
Authentication ListenersMap from request to token
Request
Response (?) Token
CoreHTTP
AuthenticationListener A
AuthenticationListener B
AuthenticationManager
Firewall
class AuthenticationListener{ public $authMan, $context;
public function handle($e) { $r = $e->getRequest(); $u = $r->headers->get('PHP_AUTH_USER');
$t = new AnonToken($u); $t = $this->authMan->authenticate($t);
$this->context->setToken($t); }}
class AuthenticationManager{ public function authenticate($t) { // always say no }}
class AuthenticationManager{ public function authenticate($t) { // always say yes return new AuthToken($t->getUser()); }}
class AuthenticationManager{ public function authenticate($t) { $u = $t->getUser(); // only names that start with "Q" if ('Q' == $u[0]) { return new AuthToken($u); } }}
Authentication ManagerResponsible for authenticating
the token
Authentication ProvidersDo the actual authentication work
UserProviders
AuthenticationProviders
AuthenticationListener A
AuthenticationListener B
AuthenticationManager
User ProvidersAccess the repository of users
class AuthenticationManager{ public $providers = array();
public function authenticate($t) { foreach ($this->providers as $p) { if ($p->supports($t)) { return $p->authenticate($t); } } }}
class AuthenticationProvider{ public $up;
public function authenticate($t) { $u = $t->getUser(); $u = $this->up->loadUserByUsername($u);
if ($u) return new AuthToken($u); }}
class UserProvider{ public $repo;
public function loadUserByUsername($u) { return ($this->repo->find(array( 'username' => $u, ))); }}
Authentication
Authentication Listeners
• Map client data from request to token
• Pass token to authentication manager
• Update state of security context
Authentication Manager
• Responsible for authenticating the token
• Calls the appropriate authentication provider
• Handles exceptions
Authentication Providers
• Performs authentication using client data in the token
• Marks the token as authenticated
• Attaches the user object to the token
User Providers
• Retrieves the user from the database
Authorization
class AuthorizationListener{ public function handle($e) { // always say yes }}
use Symfony\Component\HttpFoundation\Response;
class AuthorizationListener{ public function handle($e) { // always say no $e->setResponse( new Response('go away', 403) ); }}
Access MapLooks at a request and determines
token requirements
Access Decision ManagerThe gatekeeper
VotersDecisionManager
Listener Map
use Symfony\Component\HttpFoundation\Response;
class AccessListener{ public $context, $map, $decider;
public function handle($e) { $r = $e->getRequest(); $t = $this->context->getToken();
$reqs = $this->map->getRequirements($r);
if (!$this->decider->decide($t, $reqs)) { $e->setResponse( new Response('go away', 403) ); } }}
class AccessMap{ public function getRequirements($r) { $path = $r->getPathInfo(); if (0 === strpos($path, '/admin')) { return array('ADMIN'); } }}
class AccessDecisionManager{ public $voters;
public function decide($t, $reqs) { foreach ($this->voters as $v) { if ($v->vote($t, null, $reqs)) { return true; } }
return false; }}
class AccessVoter{ public function vote($t, $obj, $reqs) { foreach ($reqs as $req) { if (!$t->hasAttribute($req)) { return false; } }
return true; }}
Authorization
Extension Points
The firewall has many listeners
The authentication manager has many authentication providers
Which MAY rely onuser providers
The access decision manager has many voters
Authenticated
Roles
ACL
Questions?
is hiring
“Horrible”“Worst talk ever”
“Go back to high school”
https://joind.in/8665