Passed
Pull Request — master (#13)
by Simon
03:37 queued 01:36
created

YubikeyAuthProvider   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 147
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 17
dl 0
loc 147
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A checkNoYubiAttempts() 0 8 2
A validateMemberID() 0 5 3
A validateFingerprint() 0 8 3
A checkNoYubiLogins() 0 18 3
A validateMemberCount() 0 13 2
A checkNoYubiDays() 0 22 3
A validateYubikey() 0 17 1
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 YubikeyAuthProvider
13
 *
14
 * @package Firesphere\YubiAuth
15
 */
16
class YubikeyAuthProvider
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 = static::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 = static::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->validateMemberID($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(
122
        Member $member,
123
        DataList $yubikeyMembers,
124
        ValidationResult &$validationResult
125
    ) {
126
        if ($yubikeyMembers->count() > 1) {
127
            $validationResult->addError(
128
                _t(
129
                    'YubikeyAuthenticator.DUPLICATE',
130
                    'Yubikey is duplicate, contact your administrator as soon as possible!'
131
                )
132
            );
133
            $member->registerFailedLogin();
134
        }
135
    }
136
137
    /**
138
     * @param Member $member
139
     * @param DataList|Member[] $yubikeyMembers
140
     * @param ValidationResult $validationResult
141
     */
142
    protected function validateMemberID(Member $member, DataList $yubikeyMembers, ValidationResult &$validationResult)
143
    {
144
        if (!$yubikeyMembers->count() || $yubikeyMembers->first()->ID !== $member->ID) {
145
            $validationResult->addError(_t('YubikeyAuthenticator.NOMATCH', 'Yubikey does not match found member'));
146
            $member->registerFailedLogin();
147
        }
148
    }
149
150
    /**
151
     * @param Member $member
152
     * @param string $fingerPrint
153
     * @param ValidationResult $validationResult
154
     */
155
    protected function validateFingerprint(Member $member, string $fingerPrint, ValidationResult &$validationResult)
156
    {
157
        if ($member->Yubikey && strpos($fingerPrint, $member->Yubikey) !== 0) {
158
            $member->registerFailedLogin();
159
            $validationResult->addError(
160
                _t(
161
                    'YubikeyAuthenticator.NOMATCH',
162
                    'Yubikey fingerprint does not match found member'
163
                )
164
            );
165
        }
166
    }
167
}
168