Passed
Pull Request — master (#21)
by Simon
03:21
created

BootstrapMFAAuthenticator::supportedServices()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Firesphere\BootstrapMFA\Authenticators;
4
5
use Firesphere\BootstrapMFA\Handlers\BootstrapMFALoginHandler;
6
use Firesphere\BootstrapMFA\Interfaces\MFAAuthenticator;
7
use Firesphere\BootstrapMFA\Providers\BootstrapMFAProvider;
8
use SilverStripe\Control\HTTPRequest;
9
use SilverStripe\Core\Injector\Injector;
10
use SilverStripe\ORM\ValidationException;
11
use SilverStripe\ORM\ValidationResult;
12
use SilverStripe\Security\Authenticator;
13
use SilverStripe\Security\Member;
14
use SilverStripe\Security\MemberAuthenticator\MemberAuthenticator;
15
use SilverStripe\Security\PasswordEncryptor_NotFoundException;
16
17
/**
18
 * Class BootstrapMFAAuthenticator
19
 * It needs to be instantiable, therefore it can't be an Abstract.
20
 *
21
 * @package Firesphere\BootstrapMFA\Authenticators
22
 * @method getTokenField() Stub for child implementations
23
 */
24
class BootstrapMFAAuthenticator extends MemberAuthenticator implements MFAAuthenticator
25
{
26
    /**
27
     * Key for array to be stored in between steps in the session
28
     */
29
    const SESSION_KEY = 'MFALogin';
30
31
    /**
32
     * @return int
33
     */
34
    public function supportedServices()
35
    {
36
        // Bitwise-OR of all the supported services in this Authenticator, to make a bitmask
37
        return Authenticator::LOGIN | Authenticator::LOGOUT | Authenticator::CHANGE_PASSWORD
38
            | Authenticator::RESET_PASSWORD | Authenticator::CHECK_PASSWORD;
39
    }
40
41
    /**
42
     * @param Member $member
43
     * @param string $token
44
     * @param ValidationResult|null $result
45
     * @return bool|Member
46
     * @throws ValidationException
47
     * @throws PasswordEncryptor_NotFoundException
48
     */
49
    public function validateBackupCode($member, $token, &$result = null)
50
    {
51
        if (!$result) {
52
            $result = new ValidationResult();
53
        }
54
        $token = $member->encryptWithUserSettings($token);
55
56
        /** @var BootstrapMFAProvider $provider */
57
        $provider = Injector::inst()->get(BootstrapMFAProvider::class);
58
        $provider->setMember($member);
59
60
        $backupCode = $provider->fetchToken($token);
61
62
        if ($backupCode && $backupCode->exists()) {
63
            $backupCode->expire();
64
            // Reset the subclass authenticator results
65
            $result = Injector::inst()->get(ValidationResult::class, false);
66
67
            /** @var Member $member */
68
            return $member;
69
        }
70
71
        $member->registerFailedLogin();
72
        $result->addError(_t(self::class . '.INVALIDTOKEN', 'Invalid token'));
73
74
        return false;
75
    }
76
77
    /**
78
     * @param string $link
79
     * @return BootstrapMFALoginHandler|static
80
     */
81
    public function getLoginHandler($link)
82
    {
83
        return BootstrapMFALoginHandler::create($link, $this);
84
    }
85
86
    /**
87
     * This implementation should be on the subclass
88
     *
89
     * @param array $data
90
     * @param HTTPRequest $request
91
     * @param string $token
92
     * @param ValidationResult $result
93
     * @throws \LogicException
94
     */
95
    public function verifyMFA($data, $request, $token, &$result)
96
    {
97
        throw new \LogicException('No token verification implemented');
98
    }
99
100
    /**
101
     * This implementation should be on the subclass
102
     *
103
     * @param BootstrapMFALoginHandler $controller
104
     * @param string $name
105
     */
106
    public function getMFAForm($controller, $name)
107
    {
108
        throw new \LogicException('No MFA Form implementation found');
109
    }
110
}
111