explain the storage, explain why you never use it directly
explain the user, how it works, what you can do with it, how you do authentication, credentials etc
Role-Based Access Control (RBAC) is an approach to restricting system access to authorized users. To learn more about Role-Base Access Control (RBAC) in general you could start from http://en.wikipedia.org/wiki/Role-Based_Access_Control. For an in-depth paper about Role-Base Access Control (RBAC) see National Institute of Standards and Technology's "Proposed NIST Standard for Role-Based Access Control" (a link to that paper can be found from the Wikipedia's page).
Agavi has an easy-to-use RBAC user implementation
AgaviRbacSecurityUser. It extends the features
of AgaviSecurityUser to enable automatic
assignment of credentials based on a role or roles granted to the
user.
The user implementation used by Agavi is configured in
%core.app_dir%/config/factories.xml. To plug in
the RBAC user you simply alter the user class to be used.
<user class="AgaviRbacSecurityUser" />
Normally you would extend
AgaviRbacSecurityUser and create your own
user implementation with custom login and logout methods but for now
we want to keep our set-up simple and use
AgaviRbacSecurityUser directly.
AgaviRbacSecurityUser reads the role
and credential definitions from an XML-file located by default in
%core.app_dir%/config/rbac_definitions.xml. If
you want to keep them in some other file you can use a configuration
parameter definitions_file in
factories.xml.
<user class="AgaviRbacSecurityUser"> <parameter name="definitions_file">%core.app_dir%/data/roles.xml</parameter> </user>
Roles in the definition file are defined hierarchically from the bottom up so to speak. That means that a role can have an inner role (or many of them) that inherits all the credentials of the parent. This is a very common way to define roles in RBAC. Here is a simple exaple with three roles that are all in a straight line in the hierarchy ie. all photomoderators are photographers and all photographers are members and they inherit all the credentials from the parent. This is important to understand because now you don't need to grant the user all three roles separately but just the topmost.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<configurations>
<configuration>
<roles>
<role name="member">
<permissions>
<permission>photos.comments.add</permission>
</permissions>
<roles>
<role name="photographer">
<permissions>
<permission>photos.add</permission>
</permissions>
<roles>
<role name="photomoderator">
<permissions>
<permission>photos.edit</permission>
<permission>photos.delete</permission>
</permissions>
</role>
</roles>
</role>
</roles>
</role>
</roles>
</configuration>
</configurations>For larger systems this is obviously not the perfect way to
store the definitions but instead a database of some sort would be
used. To load the definitions from some other source you only have
to override AgaviRbacSecurityUser's
loadDefinitions() method
The roles have now been designed and defined in the XML-file and we have some database of the users and their roles. For simplicity's sake we don't bother ourselves with that database now but simply take it for granted that know the role(s) of the user after he has logged in.
AgaviRbacSecurityUser has six methods for role managing:
grantRole(string),
grantRoles(array),
revokeRole(string),
revokeAllRoles(),
hasRoles(string) and
getRoles(). The methods are
self-explanatory.
If you want to understand how
AgaviRbacSecurityUser actually works the
method grantRole(string) is worth looking
into. What it actually does is quite simple; it reads the role
definitions and gives the user each credential the given role has
explicitly or implicitly from the parent roles. The credential
management itself is actually part of
AgaviSecurityUser and
AgaviRbacSecurityUser only extends it with
role-to-credential mapping. This is the beauty of the
object-oriented design in action.
Protecting your action is simply a matter of defining the
credential needed to be able use the action. This is done by
overriding AgaviAction's
getCredentials() method.
class Photos_AddAction extends PhotoSystemBaseAction
{
public function getCredentials()
{
return 'photos.add';
}As the method name implies you can require more than one credential or even complex combinations of credentials (eg. 'a' OR 'b' AND 'c') but this is explained in detail in another chapter (a link is going to be added later).