Passed
Pull Request — master (#13)
by Simon
02:00
created

YubikeyAuthProvider   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 17
dl 0
loc 149
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 20 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
        Debug::dump($maxNoYubi);
45
        Debug::dump($member->NoYubikeyCount);
46
        if ($maxNoYubi > 0 && $maxNoYubi <= $member->NoYubikeyCount) {
47
            $validationResult = ValidationResult::create();
48
            $validationResult->addError(
49
                _t(
50
                    'YubikeyAuthenticator.ERRORMAXYUBIKEY',
51
                    'Maximum login without yubikey exceeded'
52
                )
53
            );
54
55
            $member->registerFailedLogin();
56
57
            return $validationResult;
58
        }
59
60
        return $member;
61
    }
62
63
    /**
64
     * Check if the member is allowed login after so many days of not using a yubikey
65
     *
66
     * @param  Member $member
67
     * @return ValidationResult|Member
68
     */
69
    public function checkNoYubiDays(Member $member)
70
    {
71
        $date1 = new DateTime($member->Created);
72
        $date2 = new DateTime(date('Y-m-d'));
73
74
        $diff = $date2->diff($date1)->format("%a");
75
        $maxNoYubiDays = static::config()->get('MaxNoYubiLoginDays');
76
77
        if ($maxNoYubiDays > 0 && $diff >= $maxNoYubiDays) {
78
            $validationResult = ValidationResult::create();
79
            $validationResult->addError(
80
                _t(
81
                    'YubikeyAuthenticator.ERRORMAXYUBIKEYDAYS',
82
                    'Maximum days without yubikey exceeded'
83
                )
84
            );
85
            $member->registerFailedLogin();
86
87
            return $validationResult;
88
        }
89
90
        return $member;
91
    }
92
93
    /**
94
     * Check if the yubikey is unique and linked to the member trying to logon
95
     *
96
     * @param  Member $member
97
     * @param  string $yubiFingerprint
98
     * @return ValidationResult
99
     */
100
    public function validateYubikey(Member $member, $yubiFingerprint)
101
    {
102
        /** @var DataList|Member[] $yubikeyMembers */
103
        $yubikeyMembers = Member::get()->filter(['Yubikey' => $yubiFingerprint]);
104
105
        /** @var ValidationResult $validationResult */
106
        $validationResult = ValidationResult::create();
107
108
        $this->validateMemberCount($member, $yubikeyMembers, $validationResult);
109
        // Yubikeys have a unique fingerprint, if we find a different member with this yubikey ID, something's wrong
110
        $this->validateMemberID($member, $yubikeyMembers, $validationResult);
111
112
        // If the member has a yubikey ID set, compare it to the fingerprint.
113
        $this->validateFingerprint($member, $yubiFingerprint, $validationResult);
114
115
116
        return $validationResult;
117
    }
118
119
    /**
120
     * @param Member $member
121
     * @param DataList|Member[] $yubikeyMembers
122
     * @param ValidationResult $validationResult
123
     */
124
    protected function validateMemberCount(
125
        Member $member,
126
        DataList $yubikeyMembers,
127
        ValidationResult &$validationResult
128
    ) {
129
        if ($yubikeyMembers->count() > 1) {
130
            $validationResult->addError(
131
                _t(
132
                    'YubikeyAuthenticator.DUPLICATE',
133
                    'Yubikey is duplicate, contact your administrator as soon as possible!'
134
                )
135
            );
136
            $member->registerFailedLogin();
137
        }
138
    }
139
140
    /**
141
     * @param Member $member
142
     * @param DataList|Member[] $yubikeyMembers
143
     * @param ValidationResult $validationResult
144
     */
145
    protected function validateMemberID(Member $member, DataList $yubikeyMembers, ValidationResult &$validationResult)
146
    {
147
        if (!$yubikeyMembers->count() || $yubikeyMembers->first()->ID !== $member->ID) {
148
            $validationResult->addError(_t('YubikeyAuthenticator.NOMATCH', 'Yubikey does not match found member'));
149
            $member->registerFailedLogin();
150
        }
151
    }
152
153
    /**
154
     * @param Member $member
155
     * @param string $fingerPrint
156
     * @param ValidationResult $validationResult
157
     */
158
    protected function validateFingerprint(Member $member, string $fingerPrint, ValidationResult &$validationResult)
159
    {
160
        if ($member->Yubikey && strpos($fingerPrint, $member->Yubikey) !== 0) {
161
            $member->registerFailedLogin();
162
            $validationResult->addError(
163
                _t(
164
                    'YubikeyAuthenticator.NOMATCH',
165
                    'Yubikey fingerprint does not match found member'
166
                )
167
            );
168
        }
169
    }
170
}
171