Completed
Push — master ( 61569d...e55815 )
by Raffael
01:45
created

Ldap::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
declare(strict_types = 1);
3
4
/**
5
 * Micro
6
 *
7
 * @author      Raffael Sahli <[email protected]>
8
 * @copyright   Copryright (c) 2017 gyselroth GmbH (https://gyselroth.com)
9
 * @license     MIT https://opensource.org/licenses/MIT
10
 */
11
12
namespace Micro\Auth\Adapter\Basic;
13
14
use \Micro\Auth\Exception;
15
use \Psr\Log\LoggerInterface as Logger;
16
use \Micro\Ldap as LdapServer;
17
use \Micro\Auth\Adapter\AdapterInterface;
18
use \Micro\Auth\Adapter\AbstractAdapter;
19
20
class Ldap extends AbstractAdapter
21
{
22
    /**
23
     * Ldap
24
     *
25
     * @var LdapServer
26
     */
27
    protected $ldap;
28
29
30
    /**
31
     * LDAP DN
32
     *
33
     * @var string
34
     */
35
    protected $ldap_dn;
36
37
38
    /**
39
     * my account filter
40
     *
41
     * @var string
42
     */
43
    protected $account_filter = '(uid=%s)';
44
    
45
46
    /**
47
     * Set options
48
     *
49
     * @param   Iterable $config
50
     * @return  AdapterInterface
51
     */
52
    public function setOptions(? Iterable $config = null) : AdapterInterface
53
    {
54
        if ($config === null) {
55
            return $this;
56
        }
57
        
58
        foreach ($config as $option => $value) {
59
            switch ($option) {
60
                case 'ldap':
61
                    $this->ldap = new LdapServer($value, $this->logger);
62
                break;
63
                
64
                case 'account_filter':
65
                    $this->account_filter = $value;
66
                break;
67
            }
68
        }
69
        
70
        if (!isset($config['ldap'])) {
71
            $this->ldap = new LdapServer();
0 ignored issues
show
Bug introduced by
The call to Ldap::__construct() misses some required arguments starting with $config.
Loading history...
72
        }
73
74
        return parent::setOptions($config);
75
    }
76
    
77
78
    /**
79
     * Authenticate
80
     *
81
     * @return bool
82
     */
83
    public function authenticate(): bool
84
    {
85
        if (!isset($_SERVER['HTTP_AUTHORIZATION'])) {
86
            $this->logger->debug('skip auth adapter ['.get_class($this).'], no http authorization header found', [
87
                'category' => get_class($this)
88
            ]);
89
        
90
            return false;
91
        }
92
93
        $header = $_SERVER['HTTP_AUTHORIZATION'];
94
        $parts  = explode(' ', $header);
95
        
96
        if ($parts[0] == 'Basic') {
97
            $this->logger->debug('found http basic authorization header', [
98
                'category' => get_class($this)
99
            ]);
100
101
            $username = $_SERVER['PHP_AUTH_USER'];
102
            $password = $_SERVER['PHP_AUTH_PW'];
103
104
            return $this->plainAuth($username, $password);
105
        } else {
106
            $this->logger->warning('http authorization header contains no basic string or invalid authentication string', [
107
                'category' => get_class($this)
108
            ]);
109
        
110
            return false;
111
        }
112
    }
113
114
115
    /**
116
     * LDAP Auth
117
     *
118
     * @param   string $username
119
     * @param   string $password
120
     * @return  bool
121
     */
122
    protected function plainAuth(string $username, string $password): bool
123
    {
124
        $this->ldap->connect();
125
        $resource = $this->ldap->getResource();
126
127
        $esc_username = ldap_escape($username);
128
        $filter       = htmlspecialchars_decode(sprintf($this->account_filter, $esc_username));
129
        $result       = ldap_search($resource, $this->ldap->getBase(), $filter, ['dn']);
130
        $entries      = ldap_get_entries($resource, $result);
131
132
        if ($entries['count'] === 0) {
133
            $this->logger->warning("user not found with ldap filter [{$filter}]", [
134
                'category' => get_class($this)
135
            ]);
136
137
            return false;
138
        } elseif ($entries['count'] > 1) {
139
            $this->logger->warning("more than one user found with ldap filter [{$filter}]", [
140
                'category' => get_class($this)
141
            ]);
142
143
            return false;
144
        }
145
146
        $dn = $entries[0]['dn'];
147
        $this->logger->info("found ldap user [{$dn}] with filter [{$filter}]", [
148
            'category' => get_class($this)
149
        ]);
150
151
        $result = ldap_bind($resource, $dn, $password);
152
        $this->logger->info("bind ldap user [{$dn}]", [
153
            'category' => get_class($this),
154
            'result'   => $result
155
        ]);
156
157
        if ($result === false) {
158
            return false;
159
        }
160
161
        $this->identifier  = $username;
162
        $this->ldap_dn     = $dn;
163
164
        return true;
165
    }
166
167
    
168
    /**
169
     * Get attributes
170
     *
171
     * @return array
172
     */
173
    public function getAttributes(): array
174
    {
175
        $search = [];
176
        foreach ($this->map as $attr => $value) {
177
            $search[] = $value['attr'];
178
        }
179
180
        $result     = ldap_read($this->ldap->getResource(), $this->ldap_dn, '(objectClass=*)', $search);
181
        $entries    = ldap_get_entries($this->ldap->getResource(), $result);
182
        $attributes = $entries[0];
183
184
        $this->logger->info("get ldap user [{$this->ldap_dn}] attributes", [
185
            'category' => get_class($this),
186
            'params'   => $attributes,
187
        ]);
188
189
        return $attributes;
190
    }
191
}
192