Passed
Push — master ( cfbdd1...c907d1 )
by Raffael
02:11
created

Auth::getDefaultAdapter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

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