Unverified Commit da454ba2 authored by Saturnino Abril's avatar Saturnino Abril Committed by GitHub
Browse files

move password settings to team edition (#1242)


Signed-off-by: default avatarSaturnino Abril <saturnino.abril@gmail.com>
parent 67cff7c9
......@@ -35,42 +35,37 @@ export default class PasswordSettings extends AdminSettings {
});
// Update sample message from config settings
this.sampleErrorMsg = null;
if (this.props.license.IsLicensed === 'true' && this.props.license.PasswordRequirements === 'true') {
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (props.config.PasswordSettings.Lowercase) {
sampleErrorMsgId += 'Lowercase';
}
if (props.config.PasswordSettings.Uppercase) {
sampleErrorMsgId += 'Uppercase';
}
if (props.config.PasswordSettings.Number) {
sampleErrorMsgId += 'Number';
}
if (props.config.PasswordSettings.Symbol) {
sampleErrorMsgId += 'Symbol';
}
this.sampleErrorMsg = (
<FormattedMessage
id={sampleErrorMsgId}
default='Your password must contain between {min} and {max} characters.'
values={{
min: (this.state.passwordMinimumLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
}}
/>
);
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (props.config.PasswordSettings.Lowercase) {
sampleErrorMsgId += 'Lowercase';
}
if (props.config.PasswordSettings.Uppercase) {
sampleErrorMsgId += 'Uppercase';
}
if (props.config.PasswordSettings.Number) {
sampleErrorMsgId += 'Number';
}
if (props.config.PasswordSettings.Symbol) {
sampleErrorMsgId += 'Symbol';
}
this.sampleErrorMsg = (
<FormattedMessage
id={sampleErrorMsgId}
default='Your password must contain between {min} and {max} characters.'
values={{
min: (this.state.passwordMinimumLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
}}
/>
);
}
getConfigFromState(config) {
if (this.props.license.IsLicensed === 'true' && this.props.license.PasswordRequirements === 'true') {
config.PasswordSettings.MinimumLength = this.parseIntNonZero(this.state.passwordMinimumLength, Constants.MIN_PASSWORD_LENGTH);
config.PasswordSettings.Lowercase = this.refs.lowercase.checked;
config.PasswordSettings.Uppercase = this.refs.uppercase.checked;
config.PasswordSettings.Number = this.refs.number.checked;
config.PasswordSettings.Symbol = this.refs.symbol.checked;
}
config.PasswordSettings.MinimumLength = this.parseIntNonZero(this.state.passwordMinimumLength, Constants.MIN_PASSWORD_LENGTH);
config.PasswordSettings.Lowercase = this.refs.lowercase.checked;
config.PasswordSettings.Uppercase = this.refs.uppercase.checked;
config.PasswordSettings.Number = this.refs.number.checked;
config.PasswordSettings.Symbol = this.refs.symbol.checked;
config.ServiceSettings.MaximumLoginAttempts = this.parseIntNonZero(this.state.maximumLoginAttempts);
......@@ -89,41 +84,37 @@ export default class PasswordSettings extends AdminSettings {
}
getSampleErrorMsg(minLength) {
if (this.props.license.IsLicensed === 'true' && this.props.license.PasswordRequirements === 'true') {
if (this.props.config.PasswordSettings.MinimumLength > Constants.MAX_PASSWORD_LENGTH || this.props.config.PasswordSettings.MinimumLength < Constants.MIN_PASSWORD_LENGTH) {
return (
<FormattedMessage
id='user.settings.security.passwordMinLength'
default='Invalid minimum length, cannot show preview.'
/>
);
}
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (this.refs.lowercase.checked) {
sampleErrorMsgId += 'Lowercase';
}
if (this.refs.uppercase.checked) {
sampleErrorMsgId += 'Uppercase';
}
if (this.refs.number.checked) {
sampleErrorMsgId += 'Number';
}
if (this.refs.symbol.checked) {
sampleErrorMsgId += 'Symbol';
}
if (this.props.config.PasswordSettings.MinimumLength > Constants.MAX_PASSWORD_LENGTH || this.props.config.PasswordSettings.MinimumLength < Constants.MIN_PASSWORD_LENGTH) {
return (
<FormattedMessage
id={sampleErrorMsgId}
default='Your password must contain between {min} and {max} characters.'
values={{
min: (minLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
}}
id='user.settings.security.passwordMinLength'
default='Invalid minimum length, cannot show preview.'
/>
);
}
return null;
let sampleErrorMsgId = 'user.settings.security.passwordError';
if (this.refs.lowercase.checked) {
sampleErrorMsgId += 'Lowercase';
}
if (this.refs.uppercase.checked) {
sampleErrorMsgId += 'Uppercase';
}
if (this.refs.number.checked) {
sampleErrorMsgId += 'Number';
}
if (this.refs.symbol.checked) {
sampleErrorMsgId += 'Symbol';
}
return (
<FormattedMessage
id={sampleErrorMsgId}
default='Your password must contain between {min} and {max} characters.'
values={{
min: (minLength || Constants.MIN_PASSWORD_LENGTH),
max: Constants.MAX_PASSWORD_LENGTH,
}}
/>
);
}
handlePasswordLengthChange(id, value) {
......@@ -146,9 +137,8 @@ export default class PasswordSettings extends AdminSettings {
}
renderSettings() {
let passwordSettings = null;
if (this.props.license.IsLicensed === 'true' && this.props.license.PasswordRequirements === 'true') {
passwordSettings = (
return (
<SettingsGroup>
<div>
<TextSetting
id='passwordMinimumLength'
......@@ -254,12 +244,6 @@ export default class PasswordSettings extends AdminSettings {
</div>
</Setting>
</div>
);
}
return (
<SettingsGroup>
{passwordSettings}
<TextSetting
id='maximumLoginAttempts'
label={
......
......@@ -62,9 +62,9 @@ export default class ResetPasswordModal extends React.Component {
const password = this.refs.password.value;
const passwordErr = Utils.isValidPassword(password, this.props.passwordConfig);
if (passwordErr) {
this.setState({serverErrorNewPass: passwordErr});
const {valid, error} = Utils.isValidPassword(password, this.props.passwordConfig);
if (!valid && error) {
this.setState({serverErrorNewPass: error});
return;
}
......
......@@ -48,10 +48,10 @@ export default class LDAPToEmail extends React.Component {
return;
}
const passwordErr = Utils.isValidPassword(password, this.props.passwordConfig);
if (passwordErr !== '') {
const {valid, error} = Utils.isValidPassword(password, this.props.passwordConfig);
if (!valid && error) {
this.setState({
passwordError: passwordErr,
passwordError: error,
});
return;
}
......
......@@ -30,11 +30,9 @@ export default class OAuthToEmail extends React.Component {
return;
}
const passwordErr = Utils.isValidPassword(password, this.props.passwordConfig);
if (passwordErr !== '') {
this.setState({
error: passwordErr,
});
const {valid, error} = Utils.isValidPassword(password, this.props.passwordConfig);
if (!valid && error) {
this.setState({error});
return;
}
......
......@@ -32,7 +32,10 @@ export default class SettingItemMax extends React.PureComponent {
/**
* Client error
*/
clientError: PropTypes.string,
clientError: PropTypes.oneOfType([
PropTypes.string,
PropTypes.object,
]),
/**
* Server error
......
......@@ -218,12 +218,12 @@ export default class SignupEmail extends React.Component {
}
const providedPassword = this.refs.password.value;
const pwdError = Utils.isValidPassword(providedPassword, this.props.passwordConfig);
if (pwdError) {
const {valid, error} = Utils.isValidPassword(providedPassword, this.props.passwordConfig);
if (!valid && error) {
this.setState({
nameError: '',
emailError: '',
passwordError: pwdError,
passwordError: error,
serverError: '',
});
return false;
......
......@@ -126,10 +126,10 @@ export default class SecurityTab extends React.Component {
return;
}
const passwordErr = Utils.isValidPassword(newPassword, this.props.passwordConfig);
if (passwordErr !== '') {
const {valid, error} = Utils.isValidPassword(newPassword, this.props.passwordConfig);
if (!valid && error) {
this.setState({
passwordError: passwordErr,
passwordError: error,
serverError: '',
});
return;
......
......@@ -206,107 +206,11 @@ describe('Utils.sortUsersByStatusAndDisplayName', function() {
});
describe('Utils.isValidPassword', function() {
test('Password min/max length enforced if no EE password requirements set', function() {
for (const data of [
{
password: 'four',
config: { // not EE, so password just has to be min < length < max
isEnterprise: false,
isLicensed: true,
isPasswordRequirements: true,
},
valid: false,
},
{
password: 'thistestpasswordismorethansixtyfourcharacterslongsoitstoolongtobeapassword',
config: { // not EE, so password just has to be min < length < max
isEnterprise: false,
isLicensed: true,
isPasswordRequirements: true,
},
valid: false,
},
{
password: 'thisisavalidpassword',
config: { // not EE, so password just has to be min < length < max
isEnterprise: false,
isLicensed: true,
isPasswordRequirements: true,
},
valid: true,
},
{
password: 'four',
config: { // not licensed, so password just has to be min < length < max
isEnterprise: true,
isLicensed: false,
isPasswordRequirements: true,
},
valid: false,
},
{
password: 'thistestpasswordismorethansixtyfourcharacterslongsoitstoolongtobeapassword',
config: { // not licensed, so password just has to be min < length < max
isEnterprise: true,
isLicensed: false,
isPasswordRequirements: true,
},
valid: false,
},
{
password: 'thisisavalidpassword',
config: { // not licensed, so password just has to be min < length < max
isEnterprise: true,
isLicensed: false,
isPasswordRequirements: true,
},
valid: true,
},
{
password: 'four',
config: { // no password requirements, so password just has to be min < length < max
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: false,
},
valid: false,
},
{
password: 'thistestpasswordismorethansixtyfourcharacterslongsoitstoolongtobeapassword',
config: { // no password requirements, so password just has to be min < length < max
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: false,
},
valid: false,
},
{
password: 'thisisavalidpassword',
config: { // no password requirements, so password just has to be min < length < max
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: false,
},
valid: true,
},
]) {
const errorMsg = Utils.isValidPassword(data.password, data.config);
if (data.valid) {
expect(errorMsg).toEqual('');
} else {
expect(errorMsg).not.toEqual('');
}
}
});
test('Minimum length enforced', function() {
for (const data of [
{
password: 'tooshort',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 10,
requireLowercase: false,
requireUppercase: false,
......@@ -318,9 +222,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'longenoughpassword',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 10,
requireLowercase: false,
requireUppercase: false,
......@@ -330,12 +231,8 @@ describe('Utils.isValidPassword', function() {
valid: true,
},
]) {
const errorMsg = Utils.isValidPassword(data.password, data.config);
if (data.valid) {
expect(errorMsg).toEqual('');
} else {
expect(errorMsg).not.toEqual('');
}
const {valid} = Utils.isValidPassword(data.password, data.config);
expect(data.valid).toEqual(valid);
}
});
......@@ -344,9 +241,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'UPPERCASE',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 5,
requireLowercase: true,
requireUppercase: false,
......@@ -358,9 +252,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'SOMELowercase',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 5,
requireLowercase: true,
requireUppercase: false,
......@@ -370,12 +261,8 @@ describe('Utils.isValidPassword', function() {
valid: true,
},
]) {
const errorMsg = Utils.isValidPassword(data.password, data.config);
if (data.valid) {
expect(errorMsg).toEqual('');
} else {
expect(errorMsg).not.toEqual('');
}
const {valid} = Utils.isValidPassword(data.password, data.config);
expect(data.valid).toEqual(valid);
}
});
......@@ -384,9 +271,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'lowercase',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 5,
requireLowercase: false,
requireUppercase: true,
......@@ -398,9 +282,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'SOMEUppercase',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 5,
requireLowercase: false,
requireUppercase: true,
......@@ -410,12 +291,8 @@ describe('Utils.isValidPassword', function() {
valid: true,
},
]) {
const errorMsg = Utils.isValidPassword(data.password, data.config);
if (data.valid) {
expect(errorMsg).toEqual('');
} else {
expect(errorMsg).not.toEqual('');
}
const {valid} = Utils.isValidPassword(data.password, data.config);
expect(data.valid).toEqual(valid);
}
});
......@@ -424,9 +301,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'NoNumbers',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 5,
requireLowercase: true,
requireUppercase: true,
......@@ -438,9 +312,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'S0m3Numb3rs',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 5,
requireLowercase: true,
requireUppercase: true,
......@@ -450,12 +321,8 @@ describe('Utils.isValidPassword', function() {
valid: true,
},
]) {
const errorMsg = Utils.isValidPassword(data.password, data.config);
if (data.valid) {
expect(errorMsg).toEqual('');
} else {
expect(errorMsg).not.toEqual('');
}
const {valid} = Utils.isValidPassword(data.password, data.config);
expect(data.valid).toEqual(valid);
}
});
......@@ -464,9 +331,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'N0Symb0ls',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 5,
requireLowercase: true,
requireUppercase: true,
......@@ -478,9 +342,6 @@ describe('Utils.isValidPassword', function() {
{
password: 'S0m3Symb0!s',
config: {
isEnterprise: true,
isLicensed: true,
isPasswordRequirements: true,
minimumLength: 5,
requireLowercase: true,
requireUppercase: true,
......@@ -490,12 +351,8 @@ describe('Utils.isValidPassword', function() {
valid: true,
},
]) {
const errorMsg = Utils.isValidPassword(data.password, data.config);
if (data.valid) {
expect(errorMsg).toEqual('');
} else {
expect(errorMsg).not.toEqual('');
}
const {valid} = Utils.isValidPassword(data.password, data.config);
expect(data.valid).toEqual(valid);
}
});
});
......
......@@ -1346,9 +1346,6 @@ export function canCreateCustomEmoji(user) {
export function getPasswordConfig(license, config) {
return {
isEnterprise: config.BuildEnterpriseReady === 'true',
isLicensed: license.IsLicensed === 'true',
isPasswordRequirements: license.PasswordRequirements === 'true',
minimumLength: parseInt(config.PasswordMinimumLength, 10),
requireLowercase: config.PasswordRequireLowercase === 'true',
requireUppercase: config.PasswordRequireUppercase === 'true',
......@@ -1358,55 +1355,49 @@ export function getPasswordConfig(license, config) {
}
export function isValidPassword(password, passwordConfig) {
let errorMsg = '';
let errorId = 'user.settings.security.passwordError';
let error = false;
let minimumLength = Constants.MIN_PASSWORD_LENGTH;
let valid = true;
const minimumLength = passwordConfig.minimumLength || Constants.MIN_PASSWORD_LENGTH;
if (passwordConfig.isEnterprise && passwordConfig.isLicensed && passwordConfig.isPasswordRequirements) {
if (password.length < passwordConfig.minimumLength || password.length > Constants.MAX_PASSWORD_LENGTH) {
error = true;
}
if (passwordConfig.requireLowercase) {
if (!password.match(/[a-z]/)) {
error = true;
}
if (password.length < minimumLength || password.length > Constants.MAX_PASSWORD_LENGTH) {
valid = false;
}
errorId += 'Lowercase';
if (passwordConfig.requireLowercase) {
if (!password.match(/[a-z]/)) {
valid = false;
}
if (passwordConfig.requireUppercase) {
if (!password.match(/[A-Z]/)) {
error = true;
}
errorId += 'Lowercase';
}
errorId += 'Uppercase';
if (passwordConfig.requireUppercase) {
if (!password.match(/[A-Z]/)) {
valid = false;
}
if (passwordConfig.requireNumber) {
if (!password.match(/[0-9]/)) {
error = true;
}
errorId += 'Uppercase';
}
errorId += 'Number';
if (passwordConfig.requireNumber) {
if (!password.match(/[0-9]/)) {
valid = false;
}
if (passwordConfig.requireSymbol) {
if (!password.match(/[ !"\\#$%&'()*+,-./:;<=>?@[\]^_`|~]/)) {
error = true;
}
errorId += 'Number';
}
errorId += 'Symbol';
if (passwordConfig.requireSymbol) {
if (!password.match(/[ !"\\#$%&'()*+,-./:;<=>?@[\]^_`|~]/)) {
valid = false;
}
minimumLength = passwordConfig.minimumLength;
} else if (password.length < Constants.MIN_PASSWORD_LENGTH || password.length > Constants.MAX_PASSWORD_LENGTH) {
error = true;
errorId += 'Symbol';