instant acls with zend framework 2
DESCRIPTION
Slides of my Zend Framework Day 2014 presentation in Turin (Italy) about ZF2 authentication and authorization.TRANSCRIPT
Zend Framework Day – Turin, Italy – 07/02/2014
Instant ACLswith Zend Framework 2
@stefanovalle
http://www.mvlabs.it/
http://friuli.grusp.org/
5
AUTHENTICATION AUTHORIZATION
Two step process
Two step process
WHO
WHAT
Two step process
WHO
WHAT
Authentication
Definitions from http://www.techopedia.com
“a process that ensures and confirmsa user’s identity”
Two step process
WHO
WHAT
Authentication
Definitions from http://www.techopedia.com
“a process that ensures and confirmsa user’s identity”
Authorization“a security mechanism used to determine user/client privileges or access levels
related to system resources”
11
In ZF2
WHO Zend/Authentication
In ZF2
WHO Zend/Authentication
Authenticate against:• DB table• LDAP• HTTP• And more…
In ZF2
WHAT Zend/Permissions/AclZend/Permissions/Rbac
In ZF2
WHAT Zend/Permissions/AclZend/Permissions/Rbac
Identity
Role Permission
Resource
SEEMS TOUGH…
JUST AS IT SHOULD!
CONSEQUENCES COULD BE UNDERESTIMATED
How does ZF2 help?
19
‘NUFF TALK. TIME FOR ACTION…
1ST NEEDWe need to add/editconferences through
a restricted area
THE ADMINISTRATOR
NEEDS TO BE RECOGNIZED
THE ADMINISTRATOR
NEEDS TO BE RECOGNIZEDNEEDS TO BE IDENTIFIED
HEAD TO OFFICIAL MODULES’ WEBSITE
OH, LOOK WHAT WE JUST GOT!
Installing and enabling ZfcUser
28
// composer.json
"require": {"zf-commons/zfc-user-doctrine-orm": "0.1.*"
}
Installing and enabling ZfcUser
29
// composer.json
"require": {"zf-commons/zfc-user-doctrine-orm": "0.1.*"
}
let’s suppose we use the Doctrine ORM
Installing and enabling ZfcUser
30
// composer.json
"require": {"zf-commons/zfc-user-doctrine-orm": "0.1.*"
}
// config/application.config.php
<?phpreturn array(
'modules' => array(// ...'ZfcBase','ZfcUser','ZfcUserDoctrineORM',
),);
Back to our user…
31
How shall we represent him?
class Systemuser {
private $id;
private $name;
private $city;
private $birthday;
private $username;
private $password;
}
We need a class
class Systemuser {
private $id;
private $name;
private $city;
private $birthday;
private $username;
private $password;
}
With some mandatory fields
class Systemuserimplements\ZfcUser\Entity\UserInterface {
private $id;
private $name;
private $city;
private $birthday;
private $username;
private $password;
}
Implementing an interface
Let’s configure ZfcUser
36
// config/autoload/zfcuser.global.php
/** ZfcUser Configuration */
$settings = array(
/** User Model Entity Class */'user_entity_class' => 'Application\Entity\Systemuser',
/** Start configuration for ZfcUserDoctrineORM */'enable_default_entities' => false,
);
Yay, here’s our working login form!
37
Yay, here’s our working login form!
38
Available at:http://myaddress/user/login
Yay, it works!
39
ZfcUser also allows to:• Customize login form• Customize User entity fields• Quickly implement a registration form• Interact with either Zend/DB or Doctrine
out of the box• Do much more stuff…
40
ZfcUser also allows to:• Customize login form• Customize User entity fields• Quickly implement a registration form• Interact with either Zend/DB or Doctrine
out of the box• Do much more stuff…
41
Remember the two steps?
WHO
WHAT
Remember the two steps?
WHO
WHAT
We need an admin panel!
44
We need an admin panel!
45
Welcome ZfcAdmin!provides a ready to use /admin route
hubme.in has an admin panel!
hubme.in has an admin panel!
Are we done yet?
48
What ifa malicious user…
What ifa malicious user…
What ifa malicious user…
…hits this url:http://myawesomewebsite/admin/conferences
What ifa malicious user…
…hits this url:http://myawesomewebsite/admin/conferences
accessible to everyone!
What ifa malicious user…
…hits this url:http://myawesomewebsite/admin/conferences
nothing’s protectingour private area
What ifa malicious user…
…hits this url:http://myawesomewebsite/admin/conferences
nothing’s protectingour private area
Login form could be bypassed!
No worries!
55
/** On each action*/
<?php
public function indexAction() {
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('home');
}
}
No worries!
56
/** On each action*/
<?php
public function indexAction() {
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('home');
}
} in EACH actionof EACH controller
WHAAAT?
IN EACH ACTION???
SOMEONE HELP US!
ZEND\PERMISSIONS\ACL
Remember? There were two steps…
WHO
WHAT
Using Zend/Permissions/Acl
62
<?php
use Zend\Permissions\Acl\Acl; use Zend\Permissions\Acl\Role\GenericRole as Role; use Zend\Permissions\Acl\Resource\GenericResource as Resource;
$acl = new Acl();
$acl->addRole(new Role('guest'))->addRole(new Role('admin'));
$acl->addResource(new Resource('someResource')); $acl->addResource(new Resource('adminarea')); $acl->addResource(new Resource('adminconferencearea')); $acl->addResource(new Resource('adminsettingsarea'));
$acl->allow('guest', 'someResource'); $acl->allow('admin', 'adminarea');$acl->allow('admin', 'adminconferencearea ');$acl->allow('admin', 'adminsettingsarea ');
Welcome BjyAuthorize!
63
… a facade for Zend\Permissions\Acl
that will ease its usage with modules
and applications …
From https://github.com/bjyoungblood/BjyAuthorize
Welcome BjyAuthorize!
64
… a facade for Zend\Permissions\Acl
that will ease its usage with modules
and applications …
From https://github.com/bjyoungblood/BjyAuthorize
OUR EASIER WAY
How does it work?
66
Standard Zend\Mvc app workflow
67
From https://github.com/bjyoungblood/BjyAuthorize
With BjyAuthorize enabled
68
From https://github.com/bjyoungblood/BjyAuthorize
With BjyAuthorize enabled
69
From https://github.com/bjyoungblood/BjyAuthorize
With BjyAuthorize enabled
70
From https://github.com/bjyoungblood/BjyAuthorize
With BjyAuthorize enabled
71
From https://github.com/bjyoungblood/BjyAuthorize
+ control over resources
Installing and enabling BjyAuthorize
72
// composer.json
"require": {"bjyoungblood/bjy-authorize": "1.4.*"
}
// config/application.config.php
<?phpreturn array(
'modules' => array(// ...'BjyAuthorize',
),);
Configuring BjyAuthorize
73
// config/autoload/bjyauthorize.global
return array(
'bjyauthorize' => array(
'default_role' => 'guest',
'identity_provider' =>'BjyAuthorize\Provider\Identity\AuthenticationIdentityProvider',
'role_providers' => array('BjyAuthorize\Provider\Role\Config' => array( 'guest' => array(), 'admin' => array(), ),
),
), );
Configuring BjyAuthorize
74
// config/autoload/bjyauthorize.global
return array(
'bjyauthorize' => array(
'default_role' => 'guest',
'identity_provider' =>'BjyAuthorize\Provider\Identity\AuthenticationIdentityProvider',
'role_providers' => array('BjyAuthorize\Provider\Role\Config' => array( 'guest' => array(), 'admin' => array(), ),
),
), );
A new concept: the Role
Guards on routes
75
Allowed to all users
http://myawesomewebsite/
Guards on routeshttp://myawesomewebsite/
76
Allowed to all users
http://myawesomewebsite/admin/...
Restricted area! For admins only
Guards on controller actions
77
class ConferencesController {
public function listAction() {
// code...
}
public function manageAction() {
// code...
}
}
Guards on controller actions
78
Allowed to all users
class ConferencesController {
public function listAction() {
// code...
}
public function manageAction() {
// code...
}
}
Guards on controller actions
79
Allowed to all users
class ConferencesController {
public function listAction() {
// code...
}
public function manageAction() {
// code...
}
}Restricted area! For admins only
Guards on controller actions
80
array(
'controller' => 'ZfcAdmin\Controller\AdminController','roles' => array('admin')
)
81
Where shouldguards be placed?
Inside each module configuration
82
// module/Conferences/config/module.config.php
return array(
'bjyauthorize' => array(
'guards' => array(
'BjyAuthorize\Guard\Controller' => array(
//...
),
), ),
Inside each module configuration
83
// module/Conferences/config/module.config.php
return array(
'bjyauthorize' => array(
'guards' => array(
'BjyAuthorize\Guard\Controller' => array(
//...
),
), ),
Taking advantage of ZF2 configuration merge
It works!
It works!
User could be redirectedto whatever url we want
Dude, forgot to tellya! …we got 2
fellas!
2ND NEED
Two different roles
87
The reader
Two different roles
88
The reader
Two different roles
89
The reader The editor
Two different roles
90
The reader The editor
Can only viewconference info
Can viewconferences +
create, edit and delete info
What we want
Only editor shouldsee these icons
Until now…
93
'bjyauthorize' => array(
// ...
'role_providers' => array('BjyAuthorize\Provider\Role\Config' => array( 'guest' => array(), 'admin' => array(),
), ),
)
Static role list
94
'bjyauthorize' => array(
// ...
'role_providers' => array('BjyAuthorize\Provider\Role\Config' => array( 'guest' => array(), 'admin' => array(),
), ),
)
More flexibility wouldn’t hurt…
Until now…
BjyAuthorize config changes
95
// config/autoload/bjyauthorize.global
return array(
'bjyauthorize' => array(
'role_providers' => array(
'BjyAuthorize\Provider\Role\ObjectRepositoryProvider' => array(
'role_entity_class' => 'Application\Entity\Role','object_manager' => 'doctrine.entity_manager.orm_default', ),
),
), );
From array to class (persisted on db)
Let’s map the actions
New concept: the Resource
something
somethingupon which
someone
somethingupon which
someonecould perform
an action
ENTITY
IDENTITY / ROLE
PRIVILEGE
On BjyAuthorize…
102
'resource_providers' => array('BjyAuthorize\Provider\Resource\Config' => array( 'Conference' => array(),
), ),
'rule_providers' => array('BjyAuthorize\Provider\Rule\Config' => array( 'allow' => array(
// allow editors to edit conferencesarray(array('editor'), 'Conference', array('edit')),
), ),
On views…
103
//Conferences/view/…/index.phtml
<?php if ($this->isAllowed($event, 'edit')) { ?>
<a href="someurl">Remove</a><br /><a href="someurl">Edit</a>
<?php } ?>
Views, routes and controllers are safe
104
Views, routes and controllers are safe
Is this enough?
105
Another controller, another action
106
//Conferences/Controller/AnotherAdminController.php
class AnotherAdminController extends AbstractActionController {
public function someCrazyAction() {
//...
$this->conferenceService->updateConference($myConference);
}
}
What prevents this?
Choose your protection level
107
ROUT
E
CONT
ROLL
ER
SERV
ICE
Conference service
108
//Conferences/Service/ConferenceService.php
namespace Conferences\Service;
class ConferenceService {
public function getConference($id) { ... }
public function getConferenceList($someCriteria) { ... }
public function updateConference($myConf) { ... }
public function deleteConference($myConf) { ... }
}
Conference service
109
//Conferences/Service/ConferenceService.php
namespace Conferences\Service;
class ConferenceService {
public function getConference($id) { ... }
public function getConferenceList($someCriteria) { ... }
public function updateConference($myConf) { ... }
public function deleteConference($myConf) { ... }
}
Only to allowed users!
Let’s inject the Authorize class
110
//Conferences/Service/ConferenceServiceFactory.php
namespace Conferences\Service;
class ConferenceServiceFactory implements FactoryInterface {
public function createService(ServiceLocatorInterface $serviceLocator){
//...
$authorize = $serviceLocator->get('BjyAuthorize\Service\Authorize');
return new ConferenceService(..., $authorize);
}
}
Updated conference service
111
//Conferences/Service/ConferenceService.php
namespace Conferences\Service;
class ConferenceService {
//...
public function updateConference($myConf) {
if (!$this->authorize->isAllowed($myConf, 'edit')) {
throw new UnAuthorizedException();
}
// other code...
} // the same for deleteConference method }
Now our service is secured
112
ROUT
E
CONT
ROLL
ER
SERV
ICE
3RD NEEDWe’ll outsource the management of
foreign conferences
Based on their country
How database changes
116
class Systemuser {
//...
private $country;
}
class Conference {
//...
private $country;
}
Create an Assertion
117
use Zend\Permissions\Acl\Assertion\AssertionInterface;
class CheckUserCountry implements AssertionInterface {
// ...
public function assert(Acl $acl, RoleInterface $role = null,ResourceInterface $resource = null,$privilege = null) {
// ...
}
}
Create an Assertion
118
use Zend\Permissions\Acl\Assertion\AssertionInterface;
class CheckUserCountry implements AssertionInterface {
// ...
public function assert(Acl $acl, RoleInterface $role = null,ResourceInterface $resource = null,$privilege = null) {
return $resource->getCountry() ==$this->loggedUser->getCountry();
}
}
Create an Assertion
119
use Zend\Permissions\Acl\Assertion\AssertionInterface;
class CheckUserCountry implements AssertionInterface {
// ...
public function assert(Acl $acl, RoleInterface $role = null,ResourceInterface $resource = null,$privilege = null) {
return $resource->getCountry() == $this->loggedUser->getCountry();
}
}
Injected through constructor
Create an Assertion
120
use Zend\Permissions\Acl\Assertion\AssertionInterface;
class CheckUserCountry implements AssertionInterface {
// ...
public function assert(Acl $acl, RoleInterface $role = null,ResourceInterface $resource = null,$privilege = null) {
return $resource->getCountry() ==$this->loggedUser->getCountry();
}
}
1 LoC… AWESOME!!
Update rule with the new assertion
121
'rule_providers' => array('BjyAuthorize\Provider\Rule\Config' => array( 'allow' => array(
// role check through assertionarray(array('editor'),
'Conference', array('edit'),'assertion.CheckUserCountry'),
), ),
122
The reader
123
The reader
The editor
In the same way we could:• Restrict access to user owned
onferences only• or conferences owned by a group the
user is belonging to• …and much more!
124
4TH NEEDCool. How'bout the admin menu
though?
Navigation menu
126
Configure Zend/Navigation
127
// module/Conferences/config/module.config.php
return array(
'navigation' => array('admin' => array(
'conferences' => array('label' => 'Conferences','route' => 'zfcadmin/conferences','resource' => 'Conference','privilege' => 'view',
),),
),
), );
Configure Zend/Navigation
128
// module/Settings/config/module.config.php
return array(
'navigation' => array('admin' => array(
'settings' => array('label' => 'Settings','route' => 'zfcadmin/settings','resource' => 'Setting','privilege' => 'view',
),),
),
), );
How menu looks like for admins
How menu looks like for other users
FINAL NOTES
PLUGGABLE COMPONENTS
PLUGGABLE COMPONENTS
CLEAN ARCHITECTURE
PLUGGABLE COMPONENTS
CLEAN ARCHITECTURE
COMPLEX ACL LOGIC IN A FEW MINUTES
Stefano [email protected]@mvassociati.it
Thank you for your attention!
Stefano [email protected]@mvassociati.it
Questions?
Photo CreditsFrom Flickr:http://www.flickr.com/photos/cbpphotos/8652042987http://www.flickr.com/photos/disa4ever/9409743179http://www.flickr.com/photos/ben_salter/6169305845http://www.flickr.com/photos/elzey/3481161467http://www.flickr.com/photos/morris278/8022505933
A-Team members’ photos:http://5gta.com/gta-5-info/gta-5-the-a-team-similarities.html/http://www.legendarytv.com/the_a-team/the_a-team_lance_legault.asphttp://www.fanpop.com/clubs/the-a-team/imageshttp://dwightschultz.freeforums.org/dwight-photo-s-t8.htmlhttp://docmanhattan.blogspot.it/2010/10/vita-mort-immortalita-e-miracoli-di-mr.htmlhttp://www.starsky-iom.com/forum/viewtopic.php?f=8&t=58http://www.thea-teamonline.com/
And others form iStockPhoto
137