Passed
Push — master ( 05a7c1...0aa220 )
by Simon
01:55
created

YubikeyMemberAuthenticator::updateMember()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 4
nop 2
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Firesphere\YubiAuth\Authenticators;
4
5
use Firesphere\BootstrapMFA\Authenticators\BootstrapMFAAuthenticator;
6
use Firesphere\BootstrapMFA\Handlers\BootstrapMFALoginHandler;
0 ignored issues
show
Bug introduced by
The type Firesphere\BootstrapMFA\...ootstrapMFALoginHandler 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...
7
use Firesphere\YubiAuth\Handlers\YubikeyLoginHandler;
8
use Firesphere\YubiAuth\Providers\YubikeyAuthProvider;
9
use SilverStripe\Control\HTTPRequest;
10
use SilverStripe\Core\Injector\Injector;
11
use SilverStripe\ORM\ValidationException;
12
use SilverStripe\ORM\ValidationResult;
13
use SilverStripe\Security\Authenticator;
14
use SilverStripe\Security\Member;
15
use SilverStripe\Security\MemberAuthenticator\LoginHandler;
16
use Yubikey\Validate;
17
18
/**
19
 * Class YubikeyAuthenticator
20
 *
21
 * Enable Yubikey Authentication for SilverStripe CMS and member-protected pages.
22
 */
23
class YubikeyMemberAuthenticator extends BootstrapMFAAuthenticator
24
{
25
26
    /**
27
     * @var Validate
28
     */
29
    protected $yubiService;
30
31
    /**
32
     * @var YubikeyAuthProvider
33
     */
34
    protected $provider;
35
36
    /**
37
     * @var string
38
     */
39
    private $authenticatorName = 'yubiauth';
0 ignored issues
show
introduced by
The private property $authenticatorName is not used, and could be removed.
Loading history...
40
41
    /**
42
     * Set the provider to a YubikeyAuthProvider instance
43
     *
44
     * YubikeyMemberAuthenticator constructor.
45
     */
46
    public function __construct()
47
    {
48
        if (!$this->provider) {
49
            $this->provider = Injector::inst()->get(YubikeyAuthProvider::class);
50
        }
51
    }
52
53
    /**
54
     * Name of this authenticator
55
     *
56
     * @return string
57
     */
58
    public static function get_name()
59
    {
60
        return _t(self::class . '.TITLE', 'Yubikey 2 factor login');
61
    }
62
63
    /**
64
     * @return YubikeyAuthProvider
65
     */
66
    public function getProvider()
67
    {
68
        return $this->provider;
69
    }
70
71
    /**
72
     * @param YubikeyAuthProvider $provider
73
     * @return $this
74
     */
75
    public function setProvider($provider)
76
    {
77
        $this->provider = $provider;
78
79
        return $this;
80
    }
81
82
    /**
83
     * @return int
84
     */
85
    public function supportedServices()
86
    {
87
        // Bitwise-OR of all the supported services in this Authenticator, to make a bitmask
88
        return Authenticator::LOGIN | Authenticator::LOGOUT | Authenticator::CHANGE_PASSWORD
89
            | Authenticator::RESET_PASSWORD | Authenticator::CHECK_PASSWORD;
90
    }
91
92
    /**
93
     * @inheritdoc
94
     *
95
     * @param array $data
96
     * @param HTTPRequest $request
97
     * @param ValidationResult $validationResult
98
     *
99
     * @return ValidationResult|Member
100
     * @throws ValidationException
101
     */
102
    public function validateToken($data, $request, &$validationResult = null)
103
    {
104
        if (!$validationResult instanceof ValidationResult) {
105
            $validationResult = ValidationResult::create();
106
        }
107
108
        $memberID = $request->getSession()->get(BootstrapMFALoginHandler::SESSION_KEY . '.MemberID');
109
        // First, let's see if we know the member
110
        /** @var Member|null $member */
111
        $member = Member::get()->filter(['ID' => $memberID])->first();
112
113
        // Continue if we have a valid member
114
        if ($member instanceof Member) {
115
116
            // We do not have to check the YubiAuth for this situation.
117
            if (!$member->MFAEnabled && empty($data['yubiauth'])) {
118
                return $this->authenticateNoYubikey($member);
119
            }
120
121
            // If we know the member, and it's YubiAuth enabled, continue.
122
            $member = $this->provider->checkYubikey($data, $member, $validationResult);
123
        }
124
125
        $validationResult->addError(_t(self::class . '.MEMBERNOTFOUND', 'Could not identify member'));
126
127
        return $member;
128
    }
129
130
    /**
131
     * Handle login if the user did not enter a Yubikey string.
132
     * Will break out and return NULL if the member should use their Yubikey
133
     *
134
     * @param  Member $member
135
     * @return ValidationResult|Member
136
     * @throws ValidationException
137
     */
138
    private function authenticateNoYubikey($member)
139
    {
140
        ++$member->NoYubikeyCount;
141
        $member->write();
142
        $yubiAuthNoYubi = $this->provider->checkNoYubiAttempts($member);
143
        if ($yubiAuthNoYubi instanceof ValidationResult) {
144
            return $yubiAuthNoYubi;
145
        }
146
147
        return $member;
148
    }
149
150
    /**
151
     * @param string $link
152
     * @return LoginHandler|static
153
     */
154
    public function getLoginHandler($link)
155
    {
156
        return YubikeyLoginHandler::create($link, $this);
157
    }
158
}
159