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.
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.
https://itunes.apple.com/jp/app/google-authenticator/id388497605?mt=8
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.
I think the flow will be as follows.
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.
It's about the explanation of the sample code, or almost how to use the library (Google Auth).
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.
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.
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
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
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.
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