Test Failed
Push — newinternal ( 8c4587...b2f220 )
by Michael
15:41 queued 06:17
created

AuthenticationManager   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 64
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 6
eloc 30
c 1
b 0
f 0
dl 0
loc 64
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A authenticate() 0 34 5
A __construct() 0 10 1
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca\Security;
10
11
use PDO;
12
use Waca\DataObjects\User;
13
use Waca\Helpers\HttpHelper;
14
use Waca\PdoDatabase;
15
use Waca\Security\CredentialProviders\ICredentialProvider;
16
use Waca\Security\CredentialProviders\PasswordCredentialProvider;
17
use Waca\Security\CredentialProviders\ScratchTokenCredentialProvider;
18
use Waca\Security\CredentialProviders\TotpCredentialProvider;
19
use Waca\Security\CredentialProviders\U2FCredentialProvider;
20
use Waca\Security\CredentialProviders\YubikeyOtpCredentialProvider;
21
use Waca\SiteConfiguration;
0 ignored issues
show
Bug introduced by
The type Waca\SiteConfiguration was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
23
class AuthenticationManager
24
{
25
    const AUTH_OK = 1;
26
    const AUTH_FAIL = 2;
27
    const AUTH_REQUIRE_NEXT_STAGE = 3;
28
    private $typeMap = array();
29
    /**
30
     * @var PdoDatabase
31
     */
32
    private $database;
33
34
    /**
35
     * AuthenticationManager constructor.
36
     *
37
     * @param PdoDatabase       $database
38
     * @param SiteConfiguration $siteConfiguration
39
     * @param HttpHelper        $httpHelper
40
     */
41
    public function __construct(PdoDatabase $database, SiteConfiguration $siteConfiguration, HttpHelper $httpHelper)
42
    {
43
        // setup providers
44
        // note on type map: this *must* be the value in the database, as this is what it maps.
45
        $this->typeMap['password'] = new PasswordCredentialProvider($database, $siteConfiguration);
46
        $this->typeMap['yubikeyotp'] = new YubikeyOtpCredentialProvider($database, $siteConfiguration, $httpHelper);
47
        $this->typeMap['totp'] = new TotpCredentialProvider($database, $siteConfiguration);
48
        $this->typeMap['scratch'] = new ScratchTokenCredentialProvider($database, $siteConfiguration);
49
        $this->typeMap['u2f'] = new U2FCredentialProvider($database, $siteConfiguration);
50
        $this->database = $database;
51
    }
52
53
    public function authenticate(User $user, $data, $stage)
54
    {
55
        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority ASC';
56
        $statement = $this->database->prepare($sql);
57
        $statement->execute(array(':user' => $user->getId(), ':stage' => $stage));
58
        $options = $statement->fetchAll(PDO::FETCH_COLUMN);
59
60
        $sql = 'SELECT count(DISTINCT factor) FROM credential WHERE user = :user AND factor > :stage AND disabled = 0 AND type <> :scratch';
61
        $statement = $this->database->prepare($sql);
62
        $statement->execute(array(':user' => $user->getId(), ':stage' => $stage, ':scratch' => 'scratch'));
63
        $requiredFactors = $statement->fetchColumn();
64
65
        // prep the correct OK response based on how many factors are ahead of this one
66
        $success = self::AUTH_OK;
67
        if ($requiredFactors > 0) {
68
            $success = self::AUTH_REQUIRE_NEXT_STAGE;
69
        }
70
71
        foreach ($options as $type) {
72
            if (!isset($this->typeMap[$type])) {
73
                // does this type have a credentialProvider registered?
74
                continue;
75
            }
76
77
            /** @var ICredentialProvider $credentialProvider */
78
            $credentialProvider = $this->typeMap[$type];
79
            if ($credentialProvider->authenticate($user, $data)) {
80
                return $success;
81
            }
82
        }
83
84
        // We've iterated over all the available providers for this stage.
85
        // They all hate you.
86
        return self::AUTH_FAIL;
87
    }
88
}