summaryrefslogtreecommitdiffstats
path: root/library/Director/Util.php
blob: 22ad5fc9a119104cfd50bc87324354c1930897af (plain)
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
<?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);
        }
    }
}