Test Failed
Push — master ( 817d84...d52e3d )
by Raffael
05:44
created

Db::setAccessToken()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 0
cts 25
cp 0
rs 9.44
c 0
b 0
f 0
cc 3
nc 4
nop 5
crap 12
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2019 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Balloon\App\Idp\Storage;
13
14
use Balloon\App\Idp\Exception\MultiFactorAuthenticationRequired;
15
use Balloon\Hook;
16
use Balloon\Server;
17
use Balloon\Server\User;
18
use Micro\Auth\Adapter\Basic\BasicInterface;
19
use Micro\Auth\Auth;
20
use MongoDB\BSON\UTCDateTime;
21
use MongoDB\Database;
22
use OAuth2\Storage\MongoDB as OAuthMongoDB;
23
use Psr\Log\LoggerInterface;
24
25
class Db extends OAuthMongoDB
26
{
27
    /**
28
     * Auth.
29
     *
30
     * @var Auth
31
     */
32
    protected $auth;
33
34
    /**
35
     * Hook.
36
     *
37
     * @var Hook
38
     */
39
    protected $hook;
40
41
    /**
42
     * Logger.
43
     *
44
     * @var LoggerInterface
45
     */
46
    protected $logger;
47
48
    /**
49
     * Server.
50
     *
51
     * @var Server
52
     */
53
    protected $server;
54
55
    /**
56
     * Last adapter.
57
     *
58
     * @var string
59
     */
60
    protected $adapter;
61
62
    /**
63
     * {@inheritdoc}
64
     */
65
    public function __construct(Database $db, Auth $auth, Hook $hook, Server $server, LoggerInterface $logger, array $config = [])
66
    {
67
        $this->server = $server;
68
        $this->auth = $auth;
69
        $this->hook = $hook;
70
        $this->logger = $logger;
71
72
        parent::__construct($db, $config);
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    public function checkUserCredentials($username, $password)
79
    {
80
        foreach ($this->auth->getAdapters() as $name => $adapter) {
81
            if ($adapter instanceof BasicInterface) {
0 ignored issues
show
Bug introduced by
The class Micro\Auth\Adapter\Basic\BasicInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
82
                try {
83
                    if ($adapter->plainAuth($username, $password) === true) {
84
                        $user = null;
85
                        $identity = $this->auth->createIdentity($adapter);
86
87
                        try {
88
                            $user = $this->server->getUserByName($username);
89
                        } catch (User\Exception\NotFound $e) {
90
                            $this->logger->warning('failed connect authenticated user, user account does not exists', [
91
                                'category' => get_class($this),
92
                            ]);
93
                        }
94
95
                        $this->hook->run('preServerIdentity', [$identity, &$user]);
96
97
                        if (!($user instanceof User)) {
98
                            throw new User\Exception\NotAuthenticated('user does not exists', User\Exception\NotAuthenticated::USER_NOT_FOUND);
99
                        }
100
101
                        if ($user->isDeleted()) {
102
                            throw new User\Exception\NotAuthenticated(
103
                                'user is disabled and can not be used',
104
                                User\Exception\NotAuthenticated::USER_DELETED
105
                            );
106
                        }
107
108
                        $this->adapter = $name;
0 ignored issues
show
Documentation Bug introduced by
It seems like $name can also be of type integer. However, the property $adapter is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
109
110
                        return true;
111
                    }
112
                } catch (MultiFactorAuthenticationRequired $e) {
113
                    throw $e;
114
                } catch (\Exception $e) {
115
                    $this->logger->error('failed authenticate user, unexcepted exception was thrown', [
116
                        'category' => get_class($this),
117
                        'exception' => $e,
118
                    ]);
119
                }
120
            }
121
        }
122
123
        return false;
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function getUser($username)
130
    {
131
        try {
132
            return $this->server->getUserByName($username)
133
                ->getAttributes();
134
        } catch (User\Exception\NotFound $e) {
135
            $this->logger->warning('failed connect authenticated user, user account does not exists', [
136
                'category' => get_class($this),
137
            ]);
138
139
            return false;
140
        }
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    public function setAccessToken($access_token, $client_id, $user_id, $expires, $scope = null)
147
    {
148
        if ($expires === 0) {
149
            $expires = null;
150
        } else {
151
            $expires = new UTCDateTime($expires * 1000);
152
        }
153
154
        $token = [
155
            'access_token' => $access_token,
156
            'client_id' => $client_id,
157
            'expires' => $expires,
158
            'user_id' => $user_id,
159
            'scope' => $scope,
160
            'adapter' => $this->adapter,
161
        ];
162
163
        if ($this->getAccessToken($access_token)) {
164
            $result = $this->collection('access_token_table')->updateOne(
165
                ['access_token' => $access_token],
166
                ['$set' => $token]
167
            );
168
169
            return $result->getMatchedCount() > 0;
170
        }
171
172
        $result = $this->collection('access_token_table')->insertOne($token);
173
174
        return $result->getInsertedCount() > 0;
175
    }
176
177
    /**
178
     * {@inheritdoc}
179
     */
180 View Code Duplication
    public function setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope = null, $id_token = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
    {
182
        if ($expires === 0) {
183
            $expires = null;
184
        } else {
185
            $expires = new UTCDateTime($expires * 1000);
186
        }
187
188
        return parent::setAuthorizationCode($code, $client_id, $user_id, $redirect_uri, $expires, $scope, $id_token);
189
    }
190
191
    /**
192
     * {@inheritdoc}
193
     */
194 View Code Duplication
    public function setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
195
    {
196
        if ($expires === 0) {
197
            $expires = null;
198
        } else {
199
            $expires = new UTCDateTime($expires * 1000);
200
        }
201
202
        return parent::setRefreshToken($refresh_token, $client_id, $user_id, $expires, $scope);
203
    }
204
205
    /**
206
     * {@inheritdoc}
207
     */
208 View Code Duplication
    public function getAccessToken($access_token)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
209
    {
210
        $token = $this->collection('access_token_table')->findOne(['access_token' => $access_token]);
211
212
        if ($token === null) {
213
            return false;
214
        }
215
216
        if ($token['expires'] !== null) {
217
            $token['expires'] = $token['expires']->toDateTime()->format('U');
218
        }
219
220
        return $token;
221
    }
222
223
    /**
224
     * {@inheritdoc}
225
     */
226 View Code Duplication
    public function getAuthorizationCode($code)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
227
    {
228
        $code = $this->collection('code_table')->findOne([
229
            'authorization_code' => $code,
230
        ]);
231
232
        if ($code === null) {
233
            return false;
234
        }
235
236
        if ($code['expires'] !== null) {
237
            $code['expires'] = $code['expires']->toDateTime()->format('U');
238
        }
239
240
        return $code;
241
    }
242
243
    /**
244
     * {@inheritdoc}
245
     */
246 View Code Duplication
    public function getRefreshToken($refresh_token)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
247
    {
248
        $token = $this->collection('refresh_token_table')->findOne(['refresh_token' => $refresh_token]);
249
250
        if ($token === null) {
251
            return false;
252
        }
253
254
        if ($token['expires'] !== null) {
255
            $token['expires'] = $token['expires']->toDateTime()->format('U');
256
        }
257
258
        return $token;
259
    }
260
}
261