xref: /plugin/pureldap/classes/Client.php (revision da369b609d5f1a6e3171c07a63f5639762ea4ab3)
1<?php
2
3namespace dokuwiki\plugin\pureldap\classes;
4
5use FreeDSx\Ldap\Entry\Attribute;
6use FreeDSx\Ldap\Exception\BindException;
7use FreeDSx\Ldap\Exception\ConnectionException;
8use FreeDSx\Ldap\Exception\OperationException;
9use FreeDSx\Ldap\LdapClient;
10
11require_once __DIR__ . '/../vendor/autoload.php';
12
13abstract class Client
14{
15    /** @var array the configuration */
16    protected $config;
17
18    /** @var LdapClient */
19    protected $ldap;
20
21    /** @var bool is this client authenticated already? */
22    protected $isAuthenticated = false;
23
24    /** @var array cached user info */
25    protected $userCache = [];
26
27    /** @var array cached group list */
28    protected $groupCache = [];
29
30    /**
31     * Client constructor.
32     * @param array $config
33     */
34    public function __construct($config)
35    {
36        $this->config = $this->prepareConfig($config);
37        $this->ldap = new LdapClient($this->config);
38    }
39
40    /**
41     * Setup sane config defaults
42     *
43     * @param array $config
44     * @return array
45     */
46    protected function prepareConfig($config)
47    {
48        $defaults = [
49            'defaultgroup' => 'user', // we expect this to be passed from global conf
50            'use_tls' => false,
51            'use_ssl' => false,
52            'port' => '',
53            'admin_username' => '',
54            'admin_password' => '',
55            'page_size' => 1000,
56        ];
57
58        $config = array_merge($defaults, $config);
59
60        // default port depends on SSL setting
61        if (!$config['port']) {
62            $config['port'] = $config['use_ssl'] ? 636 : 389;
63        }
64
65        return $config;
66    }
67
68    /**
69     * Authenticate as admin
70     */
71    public function autoAuth()
72    {
73        if ($this->isAuthenticated) return true;
74        return $this->authenticate($this->config['admin_username'], $this->config['admin_password']);
75    }
76
77    /**
78     * Authenticates a given user. This client will remain authenticated
79     *
80     * @param string $user
81     * @param string $pass
82     * @return bool was the authentication successful?
83     * @noinspection PhpRedundantCatchClauseInspection
84     */
85    public function authenticate($user, $pass)
86    {
87        if ($this->config['use_tls']) {
88            try {
89                $this->ldap->startTls();
90            } catch (OperationException $e) {
91                $this->fatal($e);
92            }
93        }
94
95        try {
96            $this->ldap->bind($user, $pass);
97        } catch (BindException $e) {
98            return false;
99        } catch (ConnectionException $e) {
100            $this->fatal($e);
101            return false;
102        } catch (OperationException $e) {
103            $this->fatal($e);
104            return false;
105        }
106
107        $this->isAuthenticated = true;
108        return true;
109    }
110
111    /**
112     * Get info for a single user, use cache if available
113     *
114     * @param string $username
115     * @param bool $fetchgroups Are groups needed?
116     * @return array|null
117     */
118    public function getCachedUser($username, $fetchgroups = true)
119    {
120        if (isset($this->userCache[$username])) {
121            if (!$fetchgroups || is_array($this->userCache[$username]['grps'])) {
122                return $this->userCache[$username];
123            }
124        }
125
126        // fetch fresh data
127        $info = $this->getUser($username, $fetchgroups);
128
129        // store in cache
130        if ($info !== null) {
131            $this->userCache[$username] = $info;
132        }
133
134        return $info;
135    }
136
137    /**
138     * Fetch a single user
139     *
140     * @param string $username
141     * @param bool $fetchgroups Shall groups be fetched, too?
142     * @return null|array
143     */
144    abstract public function getUser($username, $fetchgroups = true);
145
146    /**
147     * Return a list of all available groups, use cache if available
148     *
149     * @return string[]
150     */
151    public function getCachedGroups()
152    {
153        if (empty($this->groupCache)) {
154            $this->groupCache = $this->getGroups();
155        }
156
157        return $this->groupCache;
158    }
159
160    /**
161     * Return a list of all available groups
162     *
163     * @return string[]
164     */
165    abstract public function getGroups();
166
167    /**
168     * Helper method to get the first value of the given attribute
169     *
170     * The given attribute may be null, an empty string is returned then
171     *
172     * @param Attribute|null $attribute
173     * @return string
174     */
175    protected function attr2str($attribute)
176    {
177        if ($attribute !== null) {
178            return $attribute->firstValue();
179        }
180        return '';
181    }
182
183    /**
184     * Handle fatal exceptions
185     *
186     * @param \Exception $e
187     */
188    protected function fatal(\Exception $e)
189    {
190        if (defined('DOKU_UNITTEST')) {
191            throw new \RuntimeException('', 0, $e);
192        }
193        msg('[pureldap] ' . hsc($e->getMessage()) . ' at ' . $e->getFile() . ':' . $e->getLine(), -1);
194    }
195
196    /**
197     * Handle debug output
198     *
199     * @param string $msg
200     * @param string $file
201     * @param int $line
202     */
203    protected function debug($msg, $file, $line)
204    {
205        msg('[pureldap] ' . hsc($msg) . ' at ' . $file . ':' . $line, 1);
206    }
207}
208