Today on the 5th day is Keycloak customization. For a description of Keycloak, see What is Keycloak. This article introduces Keycloak in last year's Keycloak by OpenStandia Advent Calendar 2017. I also participated in last year's Keycloak Advent Calendar and wrote an article about Keycloak Customization Points. This time, we will pick up the authentication function (Authentication SPI) in this customization point and SMS for authentication processing. Let's customize it to add an authentication (identity verification) function.
SMS (Short Message Service) is a service that allows you to send and receive short messages by phone number. SMS authentication is to authenticate (identify) using SMS. Expressed in a picture, it is the following image.
By sending and confirming the authentication code to Mr. A's registered phone number separately from the ID / PWD login, you can confirm your identity more reliably, so you can increase the probability of preventing unauthorized login from a third party. I will.
SMS sending and receiving services are provided by Twilio, nexmo, [Amazon SNS]( There are several such as https://aws.amazon.com/jp/sns/), but this time we used ** Twilio ** </ font> for the SMS sending and receiving service. I will.
Twilio is a cloud communications company located in San Francisco that provides services for sending and receiving phone calls and text messages using the web service API. In Japan, KDDI is the agency and Japanese document is also open to the public, so I think it will be easy to enter when using it for the first time.
As an aside, Twilio's Advent Calendar was also registered this year. (Registered every year since 2015) Twilio offers various communication APIs other than sending and receiving SMS, so please refer to it if you are interested.
To use Twilio's SMS authentication, you need a Twilio account (to be exact, you need an API-KEY for sending and receiving SMS) Free Trial Account can be registered and is free up to a certain amount in Twilio It can be used in. When you reach a certain amount, your account will be automatically suspended and you will be notified of upgrades to your paid account.
You will not be charged unless you upgrade to a paid account (as of December 2018), but it may change in the future, so please check the terms of use when registering. Registration itself is easy, so I think you can proceed normally. Phone number verification (SMS) will occur during registration, so prepare a phone that can receive SMS. (SMS communication charges are borne by the recipient.)
After creating an account, when the TOP screen is displayed, go to "Top screen" ⇒ "Phone number verification" ⇒ "Phone number verification Project dashboard" ⇒ "Verify" and the following screen will be displayed. Let's proceed in the order of the numbers.
「1. Let’s verify a phone number on your Twilio account」
Here, we will verify the phone number again.
「2. Create an application and get your API credentials」
Create application and API. Once you create an application, you will be able to check / update the SMS transmission / reception history and API-KEY.
「3. Send your first Verify code」
Use the application API-KEY created above to send the SMS verification code with cURL. The contents of the request will be displayed as shown below, so you can also check the API-KEY here. (You can also check from the setting screen)
This completes the preparations on the Twilio side.
Check the login process before customizing. You can confirm your login by accessing the account management screen.
I have confirmed that I can log in by just entering the Username / Password.
Customize the authentication function. The work order is as follows.
I created a new Themes called "openstandia" to create two screens (.ftl
) and a message file (.properties
). The source code is here. To reflect it, place the ʻopenstandiafolder of the source code as it is under
KEYCLOAK_HOME / themes /` and it will be reflected.
We have prepared two message files, one for Japanese (jp) and one for English (en). The corresponding language is set in locales
in theme.properties ..
_KEYCLOAK_HOME_/themes/Theme name/login/theme.properties
parent=keycloak
import=common/keycloak
locales=en,ja
How to customize Themes was last year's "[Organize Keycloak customization points-About Themes](https://qiita.com/yoonis/items/298d580f7e93e56ddf6a#themes%E3%81%AB%E3%81%A4" % E3% 81% 84% E3% 81% A6) ”, so please refer to it.
Create an SMS authentication module. Earlier, when "Getting API-KEY of Twilio", we issued an authentication code with cURL and confirmed the authentication code, but we will execute this in the SMS authentication module.
ʻinterface
is ʻorg.keycloak.authentication.Authenticator`First, create the following two basic classes.
SMS authentication module class
Factory class of SMS authentication module class
getId ()
method public static final String PROVIDER_ID = "sms-authenticator-with-twilio";
public String getId() {
return PROVIDER_ID;
}
getDisplayType ()
method public String getDisplayType() {
return "Twilio SMS Authentication";
}
ʻIsConfigurable ()` method
Returns whether it is an Authenticator that can be set on the screen (administrative console). Returns true
if there are items to be entered from the screen. This time, API-KEY etc. will be input, so true
getConfigProperties ()
method
Screen (Management Console) Input item definition. I want to input API-KEY, authentication code digits, proxy settings, etc. from the management console, so set them here.
private static final List<ProviderConfigProperty> configProperties;
static {
configProperties = ProviderConfigurationBuilder
.create()
.property()
.name(SMSAuthContstants.CONFIG_SMS_API_KEY)
.label("API-KEY")
.type(ProviderConfigProperty.STRING_TYPE)
.helpText("")
.add()
......
.property()
.name(SMSAuthContstants.CONFIG_CODE_LENGTH)
.label("Code Length")
.type(ProviderConfigProperty.STRING_TYPE)
.helpText("")
.defaultValue(4)
.add()
.build();
}
......
public List<ProviderConfigProperty> getConfigProperties() {
return configProperties;
}
getRequirementChoices ()
method private static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
AuthenticationExecutionModel.Requirement.REQUIRED,
AuthenticationExecutionModel.Requirement.DISABLED
};
public Requirement[] getRequirementChoices() {
return REQUIREMENT_CHOICES;
}
META-INF/services/org.keycloak.authentication.AuthenticatorFactory
jp.openstandia.keycloak.authenticator.SMSAuthenticatorFactory
public void authenticate(AuthenticationFlowContext context) {
......
if (sendVerify.sendSMS(phoneNumber)) { //Send SMS
Response challenge = context.form().createForm("sms-validation.ftl");
context.challenge(challenge);
} else {
//Returns an error screen when SMS fails
Response challenge = context.form().setError(new FormMessage("sendSMSCodeErrorMessage"))
.createForm("sms-validation-error.ftl");
context.challenge(challenge);
}
......
}
What should be noted here is how to return the result. Set the screen to return to Response (Challenge) information (createForm) to context
. You can also set an error message (setError
) if an error occurs. The setting value of setError`` new FormMessage ("sendSMSCodeErrorMessage")
is sendSMSCodeErrorMessage
of Themes messages / openstandia / login / messages) This is the message Key defined in the file messages_xx_properties
.
public void action(AuthenticationFlowContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getDecodedFormParameters();
String enteredCode = inputData.getFirst("smsCode");
......
if (sendVerify.verifySMS(phoneNumber, enteredCode)) { //Authentication code confirmation
logger.info("verify code check : OK");
//When the authentication code is OK
context.success();
} else {
//Returns an error screen when authentication fails
Response challenge = context.form()
.setAttribute("username", context.getAuthenticationSession().getAuthenticatedUser().getUsername())
.setError(new FormMessage("invalidSMSCodeMessage")).createForm("sms-validation-error.ftl");
context.challenge(challenge);
}
......
}
Again, pay attention to how to return the result. If the verification code check is successful with verifySMS
, this verification result will be OK withcontext.success ()
. In case of an error, set the display screen and error message in Response (Challenge) and set it to context
as in the ʻauthenticate` method.
The SMS sending / code verification process implemented in the above SMS Authenticator
was implemented using Twilio's API using HttpsURLConnection
. SMS transmission (Twilio API call) processing is [here](https://github.com/sangyoon-lee/keycloak-sms-authenticator/blob/master/src/main/java/jp/openstandia/keycloak/authenticator/ api / SMSSendVerify.java)
That's all for module creation. Only the important methods have been introduced here. The source code of the sample module is published on GitHub, so please check the source code for detailed settings. The source code is here
Reflect the created file in Keycloak.
Place the created Themes file (per Openstandia folder) in _KEYCLOAK_HOME_ / themes /
. If it has already been placed at the time of "Create screen (Themes)", skip it.
Package the authentication module you created with the mvn package
and place the jar file in_KEYCLOAK_HOME_ / standalone / deployments /
.
After deploying all the customization modules, start Keycloak.
Reflects Themes. This is done from the "Realm Settings"-"Themes" tab. Since only the login theme is created this time, change the "login theme" to "openstandia". Other themes will not be changed.
Modify the authentication flow from the management console to add the SMS authentication module to the authentication process.
"Management Console"-"Authentication"-"Browser" authentication flow screen
Copy the "Browser" authentication flow (because the default "Browser" authentication flow cannot be modified directly). The authentication flow name is arbitrary.
Copyed "Openstandia Browser" authentication flow
Click Actions in Openstandia Browser Forms and click Add Execution.
Select the module created this time. The display name here is the name set in getDisplayType
of SMSAuthenticatorFactory
.
Added "Twilio SMS Authentication" and moved the execution order above "OTP Form". "OTP Form" is set to disabled (DISABLED) (optional)
Click "Actions" in "Twilio SMS Authentication" and then click "Settings". The screen items set in getConfigProperties
of SMSAuthenticatorFactory
are displayed here.
Return to the authentication flow and click the "Binding" tab. Change the browser flow to "Openstandia browser" which is a copy.
This completes the management console changes.
Add the phone number information to the user attributes to log in in advance. Match the "Key" of the phone number attribute with the attribute name in the authentication module.
Log in to the account management screen (http: // localhost: 8080 / auth / realms / realm name / account)
The verification code input screen is displayed.
The verification code will be sent to the entered phone number by SMS.
Enter the verification code
Login is complete
This is the end of the operation check.
I customized the authentication SPI and added SMS authentication to the authentication process. Keycloak customization is not limited to authentication SPI, and the customization method for all SPIs is basically the same.
Simply put
Check the SPI that corresponds to the function to be customized. (This time, authentication SPI)
Check ʻinterface that the feature you want to customize should be ʻimplements
. (This time Authenticator)
Implement the method provided by ʻimplements the target ʻinterface
.
Only this.
When implementing the third method, we will implement it while understanding what role each method plays. (Because this is the main, it takes the longest time, but ...)
Once you have experienced customizing any SPI, you will be able to implement it smoothly even if you customize another SPI from now on. Please try to customize Keycloak: +1: