simplesamlphp /
simplesamlphp-module-ldap
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
| 1 | <?php |
||||
| 2 | |||||
| 3 | /** |
||||
| 4 | * Filter to add attributes to the identity by executing a query against an LDAP directory |
||||
| 5 | * |
||||
| 6 | * @package simplesamlphp/simplesamlphp-module-ldap |
||||
| 7 | */ |
||||
| 8 | |||||
| 9 | declare(strict_types=1); |
||||
| 10 | |||||
| 11 | namespace SimpleSAML\Module\ldap\Auth\Process; |
||||
| 12 | |||||
| 13 | use SimpleSAML\Assert\Assert; |
||||
| 14 | use SimpleSAML\Logger; |
||||
| 15 | use Symfony\Component\Ldap\Adapter\ExtLdap\Query; |
||||
| 16 | |||||
| 17 | use function array_values; |
||||
| 18 | |||||
| 19 | class AttributeAddFromLDAP extends BaseFilter |
||||
| 20 | { |
||||
| 21 | /** |
||||
| 22 | * LDAP attributes to add to the request attributes |
||||
| 23 | * |
||||
| 24 | * @var string[] |
||||
| 25 | */ |
||||
| 26 | protected array $searchAttributes; |
||||
| 27 | |||||
| 28 | /** |
||||
| 29 | * LDAP attributes to base64 encode |
||||
| 30 | * |
||||
| 31 | * @var string[] |
||||
| 32 | */ |
||||
| 33 | protected array $binaryAttributes; |
||||
| 34 | |||||
| 35 | /** |
||||
| 36 | * LDAP search filter to use in the LDAP query |
||||
| 37 | * |
||||
| 38 | * @var string |
||||
| 39 | */ |
||||
| 40 | protected string $searchFilter; |
||||
| 41 | |||||
| 42 | /** |
||||
| 43 | * What to do with attributes when the target already exists. Either replace, merge or add. |
||||
| 44 | * |
||||
| 45 | * @var string |
||||
| 46 | */ |
||||
| 47 | protected string $attrPolicy; |
||||
| 48 | |||||
| 49 | /** @var string|null */ |
||||
| 50 | protected ?string $searchUsername; |
||||
| 51 | |||||
| 52 | /** @var string|null */ |
||||
| 53 | protected ?string $searchPassword; |
||||
| 54 | |||||
| 55 | |||||
| 56 | /** |
||||
| 57 | * Initialize this filter. |
||||
| 58 | * |
||||
| 59 | * @param array<mixed> $config Configuration information about this filter. |
||||
| 60 | * @param mixed $reserved For future use. |
||||
| 61 | */ |
||||
| 62 | public function __construct(array $config, $reserved) |
||||
| 63 | { |
||||
| 64 | parent::__construct($config, $reserved); |
||||
| 65 | |||||
| 66 | // Get filter specific config options |
||||
| 67 | $this->binaryAttributes = $this->config->getOptionalArray('attributes.binary', []); |
||||
| 68 | $this->searchAttributes = $this->config->getOptionalArrayize('attributes', []); |
||||
| 69 | if (empty($this->searchAttributes)) { |
||||
| 70 | $new_attribute = $this->config->getString('attribute.new'); |
||||
| 71 | $this->searchAttributes[$new_attribute] = $this->config->getString('search.attribute'); |
||||
| 72 | } |
||||
| 73 | $this->searchFilter = $this->config->getString('search.filter'); |
||||
| 74 | |||||
| 75 | // get the attribute policy |
||||
| 76 | $this->attrPolicy = $this->config->getOptionalString('attribute.policy', 'merge'); |
||||
| 77 | Assert::oneOf($this->attrPolicy, ['merge', 'replace', 'add']); |
||||
| 78 | |||||
| 79 | $this->searchUsername = $this->config->getOptionalString('search.username', null); |
||||
| 80 | $this->searchPassword = $this->config->getOptionalString('search.password', null); |
||||
| 81 | } |
||||
| 82 | |||||
| 83 | |||||
| 84 | /** |
||||
| 85 | * Add attributes from an LDAP server. |
||||
| 86 | * |
||||
| 87 | * @param array<mixed> &$state The current request |
||||
| 88 | */ |
||||
| 89 | public function process(array &$state): void |
||||
| 90 | { |
||||
| 91 | Assert::keyExists($state, 'Attributes'); |
||||
| 92 | $attributes = &$state['Attributes']; |
||||
| 93 | |||||
| 94 | // perform a merge on the ldap_search_filter |
||||
| 95 | // loop over the attributes and build the search and replace arrays |
||||
| 96 | $arrSearch = $arrReplace = []; |
||||
| 97 | foreach ($attributes as $attr => $val) { |
||||
| 98 | $arrSearch[] = '%' . $attr . '%'; |
||||
| 99 | |||||
| 100 | if (is_array($val) && count($val) > 0 && is_string($val[0]) && strlen($val[0]) > 0) { |
||||
| 101 | $arrReplace[] = $this->connector->escapeFilterValue($val[0], true); |
||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 102 | } else { |
||||
| 103 | $arrReplace[] = ''; |
||||
| 104 | } |
||||
| 105 | } |
||||
| 106 | |||||
| 107 | // merge the attributes into the ldap_search_filter |
||||
| 108 | /** @psalm-var string[] $arrReplace */ |
||||
| 109 | $filter = str_replace($arrSearch, $arrReplace, $this->searchFilter); |
||||
| 110 | if (strpos($filter, '%') !== false) { |
||||
| 111 | Logger::info(sprintf( |
||||
| 112 | '%s: There are non-existing attributes in the search filter. (%s)', |
||||
| 113 | $this->title, |
||||
| 114 | $filter, |
||||
| 115 | )); |
||||
| 116 | return; |
||||
| 117 | } |
||||
| 118 | |||||
| 119 | $this->connector->bind($this->searchUsername, $this->searchPassword); |
||||
| 120 | |||||
| 121 | $wantedAttrs = $this->config->getOptionalValue( |
||||
| 122 | 'attributes', |
||||
| 123 | // If specifically set to NULL return all attributes, if not set at all return nothing (safe default) |
||||
| 124 | in_array('attributes', $this->config->getOptions(), true) ? ['*'] : [], |
||||
| 125 | ); |
||||
| 126 | |||||
| 127 | $options = [ |
||||
| 128 | 'scope' => $this->config->getOptionalString('search.scope', Query::SCOPE_SUB), |
||||
| 129 | 'timeout' => $this->config->getOptionalInteger('timeout', 3), |
||||
| 130 | 'filter' => array_values($wantedAttrs), |
||||
| 131 | ]; |
||||
| 132 | |||||
| 133 | $entries = $this->connector->searchForMultiple( |
||||
| 134 | $this->searchBase, |
||||
| 135 | $filter, |
||||
| 136 | $options, |
||||
| 137 | true, |
||||
| 138 | ); |
||||
| 139 | |||||
| 140 | $results = []; |
||||
| 141 | foreach ($entries as $entry) { |
||||
| 142 | $tmp = array_intersect_key( |
||||
| 143 | $entry->getAttributes(), |
||||
| 144 | array_fill_keys(array_values($this->searchAttributes), null), |
||||
| 145 | ); |
||||
| 146 | |||||
| 147 | $binaries = array_intersect( |
||||
| 148 | array_keys($tmp), |
||||
| 149 | $this->binaryAttributes, |
||||
| 150 | ); |
||||
| 151 | foreach ($binaries as $binary) { |
||||
| 152 | $attr = $entry->getAttribute($binary); |
||||
| 153 | $tmp[$binary] = array_map('base64_encode', $attr); |
||||
|
0 ignored issues
–
show
It seems like
$attr can also be of type null; however, parameter $array of array_map() does only seem to accept array, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 154 | } |
||||
| 155 | |||||
| 156 | $results[] = $tmp; |
||||
| 157 | } |
||||
| 158 | |||||
| 159 | // handle [multiple] values |
||||
| 160 | foreach ($results as $result) { |
||||
| 161 | foreach ($this->searchAttributes as $target => $name) { |
||||
| 162 | // If there is no mapping defined, just use the name of the LDAP-attribute as a target |
||||
| 163 | if (is_int($target)) { |
||||
| 164 | $target = $name; |
||||
| 165 | } |
||||
| 166 | |||||
| 167 | if (isset($attributes[$target]) && $this->attrPolicy === 'replace') { |
||||
| 168 | unset($attributes[$target]); |
||||
| 169 | } |
||||
| 170 | |||||
| 171 | if (isset($result[$name])) { |
||||
| 172 | if (isset($attributes[$target])) { |
||||
| 173 | foreach (array_values($result[$name]) as $value) { |
||||
| 174 | if ($this->attrPolicy === 'merge') { |
||||
| 175 | if (!in_array($value, $attributes[$target], true)) { |
||||
| 176 | $attributes[$target][] = $value; |
||||
| 177 | } |
||||
| 178 | } else { |
||||
| 179 | $attributes[$target][] = $value; |
||||
| 180 | } |
||||
| 181 | } |
||||
| 182 | } else { |
||||
| 183 | $attributes[$target] = array_values($result[$name]); |
||||
| 184 | } |
||||
| 185 | } |
||||
| 186 | } |
||||
| 187 | } |
||||
| 188 | } |
||||
| 189 | } |
||||
| 190 |