10. Session Handling and Security

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

10.1. Role-Based Access Control

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.

10.1.1. Enabling RBAC

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.

10.1.2. Defining Roles and Credentials

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>

Note

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

10.1.3. Granting Roles to the User

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.

10.1.4. Protecting Your Actions

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).