Passed
Push — 4.1.1 ( 01ed8a )
by Robbie
09:45
created

testBasicAuthDoesntCallActionOrFurtherInitOnAuthFailure()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 0
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Security\Tests;
4
5
use SilverStripe\Core\Injector\Injector;
6
use SilverStripe\Security\BasicAuth;
7
use SilverStripe\Security\BasicAuthMiddleware;
8
use SilverStripe\Security\Member;
9
use SilverStripe\Security\Security;
10
use SilverStripe\Dev\FunctionalTest;
11
use SilverStripe\Control\Director;
12
use SilverStripe\Security\Tests\BasicAuthTest\ControllerNotSecured;
13
use SilverStripe\Security\Tests\BasicAuthTest\ControllerSecuredWithoutPermission;
14
use SilverStripe\Security\Tests\BasicAuthTest\ControllerSecuredWithPermission;
15
16
/**
17
 * @skipUpgrade
18
 */
19
class BasicAuthTest extends FunctionalTest
20
{
21
    protected static $fixture_file = 'BasicAuthTest.yml';
22
23
    protected static $extra_controllers = [
24
        ControllerSecuredWithPermission::class,
25
        ControllerSecuredWithoutPermission::class,
26
        ControllerNotSecured::class,
27
    ];
28
29
    protected function setUp()
30
    {
31
        parent::setUp();
32
33
        // Fixtures assume Email is the field used to identify the log in identity
34
        Member::config()->set('unique_identifier_field', 'Email');
35
        Security::force_database_is_ready(true); // Prevents Member test subclasses breaking ready test
36
        Member::config()->set('lock_out_after_incorrect_logins', 10);
37
38
        // Temp disable is_cli() exemption for tests
39
        BasicAuth::config()->set('ignore_cli', false);
40
41
        // Set route-specific permissions
42
        /** @var BasicAuthMiddleware $middleware */
43
        $middleware = Injector::inst()->get(BasicAuthMiddleware::class);
44
        $middleware->setURLPatterns([
45
            '/^BasicAuthTest_ControllerSecuredWithPermission$/' => 'MYCODE',
46
            '/^BasicAuthTest_ControllerSecuredWithoutPermission$/' => true,
47
        ]);
48
    }
49
50
    public function testBasicAuthEnabledWithoutLogin()
51
    {
52
        $response = Director::test('BasicAuthTest_ControllerSecuredWithPermission');
53
        $this->assertEquals(401, $response->getStatusCode());
54
    }
55
56
    public function testBasicAuthEnabledWithPermission()
57
    {
58
        $headers = [
59
            'PHP_AUTH_USER' => '[email protected]',
60
            'PHP_AUTH_PW' => 'wrongpassword',
61
        ];
62
        $response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', [], [], null, null, $headers);
63
        $this->assertEquals(401, $response->getStatusCode(), 'Invalid users dont have access');
64
65
        $headers = [
66
            'PHP_AUTH_USER' => '[email protected]',
67
            'PHP_AUTH_PW' => 'test',
68
        ];
69
        $response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', [], [], null, null, $headers);
70
        $this->assertEquals(401, $response->getStatusCode(), 'Valid user without required permission has no access');
71
72
        $headers = [
73
            'PHP_AUTH_USER' => '[email protected]',
74
            'PHP_AUTH_PW' => 'test',
75
        ];
76
        $response = Director::test('BasicAuthTest_ControllerSecuredWithPermission', [], [], null, null, $headers);
77
        $this->assertEquals(200, $response->getStatusCode(), 'Valid user with required permission has access');
78
    }
79
80
    public function testBasicAuthEnabledWithoutPermission()
81
    {
82
        $headers = [
83
            'PHP_AUTH_USER' => '[email protected]',
84
            'PHP_AUTH_PW' => 'wrongpassword',
85
        ];
86
        $response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', [], [], null, null, $headers);
87
        $this->assertEquals(401, $response->getStatusCode(), 'Invalid users dont have access');
88
89
        $headers = [
90
            'PHP_AUTH_USER' => '[email protected]',
91
            'PHP_AUTH_PW' => 'test',
92
        ];
93
        $response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', [], [], null, null, $headers);
94
        $this->assertEquals(200, $response->getStatusCode(), 'All valid users have access');
95
96
        $headers = [
97
            'PHP_AUTH_USER' => '[email protected]',
98
            'PHP_AUTH_PW' => 'test',
99
        ];
100
        $response = Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', [], [], null, null, $headers);
101
        $this->assertEquals(200, $response->getStatusCode(), 'All valid users have access');
102
    }
103
104
    public function testBasicAuthFailureIncreasesFailedLoginCount()
105
    {
106
        // Prior to login
107
        $check = Member::get()->filter('Email', '[email protected]')->first();
108
        $this->assertEquals(0, $check->FailedLoginCount);
0 ignored issues
show
Bug Best Practice introduced by
The property FailedLoginCount does not exist on SilverStripe\ORM\DataObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
109
110
        // First failed attempt
111
        $headers = [
112
            'PHP_AUTH_USER' => '[email protected]',
113
            'PHP_AUTH_PW' => 'test',
114
        ];
115
        Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', [], [], null, null, $headers);
116
        $check = Member::get()->filter('Email', '[email protected]')->first();
117
        $this->assertEquals(1, $check->FailedLoginCount);
118
119
        // Second failed attempt
120
        $headers['PHP_AUTH_PW'] = 'testwrong';
121
        Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', [], [], null, null, $headers);
122
        $check = Member::get()->filter('Email', '[email protected]')->first();
123
        $this->assertEquals(2, $check->FailedLoginCount);
124
125
        // successful basic auth should reset failed login count
126
        $headers['PHP_AUTH_PW'] = 'Password';
127
        Director::test('BasicAuthTest_ControllerSecuredWithoutPermission', [], [], null, null, $headers);
128
        $check = Member::get()->filter('Email', '[email protected]')->first();
129
        $this->assertEquals(0, $check->FailedLoginCount);
130
    }
131
132
    public function testProtectEntireSite()
133
    {
134
        // Unsecured controller allows access
135
        $response = Director::test('BasicAuthTest_ControllerNotSecured');
136
        $this->assertEquals(200, $response->getStatusCode());
137
138
        // Globally enable basic auth
139
        BasicAuth::protect_entire_site();
140
        $response = Director::test('BasicAuthTest_ControllerNotSecured');
141
        $this->assertEquals(401, $response->getStatusCode());
142
        $this->assertNotEmpty($response->getHeader('WWW-Authenticate'));
143
144
        // Can be excluded via rule
145
        /** @var BasicAuthMiddleware $middleware */
146
        $middleware = Injector::inst()->get(BasicAuthMiddleware::class);
147
        $middleware->setURLPatterns([
148
            '/^BasicAuthTest_ControllerNotSecured$/' => false,
149
        ]);
150
        $response = Director::test('BasicAuthTest_ControllerNotSecured');
151
        $this->assertEquals(200, $response->getStatusCode());
152
    }
153
}
154