Completed
Push — master ( f024a0...d4b41b )
by
unknown
07:44
created

MemberAuthenticatorTest::tearDown()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Security\Tests;
4
5
use SilverStripe\Control\Controller;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\ORM\FieldType\DBDatetime;
10
use SilverStripe\ORM\ValidationResult;
11
use SilverStripe\Security\Authenticator;
12
use SilverStripe\Security\DefaultAdminService;
13
use SilverStripe\Security\IdentityStore;
14
use SilverStripe\Security\LoginAttempt;
15
use SilverStripe\Security\Member;
16
use SilverStripe\Security\MemberAuthenticator\CMSMemberAuthenticator;
17
use SilverStripe\Security\MemberAuthenticator\CMSMemberLoginForm;
18
use SilverStripe\Security\MemberAuthenticator\MemberAuthenticator;
19
use SilverStripe\Security\MemberAuthenticator\MemberLoginForm;
20
use SilverStripe\Security\Security;
21
22
class MemberAuthenticatorTest extends SapphireTest
23
{
24
25
    protected $usesDatabase = true;
26
27
    protected $defaultUsername = null;
28
    protected $defaultPassword = null;
29
30
    protected function setUp()
31
    {
32
        parent::setUp();
33
34
        if (DefaultAdminService::hasDefaultAdmin()) {
35
            $this->defaultUsername = DefaultAdminService::getDefaultAdminUsername();
36
            $this->defaultPassword = DefaultAdminService::getDefaultAdminPassword();
37
            DefaultAdminService::clearDefaultAdmin();
38
        } else {
39
            $this->defaultUsername = null;
40
            $this->defaultPassword = null;
41
        }
42
        DefaultAdminService::clearDefaultAdmin();
43
        DefaultAdminService::setDefaultAdmin('admin', 'password');
44
    }
45
46
    protected function tearDown()
47
    {
48
        DefaultAdminService::clearDefaultAdmin();
49
        if ($this->defaultUsername) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->defaultUsername of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
50
            DefaultAdminService::setDefaultAdmin($this->defaultUsername, $this->defaultPassword);
51
        }
52
        parent::tearDown();
53
    }
54
55
    public function testCustomIdentifierField()
56
    {
57
        Member::config()->set('unique_identifier_field', 'Username');
58
59
        $label = Member::singleton()
60
            ->fieldLabel(Member::config()->get('unique_identifier_field'));
61
62
        $this->assertEquals($label, 'Username');
63
    }
64
65
    public function testGenerateLoginForm()
66
    {
67
        $authenticator = new MemberAuthenticator();
68
69
        $controller = new Security();
70
71
        // Create basic login form
72
        $frontendResponse = $authenticator
73
            ->getLoginHandler($controller->link())
74
            ->handleRequest(Controller::curr()->getRequest());
75
76
        $this->assertTrue(is_array($frontendResponse));
77
        $this->assertTrue(isset($frontendResponse['Form']));
78
        $this->assertTrue($frontendResponse['Form'] instanceof MemberLoginForm);
79
    }
80
81
    public function testGenerateCMSLoginForm()
82
    {
83
        /** @var CMSMemberAuthenticator $authenticator */
84
        $authenticator = new CMSMemberAuthenticator();
85
86
        // Supports cms login form
87
        $this->assertGreaterThan(0, ($authenticator->supportedServices() & Authenticator::CMS_LOGIN));
88
        $cmsHandler = $authenticator->getLoginHandler('/');
89
        $cmsForm = $cmsHandler->loginForm();
90
        $this->assertTrue($cmsForm instanceof CMSMemberLoginForm);
91
    }
92
93
94
    /**
95
     * Test that a member can be authenticated via their temp id
96
     */
97
    public function testAuthenticateByTempID()
98
    {
99
        $authenticator = new CMSMemberAuthenticator();
100
101
        $member = new Member();
102
        $member->Email = '[email protected]';
103
        $member->PasswordEncryption = "sha1";
104
        $member->Password = "mypassword";
105
        $member->write();
106
107
        // If the user has never logged in, then the tempid should be empty
108
        $tempID = $member->TempIDHash;
109
        $this->assertEmpty($tempID);
110
111
        // If the user logs in then they have a temp id
112
        Injector::inst()->get(IdentityStore::class)->logIn($member, true);
113
        $tempID = $member->TempIDHash;
114
        $this->assertNotEmpty($tempID);
115
116
        // Test correct login
117
        /** @var ValidationResult $message */
118
        $result = $authenticator->authenticate(
119
            [
120
            'tempid' => $tempID,
121
            'Password' => 'mypassword'
122
            ],
123
            Controller::curr()->getRequest(),
124
            $message
125
        );
126
127
        $this->assertNotEmpty($result);
128
        $this->assertEquals($result->ID, $member->ID);
129
        $this->assertTrue($message->isValid());
130
131
        // Test incorrect login
132
        $result = $authenticator->authenticate(
133
            [
134
            'tempid' => $tempID,
135
            'Password' => 'notmypassword'
136
            ],
137
            Controller::curr()->getRequest(),
138
            $message
139
        );
140
141
        $this->assertEmpty($result);
142
        $messages = $message->getMessages();
143
        $this->assertEquals(
144
            _t('SilverStripe\\Security\\Member.ERRORWRONGCRED', 'The provided details don\'t seem to be correct. Please try again.'),
145
            $messages[0]['message']
146
        );
147
    }
148
149
    /**
150
     * Test that the default admin can be authenticated
151
     */
152
    public function testDefaultAdmin()
153
    {
154
        $authenticator = new MemberAuthenticator();
155
156
        // Test correct login
157
        /** @var ValidationResult $message */
158
        $result = $authenticator->authenticate(
159
            [
160
            'Email' => 'admin',
161
            'Password' => 'password'
162
            ],
163
            Controller::curr()->getRequest(),
164
            $message
165
        );
166
        $this->assertNotEmpty($result);
167
        $this->assertEquals($result->Email, DefaultAdminService::getDefaultAdminUsername());
168
        $this->assertTrue($message->isValid());
169
170
        // Test incorrect login
171
        $result = $authenticator->authenticate(
172
            [
173
            'Email' => 'admin',
174
            'Password' => 'notmypassword'
175
            ],
176
            Controller::curr()->getRequest(),
177
            $message
178
        );
179
        $messages = $message->getMessages();
180
        $this->assertEmpty($result);
181
        $this->assertEquals(
182
            'The provided details don\'t seem to be correct. Please try again.',
183
            $messages[0]['message']
184
        );
185
    }
186
187
    public function testDefaultAdminLockOut()
188
    {
189
        $authenticator = new MemberAuthenticator();
190
191
        Config::modify()->set(Member::class, 'lock_out_after_incorrect_logins', 1);
192
        Config::modify()->set(Member::class, 'lock_out_delay_mins', 10);
193
        DBDatetime::set_mock_now('2016-04-18 00:00:00');
194
195
        // Test correct login
196
        $authenticator->authenticate(
197
            [
198
                'Email' => 'admin',
199
                'Password' => 'wrongpassword'
200
            ],
201
            Controller::curr()->getRequest()
202
        );
203
204
        $defaultAdmin = DefaultAdminService::singleton()->findOrCreateDefaultAdmin();
205
        $this->assertNotNull($defaultAdmin);
206
        $this->assertFalse($defaultAdmin->canLogin());
207
        $this->assertEquals('2016-04-18 00:10:00', $defaultAdmin->LockedOutUntil);
208
    }
209
210
    public function testNonExistantMemberGetsLoginAttemptRecorded()
211
    {
212
        Security::config()->set('login_recording', true);
213
        Member::config()
214
            ->set('lock_out_after_incorrect_logins', 1)
215
            ->set('lock_out_delay_mins', 10);
216
217
        $email = '[email protected]';
218
        $this->assertFalse(Member::get()->filter(array('Email' => $email))->exists());
219
        $this->assertCount(0, LoginAttempt::get());
220
        $authenticator = new MemberAuthenticator();
221
        $result = new ValidationResult();
222
        $member = $authenticator->authenticate(
223
            [
224
                'Email' => $email,
225
                'Password' => 'password',
226
            ],
227
            Controller::curr()->getRequest(),
228
            $result
229
        );
230
        $this->assertFalse($result->isValid());
231
        $this->assertNull($member);
232
        $this->assertCount(1, LoginAttempt::get());
233
        $attempt = LoginAttempt::get()->first();
234
        $this->assertEquals($email, $attempt->Email);
235
        $this->assertEquals(LoginAttempt::FAILURE, $attempt->Status);
236
    }
237
238
    public function testNonExistantMemberGetsLockedOut()
239
    {
240
        Security::config()->set('login_recording', true);
241
        Member::config()
242
            ->set('lock_out_after_incorrect_logins', 1)
243
            ->set('lock_out_delay_mins', 10);
244
245
        $email = '[email protected]';
246
        $this->assertFalse(Member::get()->filter(array('Email' => $email))->exists());
247
248
        $authenticator = new MemberAuthenticator();
249
        $result = new ValidationResult();
250
        $member = $authenticator->authenticate(
251
            [
252
                'Email' => $email,
253
                'Password' => 'password',
254
            ],
255
            Controller::curr()->getRequest(),
256
            $result
257
        );
258
259
        $this->assertNull($member);
260
        $this->assertFalse($result->isValid());
261
        $member = new Member();
262
        $member->Email = $email;
263
264
        $this->assertTrue($member->isLockedOut());
265
        $this->assertFalse($member->canLogIn());
266
    }
267
}
268