Passed
Pull Request — master (#13)
by Simon
01:54
created

YubiAuthProvider::validateMember()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 2
nop 3
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Firesphere\YubiAuth\Providers;
4
5
use DateTime;
6
use SilverStripe\Core\Config\Configurable;
7
use SilverStripe\ORM\DataList;
8
use SilverStripe\ORM\ValidationResult;
9
use SilverStripe\Security\Member;
10
11
/**
12
 * Class YubiAuthProvider
13
 *
14
 * @package Firesphere\YubiAuth
15
 */
16
class YubiAuthProvider
17
{
18
    use Configurable;
19
20
    /**
21
     * @param Member $member
22
     * @return ValidationResult|Member
23
     */
24
    public function checkNoYubiAttempts(Member $member)
25
    {
26
        $noYubiLogins = $this->checkNoYubiLogins($member);
27
        if ($noYubiLogins instanceof Member) {
28
            return $this->checkNoYubiDays($member);
29
        }
30
31
        return $noYubiLogins;
32
    }
33
34
    /**
35
     * Check if a member is allowed to login without a yubikey
36
     *
37
     * @param  Member $member
38
     * @return ValidationResult|Member
39
     */
40
    public function checkNoYubiLogins(Member $member)
41
    {
42
        $maxNoYubi = $this->config()->get('MaxNoYubiLogin');
43
        if ($maxNoYubi > 0 && $maxNoYubi <= $member->NoYubikeyCount) {
44
            $validationResult = ValidationResult::create();
45
            $validationResult->addError(
46
                _t(
47
                    'YubikeyAuthenticator.ERRORMAXYUBIKEY',
48
                    'Maximum login without yubikey exceeded'
49
                )
50
            );
51
52
            $member->registerFailedLogin();
53
54
            return $validationResult;
55
        }
56
57
        return $member;
58
    }
59
60
    /**
61
     * Check if the member is allowed login after so many days of not using a yubikey
62
     *
63
     * @param  Member $member
64
     * @return ValidationResult|Member
65
     */
66
    public function checkNoYubiDays(Member $member)
67
    {
68
        $date1 = new DateTime($member->Created);
69
        $date2 = new DateTime(date('Y-m-d'));
70
71
        $diff = $date2->diff($date1)->format("%a");
72
        $maxNoYubiDays = $this->config()->get('MaxNoYubiLoginDays');
73
74
        if ($maxNoYubiDays > 0 && $diff >= $maxNoYubiDays) {
75
            $validationResult = ValidationResult::create();
76
            $validationResult->addError(
77
                _t(
78
                    'YubikeyAuthenticator.ERRORMAXYUBIKEYDAYS',
79
                    'Maximum days without yubikey exceeded'
80
                )
81
            );
82
            $member->registerFailedLogin();
83
84
            return $validationResult;
85
        }
86
87
        return $member;
88
    }
89
90
    /**
91
     * Check if the yubikey is unique and linked to the member trying to logon
92
     *
93
     * @param  Member $member
94
     * @param  string $yubiFingerprint
95
     * @return ValidationResult
96
     */
97
    public function validateYubikey(Member $member, $yubiFingerprint)
98
    {
99
        /** @var DataList|Member[] $yubikeyMembers */
100
        $yubikeyMembers = Member::get()->filter(['Yubikey' => $yubiFingerprint]);
101
102
        /** @var ValidationResult $validationResult */
103
        $validationResult = ValidationResult::create();
104
105
        $this->validateMemberCount($member, $yubikeyMembers, $validationResult);
106
        // Yubikeys have a unique fingerprint, if we find a different member with this yubikey ID, something's wrong
107
        $this->validateMember($member, $yubikeyMembers, $validationResult);
108
109
        // If the member has a yubikey ID set, compare it to the fingerprint.
110
        $this->validateFingerprint($member, $yubiFingerprint, $validationResult);
111
112
113
        return $validationResult;
114
    }
115
116
    /**
117
     * @param Member $member
118
     * @param DataList|Member[] $yubikeyMembers
119
     * @param ValidationResult $validationResult
120
     */
121
    protected function validateMemberCount(Member $member, DataList $yubikeyMembers, ValidationResult &$validationResult)
122
    {
123
        if ($yubikeyMembers->count() > 1) {
124
            $validationResult->addError(
125
                _t(
126
                    'YubikeyAuthenticator.DUPLICATE',
127
                    'Yubikey is duplicate, contact your administrator as soon as possible!'
128
                )
129
            );
130
            $member->registerFailedLogin();
131
        }
132
    }
133
134
    /**
135
     * @param Member $member
136
     * @param DataList|Member[] $yubikeyMembers
137
     * @param ValidationResult $validationResult
138
     */
139
    protected function validateMember(Member $member, DataList $yubikeyMembers, ValidationResult &$validationResult)
140
    {
141
        if (!$yubikeyMembers->count() || $yubikeyMembers->first()->ID !== $member->ID) {
142
            $validationResult->addError(_t('YubikeyAuthenticator.NOMATCH', 'Yubikey does not match found member'));
143
            $member->registerFailedLogin();
144
        }
145
    }
146
147
    /**
148
     * @param Member $member
149
     * @param string $fingerPrint
150
     * @param ValidationResult $validationResult
151
     */
152
    protected function validateFingerprint(Member $member, string $fingerPrint, ValidationResult &$validationResult)
153
    {
154
        if ($member->Yubikey && strpos($fingerPrint, $member->Yubikey) !== 0) {
155
            $member->registerFailedLogin();
156
            $validationResult->addError(
157
                _t(
158
                    'YubikeyAuthenticator.NOMATCH',
159
                    'Yubikey fingerprint does not match found member'
160
                )
161
            );
162
        }
163
    }
164
}
165