Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4.0.x] fix: improve default password policy to follow latest OWASP recommend… #3240

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -258,17 +258,17 @@ user:
password:
policy:
# Regex pattern for password validation (default to OWASP recommendations).
# 8 to 32 characters, no more than 2 consecutive equal characters, min 1 special characters (@ & # ...), min 1 upper case character.
pattern: ^(?:(?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))(?!.*(.)\1{2,})[A-Za-z0-9!~<>,;:_\-=?*+#."'&§`£€%°()\\\|\[\]\-\$\^\@\/]{8,32}$
# Example : ^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
# ^ # start-of-string
#(?=.*[0-9]) # a digit must occur at least once
#(?=.*[a-z]) # a lower case letter must occur at least once
#(?=.*[A-Z]) # an upper case letter must occur at least once
#(?=.*[@#$%^&+=]) # a special character must occur at least once
#(?=\S+$) # no whitespace allowed in the entire string
#.{8,} # anything, at least eight places though
#$ # end-of-string
# Password must be at least 12 characters long, contain at least one digit, one upper case letter, one lower case letter, one special character, and no more than 2
pattern: ^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!~<>.,;:_=?/*+\-#\"'&§`£€%°()|\[\]$^@])(?!.*(.)\1{2,}).{12,128}$
# Example : ^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!~<>.,;:_=?/*+\-#\"'&§`£€%°()|\[\]$^@])(?!.*(.)\1{2,}).{12,128}$
# ^ # start-of-string
#(?=.*[0-9]) # a digit must occur at least once
#(?=.*[A-Z]) # an upper case letter must occur at least once
#(?=.*[a-z]) # a lower case letter must occur at least once
#(?=.*[!~<>.,;:_=?/*+\-#\"'&§`£€%°()|\[\]$^@]) # a special character must occur at least once
#((?!.*(.)\1{2,}) # no more than 2 consecutive equal characters
#.{12,128} # anything, between 12 and 128 characters
#$ # end-of-string

## Password dictionary to exclude most commons passwords
## You need to enable the feature in the AM management console
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,17 +311,17 @@ user:
password:
policy:
# Regex pattern for password validation (default to OWASP recommendations).
# 8 to 32 characters, no more than 2 consecutive equal characters, min 1 special characters (@ & # ...), min 1 upper case character.
pattern: ^(?:(?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))(?!.*(.)\1{2,})[A-Za-z0-9!~<>,;:_\-=?*+#."'&§`£€%°()\\\|\[\]\-\$\^\@\/]{8,32}$
# Example : ^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=])(?=\S+$).{8,}$
# ^ # start-of-string
#(?=.*[0-9]) # a digit must occur at least once
#(?=.*[a-z]) # a lower case letter must occur at least once
#(?=.*[A-Z]) # an upper case letter must occur at least once
#(?=.*[@#$%^&+=]) # a special character must occur at least once
#(?=\S+$) # no whitespace allowed in the entire string
#.{8,} # anything, at least eight places though
#$ # end-of-string
# Password must be at least 12 characters long, contain at least one digit, one upper case letter, one lower case letter, one special character, and no more than 2
pattern: ^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!~<>.,;:_=?/*+\-#\"'&§`£€%°()|\[\]$^@])(?!.*(.)\1{2,}).{12,128}$
# Example : ^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!~<>.,;:_=?/*+\-#\"'&§`£€%°()|\[\]$^@])(?!.*(.)\1{2,}).{12,128}$
# ^ # start-of-string
#(?=.*[0-9]) # a digit must occur at least once
#(?=.*[A-Z]) # an upper case letter must occur at least once
#(?=.*[a-z]) # a lower case letter must occur at least once
#(?=.*[!~<>.,;:_=?/*+\-#\"'&§`£€%°()|\[\]$^@]) # a special character must occur at least once
#((?!.*(.)\1{2,}) # no more than 2 consecutive equal characters
#.{12,128} # anything, between 12 and 128 characters
#$ # end-of-string

## Password dictionary to exclude most commons passwords
## You need to enable the feature in the AM management console
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class PasswordSettings {
/**
* See https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
*/
public static final int PASSWORD_MAX_LENGTH = 64;
public static final int PASSWORD_MAX_LENGTH = 128;
public static final int PASSWORD_MIN_LENGTH = 8;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
@Component("defaultPasswordValidator")
public class DefaultPasswordValidatorImpl implements PasswordValidator {

private static final String DEFAULT_PASSWORD_PATTERN_VALUE = "^(?:(?=.*\\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))(?!.*(.)\\1{2,})[A-Za-z0-9!~<>,;:_\\-=?*+#.\"'&§`£€%°()\\\\\\|\\[\\]\\-\\$\\^\\@\\/]{8,32}$";
private static final String DEFAULT_PASSWORD_PATTERN_VALUE = "^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!~<>.,;:_=?/*+\\-#\\\"'&§`£€%°()|\\[\\]$^@])(?!.*(.)\\1{2,}).{12,128}$";

private static final String MESSAGE = "Field [password] is invalid";
private static final String ERROR_KEY = "invalid_password_value";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright (C) 2015 The Gravitee team (http://gravitee.io)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.gravitee.am.service.validators;

import io.gravitee.am.service.validators.password.PasswordValidator;
import io.gravitee.am.service.validators.password.impl.DefaultPasswordValidatorImpl;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Eric LELEU (eric.leleu at graviteesource.com)
* @author GraviteeSource Team
*/
public class DefaultPasswordValidatorTest {
@ParameterizedTest
@MethodSource("providerValidatePassword")
void validatePassword(String password, boolean expected) {
PasswordValidator validator = new DefaultPasswordValidatorImpl(
"^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!~<>.,;:_=?/*+\\-#\\\"'&§`£€%°()|\\[\\]$^@])(?!.*(.)\\1{2,}).{12,128}$"
);
assertEquals(expected, validator.validate(password));
}

private static Stream<Arguments> providerValidatePassword() {
return Stream.of(
Arguments.of("a1!atjubclzf", false),
Arguments.of("A1!ABVREFAGD", false),
Arguments.of("Aa!AHYaeffSF", false),
Arguments.of("AaBbCcDd1324", false),
Arguments.of("Aa1!", false),
Arguments.of("Password12!", false),
Arguments.of("Passsword123!", false),
Arguments.of("Password123!!!", false),
Arguments.of(
"MA48*xP:344MA48*xP:344MA48*xP:344MA48*xP:344MA48*xP:344MA48*xP:344MA48*xP:344MA48*xP:344MA48*xP:344MA48*xP:344MA48*xP:344MA48*xPz:",
false
),
Arguments.of("Password1231!", true),
Arguments.of("Password123!2£1", true),
Arguments.of("MA48*xP:344d", true),
Arguments.of("Ab0!~<>,;:_-=?*+#.\"'&§`€%°()|[]$^@", true),
Arguments.of("SomeP@ssw0rd", true)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ describe('AM - User Pre-Registration - Reset Password to confirm', () => {
expect(confirmationLink).toBeDefined();
await clearEmails();

await resetPassword(confirmationLink, 'Test123!');
await resetPassword(confirmationLink, 'SomeP@ssw0rd');
});

it('must be enabled', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ let openIdConfiguration;
let application;
let user = {
username: 'SelfAccountUser',
password: 'Test123!',
password: 'SomeP@ssw0rd',
firstName: 'SelfAccount',
lastName: 'User',
email: '[email protected]',
Expand Down Expand Up @@ -135,7 +135,7 @@ describe('SelfAccount - Change Password', () => {
describe('With default settings', () => {
describe('End User', () => {
it('must be able to change his password', async () => {
user.password = 'Test1234!!';
user.password = 'SomeP@ssw0rd!';

await performPost(
`${process.env.AM_GATEWAY_URL}/${domain.hrid}/account/api/changePassword`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ let openIdConfiguration;
let application;
let user = {
username: 'LogoutUser',
password: 'Test123!',
password: 'SomeP@ssw0rd',
firstName: 'Logout',
lastName: 'User',
email: '[email protected]',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ let openIdConfiguration;
let application;
let user = {
username: 'FlowUser',
password: 'Test123!',
password: 'SomeP@ssw0rd',
firstName: 'Flow',
lastName: 'User',
email: '[email protected]',
Expand Down
8 changes: 4 additions & 4 deletions gravitee-am-test/specs/gateway/login-flow.jest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,16 @@ beforeAll(async () => {
describe('multiple user', () => {
const contractValue = '1234';
let user1;
const user1Password = 'Zxc123!!';
const user1Password = 'ZxcPrm7123!!';
let user2;
const commonPassword = 'Asd123!!';
const commonPassword = 'AsdPrm7123!!';
const commonEmail = '[email protected]';
let user3; //user3 has same password as user2
let user4;
const user4Password = 'Qwe123!!';
const user4Password = 'QwePrm7123!!';
let user5;
let user6;
const secondCommonPassword = 'Phd123!!';
const secondCommonPassword = 'PhdPrm7123!!';
const secondCommonEmail = '[email protected]';

beforeAll(async () => {
Expand Down
12 changes: 6 additions & 6 deletions gravitee-am-test/specs/gateway/user-registration.jest.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ describe('Register User on domain', () => {
lastName: faker.name.lastName(),
username: '$£êê',
email: faker.internet.email(),
password: 'P@ssw0rd!',
password: 'P@ssw0rd!123',
};
await register(user, 'warning=invalid_user_information');

Expand All @@ -122,7 +122,7 @@ describe('Register User on domain', () => {
lastName: faker.name.lastName(),
username: faker.name.firstName(),
email: faker.random.word(),
password: 'P@ssw0rd!',
password: 'P@ssw0rd!123',
};
await register(user, 'warning=invalid_email');

Expand All @@ -131,7 +131,7 @@ describe('Register User on domain', () => {
expect(usersPage.totalCount).toEqual(0);
});

it('Should not be able to register with invalid email address', async () => {
it('Should not be able to register with invalid password', async () => {
const user = {
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
Expand All @@ -152,7 +152,7 @@ describe('Register User on domain', () => {
lastName: faker.name.lastName(),
username: faker.name.firstName(),
email: faker.internet.email(),
password: 'P@ssw0rd!',
password: 'P@ssw0rd!123',
};
await register(user, 'success=registration_succeed');

Expand Down Expand Up @@ -201,7 +201,7 @@ describe('Register User on domain', () => {
lastName: faker.name.lastName(),
username: faker.name.firstName(),
email: faker.internet.email(),
password: 'P@ssw0rd!',
password: 'P@ssw0rd!123',
};
await register(user, 'success=registration_succeed');

Expand Down Expand Up @@ -250,7 +250,7 @@ describe('Register User on domain', () => {
lastName: faker.name.lastName(),
username: faker.name.firstName(),
email: faker.internet.email(),
password: 'P@ssw0rd!',
password: 'P@ssw0rd!123',
};

await register(user, `https://acustom/web/site?client_id=${clientId}`, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@
],
"body": {
"mode": "raw",
"raw": "{\"firstName\":\"Alice\",\"lastName\":\"Wonder\",\"email\":\"[email protected]\",\"username\":\"alice\",\"password\": \"Test123!\"}",
"raw": "{\"firstName\":\"Alice\",\"lastName\":\"Wonder\",\"email\":\"[email protected]\",\"username\":\"alice\",\"password\": \"SomeP@ssw0rd\"}",
"options": {
"raw": {
"language": "json"
Expand Down Expand Up @@ -1711,7 +1711,7 @@
},
{
"key": "password",
"value": "Test123!",
"value": "SomeP@ssw0rd",
"type": "text"
}
]
Expand Down