Yii role mapping based on Active Directory

This tutorial will show you how to manage user roles based on Active Directory information.

Step one – ad-ldap integration

Lets begin with ad-ldap integration download and install my Yii exstension yii-adldap.

Step two – prepare RBAC

For learning purposes I’ve selected simple RBAC based on a PHP file. Put this into your Yii config file:

	// config/main.php

	// application components
	'components'=>array(
		'authManager'=>array(
		    'class'=>'CPhpAuthManager',
		),		
	),

Now it’s time to create application roles:

// data/auth.php
return array (
  'domain_user' => 
  array (
    'type' => 2,
    'description' => 'Standard domain user',
    'bizRule' => '',
    'data' => '',
  ),
  'administrator' => 
  array (
    'type' => 2,
    'description' => 'Domain administrator',
    'bizRule' => '',
    'data' => '',
  ),
);

RBAC is ready, now you can set rules in controllers:

    public function filters()
    {
                return array(
                        'accessControl', // perform access control for CRUD operations
		);
	}

       	/**
         * Specifies the access control rules.
         * This method is used by the 'accessControl' filter.
         * @return array access control rules
         */

	public function accessRules()
	{
		return array(
			// allow everything to administrator role
			array('allow', 'roles'=>array('administrator')),
			// alllow few actions to domain users
			array('allow', 'roles'=>array('domain_user'), 'actions'=>array('index', 'list')),
			// deny everything to everyone else
			array('deny', 'users' => array('*'))
		);
	}

Step three
Time to map domain information to application roles. Open a UserIdentity class and add this property to it:

	// components/UserIdentity.php

	/**
	 * @var array RBAC role mappings based on domain criteria.
	 * @see authenticate
	 */	
	private $_roleMappings = array(
			// based on a group
			'domain_user' => array(
				'samaccountname'=> array(),
				'groups'=> array('Domain Users'),
			),
			// based on an acccount name
			'administrator' => array(
				'samaccountname'=> array('jdoe'),
				'groups'=> array(),
			),
			// based on mutliple groups and users
			'administrator' => array(
				'samaccountname'=> array('jdoe', 'madonis'),
				'groups'=> array('Domain Admins', 'Admins'),
			),
		);

Modify authenticate method provided in a yii-ldap extension:

	/**
	 * Authenticates a user using Active Directory.
	 * 
	 * @return boolean whether authentication succeeds.
	 */
	public function authenticate()
	{
		// alter search fields if needed
	        if(isset(Yii::app()->params['adFields']))
				  $this->_fields = Yii::app()->params['adFields'];

			// authenticate
			if (Yii::app()->ldap->authenticate($this->username, $this->password)){
				$this->errorCode = self::ERROR_NONE;

				// collect AD info about users
				$info = Yii::app()->ldap->user()->infoCollection($this->username, $this->_fields);
				$groups = Yii::app()->ldap->user()->groups($this->username);

				// alter id to domain account name
				$this->_id = $info->samaccountname;

				// export ad info to user session
				foreach($this->_fields as $field)
					$this->setState($field, $info->$field);	

				// export groups array
				$this->setState('groups', $groups);

				// assign roles based on domain data
				$auth=Yii::app()->authManager;

				// assign roles
				foreach ($this->_roleMappings as $role => $criteria) {
					// assign per username
					if(in_array(strtolower($this->id), $criteria['samaccountname'])) {
						if(!$auth->isAssigned($role,$this->id)) {
							if($auth->assign($role,$this->id)) {
								Yii::trace("{$this->id} was assigned to role $role based on AD username", 'application.components.UserIdentity');
							}
						}
					}

					// assign per group
					if(count(array_intersect($groups, $criteria['groups']))>0) {
						if(!$auth->isAssigned($role,$this->id)) {
							if($auth->assign($role,$this->id)) {
								Yii::trace("{$this->id} was assigned to role $role based on AD groups", 'application.components.UserIdentity');
							}
						}
					}					
				}

				Yii::app()->authManager->save();
			}
			else {
				 $this->errorCode = self::ERROR_PASSWORD_INVALID;
			}	        

	        return !$this->errorCode;
	}

Last step – validate result

If everything went right you can login into your app using domain credentials. Enable debug mode in your index file and search for traces looking like this:

2013/11/08 14:16:57 [trace] [application.components.UserIdentity] JDoe was assigned to role domain_user based on AD groups
2013/11/08 14:16:57 [trace] [application.components.UserIdentity] JDoe was assigned to role administrator based on AD username

If you’ll find them congratulations! You’ve just connected your app to Active Directory domain. Write a comment in case of a problem.

Download:




Comments

0 responses to “Yii role mapping based on Active Directory”

  1. zubin Avatar
    zubin

    Do you have a Yii 2.0 version for this?

    1. Konrad Fedorczyk Avatar
      Konrad Fedorczyk

      Hi,
      Yes I will rewrite this but I need some time to learn Yii2.

  2. gtidubster Avatar
    gtidubster

    Nice work! I’m very interested in a Yii2 example as well!

  3. Tamer Hassan Avatar
    Tamer Hassan

    Dear Konrad,

    Hope you haven’t given up on writing a Yii 2.0 version of this wonderful guide.

  4. Jeremy Avatar
    Jeremy

    It would be great to have a tutorial like this for Yii2.