Completed
Push — master ( 195e0d...04102f )
by Raffael
03:15
created

Auth::getAdapter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
c 0
b 0
f 0
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Micro
7
 *
8
 * @copyright   Copryright (c) 2015-2018 gyselroth GmbH (https://gyselroth.com)
9
 * @license     MIT https://opensource.org/licenses/MIT
10
 */
11
12
namespace Micro\Auth;
13
14
use InvalidArgumentException;
15
use Micro\Auth\Adapter\AdapterInterface;
16
use Psr\Log\LoggerInterface;
17
18
class Auth
19
{
20
    /**
21
     * Adapter.
22
     *
23
     * @var array
24
     */
25
    protected $adapter = [];
26
27
    /**
28
     * Identity.
29
     *
30
     * @var IdentityInterface
31
     */
32
    protected $identity;
33
34
    /**
35
     * Logger.
36
     *
37
     * @var LoggerInterface
38
     */
39
    protected $logger;
40
41
    /**
42
     * Identity class.
43
     *
44
     * @var string
45
     */
46
    protected $identity_class = Identity::class;
47
48
    /**
49
     * Attribute map class.
50
     *
51
     * @var string
52
     */
53
    protected $attribute_map_class = AttributeMap::class;
54
55
    /**
56
     * Initialize.
57
     *
58
     * @param LoggerInterface $logger
59
     * @param iterable        $config
60
     */
61
    public function __construct(LoggerInterface $logger, ? Iterable $config = null)
62
    {
63
        $this->logger = $logger;
64
        $this->setOptions($config);
65
    }
66
67
    /**
68
     * Set options.
69
     *
70
     * @param iterable $config
71
     *
72
     * @return Auth
73
     */
74
    public function setOptions(? Iterable $config = null): self
75
    {
76
        if (null === $config) {
77
            return $this;
78
        }
79
80
        foreach ($config as $option => $value) {
81
            switch ($option) {
82
                case 'identity_class':
83
                case 'attribute_map_class':
84
                    $this->{$option} = (string) $value;
85
86
                break;
87
                default:
88
                    throw new InvalidArgumentException('invalid option '.$option.' given');
89
            }
90
        }
91
92
        return $this;
93
    }
94
95
    /**
96
     * Check if adapter is injected.
97
     *
98
     * @param string $name
99
     *
100
     * @return bool
101
     */
102
    public function hasAdapter(string $name): bool
103
    {
104
        return isset($this->adapter[$name]);
105
    }
106
107
    /**
108
     * Inject auth adapter.
109
     *
110
     * @param AdapterInterface $adapter
111
     * @param string           $name
112
     */
113
    public function injectAdapter(AdapterInterface $adapter, ?string $name = null): self
114
    {
115
        if (null === $name) {
116
            $name = get_class($adapter);
117
        }
118
119
        $this->logger->debug('inject auth adapter ['.$name.'] of type ['.get_class($adapter).']', [
120
            'category' => get_class($this),
121
        ]);
122
123
        if ($this->hasAdapter($name)) {
124
            throw new Exception\AdapterNotUnique('auth adapter '.$name.' is already registered');
125
        }
126
127
        $this->adapter[$name] = $adapter;
128
129
        return $this;
130
    }
131
132
    /**
133
     * Get adapter.
134
     *
135
     * @param string $name
136
     *
137
     * @return AdapterInterface
138
     */
139
    public function getAdapter(string $name): AdapterInterface
140
    {
141
        if (!$this->hasAdapter($name)) {
142
            throw new Exception\AdapterNotFound('auth adapter '.$name.' is not registered');
143
        }
144
145
        return $this->adapter[$name];
146
    }
147
148
    /**
149
     * Get adapters.
150
     *
151
     * @return AdapterInterface[]
152
     */
153
    public function getAdapters(array $adapters = []): array
0 ignored issues
show
Unused Code introduced by
The parameter $adapters is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

153
    public function getAdapters(/** @scrutinizer ignore-unused */ array $adapters = []): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
154
    {
155
        if (empty($adapter)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $adapter does not exist. Did you maybe mean $adapters?
Loading history...
156
            return $this->adapter;
157
        }
158
        $list = [];
159
        foreach ($adapter as $name) {
160
            if (!$this->hasAdapter($name)) {
161
                throw new Exception\AdapterNotFound('auth adapter '.$name.' is not registered');
162
            }
163
            $list[$name] = $this->adapter[$name];
164
        }
165
166
        return $list;
167
    }
168
169
    /**
170
     * Authenticate.
171
     *
172
     * @return bool
173
     */
174
    public function requireOne(): bool
175
    {
176
        $result = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
177
178
        foreach ($this->adapter as $name => $adapter) {
179
            try {
180
                if ($adapter->authenticate()) {
181
                    $this->createIdentity($adapter);
182
183
                    $this->logger->info("identity [{$this->identity->getIdentifier()}] authenticated over adapter [{$name}]", [
184
                        'category' => get_class($this),
185
                    ]);
186
                    $_SERVER['REMOTE_USER'] = $this->identity->getIdentifier();
187
188
                    return true;
189
                }
190
            } catch (\Exception $e) {
191
                $this->logger->error('failed authenticate user, unexcepted exception was thrown', [
192
                    'category' => get_class($this),
193
                    'exception' => $e,
194
                ]);
195
            }
196
197
            $this->logger->debug("auth adapter [{$name}] failed", [
198
                'category' => get_class($this),
199
            ]);
200
        }
201
202
        $this->logger->warning('all authentication adapter have failed', [
203
            'category' => get_class($this),
204
        ]);
205
206
        return false;
207
    }
208
209
    /**
210
     * Get identity.
211
     *
212
     * @return IdentityInterface
213
     */
214
    public function getIdentity(): IdentityInterface
215
    {
216
        if (!$this->isAuthenticated()) {
217
            throw new Exception\NotAuthenticated('no valid authentication yet');
218
        }
219
220
        return $this->identity;
221
    }
222
223
    /**
224
     * Check if valid identity exists.
225
     *
226
     * @return bool
227
     */
228
    public function isAuthenticated(): bool
229
    {
230
        return $this->identity instanceof Identity;
231
    }
232
233
    /**
234
     * Create identity.
235
     *
236
     * @param AdapterInterface $adapter
237
     *
238
     * @return IdentityInterface
239
     */
240
    public function createIdentity(AdapterInterface $adapter): IdentityInterface
241
    {
242
        $map = new $this->attribute_map_class($adapter->getAttributeMap(), $this->logger);
243
        $this->identity = new $this->identity_class($adapter, $map, $this->logger);
244
245
        return $this->identity;
246
    }
247
}
248