1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
<?php
/**
* Filter to add attributes to the identity by executing a query against an LDAP directory
*
* Original Author: Steve Moitozo II <steve_moitozo@jaars.org>
* Created: 20100513
* Updated: 20100920 Steve Moitozo II
* - incorporated feedback from Olav Morken to prep code for inclusion in SimpleSAMLphp distro
* - moved call to ldap_set_options() inside test for $ds
* - added the output of ldap_error() to the exceptions
* - reduced some of the nested ifs
* - added support for multiple values
* - added support for anonymous binds
* - added escaping of search filter and attribute
* Updated: 20111118 Ryan Panning
* - Updated the class to use BaseFilter which reuses LDAP connection features
* - Added conversion of original filter option names for backwards-compatibility
* - Updated the constructor to use the new config method
* - Updated the process method to use the new config variable names
* Updated: 20131119 Yørn de Jong / Jaime Perez
* - Added support for retrieving multiple values at once from LDAP
* - Don't crash but fail silently on LDAP errors; the plugin is to complement attributes
*
* @author Yørn de Jong
* @author Jaime Perez
* @author Steve Moitozo
* @author JAARS, Inc.
* @author Ryan Panning
* @package simpleSAMLphp
*/
class sspmod_ldap_Auth_Process_AttributeAddFromLDAP extends sspmod_ldap_Auth_Process_BaseFilter {
/**
* LDAP attribute to add to the request attributes
*
* @var string
*/
protected $search_attributes;
/**
* LDAP search filter to use in the LDAP query
*
* @var string
*/
protected $search_filter;
/**
* What to do with attributes when the target already exists. Either replace, merge or add.
*
* @var string
*/
protected $attr_policy;
/**
* Initialize this filter.
*
* @param array $config Configuration information about this filter.
* @param mixed $reserved For future use.
*/
public function __construct($config, $reserved) {
/*
* For backwards compatibility, check for old config names
* @TODO Remove after 2.0
*/
if (isset($config['ldap_host'])) {
$config['ldap.hostname'] = $config['ldap_host'];
}
if (isset($config['ldap_port'])) {
$config['ldap.port'] = $config['ldap_port'];
}
if (isset($config['ldap_bind_user'])) {
$config['ldap.username'] = $config['ldap_bind_user'];
}
if (isset($config['ldap_bind_pwd'])) {
$config['ldap.password'] = $config['ldap_bind_pwd'];
}
if (isset($config['userid_attribute'])) {
$config['attribute.username'] = $config['userid_attribute'];
}
if (isset($config['ldap_search_base_dn'])) {
$config['ldap.basedn'] = $config['ldap_search_base_dn'];
}
if (isset($config['ldap_search_filter'])) {
$config['search.filter'] = $config['ldap_search_filter'];
}
if (isset($config['ldap_search_attribute'])) {
$config['search.attribute'] = $config['ldap_search_attribute'];
}
if (isset($config['new_attribute_name'])) {
$config['attribute.new'] = $config['new_attribute_name'];
}
/*
* Remove the old config names
* @TODO Remove after 2.0
*/
unset(
$config['ldap_host'],
$config['ldap_port'],
$config['ldap_bind_user'],
$config['ldap_bind_pwd'],
$config['userid_attribute'],
$config['ldap_search_base_dn'],
$config['ldap_search_filter'],
$config['ldap_search_attribute'],
$config['new_attribute_name']
);
// Now that we checked for BC, run the parent constructor
parent::__construct($config, $reserved);
// Get filter specific config options
$this->search_attributes = $this->config->getArrayize('attributes', array());
if (empty($this->search_attributes)) {
$new_attribute = $this->config->getString('attribute.new', '');
$this->search_attributes[$new_attribute] = $this->config->getString('search.attribute');
}
$this->search_filter = $this->config->getString('search.filter');
// get the attribute policy
$this->attr_policy = $this->config->getString('attribute.policy', 'merge');
}
/**
* Add attributes from an LDAP server.
*
* @param array &$request The current request
*/
public function process(&$request) {
assert('is_array($request)');
assert('array_key_exists("Attributes", $request)');
$attributes =& $request['Attributes'];
// perform a merge on the ldap_search_filter
// loop over the attributes and build the search and replace arrays
foreach ($attributes as $attr => $val) {
$arrSearch[] = '%'.$attr.'%';
if (strlen($val[0]) > 0) {
$arrReplace[] = SimpleSAML_Auth_LDAP::escape_filter_value($val[0]);
} else {
$arrReplace[] = '';
}
}
// merge the attributes into the ldap_search_filter
$filter = str_replace($arrSearch, $arrReplace, $this->search_filter);
if (strpos($filter, '%') !== FALSE) {
SimpleSAML_Logger::info('AttributeAddFromLDAP: There are non-existing attributes in the search filter. ('.
$this->search_filter.')');
return;
}
if (!in_array($this->attr_policy, array('merge', 'replace', 'add'))) {
SimpleSAML_Logger::warning("AttributeAddFromLDAP: 'attribute.policy' must be one of 'merge',".
"'replace' or 'add'.");
return;
}
// search for matching entries
try {
$entries = $this->getLdap()->searchformultiple($this->base_dn, $filter,
array_values($this->search_attributes), TRUE, FALSE);
} catch (Exception $e) {
return; // silent fail, error is still logged by LDAP search
}
// handle [multiple] values
foreach ($entries as $entry) {
foreach ($this->search_attributes as $target => $name) {
if (is_numeric($target)) {
$target = $name;
}
if (isset($attributes[$target]) && $this->attr_policy === 'replace') {
unset($attributes[$target]);
}
$name = strtolower($name);
if (isset($entry[$name])) {
unset($entry[$name]['count']);
if (isset($attributes[$target])) {
foreach(array_values($entry[$name]) as $value) {
if ($this->attr_policy === 'merge') {
if (!in_array($value, $attributes[$target])) {
$attributes[$target][] = $value;
}
} else {
$attributes[$target][] = $value;
}
}
} else {
$attributes[$target] = array_values($entry[$name]);
}
}
}
}
}
}
|