Skip to content

Commit

Permalink
MM-12736 Migrate MFA actions to redux (mattermost#1987)
Browse files Browse the repository at this point in the history
* MM-12736 Migrate activateMfa/deactivateMfa/generateMfaSecret to be redux actions

* MM-12736 Migrate checkMfa to be a redux action

* Add unit tests

* Fix prop type for SettingItemMax
  • Loading branch information
hmhealey committed Nov 7, 2018
1 parent ca1cc6e commit 48d24bf
Show file tree
Hide file tree
Showing 18 changed files with 346 additions and 183 deletions.
44 changes: 0 additions & 44 deletions actions/user_actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
import {getBool, makeGetCategory} from 'mattermost-redux/selectors/entities/preferences';
import {getCurrentTeamId, getTeamMember} from 'mattermost-redux/selectors/entities/teams';
import * as Selectors from 'mattermost-redux/selectors/entities/users';
import {getConfig} from 'mattermost-redux/selectors/entities/general';

import {browserHistory} from 'utils/browser_history';
import {loadStatusesForProfilesList, loadStatusesForProfilesMap} from 'actions/status_actions.jsx';
Expand Down Expand Up @@ -392,15 +391,6 @@ export async function updateUser(user, success, error) {
}
}

export async function generateMfaSecret(success, error) {
const {data, error: err} = await UserActions.generateMfaSecret(Selectors.getCurrentUserId(getState()))(dispatch, getState);
if (data && success) {
success(data);
} else if (err && error) {
error({id: err.server_error_id, ...err});
}
}

export async function updateUserNotifyProps(props, success, error) {
const {data, error: err} = await UserActions.updateMe({notify_props: props})(dispatch, getState);
if (data && success) {
Expand All @@ -419,40 +409,6 @@ export async function updateUserRoles(userId, newRoles, success, error) {
}
}

export async function activateMfa(code, success, error) {
const {data, error: err} = await UserActions.updateUserMfa(Selectors.getCurrentUserId(getState()), true, code)(dispatch, getState);
if (data && success) {
success(data);
} else if (err && error) {
error({id: err.server_error_id, ...err});
}
}

export async function deactivateMfa(success, error) {
const {data, error: err} = await UserActions.updateUserMfa(Selectors.getCurrentUserId(getState()), false)(dispatch, getState);
if (data && success) {
success(data);
} else if (err && error) {
error({id: err.server_error_id, ...err});
}
}

export async function checkMfa(loginId, success, error) {
const config = getConfig(getState());

if (config.EnableMultifactorAuthentication !== 'true') {
success(false);
return;
}

const {data, error: err} = await UserActions.checkMfa(loginId)(dispatch, getState);
if (data != null && success) {
success(data);
} else if (err && error) {
error({id: err.server_error_id, ...err});
}
}

export async function updateActive(userId, active, success, error) {
const {data, error: err} = await UserActions.updateUserActive(userId, active)(dispatch, getState);
if (data && success) {
Expand Down
42 changes: 42 additions & 0 deletions actions/views/mfa.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import * as UserActions from 'mattermost-redux/actions/users';
import {getConfig} from 'mattermost-redux/selectors/entities/general';
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';

export function activateMfa(code) {
return (dispatch, getState) => {
const currentUserId = getCurrentUserId(getState());

return dispatch(UserActions.updateUserMfa(currentUserId, true, code));
};
}

export function deactivateMfa() {
return (dispatch, getState) => {
const currentUserId = getCurrentUserId(getState());

return dispatch(UserActions.updateUserMfa(currentUserId, false));
};
}

export function generateMfaSecret() {
return (dispatch, getState) => {
const currentUserId = getCurrentUserId(getState());

return dispatch(UserActions.generateMfaSecret(currentUserId));
};
}

export function checkMfa(loginId) {
return (dispatch, getState) => {
const config = getConfig(getState());

if (config.EnableMultifactorAuthentication !== 'true') {
return Promise.resolve({data: false});
}

return dispatch(UserActions.checkMfa(loginId));
};
}
50 changes: 26 additions & 24 deletions components/claim/claim_controller.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,25 @@ import EmailToOAuth from 'components/claim/components/email_to_oauth';
import LDAPToEmail from 'components/claim/components/ldap_to_email';
import EmailToLDAP from 'components/claim/components/email_to_ldap';

export default class ClaimController extends React.Component {
export default class ClaimController extends React.PureComponent {
static propTypes = {
location: PropTypes.object.isRequired,
siteName: PropTypes.string,
ldapLoginFieldName: PropTypes.string,
passwordConfig: PropTypes.object,

/*
* Object from react-router
*/
match: PropTypes.shape({
url: PropTypes.string.isRequired,
}).isRequired,

actions: PropTypes.shape({
checkMfa: PropTypes.func.isRequired,
}).isRequired,
};

render() {
const email = (new URLSearchParams(this.props.location.search)).get('email');
const newType = (new URLSearchParams(this.props.location.search)).get('new_type');
Expand All @@ -31,9 +49,8 @@ export default class ClaimController extends React.Component {
<Switch>
<Route
path={`${this.props.match.url}/oauth_to_email`}
render={(props) => (
render={() => (
<OAuthToEmail
{...props}
currentType={currentType}
email={email}
siteName={this.props.siteName}
Expand All @@ -43,34 +60,33 @@ export default class ClaimController extends React.Component {
/>
<Route
path={`${this.props.match.url}/email_to_oauth`}
render={(props) => (
render={() => (
<EmailToOAuth
{...props}
newType={newType}
email={email}
siteName={this.props.siteName}
checkMfa={this.props.actions.checkMfa}
/>
)}
/>
<Route
path={`${this.props.match.url}/ldap_to_email`}
render={(props) => (
render={() => (
<LDAPToEmail
{...props}
siteName={this.props.siteName}
email={email}
passwordConfig={this.props.passwordConfig}
checkMfa={this.props.actions.checkMfa}
/>
)}
/>
<Route
path={`${this.props.match.url}/email_to_ldap`}
render={(props) => (
render={() => (
<EmailToLDAP
{...props}
email={email}
siteName={this.props.siteName}
ldapLoginFieldName={this.props.ldapLoginFieldName}
checkMfa={this.props.actions.checkMfa}
/>
)}
/>
Expand All @@ -82,17 +98,3 @@ export default class ClaimController extends React.Component {
);
}
}

ClaimController.propTypes = {
location: PropTypes.object.isRequired,
siteName: PropTypes.string,
ldapLoginFieldName: PropTypes.string,
passwordConfig: PropTypes.object,

/*
* Object from react-router
*/
match: PropTypes.shape({
url: PropTypes.string.isRequired,
}).isRequired,
};
40 changes: 21 additions & 19 deletions components/claim/components/email_to_ldap.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ import React from 'react';
import {FormattedMessage} from 'react-intl';

import {emailToLdap} from 'actions/admin_actions.jsx';
import {checkMfa} from 'actions/user_actions.jsx';
import * as Utils from 'utils/utils.jsx';
import LoginMfa from 'components/login/login_mfa.jsx';

export default class EmailToLDAP extends React.Component {
static propTypes = {
email: PropTypes.string,
siteName: PropTypes.string,
ldapLoginFieldName: PropTypes.string,
checkMfa: PropTypes.func.isRequired,
};

constructor(props) {
super(props);

Expand Down Expand Up @@ -62,19 +68,21 @@ export default class EmailToLDAP extends React.Component {
state.ldapPassword = ldapPassword;
this.setState(state);

checkMfa(
this.props.email,
(requiresMfa) => {
if (requiresMfa) {
this.setState({showMfa: true});
} else {
this.submit(this.props.email, password, '', ldapId, ldapPassword);
}
},
(err) => {
this.setState({error: err.message});
this.props.checkMfa(this.props.email).then((result) => {
if (result.error) {
this.setState({
error: result.error.message,
});
return;
}
);

const requiresMfa = result.data;
if (requiresMfa) {
this.setState({showMfa: true});
} else {
this.submit(this.props.email, password, '', ldapId, ldapPassword);
}
});
}

submit(loginId, password, token, ldapId, ldapPassword) {
Expand Down Expand Up @@ -258,12 +266,6 @@ export default class EmailToLDAP extends React.Component {
}
}

EmailToLDAP.propTypes = {
email: PropTypes.string,
siteName: PropTypes.string,
ldapLoginFieldName: PropTypes.string,
};

const style = {
usernameInput: {display: 'none'},
};
42 changes: 22 additions & 20 deletions components/claim/components/email_to_oauth.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ import ReactDOM from 'react-dom';
import {FormattedMessage} from 'react-intl';

import {emailToOAuth} from 'actions/admin_actions.jsx';
import {checkMfa} from 'actions/user_actions.jsx';
import Constants from 'utils/constants.jsx';
import * as Utils from 'utils/utils.jsx';
import LoginMfa from 'components/login/login_mfa.jsx';

export default class EmailToOAuth extends React.Component {
export default class EmailToOAuth extends React.PureComponent {
static propTypes = {
newType: PropTypes.string,
email: PropTypes.string,
siteName: PropTypes.string,
checkMfa: PropTypes.func.isRequired,
};

constructor(props) {
super(props);

Expand All @@ -38,19 +44,21 @@ export default class EmailToOAuth extends React.Component {
state.error = null;
this.setState(state);

checkMfa(
this.props.email,
(requiresMfa) => {
if (requiresMfa) {
this.setState({showMfa: true});
} else {
this.submit(this.props.email, password, '');
}
},
(err) => {
this.setState({error: err.message});
this.props.checkMfa(this.props.email).then((result) => {
if (result.error) {
this.setState({
error: result.error.message,
});
return;
}
);

const requiresMfa = result.data;
if (requiresMfa) {
this.setState({showMfa: true});
} else {
this.submit(this.props.email, password, '');
}
});
}

submit(loginId, password, token) {
Expand Down Expand Up @@ -166,9 +174,3 @@ export default class EmailToOAuth extends React.Component {
);
}
}

EmailToOAuth.propTypes = {
newType: PropTypes.string,
email: PropTypes.string,
siteName: PropTypes.string,
};
41 changes: 23 additions & 18 deletions components/claim/components/ldap_to_email.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import PropTypes from 'prop-types';
import React from 'react';
import {FormattedMessage} from 'react-intl';

import {checkMfa, switchFromLdapToEmail} from 'actions/user_actions.jsx';
import {switchFromLdapToEmail} from 'actions/user_actions.jsx';
import * as Utils from 'utils/utils.jsx';
import LoginMfa from 'components/login/login_mfa.jsx';

export default class LDAPToEmail extends React.Component {
static propTypes = {
email: PropTypes.string,
passwordConfig: PropTypes.object,
checkMfa: PropTypes.func.isRequired,
};

constructor(props) {
super(props);

Expand Down Expand Up @@ -67,19 +73,23 @@ export default class LDAPToEmail extends React.Component {
state.ldapPassword = ldapPassword;
this.setState(state);

checkMfa(
this.props.email,
(requiresMfa) => {
if (requiresMfa) {
this.setState({showMfa: true});
} else {
this.submit(this.props.email, password, '', ldapPassword);
}
},
(err) => {
this.setState({error: err.message});
this.props.checkMfa(this.props.email).then((result) => {
if (result.error) {
this.setState({
error: result.error.message,
});
return;
}
);

const requiresMfa = result.data;
if (requiresMfa) {
this.setState({
showMfa: true,
});
} else {
this.submit(this.props.email, password, '', ldapPassword);
}
});
}

submit(loginId, password, token, ldapPassword) {
Expand Down Expand Up @@ -239,8 +249,3 @@ export default class LDAPToEmail extends React.Component {
);
}
}

LDAPToEmail.propTypes = {
email: PropTypes.string,
passwordConfig: PropTypes.object,
};
Loading

0 comments on commit 48d24bf

Please sign in to comment.