View source
<?php
namespace Drupal\ldap_servers\Processor;
use Drupal\Core\File\FileSystem;
use Drupal\Component\Utility\Unicode;
use Drupal\ldap_servers\Entity\Server;
use Drupal\ldap_servers\Helper\ConversionHelper;
use Drupal\ldap_servers\Helper\CredentialsStorage;
use Drupal\ldap_servers\Logger\LdapDetailLog;
use Drupal\user\UserInterface;
class TokenProcessor {
const PREFIX = '[';
const SUFFIX = ']';
const DELIMITER = ':';
const MODIFIER_DELIMITER = ';';
protected $detailLog;
protected $fileSystem;
public function __construct(LdapDetailLog $ldap_detail_log, FileSystem $file_system) {
$this->detailLog = $ldap_detail_log;
$this->fileSystem = $file_system;
}
public function tokenReplace($resource, $text, $resource_type = 'ldap_entry') {
$desired_tokens = ConversionHelper::findTokensNeededForTemplate($text);
if (empty($desired_tokens)) {
return $text;
}
$tokens = [];
switch ($resource_type) {
case 'ldap_entry':
$tokens = $this
->tokenizeLdapEntry($resource, $desired_tokens, self::PREFIX, self::SUFFIX);
break;
case 'user_account':
$tokens = $this
->tokenizeUserAccount($resource, $desired_tokens, self::PREFIX, self::SUFFIX);
break;
}
foreach ($tokens as $attribute => $value) {
$tokens[mb_strtolower($attribute)] = $value;
}
$attributes = array_keys($tokens);
$values = array_values($tokens);
$result = str_replace($attributes, $values, $text);
$result = preg_replace('/^\\[.*\\]$/', '', $result);
if ($result == '') {
return NULL;
}
else {
return $result;
}
}
public function tokenizeLdapEntry(array $ldap_entry, array $token_keys, $pre = self::PREFIX, $post = self::SUFFIX) {
if (!is_array($ldap_entry)) {
$this->detailLog
->log('Skipped tokenization of LDAP entry because no LDAP entry provided when called from %calling_function.', [
'%calling_function' => function_exists('debug_backtrace') ? debug_backtrace()[1]['function'] : 'undefined',
]);
return [];
}
list($ldap_entry, $tokens) = $this
->compileLdapTokenEntries($ldap_entry, $token_keys, $pre, $post);
$tokens[$pre . 'dn' . $post] = $ldap_entry['dn'];
return $tokens;
}
public function tokenizeUserAccount(UserInterface $account, array $token_keys = [], $pre = self::PREFIX, $post = self::SUFFIX) {
if (empty($token_keys)) {
$token_keys = $this
->discoverUserAttributes($account);
}
$tokens = [];
foreach ($token_keys as $token_key) {
$tokens = array_merge($tokens, $this
->fetchSingleToken($account, $pre, $post, $token_key));
}
return $tokens;
}
private function discoverUserAttributes(UserInterface $account) {
$token_keys = [];
$userData = $account
->toArray();
foreach ($userData as $propertyName => $propertyData) {
if (isset($propertyData[0], $propertyData[0]['value']) && is_scalar($propertyData[0]['value'])) {
if (substr($propertyName, 0, strlen('field')) === 'field') {
$token_keys[] = 'field.' . mb_strtolower($propertyName);
}
else {
$token_keys[] = 'property.' . mb_strtolower($propertyName);
}
}
}
$token_keys[] = 'password.random';
$token_keys[] = 'password.user-random';
$token_keys[] = 'password.user-only';
return $token_keys;
}
private function fetchSingleToken(UserInterface $account, $pre, $post, $token) {
list($attribute_type, $attribute_name, $attribute_conversion) = explode('.', $token . '.');
$value = FALSE;
$tokens = [];
switch ($attribute_type) {
case 'field':
case 'property':
$value = $this
->fetchRegularFieldToken($account, $attribute_name);
break;
case 'password':
$value = $this
->fetchPasswordToken($attribute_name);
if (empty($value)) {
return [
NULL,
NULL,
];
}
break;
}
if ($attribute_conversion == 'to-md5') {
$value = md5($value);
}
elseif ($attribute_conversion == 'to-lowercase') {
$value = mb_strtolower($value);
}
$tokens[$pre . $token . $post] = $value;
if ($token != mb_strtolower($token)) {
$tokens[$pre . mb_strtolower($token) . $post] = $value;
}
return $tokens;
}
private function fetchPasswordToken($attribute_name) {
$value = '';
switch ($attribute_name) {
case 'user':
case 'user-only':
$value = CredentialsStorage::getPassword();
break;
case 'user-random':
$pwd = CredentialsStorage::getPassword();
$value = $pwd ? $pwd : user_password();
break;
case 'random':
$value = user_password();
break;
}
return $value;
}
private function fetchRegularFieldToken(UserInterface $account, $attribute_name) {
$value = '';
if (is_scalar($account
->get($attribute_name)->value)) {
$value = $account
->get($attribute_name)->value;
}
elseif (!empty($account
->get($attribute_name)
->getValue())) {
$file_reference = $account
->get($attribute_name)
->getValue();
if (isset($file_reference[0]['target_id'])) {
$file = file_load($file_reference[0]['target_id']);
if ($file) {
$value = file_get_contents($this->fileSystem
->realpath($file
->getFileUri()));
}
}
}
return $value;
}
private function compileLdapTokenEntries(array $ldap_entry, array $token_keys, $pre, $post) {
$tokens = [];
foreach ($ldap_entry as $key => $values) {
$ldap_entry[mb_strtolower($key)] = $values;
}
$tokens = array_merge($tokens, $this
->ldapTokenizationProcessDnParts($ldap_entry, $pre, $post));
if (empty($token_keys)) {
$token_keys = array_keys($ldap_entry);
$token_keys = array_filter($token_keys, "is_string");
foreach ($token_keys as $attribute_name) {
$tokens = array_merge($tokens, $this
->processSingleLdapEntryToken($ldap_entry, $pre, $post, $attribute_name));
}
}
else {
foreach ($token_keys as $full_token_key) {
$tokens = array_merge($tokens, $this
->processSingleLdapTokenKey($ldap_entry, $pre, $post, $full_token_key));
}
}
return [
$ldap_entry,
$tokens,
];
}
private function ldapTokenizationProcessDnParts(array $ldap_entry, $pre, $post) {
$tokens = [];
$dn_parts = Server::ldapExplodeDn($ldap_entry['dn'], 0);
unset($dn_parts['count']);
$parts_count = [];
$parts_last_value = [];
foreach ($dn_parts as $pair) {
list($attribute_name, $attribute_value) = explode('=', $pair);
$attribute_value = ConversionHelper::unescapeDnValue($attribute_value);
if (!Unicode::validateUtf8($attribute_value)) {
$this->detailLog
->log('Skipped tokenization of attribute %attr_name because the value is not valid UTF-8 string.', [
'%attr_name' => $attribute_name,
]);
continue;
}
if (!isset($parts_count[$attribute_name])) {
$tokens[$pre . mb_strtolower($attribute_name) . $post] = $attribute_value;
$parts_count[$attribute_name] = 0;
}
$tokens[$pre . mb_strtolower($attribute_name) . self::DELIMITER . (int) $parts_count[$attribute_name] . $post] = $attribute_value;
$parts_last_value[$attribute_name] = $attribute_value;
$parts_count[$attribute_name]++;
}
foreach ($parts_count as $attribute_name => $count) {
$part = mb_strtolower($attribute_name);
for ($i = 0; $i < $count; $i++) {
$reversePosition = $count - $i - 1;
$tokens[$pre . $part . self::DELIMITER . 'reverse' . self::DELIMITER . $reversePosition . $post] = $tokens[$pre . $part . self::DELIMITER . $i . $post];
}
}
foreach ($parts_count as $attribute_name => $count) {
$tokens[$pre . mb_strtolower($attribute_name) . self::DELIMITER . 'last' . $post] = $parts_last_value[$attribute_name];
}
return $tokens;
}
private function processSingleLdapEntryToken(array $ldap_entry, $pre, $post, $attribute_name) {
$tokens = [];
$attribute_value = $ldap_entry[$attribute_name];
if (is_array($attribute_value) && is_scalar($attribute_value[0]) && $attribute_value['count'] == 1) {
$tokens[$pre . mb_strtolower($attribute_name) . $post] = $attribute_value[0];
$tokens[$pre . mb_strtolower($attribute_name) . self::DELIMITER . '0' . $post] = $attribute_value[0];
$tokens[$pre . mb_strtolower($attribute_name) . self::DELIMITER . 'last' . $post] = $attribute_value[0];
}
elseif (is_array($attribute_value) && $attribute_value['count'] > 1) {
$tokens[$pre . mb_strtolower($attribute_name) . self::DELIMITER . 'last' . $post] = $attribute_value[$attribute_value['count'] - 1];
for ($i = 0; $i < $attribute_value['count']; $i++) {
$tokens[$pre . mb_strtolower($attribute_name) . self::DELIMITER . $i . $post] = $attribute_value[$i];
}
}
elseif (is_scalar($attribute_value)) {
$tokens[$pre . mb_strtolower($attribute_name) . $post] = $attribute_value;
$tokens[$pre . mb_strtolower($attribute_name) . self::DELIMITER . '0' . $post] = $attribute_value;
$tokens[$pre . mb_strtolower($attribute_name) . self::DELIMITER . 'last' . $post] = $attribute_value;
}
return $tokens;
}
private function processSingleLdapTokenKey(array $ldap_entry, $pre, $post, $full_token_key) {
$tokens = [];
$value = NULL;
list($token_key, $conversion) = explode(';', $full_token_key . ';');
$parts = explode(self::DELIMITER, $token_key);
$attribute_name = mb_strtolower($parts[0]);
$ordinal_key = isset($parts[1]) ? $parts[1] : 0;
$i = NULL;
if ($attribute_name == 'dn' || !isset($ldap_entry[$attribute_name])) {
return [];
}
else {
$count = $ldap_entry[$attribute_name]['count'];
if ($ordinal_key === 'last') {
$i = $count > 0 ? $count - 1 : 0;
$value = $ldap_entry[$attribute_name][$i];
}
elseif (is_numeric($ordinal_key) || $ordinal_key == '0') {
$value = $ldap_entry[$attribute_name][$ordinal_key];
}
else {
return [];
}
}
$value = ConversionHelper::convertAttribute($value, $conversion);
$tokens[$pre . $full_token_key . $post] = $value;
if ($full_token_key != mb_strtolower($full_token_key)) {
$tokens[$pre . mb_strtolower($full_token_key) . $post] = $value;
}
return $tokens;
}
}