Completed
Push — master ( 20efb0...a2cc06 )
by Hamish
29s
created

testNoLegacyPasswordHashMigrationOnIncompatibleAlgorithm()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 19
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 25
rs 8.8571
1
<?php
2
3
use SilverStripe\ORM\DataObject;
4
use SilverStripe\ORM\FieldType\DBDatetime;
5
use SilverStripe\Security\Security;
6
use SilverStripe\Security\Member;
7
use SilverStripe\Security\MemberAuthenticator;
8
use SilverStripe\Security\MemberLoginForm;
9
use SilverStripe\Security\CMSMemberLoginForm;
10
11
/**
12
 * @package framework
13
 * @subpackage tests
14
 */
15
class MemberAuthenticatorTest extends SapphireTest {
16
17
	protected $usesDatabase = true;
18
19
	protected $defaultUsername = null;
20
	protected $defaultPassword = null;
21
22
	public function setUp() {
23
		parent::setUp();
24
25
		$this->defaultUsername = Security::default_admin_username();
26
		$this->defaultPassword = Security::default_admin_password();
27
		Security::clear_default_admin();
28
		Security::setDefaultAdmin('admin', 'password');
29
	}
30
31
	public function tearDown() {
32
		Security::setDefaultAdmin($this->defaultUsername, $this->defaultPassword);
33
		parent::tearDown();
34
	}
35
36
	public function testLegacyPasswordHashMigrationUponLogin() {
37
		$member = new Member();
38
39
		$field=Member::config()->unique_identifier_field;
0 ignored issues
show
Documentation introduced by
The property unique_identifier_field does not exist on object<Config_ForClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
40
41
		$member->$field = '[email protected]';
42
		$member->PasswordEncryption = "sha1";
43
		$member->Password = "mypassword";
44
		$member->write();
45
46
		$data = array(
47
			'Email' => $member->$field,
48
			'Password' => 'mypassword'
49
		);
50
		MemberAuthenticator::authenticate($data);
51
52
		$member = DataObject::get_by_id('SilverStripe\\Security\\Member', $member->ID);
53
		$this->assertEquals($member->PasswordEncryption, "sha1_v2.4");
54
		$result = $member->checkPassword('mypassword');
55
		$this->assertTrue($result->valid());
56
	}
57
58
	public function testNoLegacyPasswordHashMigrationOnIncompatibleAlgorithm() {
59
		Config::inst()->update(
60
			'SilverStripe\\Security\\PasswordEncryptor',
61
			'encryptors',
62
			array('crc32' => array('SilverStripe\\Security\\PasswordEncryptor_PHPHash' => 'crc32'))
63
		);
64
		$field=Member::config()->unique_identifier_field;
0 ignored issues
show
Documentation introduced by
The property unique_identifier_field does not exist on object<Config_ForClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
65
66
		$member = new Member();
67
		$member->$field = '[email protected]';
68
		$member->PasswordEncryption = "crc32";
69
		$member->Password = "mypassword";
70
		$member->write();
71
72
		$data = array(
73
			'Email' => $member->$field,
74
			'Password' => 'mypassword'
75
		);
76
		MemberAuthenticator::authenticate($data);
77
78
		$member = DataObject::get_by_id('SilverStripe\\Security\\Member', $member->ID);
79
		$this->assertEquals($member->PasswordEncryption, "crc32");
80
		$result = $member->checkPassword('mypassword');
81
		$this->assertTrue($result->valid());
82
	}
83
84
	public function testCustomIdentifierField(){
85
86
		$origField = Member::config()->unique_identifier_field;
0 ignored issues
show
Documentation introduced by
The property unique_identifier_field does not exist on object<Config_ForClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
87
		Member::config()->unique_identifier_field = 'Username';
0 ignored issues
show
Documentation introduced by
The property unique_identifier_field does not exist on object<Config_ForClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
88
89
		$label=singleton('SilverStripe\\Security\\Member')->fieldLabel(Member::config()->unique_identifier_field);
90
91
		$this->assertEquals($label, 'Username');
92
93
		Member::config()->unique_identifier_field = $origField;
0 ignored issues
show
Documentation introduced by
The property unique_identifier_field does not exist on object<Config_ForClass>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
94
	}
95
96
	public function testGenerateLoginForm() {
97
		$controller = new Security();
98
99
		// Create basic login form
100
		$frontendForm = MemberAuthenticator::get_login_form($controller);
101
		$this->assertTrue($frontendForm instanceof MemberLoginForm);
102
103
		// Supports cms login form
104
		$this->assertTrue(MemberAuthenticator::supports_cms());
105
		$cmsForm = MemberAuthenticator::get_cms_login_form($controller);
106
		$this->assertTrue($cmsForm instanceof CMSMemberLoginForm);
107
	}
108
109
	/**
110
	 * Test that a member can be authenticated via their temp id
111
	 */
112
	public function testAuthenticateByTempID() {
113
		$member = new Member();
114
		$member->Email = '[email protected]';
115
		$member->PasswordEncryption = "sha1";
116
		$member->Password = "mypassword";
117
		$member->write();
118
119
		// Make form
120
		$controller = new Security();
121
		$form = new Form($controller, 'Form', new FieldList(), new FieldList());
122
123
		// If the user has never logged in, then the tempid should be empty
124
		$tempID = $member->TempIDHash;
125
		$this->assertEmpty($tempID);
126
127
		// If the user logs in then they have a temp id
128
		$member->logIn(true);
129
		$tempID = $member->TempIDHash;
130
		$this->assertNotEmpty($tempID);
131
132
		// Test correct login
133
		$result = MemberAuthenticator::authenticate(array(
134
			'tempid' => $tempID,
135
			'Password' => 'mypassword'
136
		), $form);
137
		$this->assertNotEmpty($result);
138
		$this->assertEquals($result->ID, $member->ID);
139
		$this->assertEmpty($form->Message());
140
141
		// Test incorrect login
142
		$form->clearMessage();
143
		$result = MemberAuthenticator::authenticate(array(
144
			'tempid' => $tempID,
145
			'Password' => 'notmypassword'
146
		), $form);
147
		$this->assertEmpty($result);
148
		$this->assertEquals('The provided details don&#039;t seem to be correct. Please try again.', $form->Message());
149
		$this->assertEquals('bad', $form->MessageType());
150
	}
151
152
	/**
153
	 * Test that the default admin can be authenticated
154
	 */
155
	public function testDefaultAdmin() {
156
		// Make form
157
		$controller = new Security();
158
		$form = new Form($controller, 'Form', new FieldList(), new FieldList());
159
160
		// Test correct login
161
		$result = MemberAuthenticator::authenticate(array(
162
			'Email' => 'admin',
163
			'Password' => 'password'
164
		), $form);
165
		$this->assertNotEmpty($result);
166
		$this->assertEquals($result->Email, Security::default_admin_username());
167
		$this->assertEmpty($form->Message());
168
169
		// Test incorrect login
170
		$form->clearMessage();
171
		$result = MemberAuthenticator::authenticate(array(
172
			'Email' => 'admin',
173
			'Password' => 'notmypassword'
174
		), $form);
175
		$this->assertEmpty($result);
176
		$this->assertEquals('The provided details don&#039;t seem to be correct. Please try again.', $form->Message());
177
		$this->assertEquals('bad', $form->MessageType());
178
	}
179
180
	public function testDefaultAdminLockOut()
181
	{
182
		Config::inst()->update('SilverStripe\\Security\\Member', 'lock_out_after_incorrect_logins', 1);
183
		Config::inst()->update('SilverStripe\\Security\\Member', 'lock_out_delay_mins', 10);
184
		DBDatetime::set_mock_now('2016-04-18 00:00:00');
185
		$controller = new Security();
186
		$form = new Form($controller, 'Form', new FieldList(), new FieldList());
187
188
		// Test correct login
189
		MemberAuthenticator::authenticate(array(
190
			'Email' => 'admin',
191
			'Password' => 'wrongpassword'
192
		), $form);
193
194
		$this->assertTrue(Member::default_admin()->isLockedOut());
195
		$this->assertEquals(Member::default_admin()->LockedOutUntil, '2016-04-18 00:10:00');
196
	}
197
}
198