Compare commits

...

9 Commits

Author SHA1 Message Date
Ionut Padurariu
7edeb89147 - use constants from generis 2017-10-09 11:14:42 +02:00
Lionel Lecaque
5bcd1fda62 Merge pull request #2 from oat-sa/feature/complex-mapping
Feature/complex mapping
2015-12-23 17:58:50 +01:00
Joel Bout
2e43d18c53 specified override of example 2015-12-23 17:37:43 +01:00
Joel Bout
ee2974c8be added mapping examples and explanations 2015-12-23 17:35:12 +01:00
Joel Bout
ae186f3bf5 Fix double constructor 2015-12-21 15:07:34 +01:00
Joel Bout
2ca812159d Merge branch 'develop' into feature/complex-mapping
Conflicts:
	model/LdapAdapter.php
2015-12-18 15:10:54 +01:00
Joel Bout
767943223d Adapted to new LoginAdapter interface 2015-11-30 09:52:26 +01:00
Joel Bout
d5d2ad9b03 Added complex rules to map the user attributes 2015-03-13 18:39:02 +01:00
Joel Bout
9727c8efce Added message to failed login for debug 2015-03-10 15:09:27 +01:00
5 changed files with 229 additions and 252 deletions

View File

@ -55,3 +55,59 @@ here the domain is test.com All the parameters are in a separate dc in ldap
These are the configuration of the connection to the ldap server. These are the configuration of the connection to the ldap server.
Then the login will try to use this library. Then the login will try to use this library.
Configuration
============================
By default and LDAP user will be considered a test-taker belonging to no group.
The following attributes will be taken from LDAP and mapped to TAO properties by default:
* 'mail' as PROPERTY_USER_MAIL
* 'givenName' as PROPERTY_USER_FIRSTNAME
* 'sn' as PROPERTY_USER_LASTNAME
* 'displayName' as RDFS_LABEL
However there are several ways to enhance or override this default behaviour:
------------------------------
To hardcode one of the user properties, you would need to add a mapping of the type 'value' to the configuration:
array(
'driver' => 'oat\authLdap\model\LdapAdapter',
'config' => SEE_ABOVE
'mapping' => array(
'http://www.tao.lu/Ontologies/TAOGroup.rdf#member' => array(
'type' => 'value',
'value' => array('http://localnamespace.com/install#i123456789')
)
);
),
This example would set the group membership of all users loging in to a group identified by the id http://localnamespace.com/install#i123456789
------------------------------
Alternatively if you want to take over a value of an LDAP attribute you would add a mapping of type 'attributeValue'
array(
'driver' => 'oat\authLdap\model\LdapAdapter',
'config' => SEE_ABOVE
'mapping' => array(
'http://www.tao.lu/Ontologies/TAOGroup.rdf#member' => array(
'type' => 'value',
'value' => array('http://localnamespace.com/install#i123456789')
),
'http://www.w3.org/2000/01/rdf-schema#label' => array(
'type' => 'attributeValue',
'attribute' => 'username'
)
);
),
This would use the value of the LDAP attribute 'username' as label (RDFS_LABEL) for the user, overriding the default rule to use 'displayName'.
------------------------------
For more advanced cases there is the type 'callback' which allows you to programmatically enhance the mapping of the LDAP attributes to the TAO properties. See oat\authLdap\model\LdapUserFactory for details.

View File

@ -45,6 +45,10 @@ use common_persistence_Manager;
*/ */
class LdapAdapter implements LoginAdapter class LdapAdapter implements LoginAdapter
{ {
const OPTION_ADAPTER_CONFIG = 'config';
const OPTION_USER_MAPPING = 'mapping';
/** @var $username string */ /** @var $username string */
private $username; private $username;
@ -54,9 +58,6 @@ class LdapAdapter implements LoginAdapter
/** @var $configuration array $configuration */ /** @var $configuration array $configuration */
protected $configuration; protected $configuration;
/** @var $mapping array $mapping */
protected $mapping;
/** /**
* @var \Zend\Authentication\Adapter\Ldap * @var \Zend\Authentication\Adapter\Ldap
*/ */
@ -69,19 +70,29 @@ class LdapAdapter implements LoginAdapter
* @return oat\authLdap\model\LdapAdapter * @return oat\authLdap\model\LdapAdapter
*/ */
public static function createFromConfig(array $configuration) { public static function createFromConfig(array $configuration) {
return new self($configuration); $adapter = new self();
$adapter->setOptions($configuration);
return $adapter;
} }
/** /**
* @param array $configuration * Instantiates Zend Ldap adapter
*/ */
public function __construct(array $configuration) { public function __construct() {
$this->configuration = $configuration;
$this->adapter = new Ldap(); $this->adapter = new Ldap();
$this->adapter->setOptions($configuration['config']); }
$this->setMapping($configuration['mapping']);
public function setOptions(array $options) {
$this->configuration = $options;
$this->adapter->setOptions($options['config']);
}
public function getOption($name) {
return $this->configuration[$name];
}
public function hasOption($name) {
return isset($this->configuration[$name]);
} }
/** /**
@ -109,13 +120,16 @@ class LdapAdapter implements LoginAdapter
$result = $adapter->getAccountObject(); $result = $adapter->getAccountObject();
$params = get_object_vars($result); $params = get_object_vars($result);
$user = new LdapUser($this->getMapping()); $mapping = $this->hasOption(self::OPTION_USER_MAPPING)
? $this->getOption(self::OPTION_USER_MAPPING)
: array();
$factory = new LdapUserFactory($mapping);
$user = $factory->createUser($params);
$user->setUserRawParameters($params);
return $user; return $user;
} else { } else {
throw new core_kernel_users_InvalidLoginException(); throw new core_kernel_users_InvalidLoginException('User "'.$this->getUsername().'" failed LDAP authentication.');
} }
@ -154,24 +168,6 @@ class LdapAdapter implements LoginAdapter
return $this->configuration; return $this->configuration;
} }
/**
* @param array $mapping
*/
public function setMapping($mapping)
{
$this->mapping = $mapping;
}
/**
* @return array
*/
public function getMapping()
{
return $this->mapping;
}
/** /**
* @param string $password * @param string $password
*/ */

View File

@ -33,230 +33,32 @@ use common_user_User;
use core_kernel_classes_Resource; use core_kernel_classes_Resource;
use core_kernel_classes_Property; use core_kernel_classes_Property;
use common_Logger; use common_Logger;
use SebastianBergmann\Exporter\Exception;
class LdapUser extends common_user_User { class LdapUser extends common_user_User {
/** @var array of configuration */ private $identifier;
protected $configuration;
/** private $cache;
* @var array
*/
protected $userRawParameters;
/** public function __construct($id, $data)
* @var array
*/
protected $userExtraParameters = array();
/**
* @var string
*/
protected $identifier;
/** @var array $roles */
protected $roles;
/**
* Array that contains the language code as a single string
*
* @var array
*/
protected $languageUi = array(DEFAULT_LANG);
/**
* Array that contains the language code as a single string
*
* @var array
*/
protected $languageDefLg = array(DEFAULT_LANG);
/**
* The mapping of custom parameter from ldap to TAO property
*
* @var array
*/
protected $mapping;
public function __construct(array $mapping = null){
$this->mapping = $mapping;
}
/**
* @return array
*/
public function getMapping()
{ {
return $this->mapping; $this->identifier = $id;
$this->cache = $data;
} }
/** public function getIdentifier()
* Sets the language URI
*
* @param string $languageDefLgUri
*/
public function setLanguageDefLg($languageDefLgUri)
{ {
$this->languageDefLg = array((string)$languageDefLgUri);
return $this;
}
/**
* Returns the language code
*
* @return array
*/
public function getLanguageDefLg()
{
return $this->languageDefLg;
}
/**
* @param $property string
* @param $value string
*/
public function setUserParameter($property, $value){
$this->userRawParameters[$property] = $value;
}
public function getUserParameter($property) {
if (isset ($this->userRawParameters[$property] ) )
return $this->userRawParameters[$property];
return null;
}
/**
* @param array $params
* @return AuthKeyValueUser
*/
public function setUserRawParameters(array $params)
{
$this->setRoles(array('http://www.tao.lu/Ontologies/TAO.rdf#DeliveryRole'));
// initialize parameter that should be set
isset($params['preferredlanguage']) ? $this->setLanguageUi($params['preferredlanguage']) : DEFAULT_LANG;
isset($params['preferredlanguage']) ? $this->setLanguageDefLg($params['preferredlanguage']) : DEFAULT_LANG;
isset($params['mail']) ? $this->setUserParameter(PROPERTY_USER_MAIL, $params['mail']) : '';
isset($params['displayname']) ? $this->setUserParameter(PROPERTY_USER_LASTNAME, $params['displayname']) : $this->setUserParameter(PROPERTY_USER_LASTNAME, $params['cn']) ;
$mapping = $this->getMapping();
foreach($params as $key => $value) {
if(! in_array($key, array('preferredlanguage','mail', 'displayname'))) {
if(array_key_exists($key, $mapping)){
$this->setUserParameter($mapping[$key], $value);
}
}
}
return $this;
}
/**
* @return array
*/
public function getUserRawParameters()
{
return $this->userRawParameters;
}
/**
* @param mixed $language
*/
public function setLanguageUi($languageUri)
{
$this->languageUi = array((string)$languageUri);
return $this;
}
/**
* @return array
*/
public function getLanguageUi()
{
return $this->languageUi;
}
/**
* @return string
*/
public function getIdentifier(){
return $this->identifier; return $this->identifier;
} }
/**
* @param $identifier
* @return $this
*/
public function setIdentifier($identifier){
$this->identifier = $identifier;
return $this;
}
/**
* @param $property string
* @return array|null
*/
public function getPropertyValues($property) public function getPropertyValues($property)
{ {
$returnValue = null; return isset($this->cache[$property])
? $this->cache[$property]
switch ($property) { : array();
case PROPERTY_USER_DEFLG :
$returnValue = $this->getLanguageDefLg();
break;
case PROPERTY_USER_UILG :
$returnValue = $this->getLanguageUi();
break;
case PROPERTY_USER_ROLES :
$returnValue = $this->getRoles();
break;
default:
$returnValue = array($this->getUserParameter($property));
}
return $returnValue;
} }
/**
* Function that will refresh the parameters.
*/
public function refresh() { public function refresh() {
return false;
} }
/**
* @return array
*/
public function getRoles() {
return $this->roles;
}
/**
* @param array $roles
* @return $this
*/
public function setRoles(array $roles ) {
$this->roles = $roles;
return $this;
}
} }

122
model/LdapUserFactory.php Normal file
View File

@ -0,0 +1,122 @@
<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2014 (original work) Open Assessment Technologies SA;
*
*
*/
/**
* Authentication user for key value db access
*
* @author christophe massin
* @package authLdap
*/
namespace oat\authLdap\model;
use oat\oatbox\Configurable;
class LdapUserFactory extends Configurable {
public function createUser($rawData) {
if (!isset($rawData['dn'])) {
throw new \common_exception_InconsistentData('Missing DN for LDAP user');
} else {
$id = $rawData['dn'];
}
$data = array();
foreach ($this->getRules() as $property => $rule) {
$data[$property] = $this->map($rule, $rawData);
}
return new LdapUser($id, $data);
}
public function map($propertyConfig, $rawData) {
$data = array();
switch ($propertyConfig['type']) {
case 'value' :
$data = $propertyConfig['value'];
break;
case 'attributeValue' :
if (isset($rawData[$propertyConfig['attribute']])) {
$value = $rawData[$propertyConfig['attribute']];
$data = is_array($value) ? $value : array($value);
}
break;
case 'callback' :
if (isset($rawData[$propertyConfig['attribute']])) {
$callback = $propertyConfig['callable'];
if (is_callable($callback)) {
$data = call_user_func($callback, $rawData[$propertyConfig['attribute']]);
}
}
break;
default :
throw new \common_exception_InconsistentData('Unknown mapping: '.$propertyConfig['type']);
}
return $data;
}
public function getRules() {
$rules = self::getDefaultConfig();
foreach ($this->getOptions() as $key => $value) {
$rules[$key] = $value;
}
return $rules;
}
static public function getDefaultConfig()
{
return array(
PROPERTY_USER_ROLES => self::rawValue(INSTANCE_ROLE_DELIVERY)
,PROPERTY_USER_UILG => self::rawValue(DEFAULT_LANG)
,PROPERTY_USER_DEFLG => self::rawValue(DEFAULT_LANG)
,PROPERTY_USER_TIMEZONE => self::rawValue(TIME_ZONE)
,PROPERTY_USER_MAIL => self::attributeValue('mail')
,PROPERTY_USER_FIRSTNAME => self::attributeValue('givenName')
,PROPERTY_USER_LASTNAME => self::attributeValue('sn')
,RDFS_LABEL => self::attributeValue('displayName')
);
}
static protected function rawValue($value) {
return array(
'type' => 'value',
'value' => array($value)
);
}
static protected function attributeValue($attributeName) {
return array(
'type' => 'attributeValue',
'attribute' => $attributeName
);
}
static protected function callback($callable, $attributeName) {
return array(
'type' => 'callback',
'callable' => $callable,
'attribute' => $attributeName
);
}
}

View File

@ -10,6 +10,7 @@ namespace oat\authLdap\test;
use oat\authLdap\model\LdapUser; use oat\authLdap\model\LdapUser;
use GenerisPhpUnitTestRunner; use GenerisPhpUnitTestRunner;
use oat\generis\model\GenerisRdf;
require_once dirname(__FILE__) . '/../../generis/test/GenerisPhpUnitTestRunner.php'; require_once dirname(__FILE__) . '/../../generis/test/GenerisPhpUnitTestRunner.php';
@ -66,8 +67,8 @@ class AuthKeyValueUserTest extends GenerisPhpUnitTestRunner {
*/ */
public function testPropertyValue(){ public function testPropertyValue(){
$this->assertEquals(array(0 => 'en-US'), $this->user->getPropertyValues(PROPERTY_USER_DEFLG)); $this->assertEquals(array(0 => 'en-US'), $this->user->getPropertyValues(GenerisRdf::PROPERTY_USER_DEFLG));
$this->assertEquals(array(0 => 'en-US'), $this->user->getPropertyValues(PROPERTY_USER_UILG)); $this->assertEquals(array(0 => 'en-US'), $this->user->getPropertyValues(GenerisRdf::PROPERTY_USER_UILG));
} }
@ -80,7 +81,7 @@ class AuthKeyValueUserTest extends GenerisPhpUnitTestRunner {
{ {
$this->user->setRoles(array('http://www.tao.lu/Ontologies/TAO.rdf#DeliveryRole')); $this->user->setRoles(array('http://www.tao.lu/Ontologies/TAO.rdf#DeliveryRole'));
$this->assertEquals(array('http://www.tao.lu/Ontologies/TAO.rdf#DeliveryRole'), $this->user->getRoles()); $this->assertEquals(array('http://www.tao.lu/Ontologies/TAO.rdf#DeliveryRole'), $this->user->getRoles());
$this->assertEquals(array('http://www.tao.lu/Ontologies/TAO.rdf#DeliveryRole'), $this->user->getPropertyValues(PROPERTY_USER_ROLES)); $this->assertEquals(array('http://www.tao.lu/Ontologies/TAO.rdf#DeliveryRole'), $this->user->getPropertyValues(GenerisRdf::PROPERTY_USER_ROLES));
} }
@ -94,10 +95,10 @@ class AuthKeyValueUserTest extends GenerisPhpUnitTestRunner {
// check array is currently empty // check array is currently empty
$this->assertEmpty($array); $this->assertEmpty($array);
$mail = $this->user->getPropertyValues(PROPERTY_USER_MAIL); $mail = $this->user->getPropertyValues(GenerisRdf::PROPERTY_USER_MAIL);
$this->assertNotEmpty($this->user->getUserExtraParameters()); $this->assertNotEmpty($this->user->getUserExtraParameters());
$this->assertArrayHasKey(PROPERTY_USER_MAIL,$this->user->getUserExtraParameters()); $this->assertArrayHasKey(GenerisRdf::PROPERTY_USER_MAIL,$this->user->getUserExtraParameters());
} }