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