PLT-4767 Implement MFA Enforcement (#4662)

* Create MFA setup page and remove MFA setup from account settings modal

* Add enforce MFA to system console and force redirect

* Lockdown mfa required API routes, add localization, other changes

* Minor fixes

* Fix typo

* Fix some unit tests

* Fix more unit tests

* Minor fix

* Updating UI for MFA screen (#4670)

* Updating UI for MFA screen

* Updating styles for MFA page

* Add the ability to switch between email/sso with MFA enabled

* Added mfa change email

* Minor UI updates for MFA enforcement

* Fix unit test

* Fix client unit test

* Allow switching email to ldap and back when MFA is enabled

* Fix unit test

* Revert config.json
Этот коммит содержится в:
Joram Wilander
2016-12-12 08:16:10 -05:00
коммит произвёл enahum
родитель f0d71d8789
Коммит 30a10d35a8
34 изменённых файлов: 1001 добавлений и 231 удалений

Просмотреть файл

@@ -194,6 +194,7 @@ export default class AdminSidebar extends React.Component {
let clusterSettings = null;
let metricsSettings = null;
let complianceSettings = null;
let mfaSettings = null;
let license = null;
let audits = null;
@@ -284,6 +285,20 @@ export default class AdminSidebar extends React.Component {
);
}
if (global.window.mm_license.MFA === 'true') {
mfaSettings = (
<AdminSidebarSection
name='mfa'
title={
<FormattedMessage
id='admin.sidebar.mfa'
defaultMessage='MFA'
/>
}
/>
);
}
oauthSettings = (
<AdminSidebarSection
name='oauth'
@@ -507,6 +522,7 @@ export default class AdminSidebar extends React.Component {
{oauthSettings}
{ldapSettings}
{samlSettings}
{mfaSettings}
</AdminSidebarSection>
<AdminSidebarSection
name='security'

Просмотреть файл

@@ -0,0 +1,99 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import AdminSettings from './admin_settings.jsx';
import SettingsGroup from './settings_group.jsx';
import BooleanSetting from './boolean_setting.jsx';
import React from 'react';
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
export default class MfaSettings extends AdminSettings {
constructor(props) {
super(props);
this.getConfigFromState = this.getConfigFromState.bind(this);
this.renderSettings = this.renderSettings.bind(this);
this.state = Object.assign(this.state, {
enableMultifactorAuthentication: props.config.ServiceSettings.EnableMultifactorAuthentication,
enforceMultifactorAuthentication: props.config.ServiceSettings.EnforceMultifactorAuthentication
});
}
getConfigFromState(config) {
config.ServiceSettings.EnableMultifactorAuthentication = this.state.enableMultifactorAuthentication;
config.ServiceSettings.EnforceMultifactorAuthentication = this.state.enableMultifactorAuthentication && this.state.enforceMultifactorAuthentication;
return config;
}
getStateFromConfig(config) {
return {
enableMultifactorAuthentication: config.ServiceSettings.EnableMultifactorAuthentication,
enforceMultifactorAuthentication: config.ServiceSettings.EnableMultifactorAuthentication && config.ServiceSettings.EnforceMultifactorAuthentication
};
}
renderTitle() {
return (
<h3>
<FormattedMessage
id='admin.mfa.title'
defaultMessage='Multi-factor Authentication'
/>
</h3>
);
}
renderSettings() {
return (
<SettingsGroup>
<div className='banner'>
<div className='banner__content'>
<FormattedMessage
id='admin.mfa.bannerDesc'
defaultMessage='Multi-factor authentication is only available for accounts with LDAP and email login methods. If there are users on your system with other login methods, it is recommended you set up multi-factor authentication directly with the SSO or SAML provider.'
/>
</div>
</div>
<BooleanSetting
id='enableMultifactorAuthentication'
label={
<FormattedMessage
id='admin.service.mfaTitle'
defaultMessage='Enable Multi-factor Authentication:'
/>
}
helpText={
<FormattedMessage
id='admin.service.mfaDesc'
defaultMessage='When true, users will be given the option to add multi-factor authentication to their account. They will need a smartphone and an authenticator app such as Google Authenticator.'
/>
}
value={this.state.enableMultifactorAuthentication}
onChange={this.handleChange}
/>
<BooleanSetting
id='enforceMultifactorAuthentication'
label={
<FormattedMessage
id='admin.service.enforceMfaTitle'
defaultMessage='Enforce Multi-factor Authentication:'
/>
}
helpText={
<FormattedHTMLMessage
id='admin.service.enforceMfaDesc'
defaultMessage='When true, users on the system will be required to set up [multi-factor authentication]. Any logged in users will be redirected to the multi-factor authentication setup page until they successfully add MFA to their account.<br/><br/>It is recommended you turn on enforcement during non-peak hours, when people are less likely to be using the system. New users will be required to set up multi-factor authentication when they first sign up. After set up, users will not be able to remove multi-factor authentication unless enforcement is disabled.<br/><br/>Please note that multi-factor authentication is only available for accounts with LDAP and email login methods. Mattermost will not enforce multi-factor authentication for other login methods. If there are users on your system using other login methods, it is recommended you set up and enforce multi-factor authentication directly with the SSO or SAML provider.'
/>
}
disabled={!this.state.enableMultifactorAuthentication}
value={this.state.enforceMultifactorAuthentication}
onChange={this.handleChange}
/>
</SettingsGroup>
);
}
}

Просмотреть файл

@@ -6,7 +6,6 @@ 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';
@@ -32,7 +31,6 @@ export default class PasswordSettings extends AdminSettings {
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
});
@@ -75,9 +73,6 @@ export default class PasswordSettings extends AdminSettings {
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;
}
@@ -90,7 +85,6 @@ export default class PasswordSettings extends AdminSettings {
passwordUppercase: config.PasswordSettings.Uppercase,
passwordSymbol: config.PasswordSettings.Symbol,
maximumLoginAttempts: config.ServiceSettings.MaximumLoginAttempts,
enableMultifactorAuthentication: config.ServiceSettings.EnableMultifactorAuthentication,
passwordResetSalt: config.EmailSettings.PasswordResetSalt
};
}
@@ -154,29 +148,6 @@ export default class PasswordSettings extends AdminSettings {
}
renderSettings() {
let mfaSetting = null;
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true') {
mfaSetting = (
<BooleanSetting
id='enableMultifactorAuthentication'
label={
<FormattedMessage
id='admin.service.mfaTitle'
defaultMessage='Enable Multi-factor Authentication:'
/>
}
helpText={
<FormattedMessage
id='admin.service.mfaDesc'
defaultMessage='When true, users will be given the option to add multi-factor authentication to their account. They will need a smartphone and an authenticator app such as Google Authenticator.'
/>
}
value={this.state.enableMultifactorAuthentication}
onChange={this.handleChange}
/>
);
}
let passwordSettings = null;
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.PasswordRequirements === 'true') {
passwordSettings = (
@@ -332,8 +303,7 @@ export default class PasswordSettings extends AdminSettings {
value={this.state.maximumLoginAttempts}
onChange={this.handleChange}
/>
{mfaSetting}
</SettingsGroup>
);
}
}
}