From 683f7133190aa350cdd1ea2608c90fe5f47b35cd Mon Sep 17 00:00:00 2001 From: David Lu Date: Wed, 6 Jul 2016 18:54:54 -0400 Subject: PLT-1465 Added password requirements (#3489) * Added password requirements * added tweaks * fixed error code * removed http.StatusNotAcceptable --- webapp/components/admin_console/admin_sidebar.jsx | 6 +- webapp/components/admin_console/login_settings.jsx | 125 --------- .../components/admin_console/password_settings.jsx | 310 +++++++++++++++++++++ 3 files changed, 313 insertions(+), 128 deletions(-) delete mode 100644 webapp/components/admin_console/login_settings.jsx create mode 100644 webapp/components/admin_console/password_settings.jsx (limited to 'webapp/components/admin_console') diff --git a/webapp/components/admin_console/admin_sidebar.jsx b/webapp/components/admin_console/admin_sidebar.jsx index 5a31519c9..49df8f820 100644 --- a/webapp/components/admin_console/admin_sidebar.jsx +++ b/webapp/components/admin_console/admin_sidebar.jsx @@ -428,11 +428,11 @@ export default class AdminSidebar extends React.Component { } /> } /> diff --git a/webapp/components/admin_console/login_settings.jsx b/webapp/components/admin_console/login_settings.jsx deleted file mode 100644 index 651d8352b..000000000 --- a/webapp/components/admin_console/login_settings.jsx +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -import React from 'react'; - -import * as Utils from 'utils/utils.jsx'; - -import AdminSettings from './admin_settings.jsx'; -import BooleanSetting from './boolean_setting.jsx'; -import {FormattedMessage} from 'react-intl'; -import GeneratedSetting from './generated_setting.jsx'; -import SettingsGroup from './settings_group.jsx'; -import TextSetting from './text_setting.jsx'; - -export default class LoginSettings extends AdminSettings { - constructor(props) { - super(props); - - this.getConfigFromState = this.getConfigFromState.bind(this); - - this.renderSettings = this.renderSettings.bind(this); - } - - getConfigFromState(config) { - config.EmailSettings.PasswordResetSalt = this.state.passwordResetSalt; - config.ServiceSettings.MaximumLoginAttempts = this.parseIntNonZero(this.state.maximumLoginAttempts); - if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') { - config.ServiceSettings.EnableMultifactorAuthentication = this.state.enableMultifactorAuthentication; - } - - return config; - } - - getStateFromConfig(config) { - return { - passwordResetSalt: config.EmailSettings.PasswordResetSalt, - maximumLoginAttempts: config.ServiceSettings.MaximumLoginAttempts, - enableMultifactorAuthentication: config.ServiceSettings.EnableMultifactorAuthentication - }; - } - - renderTitle() { - return ( -

- -

- ); - } - - renderSettings() { - let mfaSetting = null; - if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') { - mfaSetting = ( - - } - helpText={ - - } - value={this.state.enableMultifactorAuthentication} - onChange={this.handleChange} - /> - ); - } - - return ( - - - } - helpText={ - - } - value={this.state.passwordResetSalt} - onChange={this.handleChange} - disabled={this.state.sendEmailNotifications} - disabledText={ - - } - /> - - } - placeholder={Utils.localizeMessage('admin.service.attemptExample', 'Ex "10"')} - helpText={ - - } - value={this.state.maximumLoginAttempts} - onChange={this.handleChange} - /> - {mfaSetting} - - ); - } -} diff --git a/webapp/components/admin_console/password_settings.jsx b/webapp/components/admin_console/password_settings.jsx new file mode 100644 index 000000000..9d335c539 --- /dev/null +++ b/webapp/components/admin_console/password_settings.jsx @@ -0,0 +1,310 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import React from 'react'; +import AdminSettings from './admin_settings.jsx'; +import {FormattedMessage} from 'react-intl'; +import SettingsGroup from './settings_group.jsx'; +import TextSetting from './text_setting.jsx'; +import BooleanSetting from './boolean_setting.jsx'; +import Setting from './setting.jsx'; +import * as Utils from 'utils/utils.jsx'; +import Constants from 'utils/constants.jsx'; +import GeneratedSetting from './generated_setting.jsx'; + +export default class PasswordSettings extends AdminSettings { + constructor(props) { + super(props); + + this.getConfigFromState = this.getConfigFromState.bind(this); + + this.renderSettings = this.renderSettings.bind(this); + + this.getSampleErrorMsg = this.getSampleErrorMsg.bind(this); + + this.state = Object.assign(this.state, { + passwordMinimumLength: props.config.PasswordSettings.MinimumLength, + passwordLowercase: props.config.PasswordSettings.Lowercase, + passwordNumber: props.config.PasswordSettings.Number, + passwordUppercase: props.config.PasswordSettings.Uppercase, + passwordSymbol: props.config.PasswordSettings.Symbol, + maximumLoginAttempts: props.config.ServiceSettings.MaximumLoginAttempts, + enableMultifactorAuthentication: props.config.ServiceSettings.EnableMultifactorAuthentication, + passwordResetSalt: props.config.EmailSettings.PasswordResetSalt + }); + + // Update sample message from config settings + let sampleErrorMsgId = 'user.settings.security.passwordError'; + if (props.config.PasswordSettings.Lowercase) { + sampleErrorMsgId = sampleErrorMsgId + 'Lowercase'; + } + if (props.config.PasswordSettings.Uppercase) { + sampleErrorMsgId = sampleErrorMsgId + 'Uppercase'; + } + if (props.config.PasswordSettings.Number) { + sampleErrorMsgId = sampleErrorMsgId + 'Number'; + } + if (props.config.PasswordSettings.Symbol) { + sampleErrorMsgId = sampleErrorMsgId + 'Symbol'; + } + this.sampleErrorMsg = ( + + ); + } + + componentWillUpdate() { + this.sampleErrorMsg = this.getSampleErrorMsg(); + } + + getConfigFromState(config) { + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') { + config.PasswordSettings.MinimumLength = this.parseIntNonZero(this.state.passwordMinimumLength, 10); + 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); + config.EmailSettings.PasswordResetSalt = this.state.passwordResetSalt; + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') { + config.ServiceSettings.EnableMultifactorAuthentication = this.state.enableMultifactorAuthentication; + } + + return config; + } + + getSampleErrorMsg() { + if (this.props.config.PasswordSettings.MinimumLength > Constants.MAX_PASSWORD_LENGTH || this.props.config.PasswordSettings.MinimumLength < Constants.MIN_PASSWORD_LENGTH) { + return ( + + ); + } + + let sampleErrorMsgId = 'user.settings.security.passwordError'; + if (this.refs.lowercase.checked) { + sampleErrorMsgId = sampleErrorMsgId + 'Lowercase'; + } + if (this.refs.uppercase.checked) { + sampleErrorMsgId = sampleErrorMsgId + 'Uppercase'; + } + if (this.refs.number.checked) { + sampleErrorMsgId = sampleErrorMsgId + 'Number'; + } + if (this.refs.symbol.checked) { + sampleErrorMsgId = sampleErrorMsgId + 'Symbol'; + } + return ( + + ); + } + + renderTitle() { + return ( +

+ +

+ ); + } + + renderSettings() { + let mfaSetting = null; + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') { + mfaSetting = ( + + } + helpText={ + + } + value={this.state.enableMultifactorAuthentication} + onChange={this.handleChange} + /> + ); + } + + let passwordSettings = null; + if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') { + passwordSettings = ( +
+ + } + helpText={ + + } + value={this.state.passwordMinimumLength} + onChange={this.handleChange} + /> + + } + > +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+ {this.sampleErrorMsg} +
+
+
+ ); + } + + return ( + + {passwordSettings} + + } + helpText={ + + } + value={this.state.passwordResetSalt} + onChange={this.handleChange} + disabled={this.state.sendEmailNotifications} + disabledText={ + + } + /> + + } + placeholder={Utils.localizeMessage('admin.service.attemptExample', 'Ex "10"')} + helpText={ + + } + value={this.state.maximumLoginAttempts} + onChange={this.handleChange} + /> + {mfaSetting} + + ); + } +} \ No newline at end of file -- cgit v1.2.3-1-g7c22