Java MFA Integration
Introduction
The following instructions demonstrate how to integrate Acceptto multi-factor authentication with your Java codebase.
Requirement
Before being able to use this sample you need to obtain an Acceptto MFA Application UID and Secret:
- Signup for a new Acceptto account or Login to your Acceptto dashboard
- Navigate to Applications through the side menu
- Click on the New Application button to create a new application, and then
- Choose a Name for your application which you're going to enable the multi-factor authentication for
- Set the Redirect URL to
http://localhost:9000/auth/mfa/callback
- Set the Color to whatever you like, this is the color band that the user will see next to your application name in the Acceptto It'sMe
app
- Find the new create application in the list and click on the Details button
- Copy and keep the UID and Secret. You will need them in the next steps
Run the sample project
- Install sbt
git clone git@github.com:acceptto-corp/mfa-web-java.git
and go tomfa-web-java
directory- Update
mfa.app.uid
,mfa.app.secret
values inconf/application.conf
as obtained in the previous section - Run
sbt run
and browse tolocalhost:9000
- Apply evolution (You'll be asked only for the first time in order to setup the database)
How it works
Although you can go ahead and look at the code to see how it works, for better understanding we explain the key components that are needed in order to enable MFA on an existing Java application.
This guide uses Play Framework (Java version) but the concepts are the same for any other Java framework. You can use most parts of the provided code as it is in any other framework.
Data model
The following fields are added to the normal User
model in LocalUser.java
:
public String mfa_email;
public Boolean mfa_authenticated;
mfa_email
represents the corresponding email which is used to register with Accepttomfa_authenticated
indicates whether the user second factor authentication was successful or not
Authentication
The user token is stored in session, but in addition to that when mfa_email
is set (which means MFA is enabled for the account), user is not considered authenticated unless mfa_authenticated
is true
. Here is the piece of code which retrieves the current authenticated user in app/controllers/Secured.java
:
public String getUsername(Http.Context ctx) {
String email = ctx.session().get("email");
if (email == "" || email == null) {
return null;
}
LocalUser user = LocalUser.findByEmail(email);
if (user == null || (user.mfa_email != null && user.mfa_email != "" && (user.mfa_authenticated == null || !user.mfa_authenticated))) {
return null;
}
return email;
}
More about MFA email
In this sample app, email
(in models/LocalUser.java
) is basically the username, but we also have mfa_email
to be able to connect Acceptto It'sMe accounts to the accounts in this sample app.
Here is an example to make it easier to understand the relationship between mfa_email
and email
:
Scenario 1
- You've created an account in Acceptto It'sMe application using
A@email.com
- You run this sample Java app and use the same email
A@email.com
in the sign up form - As this email has already been registered with It'sMe, you'll be asked for MFA in your next login in this sample app
- You receive MFA confirmations on your It'sMe app which is logged in with
A@email.com
In this scenario, both email
and mfa_email
was set to A@email.com
.
Scenario 2
- You run this sample Java app and use the same email
B@email.com
in the sign up form - You'll be able to login to the sample app only with email and password
- You'll see
Enable MFA
link after login and you click on the link - You enter
A@email.com
asAcceptto's MFA email
and click onEnable
- This enables the MFA, connects
B@email.com
in this sample app toA@email.com
in It'sMe - When you login using
B@email.com
in this sample app, you receive MFA confirmations on your It'sMe app which is logged in withA@email.com
In this scenario, email
was set to B@email.com
and mfa_email
was set to A@email.com
.
Enabling the MFA during the sign up
We'll check the registered email (by calling /api/v9/is_user_valid
API) to see if an Acceptto account has already been created using that email. If that was the case by setting mfa_email
to the same email as LocalUser.email
, we'll be able to use that in the further API calls and basically we've enabled the MFA automatically. If the email wasn't registered in Acceptto we allow the user to it later.
Here is the block of the code in Signup.java
that checks the sign up email:
LocalUser user = new LocalUser();
user.email = register.email;
user.fullname = register.fullname;
user.passwordHash = Hash.createPassword(register.inputPassword);
user.confirmationToken = UUID.randomUUID().toString();
// Temporary confirm user
user.validated = true;
final String mfaSite = Play.application().configuration().getString("mfa.site");
F.Promise<WSResponse> responsePromise = WS.url(mfaSite + "/api/v9/is_user_valid")
.setQueryParameter("email", register.email)
.setQueryParameter("uid", Application.appUID)
.setQueryParameter("secret", Application.appSecret)
.setContentType("application/x-www-form-urlencoded")
.post("");
F.Promise<Result> resultPromise = responsePromise.map(new F.Function<WSResponse, Result>() {
@Override
public Result apply(WSResponse wsResponse) throws Throwable {
JsonNode json = wsResponse.asJson();
if (json.has("valid") && json.get("valid").asBoolean()) {
if (json.has("registration_state") && json.get("registration_state").asText().equals("finished")) {
// Using the same email as Acceptto one.
user.mfa_email = register.email;
Logger.debug("MFA email has set to " + register.email);
} else {
Logger.warn("User has started registration in Acceptto but hasn't finished");
}
}
user.save();
return ok(created.render());
}
});
Add enabling MFA link to view
When mfa_email
is null, it shows that the email used for sign up hasn't been registered in Acceptto's It'sMe App. So we need to show the user how he/she can enable the MFA by creating a new Acceptto account (using the existing email) or use and existing one and connect them to their account in this Java sample application.
We do this by showing a link to /auth/mfa/enable
(which simply renders mfa/enablemfa.scala.html
) in dashboard when mfa_email
is null. In Enable MFA page we've provided links to Acceptto apps and a text box to get the Acceptto's account email through which the user wants to enable the MFA.
MFA authentication process
Here is what happens when the user logs in, while MFA is enabled:
mfa_authenticated
will be set tofalse
(authenticate
method inapp/controllers/Application.java
)/api/v9/authenticate_with_options
will be called (accepttoAuthenticate
method inapp/controllers/Mfa.java
)- Returned
channel
will be stored in session - The user will be redirected to Acceptto's
/mfa/index
page - The callback will post the data to
/auth/mfa_check
(check
method inapp/controllers/Mfa.java
) /api/v9/check
will be called to validate the callback- If successful, the user will be marked as authenticated by setting
mfa_authenticated
totrue
Support
If you require assistance, please email us at support@acceptto.com
Sales
Want to learn more about our MFA solutions? Contact our Professional Services for a Demo today.