AuthenticationManager   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 63
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 6
eloc 29
dl 0
loc 63
ccs 0
cts 25
cp 0
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A authenticate() 0 34 5
A __construct() 0 9 1
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 * ACC Development Team. Please see team.json for a list of contributors.     *
5
 *                                                                            *
6
 * This is free and unencumbered software released into the public domain.    *
7
 * Please see LICENSE.md for the full licencing statement.                    *
8
 ******************************************************************************/
9
10
namespace Waca\Security;
11
12
use PDO;
13
use Waca\DataObjects\User;
14
use Waca\Helpers\HttpHelper;
15
use Waca\PdoDatabase;
16
use Waca\Security\CredentialProviders\ICredentialProvider;
17
use Waca\Security\CredentialProviders\PasswordCredentialProvider;
18
use Waca\Security\CredentialProviders\ScratchTokenCredentialProvider;
19
use Waca\Security\CredentialProviders\TotpCredentialProvider;
20
use Waca\Security\CredentialProviders\YubikeyOtpCredentialProvider;
21
use Waca\SiteConfiguration;
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->database = $database;
50
    }
51
52
    public function authenticate(User $user, $data, $stage)
53
    {
54
        $sql = 'SELECT type FROM credential WHERE user = :user AND factor = :stage AND disabled = 0 ORDER BY priority ASC';
55
        $statement = $this->database->prepare($sql);
56
        $statement->execute(array(':user' => $user->getId(), ':stage' => $stage));
57
        $options = $statement->fetchAll(PDO::FETCH_COLUMN);
58
59
        $sql = 'SELECT count(DISTINCT factor) FROM credential WHERE user = :user AND factor > :stage AND disabled = 0 AND type <> :scratch';
60
        $statement = $this->database->prepare($sql);
61
        $statement->execute(array(':user' => $user->getId(), ':stage' => $stage, ':scratch' => 'scratch'));
62
        $requiredFactors = $statement->fetchColumn();
63
64
        // prep the correct OK response based on how many factors are ahead of this one
65
        $success = self::AUTH_OK;
66
        if ($requiredFactors > 0) {
67
            $success = self::AUTH_REQUIRE_NEXT_STAGE;
68
        }
69
70
        foreach ($options as $type) {
71
            if (!isset($this->typeMap[$type])) {
72
                // does this type have a credentialProvider registered?
73
                continue;
74
            }
75
76
            /** @var ICredentialProvider $credentialProvider */
77
            $credentialProvider = $this->typeMap[$type];
78
            if ($credentialProvider->authenticate($user, $data)) {
79
                return $success;
80
            }
81
        }
82
83
        // We've iterated over all the available providers for this stage.
84
        // They all hate you.
85
        return self::AUTH_FAIL;
86
    }
87
}