diff options
Diffstat (limited to 'library/Director/Util.php')
-rw-r--r-- | library/Director/Util.php | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/library/Director/Util.php b/library/Director/Util.php new file mode 100644 index 0000000..22ad5fc --- /dev/null +++ b/library/Director/Util.php @@ -0,0 +1,175 @@ +<?php + +namespace Icinga\Module\Director; + +use Icinga\Authentication\Auth; +use Icinga\Data\ResourceFactory; +use Icinga\Module\Director\Web\Form\QuickForm; +use Icinga\Exception\NotImplementedError; +use Icinga\Exception\ProgrammingError; +use ipl\Html\Html; +use gipfl\IcingaWeb2\Link; + +class Util +{ + protected static $auth; + + protected static $allowedResources; + + /** + * PBKDF2 - Password-Based Cryptography Specification (RFC2898) + * + * This method strictly follows examples in php.net's documentation + * comments. Hint: RFC6070 would be a good source for related tests + * + * @param string $alg Desired hash algorythm (sha1, sha256...) + * @param string $secret Shared secret, password + * @param string $salt Hash salt + * @param int $iterations How many iterations to perform. Please use at + * least 1000+. More iterations make it slower + * but more secure. + * @param int $length Desired key length + * @param bool $raw Returns the binary key if true, hex string otherwise + * + * @throws NotImplementedError when asking for an unsupported algorightm + * @throws ProgrammingError when passing invalid parameters + * + * @return string A $length byte long key, derived from secret and salt + */ + public static function pbkdf2($alg, $secret, $salt, $iterations, $length, $raw = false) + { + if (! in_array($alg, hash_algos(), true)) { + throw new NotImplementedError('No such hash algorithm found: "%s"', $alg); + } + + if ($iterations <= 0 || $length <= 0) { + throw new ProgrammingError('Positive iterations and length required'); + } + + $hashLength = strlen(hash($alg, '', true)); + $blocks = ceil($length / $hashLength); + + $out = ''; + + for ($i = 1; $i <= $blocks; $i++) { + // $i encoded as 4 bytes, big endian. + $last = $salt . pack('N', $i); + // first iteration + $last = $xorsum = hash_hmac($alg, $last, $secret, true); + // perform the other $iterations - 1 iterations + for ($j = 1; $j < $iterations; $j++) { + $xorsum ^= ($last = hash_hmac($alg, $last, $secret, true)); + } + $out .= $xorsum; + } + + if ($raw) { + return substr($out, 0, $length); + } + + return bin2hex(substr($out, 0, $length)); + } + + public static function auth() + { + if (self::$auth === null) { + self::$auth = Auth::getInstance(); + } + return self::$auth; + } + + public static function hasPermission($name) + { + return self::auth()->hasPermission($name); + } + + public static function getRestrictions($name) + { + return self::auth()->getRestrictions($name); + } + + public static function resourceIsAllowed($name) + { + if (self::$allowedResources === null) { + $restrictions = self::getRestrictions('director/resources/use'); + $list = array(); + foreach ($restrictions as $restriction) { + foreach (preg_split('/\s*,\s*/', $restriction, -1, PREG_SPLIT_NO_EMPTY) as $key) { + $list[$key] = $key; + } + } + + self::$allowedResources = $list; + } else { + $list = self::$allowedResources; + } + + if (empty($list) || array_key_exists($name, $list)) { + return true; + } + + return false; + } + + public static function enumDbResources() + { + return self::enumResources('db'); + } + + public static function enumLdapResources() + { + return self::enumResources('ldap'); + } + + protected static function enumResources($type) + { + $resources = array(); + foreach (ResourceFactory::getResourceConfigs() as $name => $resource) { + if ($resource->get('type') === $type && self::resourceIsAllowed($name)) { + $resources[$name] = $name; + } + } + + return $resources; + } + + public static function addDbResourceFormElement(QuickForm $form, $name) + { + static::addResourceFormElement($form, $name, 'db'); + } + + public static function addLdapResourceFormElement(QuickForm $form, $name) + { + static::addResourceFormElement($form, $name, 'ldap'); + } + + protected static function addResourceFormElement(QuickForm $form, $name, $type) + { + $list = self::enumResources($type); + + $form->addElement('select', $name, array( + 'label' => 'Resource name', + 'multiOptions' => $form->optionalEnum($list), + 'required' => true, + )); + + if (empty($list)) { + if (self::hasPermission('config/application/resources')) { + $form->addHtmlHint(Html::sprintf( + $form->translate('Please click %s to create new resources'), + Link::create( + $form->translate('here'), + 'config/resource', + null, + ['data-base-target' => '_main'] + ) + )); + $msg = sprintf($form->translate('No %s resource available'), $type); + } else { + $msg = $form->translate('Please ask an administrator to grant you access to resources'); + } + + $form->getElement($name)->addError($msg); + } + } +} |