Multi-factor authentication for Mendix (MFA/2FA)

Category: Modules
Subcategory: Authentication

Overview

The musthave multi-factor(MFA) / twofactor(2FA) authentication module that uses the Mendix core login/authentication capabilities together with an additional layer of security. It creates a usersession after user+password AND an additional code is validated. It supports all the common ways to create/validating codes like SMS, e-mail and (Google) Authenticator app.

- 29-12-2022: Please upgrade to version 2.0 (Mendix 9 compatible, see improvements in release notes)

- 24-12-2021: Please upgrade to version 1.5 (Vulnerability fix, rate limit and documentation)

Documentation

Multi-factor authentication for Mendix

What is Multi-factor Authentication?

Multi-factor authentication (MFA; also known as Two-factor authentication or 2FA, along with similar terms) is an electronic authentication method in which a user is granted access to a website or application only after successfully presenting two or more pieces of evidence (or factors) to an authentication mechanism: knowledge (something only the user knows), possession (something only the user has), and inherence (something only the user is). MFA protects the user from an unknown person trying to access their data such as personal ID details or financial assets.

A third-party authenticator (TPA) app enables two-factor authentication, usually by showing a randomly generated and constantly refreshing code to use for authentication. (source:Wikipedia)

What is the problem we solve?

The available multi-factor implementations in the Marketplace offer the end-user of an Mendix application during the login procedure to enter the code from a SMS, E-mail or generated by an authenticator (Google or other) after the actual login (and creation of the user session). See the diagram below:

alt text

https://swimlanes.io/d/zEPQlLV3T

At a successful login and prior to entering an MFA code, the user already has a valid user session and access to the user's authorized pages, microflows etc. (but you cannot see them nor easy access them). This approach only works when dynamic role assignment is done after a valid MFA code (which is not default Mendix functionality).

What is the solution?

We have built a MFA module that extends the Mendix LoginAction, documented at https://apidocs.rnd.mendix.com/7/runtime/com/mendix/core/action/user/LoginAction.html The MFA code is validated first and only then the module creates a user session which grants the user access to their pages, microflows etc.

alt text

https://swimlanes.io/u/4o7jaAOjY

We depricated the login.html compatibility in commbination of MFA. This will make the code more simple and safer.

How did we prove that this module is secure?

At the point in time after login in the first step:

mx.data.get({ xpath:'//System.User', callback:function(data){console.log(data);} })

still returns the anonymous User object:

alt text

Scenarios to cover:

  • Default login via widgets for accounts with MFA disabled.
  • Default login for webservice and REST accounts.
  • Login by default widgets but extended with ability to enter MFA code with MFA enabled.
  • Native mobile login

Configuration

  1. Download the module from the Mendix Marketplace here:

Or from Github: https://github.com/appronto/multifactor-authentication

  1. Download the Nanoflow Commons from the Mendix Marketplace

There are a few things to configure:

After startup configuration:

  1. Add ASU_MFA Microflow in your After Startup.

  2. Change SUB_MFA_UserDisabledCheck to call your logic to determine if the logged in user needs to be multi-factor authenticated.

    Example is available in SUB_MFA_UserDisabledCheck (copy this to your own module). If you use this example please Add the new attributes HasMFAenabled(Boolean) and LastLogin2FA (datetime) to the Account entity.

  3. Add your method(s) of multifactor authentication in SUB_MFA_ValidateCode.

    Examples are available:

  4. Add snippet SN_MFA_LoginPage / SN_Login_Native to your login page

  5. Set the constant EnabledMFA to true to get started!

Keep in mind when upgrading the module from the Appstore in the future:

It will break the login mechanism, but you will be notified because by default an exception will be raised and warnings will be shown when the module with your MFA logic hasn't been configured correcty. Like this "An error has occurred while handling the request: java.lang.Exception: SUB_MFA_UserDisabledCheck microflow not yet implemented. Did you upgrade? ".

What we learned

We preferred a non-persistent approach to keep track of the anonymous user login steps (first with login, second with MFA code). We found out when the first attempt was successfully validated, in the second step when passing the MFA code, the context/relation to the previous anonymous session was deleted. Therefore we could not correlate this to the first step. When we use a persistent MFA entity (and commit the MFA object after the first login step) it works.

alt text

For native mobile we needed to change the sign in nanoflow activity to save the login object in the local mobile device storage(that is not possible in web for security reasons).

Advanced java challenges:

When extending the LoginAction class and trying to set parameters from this class in our extended class, we found out this was not possible in combination with the super.execute() method. We decided to use createSession. We have already validated the username and password in the first step and the MFA object can't be modified/created by the anonymous user (and is also checked twice).

Please report issues

Have you found an issue or a vulnerability in this module, please reach out to pim@appronto.nl. I will reward you with a nice goodie bag and will publish the new version to the Marketplace.

Releases

Version: 2.0.0
Framework Version: 8.18.8
Release Notes: After reviewing and feedback we released 2.0 of the module. Please upgrade to this version! * When your mark this module as your favorite marketplace content you will receive notifications about new releases. Breaking change: - We removed the capability to use MFA from login.html (too complex) Configuration: - Remove MFA directory from your resources directory Improvements: - For MFA users: Max login attempts and Max MFA attempts can be configured with constants (default is 3) - For non-MFA user after the default platform attempts of 3 the user will be blocked according to the Mendix platform default and is released after 5 minutes (but read https://docs.mendix.com/refguide/login-behavior) - Improved logging message when user is blocked (so it's in line with unblocks by the Core runtime) - Reduced lines of java code - Added unit tests (if you experience issues, please check if you can create a unit test for the case) - Removed a HTML snippet and replaced this with a nanoflow + Javascript action - Create code flow is more fail proof if the custom implementation of creating code was not correct, the flow remains secure (by always setting a random code) - This Mendix 8.18.8 version of the module is Mendix 9 compatible (BlockSince attribute on User entity fix for Mendix 9 included!)
Version: 1.5.0
Framework Version: 8.18.8
Release Notes: - Added check on MFA code by the user (thanks Dirk of S-Unit for reporting after pentests!) - Added rate limit on attempts for MFA codes. Will block after user after 3 times (just like normal login attempts) - Custom info and error messages are now possible - Small documentation fixes