Implement two-step verification in Java

Overview I've always wanted to implement two-step verification, but it was easier than I expected because of the existence of a good library.

GoogleAuth (server-side library for two-step verification)

https://github.com/wstrange/GoogleAuth

GoogleAuth is a server-side Java library that creates a Time-based One-time Password (TOTP) as defined in RFC6238.

If you implement the server side using the above library, you can authenticate the user using the one-time token issued by an application such as Google Authenticator provided by Google.

Google Authenticator for iOS

https://itunes.apple.com/jp/app/google-authenticator/id388497605?mt=8

Android version Google Authenticator

https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=ja

Google Authenticator can also be used because it creates a one-time token according to the TOTP specifications.

General flow of two-step verification

I think the flow will be as follows.

two-factor-auth-seq.png

Sample code

https://github.com/yuizho/two-factor-auth-sample

It is the implementation code of the Server part in the above sequence diagram.

The language uses Java.

The process of saving user information is cheated by using Singleton's Map instead of DB.

Sample code explanation

It's about the explanation of the sample code, or almost how to use the library (Google Auth).

Issuing & saving SecretKey

You can issue a Secret Key for "user_id" with the code below and save it in a database.

GoogleAuthenticator gAuth = new GoogleAuthenticator();
GoogleAuthenticatorKey key = gAuth.createCredentials("user_id");

Before executing the above code, you need to make the following preparations.

Prepare implementation class of ICredentialRepository

When you execute the above createCredentials, GoogleAuth will call the saveUserCredentials method of the implementation class of ICredentialRepository to save the secretKey.

public class MyCredentialRepository implements ICredentialRepository {
    // ...
    @Override
    public void saveUserCredentials(String userId, String secretKey, int validationCode, List<Integer> scratchCodes) {
        //Describe the process to save secretKey with userId as key
    }
}

By the way, scratchCodes is a code to be used when the user loses the terminal, and it seems that 5 are issued by default. https://github.com/wstrange/GoogleAuth#scratch-codes

I couldn't quite understand what the validationCode was supposed to be for (similar to scratchCodes?). If you know, please teach me: bow:

I haven't done it in the sample code, but I think it's a good idea to implement the processing of these values as needed.

Preparation for Java Service Loader

GoogleAuth implements ICredentialRepository using Java ServiceLoader API when createCredentials is executed Get the class and save the secretKey.

Create a META-INF / services folder in a location where the classpath passes, such as under src / resource, and create a text file called com.warrenstrange.googleauth.ICredentialRepository.

If you describe the implementation class name of ICredentialRepository in the created file as follows, GoogleAuth will use this class.

io.github.yuizho.twofactorauth.MyCredentialRepository

Return of Secret information

When loading the Secret information including the generated secretKey into Google Authenticator, generate a URI in the following format and convert it to a QR code.

otpauth://totp/<userId>?secret=<secretKey>&issuer=<applicationName>

e.g. otpauth://totp/test_user?secret=ZYWAZKOQLG3YHBSZ&issuer=two-factor-auth-sample

See below for details on the URI format. https://github.com/google/google-authenticator/wiki/Key-Uri-Format

Token verification

You can get the secretKey for "user_id" from the save destination like below, generate a token, and check if it matches the passed token (the one obtained with Google Authenticator).

GoogleAuthenticator gAuth = new GoogleAuthenticator();
boolean isCodeValid = gAuth.authorizeUser("user_id", token);

At this time, GoogleAuth calls the getSecretKey method of the implementation class of ICredentialRepository in the same way as when saving the secretKey, and performs the secretKey acquisition process.

public class MyCredentialRepository implements ICredentialRepository {
    // ...
    @Override
    public String getSecretKey(String userId) {
        //Implemented the process to get secretKey from table with userId as key and return it
    }
}

After that, it will generate a token based on the secret key acquired by GoogleAuth and the current timestamp, and compare it with the token passed to the second argument of GoogleAuthenticator # authorizeUser.

Summary

So it was relatively easy to implement two-step verification.

This time, GoogleAuth is used for the server-side library, but of course you can implement it yourself without using the library.

In that case, I think that you should implement the token TOTP generation process while referring to the following RFC etc. (Sample code is also available). https://tools.ietf.org/html/rfc6238

Recommended Posts

Implement two-step verification in Java
Implement Basic authentication in Java
Implement math combinations in Java
2 Implement simple parsing in Java
Implement Email Sending in Java
Implement functional quicksort in Java
Two-step verification JAVA realization (TOTP)
Implement rm -rf in Java.
Implement XML signature in Java
Implement Table Driven Test in Java 14
3 Implement a simple interpreter in Java
Implement reCAPTCHA v3 in Java / Spring
Implement PHP implode function in Java
Try to implement Yubaba in Java
1 Implement simple lexical analysis in Java
How to implement date calculation in Java
How to implement Kalman filter in Java
Implement API Gateway Lambda Authorizer in Java Lambda
Partization in Java
Try to implement n-ary addition in Java
Changes in Java 11
Rock-paper-scissors in Java
How to implement coding conventions in Java
Implement something like a stack in Java
Pi in Java
FizzBuzz in Java
I tried to implement deep learning in Java
[java] sort in list
Read JSON in Java
Interpreter implementation in Java
Make Blackjack in Java
Rock-paper-scissors app in Java
Constraint programming in Java
Put java8 in centos7
NVL-ish guy in Java
Combine arrays in Java
"Hello World" in Java
Callable Interface in Java
Azure functions in java
Format XML in Java
Simple htmlspecialchars in Java
Boyer-Moore implementation in Java
Hello World in Java
Use OpenCV in Java
webApi memorandum in java
Type determination in Java
Ping commands in Java
Various threads in java
Heapsort implementation (in java)
Zabbix API in Java
ASCII art in Java
Compare Lists in Java
POST JSON in Java
Express failure in Java
Implement CustomView in code
Create JSON in Java
Date manipulation in Java 8
What's new in Java 8
Use PreparedStatement in Java
What's new in Java 9,10,11
Parallel execution in Java