Skip to content

Commit

Permalink
パスワードの複雑性の向上
Browse files Browse the repository at this point in the history
  • Loading branch information
seto1 committed Mar 15, 2024
1 parent 5bf7870 commit ec1a601
Show file tree
Hide file tree
Showing 16 changed files with 243 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ q {}","",""
"27","mail_additional_parameters","","",""
"28","outer_service_output_header","","",""
"29","outer_service_output_footer","","",""
"30","allow_simple_password","0","",""
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ q {}","",""
"27","mail_additional_parameters","","",""
"28","outer_service_output_header","","",""
"29","outer_service_output_footer","","",""
"30","allow_simple_password","0","",""
7 changes: 7 additions & 0 deletions plugins/baser-core/config/Seeds/SiteConfigsSeed.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,13 @@ public function run(): void
'created' => '',
'modified' => ''
],
[
'id' => '30',
'name' => 'allow_simple_password',
'value' => '0',
'created' => '',
'modified' => ''
],
];
$table = $this->table('site_configs');
$table->insert($data)->save();
Expand Down
21 changes: 20 additions & 1 deletion plugins/baser-core/config/setting.php
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,26 @@
]
]
]
]
],

/*
* パスワードの設定ルール
*/
'passwordRule' => [
// 最小文字数
'minLength' => 12,
// 入力必須な文字種
'requiredCharacterTypes' => [
// 数値
'numeric',
// 大文字英字
'uppercase',
// 小文字英字
'lowercase',
// 記号
// 'symbol',
],
],
],

/**
Expand Down
99 changes: 79 additions & 20 deletions plugins/baser-core/src/Model/Table/UsersTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
use ArrayObject;
use Authentication\Authenticator\SessionAuthenticator;
use BaserCore\Utility\BcUtil;
use Cake\Core\Configure;
use Cake\ORM\Query;
use Cake\Event\Event;
use Cake\ORM\TableRegistry;
use Cake\Routing\Router;
use Cake\Utility\Hash;
use Cake\Validation\Validator;
use BaserCore\Model\Entity\User;
use BaserCore\View\BcAdminAppView;
Expand All @@ -27,6 +29,7 @@
use BaserCore\Annotation\NoTodo;
use BaserCore\Annotation\Checked;
use BaserCore\Annotation\UnitTest;
use BaserCore\Service\SiteConfigsService;

/**
* Class UsersTable
Expand Down Expand Up @@ -192,22 +195,8 @@ public function validationDefault(Validator $validator): Validator
'provider' => 'table',
'message' => __d('baser_core', '既に登録のあるEメールです。')
]]);
$validator
->scalar('password')
->minLength('password', 6, __d('baser_core', 'パスワードは6文字以上で入力してください。'))
->maxLength('password', 255, __d('baser_core', 'パスワードは255文字以内で入力してください。'))
->add('password', [
'passwordAlphaNumericPlus' => [
'rule' => ['alphaNumericPlus', ' \.:\/\(\)#,@\[\]\+=&;\{\}!\$\*'],
'provider' => 'bc',
'message' => __d('baser_core', 'パスワードは半角英数字(英字は大文字小文字を区別)とスペース、記号(._-:/()#,@[]+=&;{}!$*)のみで入力してください。')
]])
->add('password', [
'passwordConfirm' => [
'rule' => ['confirm', ['password_1', 'password_2']],
'provider' => 'bc',
'message' => __d('baser_core', 'パスワードが同じものではありません。')
]]);

$this->validationPassword($validator);

return $validator;
}
Expand All @@ -229,24 +218,27 @@ public function validationNew(Validator $validator): Validator
}

/**
* validationPasswordUpdate
* validationPassword
* @param Validator $validator
* @return Validator
* @checked
* @unitTest
* @noTodo
*/
public function validationPasswordUpdate(Validator $validator): Validator
public function validationPassword(Validator $validator): Validator
{
$symbol = ' ._-:/()#,@[]+=&;{}!$*';
$quotedSymbol = preg_quote($symbol, '/');

$validator
->scalar('password')
->minLength('password', 6, __d('baser_core', 'パスワードは6文字以上で入力してください。'))
->maxLength('password', 255, __d('baser_core', 'パスワードは255文字以内で入力してください。'))
->add('password', [
'passwordAlphaNumericPlus' => [
'rule' => ['alphaNumericPlus', ' \.:\/\(\)#,@\[\]\+=&;\{\}!\$\*'],
'rule' => ['alphaNumericPlus', $quotedSymbol],
'provider' => 'bc',
'message' => __d('baser_core', 'パスワードは半角英数字(英字は大文字小文字を区別)とスペース、記号(._-:/()#,@[]+=&;{}!$*)のみで入力してください。')
'message' => __d('baser_core', 'パスワードは半角英数字(英字は大文字小文字を区別)とスペース、記号(' . trim($symbol) . ')のみで入力してください。')
]])
->add('password', [
'passwordConfirm' => [
Expand All @@ -255,9 +247,76 @@ public function validationPasswordUpdate(Validator $validator): Validator
'message' => __d('baser_core', 'パスワードが同じものではありません。')
]]);

// 複雑性のチェック
$SiteConfigsService = new SiteConfigsService();
if (!$SiteConfigsService->getValue('allow_simple_password')) {
// 最小文字数
$minLength = Configure::read('BcApp.passwordRule.minLength');
if ($minLength && is_numeric($minLength)) {
$validator->minLength('password', $minLength,
__d('baser_core', 'パスワードは{0}文字以上で入力してください。', $minLength));
}

// 入力必須な文字種
$requiredCharacterTypePatterns = [
'numeric' => [
'name' => __d('baser_core', '数字'),
'pattern' => '\d',
],
'uppercase' => [
'name' => __d('baser_core', '大文字英字'),
'pattern' => '[A-Z]',
],
'lowercase' => [
'name' => __d('baser_core', '小文字英字'),
'pattern' => '[a-z]',
],
'symbol' => [
'name' => __d('baser_core', '大文字英字'),
'pattern' => '[' . $quotedSymbol . ']',
],
];

// 無効な文字種を削除
$requiredCharacterTypes = Configure::read('BcApp.passwordRule.requiredCharacterTypes');
foreach ($requiredCharacterTypePatterns as $key => $name) {
if (!in_array($key, $requiredCharacterTypes)) {
unset($requiredCharacterTypePatterns[$key]);
}
}

// AND条件の正規表現
$patterns = array_map(function($pattern) {
return '(?=.*' . $pattern . ')';
}, Hash::extract($requiredCharacterTypePatterns, '{s}.pattern'));
$pattern = '/^' . implode('', $patterns) . '.*$/';

$validator->add('password', [
'passwordRequiredCharacterType' => [
'rule' => ['custom', $pattern],
'message' => __d('baser_core', 'パスワードは{0}を含む必要があります。',
implode('', Hash::extract($requiredCharacterTypePatterns, '{s}.name'))),
]]);
}

return $validator;
}

/**
* validationPasswordUpdate
* @param Validator $validator
* @return Validator
* @checked
* @unitTest
* @noTodo
*/
public function validationPasswordUpdate(Validator $validator): Validator
{
return $this->validationPassword($validator)
->requirePresence('password', true, __d('baser_core', 'パスワードを入力してください。'))
->notEmptyString('password', __d('baser_core', 'パスワードを入力してください。'));
}

/**
* コントロールソースを取得する
*
Expand Down
99 changes: 82 additions & 17 deletions plugins/baser-core/tests/TestCase/Model/Table/UsersTableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
namespace BaserCore\Test\TestCase\Model\Table;

use BaserCore\Model\Table\UsersTable;
use BaserCore\Service\SiteConfigsServiceInterface;
use BaserCore\TestSuite\BcTestCase;
use BaserCore\Test\Scenario\InitAppScenario;
use BaserCore\Test\Scenario\LoginStoresScenario;
use BaserCore\Test\Scenario\UserGroupsScenario;
use BaserCore\Test\Scenario\UserScenario;
use BaserCore\Test\Scenario\UsersUserGroupsScenario;
use BaserCore\TestSuite\BcTestCase;
use Cake\Core\Configure;
use Cake\Validation\Validator;
use CakephpFixtureFactories\Scenario\ScenarioAwareTrait;

Expand Down Expand Up @@ -141,15 +143,27 @@ public function testValidationDefault()
}

/**
* Test validationPasswordUpdate
* Test validationPassword
* @param $isValid 妥当でない場合、$validator->validateからエラーが返る
* @param $data パスワード文字列
* @param $allowSimplePassword 簡易なパスワードを許可
* @param $passwordRule パスワードの設定ルール
* @return void
* @dataProvider validationPasswordUpdateDataProvider
* @dataProvider validationPasswordDataProvider
*/
public function testValidationPasswordUpdate($isValid, $data)
public function testValidationPassword($isValid, $data, $allowSimplePassword, $passwordRule = [])
{
$validator = $this->Users->validationPasswordUpdate(new Validator());
$siteConfigsService = $this->getService(SiteConfigsServiceInterface::class);
if ($allowSimplePassword) {
$siteConfigsService->setValue('allow_simple_password', 1);
} else {
$siteConfigsService->setValue('allow_simple_password', 0);
}
if ($passwordRule) {
Configure::write('BcApp.passwordRule', $passwordRule);
}

$validator = $this->Users->validationPassword(new Validator());
$validator->setProvider('table', $this->Users);
if ($isValid) {
$this->assertEmpty($validator->validate($data));
Expand All @@ -158,23 +172,74 @@ public function testValidationPasswordUpdate($isValid, $data)
}
}

public static function validationPasswordUpdateDataProvider()
public static function validationPasswordDataProvider()
{
$exceedMax = "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest";
$exceedMax = str_repeat('a', 256);

return [
// 妥当な例
[true, ['password' => 'testtest', 'password_1' => 'testtest', 'password_2' => 'testtest']],
// 文字数が少ない場合
[false, ['password' => 'test', 'password_1' => 'test', 'password_2' => 'test']],
// 文字数が少ない場合
[false, ['password' => $exceedMax, 'password_1' => $exceedMax, 'password_2' => $exceedMax]],
// 不適切な文字が入ってる場合
[false, ['password' => '^^^^^^^^', 'password_1' => '^^^^^^^^', 'password_2' => '^^^^^^^^']],
// パスワードが異なる例
[false, ['password' => 'testtest', 'password_1' => 'test', 'password_2' => 'testtest']],
// 簡易なパスワードを許可

// - OK
[true, ['password' => 'testtest', 'password_1' => 'testtest', 'password_2' => 'testtest'], true],
// - 文字数が少ない
[false, ['password' => 'test', 'password_1' => 'test', 'password_2' => 'test'], true],
// - 文字数が多い
[false, ['password' => $exceedMax, 'password_1' => $exceedMax, 'password_2' => $exceedMax], true],
// - 不適切な文字が入っている
[false, ['password' => '^^^^^^^^', 'password_1' => '^^^^^^^^', 'password_2' => '^^^^^^^^'], true],
// - パスワードが異なる
[false, ['password' => 'testtest', 'password_1' => 'test', 'password_2' => 'testtest'], true],

// 簡易なパスワードを許可しない

// - OK
[true, ['password' => 'TestPassword1!', 'password_1' => 'TestPassword1!', 'password_2' => 'TestPassword1!'], false, [
'minLength' => 12,
'requiredCharacterTypes' => [ 'numeric', 'uppercase', 'lowercase', 'symbol' ],
]],
[true, ['password' => '1234', 'password_1' => '1234', 'password_2' => '1234'], false, [
'minLength' => 4,
'requiredCharacterTypes' => [ 'numeric' ],
]],
[true, ['password' => 'AAAA', 'password_1' => 'AAAA', 'password_2' => 'AAAA'], false, [
'minLength' => 4,
'requiredCharacterTypes' => [ 'uppercase' ],
]],
[true, ['password' => 'aaaa', 'password_1' => 'aaaa', 'password_2' => 'aaaa'], false, [
'minLength' => 4,
'requiredCharacterTypes' => [ 'lowercase' ],
]],
[true, ['password' => '!!!!', 'password_1' => '!!!!', 'password_2' => '!!!!'], false, [
'minLength' => 4,
'requiredCharacterTypes' => [ 'symbol' ],
]],
// - 文字数が少ない
[false, ['password' => 'TestPassword1!', 'password_1' => 'TestPassword1!', 'password_2' => 'TestPassword1!'], false, [
'minLength' => 24,
'requiredCharacterTypes' => [ 'numeric', 'uppercase', 'lowercase', 'symbol' ],
]],
// - 文字種が少ない
[false, ['password' => '1234', 'password_1' => '1234', 'password_2' => '1234'], false, [
'minLength' => 4,
'requiredCharacterTypes' => [ 'numeric', 'uppercase', 'lowercase', 'symbol' ],
]],
];
}

/**
* Test validationPasswordUpdate
* @return void
*/
public function testValidationPasswordUpdate()
{
$validator = $this->Users->validationPasswordUpdate(new Validator());

$this->assertEmpty($validator->validate([
'password' => 'TestPassword1!', 'password_1' => 'TestPassword1!', 'password_2' => 'TestPassword1!',
]));

$this->assertNotEmpty($validator->validate([]));
}

/**
* Test validationNew
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,8 @@ $(function () {
} else if ($("#admin-email").val() === "") {
alert(bcI18n.message1);
result = false;
} else if ($("#admin-password").val().length < 6) {
alert(bcI18n.message4);
result = false;
} else if ($("#admin-password").val() !== $("#admin-confirm-password").val()) {
alert(bcI18n.message5);
result = false;
} else if (!$("#admin-password").val().match(/^[a-zA-Z0-9\-_ \.:\/\(\)#,@\[\]\+=&;\{\}!\$\*]+$/)) {
alert(bcI18n.message6);
} else if ($("#admin-password").val() === "") {
alert(bcI18n.message2);
result = false;
}
} else if (this.id === 'BtnBack') {
Expand Down
7 changes: 6 additions & 1 deletion plugins/bc-admin-third/src/css/components/_install.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,14 @@
}
}
}
.bca-checkbox__label {
margin-top: 10px;
font-weight: normal;
font-size: 80%;
}
}
.step-5 {
li {
margin:20px 0;
}
}
}
Loading

0 comments on commit ec1a601

Please sign in to comment.