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