Skip to content

Commit

Permalink
OHRM5X-2042: Enforce auth - password strength in the login (orangehrm…
Browse files Browse the repository at this point in the history
  • Loading branch information
ManulMax authored Feb 17, 2023
1 parent c2226a2 commit 2a77f1f
Show file tree
Hide file tree
Showing 25 changed files with 1,140 additions and 183 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cypress.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
run: |
docker exec os_dev_php80 bash --login -c 'cd src/client && yarn build --mode development'
docker exec os_dev_php80 bash -c "sed -i 's/hostName: 127.0.0.1/hostName: mysql55/g' installer/cli_install_config.yaml"
docker exec os_dev_php80 bash -c "sed -i 's/adminPassword: Ohrm@1423/adminPassword: Admin@123/g' installer/cli_install_config.yaml"
docker exec os_dev_php80 bash -c "sed -i 's/adminPassword: Ohrm@1423/adminPassword: Jacqueline@OHRM123/g' installer/cli_install_config.yaml"
docker exec os_dev_php80 bash -c "sed -i 's/adminEmployeeFirstName: OrangeHRM/adminEmployeeFirstName: Jacqueline/g' installer/cli_install_config.yaml"
docker exec os_dev_php80 bash -c "sed -i 's/adminEmployeeLastName: Admin/adminEmployeeLastName: White/g' installer/cli_install_config.yaml"
docker exec os_dev_php80 bash -c "sed -i 's/public const PRODUCT_MODE = self::MODE_PROD/public const PRODUCT_MODE = self::MODE_DEV/g' src/lib/config/Config.php"
Expand Down
47 changes: 47 additions & 0 deletions installer/Migration/V5_4_0/Migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
namespace OrangeHRM\Installer\Migration\V5_4_0;

use Doctrine\DBAL\Schema\ForeignKeyConstraint;
use Doctrine\DBAL\Schema\Index;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Types\Types;
use OrangeHRM\Installer\Util\V1\AbstractMigration;
Expand Down Expand Up @@ -167,10 +168,35 @@ public function up(): void
$this->getSchemaHelper()->addForeignKey('ohrm_claim_request', $foreignKeyConstraint3);
}

$this->getSchemaHelper()->createTable('ohrm_enforce_password')
->addColumn('id', Types::INTEGER, ['Autoincrement' => true])
->addColumn('user_id', Types::INTEGER, ['Notnull' => true])
->addColumn('enforce_request_date', Types::DATETIME_MUTABLE, ['Notnull' => false])
->addColumn('reset_code', Types::STRING, ['Notnull' => true])
->addColumn('expired', Types::BOOLEAN, ['Notnull' => true, 'Default' => 0])
->setPrimaryKey(['id'])
->create();

$resetCode = new Index(
'reset_code',
['reset_code']
);
$this->getSchemaManager()->createIndex($resetCode, 'ohrm_enforce_password');

$foreignKeyConstraint = new ForeignKeyConstraint(
['user_id'],
'ohrm_user',
['id'],
'enforcePasswordUser',
['onDelete' => 'NO ACTION']
);
$this->getSchemaHelper()->addForeignKey('ohrm_enforce_password', $foreignKeyConstraint);

$this->changeClaimExpenseTypeTableStatusToBoolean();
$this->modifyClaimTables();
$this->modifyClaimRequestCurrencyToForeignKey();
$this->modifyDefaultRequiredPasswordStrength();
$this->modifyDefaultPasswordEnforcement();

if (!$this->checkClaimExists()) {
$this->getConnection()->createQueryBuilder()
Expand Down Expand Up @@ -493,4 +519,25 @@ private function cleanClaimScreens(): void
->executeQuery();
}
}

public function modifyDefaultPasswordEnforcement(): void
{
$value = $this->getConfigHelper()->getConfigValue('authentication.enforce_password_strength');

if ($value !== 'on') {
$value = 'off';
}
$this->getConnection()->createQueryBuilder()
->insert('hs_hr_config')
->values([
'name' => ':name',
'value' => ':value',
])
->setParameters([
'name' => 'auth.password_policy.enforce_password_strength',
'value' => $value,
])
->executeQuery();
$this->getConfigHelper()->deleteConfigValue('authentication.enforce_password_strength');
}
}
6 changes: 6 additions & 0 deletions installer/Migration/V5_4_0/lang-string/auth.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ langStrings:
-
value: 'Change Weak Password'
unitId: change_weak_password
-
value: 'Your current password is weak. Please choose a stronger password.'
unitId: password_not_strong
-
value: 'Invalid password reset code'
unitId: invalid_password_reset_code
Original file line number Diff line number Diff line change
Expand Up @@ -30,65 +30,80 @@
{{ $t('auth.change_weak_password') }}
</oxd-text>
<oxd-divider />
<oxd-form-row>
<oxd-input-field
:value="username"
:label="$t('auth.username')"
readonly
name="username"
label-icon="person"
/>
</oxd-form-row>
<oxd-form-row>
<oxd-input-field
v-model="user.currentPassword"
:rules="rules.currentPassword"
:label="$t('pim.current_password')"
type="password"
label-icon="key"
autocomplete="off"
name="currentPassword"
/>
</oxd-form-row>
<oxd-form-row class="orangehrm-forgot-password-row">
<password-strength-indicator
v-if="user.newPassword"
:password-strength="passwordStrength"
>
</password-strength-indicator>
<oxd-input-field
v-model="user.newPassword"
:rules="rules.newPassword"
:label="$t('auth.new_password')"
:placeholder="$t('auth.password')"
name="password"
type="password"
label-icon="key"
autocomplete="off"
/>
</oxd-form-row>
<oxd-form-row>
<oxd-input-field
v-model="user.confirmPassword"
:rules="rules.confirmPassword"
:placeholder="$t('auth.password')"
:label="$t('general.confirm_password')"
type="password"
label-icon="key"
autocomplete="off"
name="confirmPassword"
/>
</oxd-form-row>
<oxd-divider />
<div class="orangehrm-forgot-password-buttons">
<oxd-button
:label="$t('general.save')"
size="large"
type="submit"
display-type="secondary"
class="orangehrm-forgot-password-button"
/>
<div class="orangehrm-login-error">
<oxd-alert
:show="true"
:message="
invalidCode
? $t('auth.invalid_password_reset_code')
: error?.message || $t('auth.password_not_strong')
"
type="error"
></oxd-alert>
</div>
<template v-if="!invalidCode">
<input name="resetCode" :value="code" type="hidden" />
<input name="_token" :value="token" type="hidden" />
<oxd-form-row>
<oxd-input-field
:value="username"
:label="$t('auth.username')"
readonly
name="username"
label-icon="person"
/>
</oxd-form-row>
<oxd-form-row>
<oxd-input-field
v-model="user.currentPassword"
:rules="rules.currentPassword"
:label="$t('pim.current_password')"
type="password"
label-icon="key"
autocomplete="off"
name="currentPassword"
/>
</oxd-form-row>
<oxd-form-row class="orangehrm-forgot-password-row">
<password-strength-indicator
v-if="user.newPassword"
:password-strength="passwordStrength"
>
</password-strength-indicator>
<oxd-input-field
v-model="user.newPassword"
:rules="rules.newPassword"
:label="$t('auth.new_password')"
:placeholder="$t('auth.password')"
name="password"
type="password"
label-icon="key"
autocomplete="off"
/>
</oxd-form-row>
<oxd-form-row>
<oxd-input-field
v-model="user.confirmPassword"
:rules="rules.confirmPassword"
:placeholder="$t('auth.password')"
:label="$t('general.confirm_password')"
type="password"
label-icon="key"
autocomplete="off"
name="confirmPassword"
/>
</oxd-form-row>
<oxd-divider />
<div class="orangehrm-forgot-password-buttons">
<oxd-button
:label="$t('general.save')"
size="large"
type="submit"
display-type="secondary"
class="orangehrm-forgot-password-button"
/>
</div>
</template>
</oxd-form>
</div>
</div>
Expand All @@ -101,7 +116,7 @@ import {
required,
shouldNotExceedCharLength,
} from '@ohrm/core/util/validation/rules';
import {promiseDebounce} from '@ohrm/oxd';
import {promiseDebounce, OxdAlert} from '@ohrm/oxd';
import {urlFor} from '@/core/util/helper/url';
import {APIService} from '@/core/util/services/api.service';
import usePasswordPolicy from '@/core/util/composable/usePasswordPolicy';
Expand All @@ -112,13 +127,30 @@ export default {

components: {
'password-strength-indicator': PasswordStrengthIndicator,
'oxd-alert': OxdAlert,
},

props: {
username: {
type: String,
required: true,
},
code: {
type: String,
required: true,
},
token: {
type: String,
required: true,
},
error: {
type: Object,
default: () => null,
},
invalidCode: {
type: Boolean,
default: () => false,
},
},

setup() {
Expand All @@ -136,7 +168,6 @@ export default {
return {
user: {
username: '',
newPassword: '',
currentPassword: '',
confirmPassword: '',
},
Expand All @@ -160,7 +191,6 @@ export default {

computed: {
submitUrl() {
// TODO: Replace correct URL
return urlFor('/auth/resetWeakPassword');
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,22 @@

use OrangeHRM\Authentication\Dto\AuthParamsInterface;
use OrangeHRM\Authentication\Dto\UserCredentialInterface;
use OrangeHRM\Authentication\Exception\AuthenticationException;
use OrangeHRM\Authentication\Exception\PasswordEnforceException;
use OrangeHRM\Authentication\Service\AuthenticationService;
use OrangeHRM\Authentication\Traits\Service\PasswordStrengthServiceTrait;
use OrangeHRM\Authentication\Utility\PasswordStrengthValidation;
use OrangeHRM\Core\Service\ConfigService;
use OrangeHRM\Core\Traits\Service\ConfigServiceTrait;
use OrangeHRM\Framework\Services;
use OrangeHRM\I18N\Traits\Service\I18NHelperTrait;

class LocalAuthProvider extends AbstractAuthProvider
{
use ConfigServiceTrait;
use PasswordStrengthServiceTrait;
use I18NHelperTrait;

private AuthenticationService $authenticationService;

/**
Expand All @@ -36,14 +48,41 @@ private function getAuthenticationService(): AuthenticationService
}

/**
* @inheritDoc
* @param AuthParamsInterface $authParams
* @return bool
* @throws AuthenticationException
* @throws PasswordEnforceException
*/
public function authenticate(AuthParamsInterface $authParams): bool
{
if (!$authParams->getCredential() instanceof UserCredentialInterface) {
return false;
}
return $this->getAuthenticationService()->setCredentials($authParams->getCredential());
$success = $this->getAuthenticationService()->setCredentials($authParams->getCredential());
if ($success) {
if ($this->getConfigService()->getConfigDao()
->getValue(ConfigService::KEY_ENFORCE_PASSWORD_STRENGTH) === 'on') {
$passwordStrengthValidation = new PasswordStrengthValidation();
$passwordStrength = $passwordStrengthValidation->checkPasswordStrength(
$authParams->getCredential()
);

if (!($this->getPasswordStrengthService()
->isValidPassword($authParams->getCredential(), $passwordStrength))
) {
$e = new PasswordEnforceException(
AuthenticationException::PASSWORD_NOT_STRONG,
$this->getI18NHelper()->trans('password_not_strong'),
);
$e->generateResetCode();

$session = $this->getContainer()->get(Services::SESSION);
$session->invalidate();
throw $e;
}
}
}
return $success;
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/plugins/orangehrmAuthenticationPlugin/Auth/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class User
public const USER_EMPLOYEE_NUMBER = 'user.user_employee_number';

public const FLASH_LOGIN_ERROR = 'flash.login_error';
public const FLASH_PASSWORD_ENFORCE_ERROR = 'flash.password_enforce_error';
public const FLASH_VERIFY_ERROR = 'flash.admin_access.verify_error';
public const FLASH_SEND_EMAIL_FLAG = 'flash.send_email_flag';

Expand Down
Loading

0 comments on commit 2a77f1f

Please sign in to comment.