Completed
Push — master ( c779b6...fe1a09 )
by Raffael
02:34
created

Auth::__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 Copyright (c) 2017 gyselroth GmbH (https://gyselroth.com)
9
 * @license   MIT https://opensource.org/licenses/MIT
10
 */
11
12
namespace Micro;
13
14
use \Micro\Auth\Exception;
15
use \Micro\Auth\Adapter\AdapterInterface;
16
use \Micro\Auth\Identity;
17
use \Psr\Log\LoggerInterface as Logger;
18
use \Micro\Auth\AttributeMap;
19
use \Micro\Container\AdapterAwareInterface;
20
21
class Auth implements AdapterAwareInterface;
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ';', expecting '{'
Loading history...
22
{
23
    /**
24
     * Adapter
25
     *
26
     * @var array
27
     */
28
    protected $adapter = [];
29
30
31
    /**
32
     * Identity
33
     *
34
     * @var Identity
35
     */
36
    protected $identity;
37
38
39
    /**
40
     * Logger
41
     *
42
     * @var Logger
43
     */
44
    protected $logger;
45
46
47
    /**
48
     * Identity class
49
     *
50
     * @var string
51
     */
52
    protected $identity_class = Identity::class;
53
54
55
    /**
56
     * Attribute map class
57
     *
58
     * @var string
59
     */
60
    protected $attribute_map_class = AttributeMap::class;
61
62
63
    /**
64
     * Initialize
65
     *
66
     * @param   Logger $logger
67
     * @param   Iterable $config
68
     * @return  void
69
     */
70
    public function __construct(Logger $logger, ? Iterable $config = null)
71
    {
72
        $this->logger = $logger;
73
        $this->setOptions($config);
74
    }
75
76
77
    /**
78
     * Set options
79
     *
80
     * @param  Iterable $config
81
     * @return Auth
82
     */
83
    public function setOptions(? Iterable $config = null) : Auth
84
    {
85
        if ($config === null) {
86
            return $this;
87
        }
88
89
        foreach ($config as $option => $value) {
90
            switch ($option) {
91
                case 'identity_class':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
92
                case 'attribute_map_class':
93
                    $this->{$option} = (string)$value;
94
                break;
95
96
                case 'adapter':
97
                    foreach ($value as $name => $adapter) {
98
                        $this->injectAdapter($name, $adapter);
99
                    }
100
                break;
101
            }
102
        }
103
104
        return $this;
105
    }
106
107
108
    /**
109
     * Has adapter
110
     *
111
     * @param  string $name
112
     * @return bool
113
     */
114
    public function hasAdapter(string $name): bool
115
    {
116
        return isset($this->adapter[$name]);
117
    }
118
119
120
    /**
121
     * Inject adapter
122
     *
123
     * @param  string $name
124
     * @param  AdapterInterface $adapter
125
     * @return AdapterInterface
126
     */
127
    public function injectAdapter(string $name, AdapterInterface $adapter) : AdapterInterface
128
    {
129
        if ($this->hasAdapter($name)) {
130
            throw new Exception('auth adapter '.$name.' is already registered');
131
        }
132
133
        $this->adapter[$name] = $adapter;
134
        return $adapter;
135
    }
136
137
138
    /**
139
     * Get adapter
140
     *
141
     * @param  string $name
142
     * @return AdapterInterface
143
     */
144
    public function getAdapter(string $name): AdapterInterface
145
    {
146
        if (!$this->hasAdapter($name)) {
147
            throw new Exception('auth adapter '.$name.' is not registered');
148
        }
149
150
        return $this->adapter[$name];
151
    }
152
153
154
    /**
155
     * Get adapters
156
     *
157
     * @param  array $adapters
158
     * @return array
159
     */
160
    public function getAdapters(array $adapters = []): array
161
    {
162
        if (empty($adapter)) {
163
            return $this->adapter;
164
        } else {
165
            $list = [];
166
            foreach ($adapter as $name) {
167
                if (!$this->hasAdapter($name)) {
168
                    throw new Exception('auth adapter '.$name.' is not registered');
169
                }
170
                $list[$name] = $this->adapter[$name];
171
            }
172
173
            return $list;
174
        }
175
    }
176
177
178
    /**
179
     * Create identity
180
     *
181
     * @param  AdapterInterface $adapter
182
     * @return Identity
183
     */
184
    protected function createIdentity(AdapterInterface $adapter): Identity
185
    {
186
        $map = new $this->attribute_map_class($adapter->getAttributeMap(), $this->logger);
187
        $this->identity = new $this->identity_class($adapter, $map, $this->logger);
188
        return $this->identity;
189
    }
190
191
192
    /**
193
     * Authenticate
194
     *
195
     * @return  bool
196
     */
197
    public function requireOne(): bool
198
    {
199
        $result = false;
200
201
        foreach ($this->adapter as $name => $adapter) {
202
            try {
203
                if ($adapter->authenticate()) {
204
                    $this->createIdentity($adapter);
205
206
                    $this->logger->info("identity [{$this->identity->getIdentifier()}] authenticated over adapter [{$name}]", [
207
                        'category' => get_class($this)
208
                    ]);
209
                    $_SERVER['REMOTE_USER'] = $this->identity->getIdentifier();
210
211
                    return true;
212
                }
213
            } catch (\Exception $e) {
214
                $this->logger->error("failed authenticate user, unexcepted exception was thrown", [
215
                    'category' => get_class($this),
216
                    'exception'=> $e
217
                ]);
218
            }
219
220
            $this->logger->debug("auth adapter [{$name}] failed", [
221
                'category' => get_class($this)
222
            ]);
223
        }
224
225
        $this->logger->warning("all authentication adapter have failed", [
226
            'category' => get_class($this)
227
        ]);
228
229
        return false;
230
    }
231
232
233
    /**
234
     * Get identity
235
     *
236
     * @return Identity
237
     */
238
    public function getIdentity(): Identity
239
    {
240
        if (!$this->isAuthenticated()) {
241
            throw new Exception('no valid authentication yet');
242
        } else {
243
            return $this->identity;
244
        }
245
    }
246
247
248
    /**
249
     * Check if valid identity exists
250
     *
251
     * @return bool
252
     */
253
    public function isAuthenticated(): bool
254
    {
255
        return ($this->identity instanceof Identity);
256
    }
257
}
258