Skip to content

Commit

Permalink
resend otp and error should be shown on same page with custom response
Browse files Browse the repository at this point in the history
  • Loading branch information
varadeth committed Mar 9, 2023
1 parent ea78fe7 commit ab841d7
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package in.divoc.api.authenticator;

public interface IValidation {
boolean validate(String mobileNumber);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.ErrorRepresentation;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
Expand All @@ -22,13 +25,16 @@ public class MobileNumberAuthenticator extends AbstractUsernameFormAuthenticator
private final OTPService mockOTPService;
private final OTPService otpService;
private final NotifyService notifyService;
private final IValidation iValidation;


private static final String mockOtp = System.getenv().getOrDefault("MOCK_OTP", "true");

public MobileNumberAuthenticator() {
this.mockOTPService = new MockOTPServiceImpl();
this.otpService = new OTPServiceImpl();
this.notifyService = new NotifyService();
this.iValidation = new ValidationService();
}

@Override
Expand All @@ -39,39 +45,93 @@ public void action(AuthenticationFlowContext context) {
System.err.println("action request " + type);
if (type.equals(LOGIN_FORM)) {
//TODO: rename form id
String INVALID_REGISTRATION = "INVALID_REGISTRATION";
String INVALID_USERNAME = "INVALID_USERNAME";
String mobileNumber = formData.getFirst(MOBILE_NUMBER);
List<UserModel> users = context.getSession().users()
.searchForUserByUserAttributeStream(context.getSession().getContext().getRealm(), MOBILE_NUMBER, mobileNumber).collect(Collectors.toList());
if (users.size() > 0) {
generateOTPAndNotify(context, mobileNumber, users);
} else {
users = context.getSession().users()
.searchForUserByUserAttributeStream(context.getSession().getContext().getRealm(), EMAIL, mobileNumber).collect(Collectors.toList());
if(iValidation.validate(mobileNumber)) {
List<UserModel> users = context.getSession().users()
.searchForUserByUserAttributeStream(context.getSession().getContext().getRealm(), MOBILE_NUMBER, mobileNumber).collect(Collectors.toList());
if (users.size() > 0) {
if (checkIfMaxResendOtpLimitReached(context)) return;
generateOTPAndNotify(context, mobileNumber, users);
} else {
context.failure(AuthenticationFlowError.INVALID_USER);
users = context.getSession().users()
.searchForUserByUserAttributeStream(context.getSession().getContext().getRealm(), EMAIL, mobileNumber).collect(Collectors.toList());
if (users.size() > 0) {
generateOTPAndNotify(context, mobileNumber, users);
} else {
Response response = context.form().setError(System.getenv(INVALID_REGISTRATION)).createForm(MOBILE_LOGIN_UI);
context.failure(AuthenticationFlowError.INVALID_USER, response);
}
}
}
else {
Response response = context.form().setError(System.getenv(INVALID_USERNAME)).createForm(MOBILE_LOGIN_UI);
context.failure(AuthenticationFlowError.INVALID_USER, response);
}
} else if (type.equals(VERIFY_OTP_FORM)) {
String sessionKey = context.getAuthenticationSession().getAuthNote(OTP);
if (sessionKey != null) {
String secret = formData.getFirst(OTP);
String VALID_OTP = "VALID_OTP";
if (secret != null) {
if (secret.equals(sessionKey)) {
context.success();
} else {
context.failure(AuthenticationFlowError.INVALID_CREDENTIALS);
Response response = context.form().setError(System.getenv(VALID_OTP)).createForm(VERIFY_OTP_UI);
if(checkIfMaxOtpTriesReached(context)) {
return;
}
context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, response);
}
} else {
context.failure(AuthenticationFlowError.INVALID_CREDENTIALS);
Response response = context.form().setError(System.getenv(VALID_OTP)).createForm(VERIFY_OTP_UI);
if(checkIfMaxOtpTriesReached(context)) {
return;
}
context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, response);
}
} else {
context.challenge(context.form().createForm(MOBILE_LOGIN_UI));
}
}
}

private static boolean checkIfMaxResendOtpLimitReached(AuthenticationFlowContext context) {
String MAX_RESEND_TRIES = "MAX_RESEND_TRIES";
String RESEND_OTP_TRY_COUNT = "RESEND_OTP_TRY_COUNT";
String resendTries = context.getAuthenticationSession().getAuthNote(RESEND_OTP_TRY_COUNT);
System.out.println("RESEND RETRIES : " + resendTries);
int count = resendTries == null ? 0 : Integer.parseInt(resendTries);
count++;
if(count == Integer.parseInt(System.getenv(MAX_RESEND_TRIES)) + 1) {
context.getAuthenticationSession().setAuthNote(RESEND_OTP_TRY_COUNT, null);
context.failure(AuthenticationFlowError.INTERNAL_ERROR);
return true;
}
context.getAuthenticationSession().setAuthNote(RESEND_OTP_TRY_COUNT, count + "" );
return false;
}

private boolean checkIfMaxOtpTriesReached(AuthenticationFlowContext context) {
String OTP_TRIES = "OTP_TRIES";
String OTP_MAX_RETRY_LIMIT = "OTP_MAX_RETRY_LIMIT";
String otpTries = context.getAuthenticationSession().getAuthNote(OTP_TRIES);
System.out.println("OTP TRIES : " + otpTries);
int count = (otpTries == null ? 0 : Integer.parseInt(otpTries));
count++;
int maxLimit = Integer.parseInt(System.getenv(OTP_MAX_RETRY_LIMIT));
if(count == maxLimit) {
context.getAuthenticationSession().setAuthNote(OTP_TRIES, null);
String MAX_RETRIES_LIMIT_MESSAGE = "MAX_RETRIES_LIMIT_MESSAGE";
Response response = context.form().setError(System.getenv(MAX_RETRIES_LIMIT_MESSAGE)).createForm(MOBILE_LOGIN_UI);
context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, response);
return true;
}
context.getAuthenticationSession().setAuthNote(OTP_TRIES, "" + count);
return false;
}

private void generateOTPAndNotify(AuthenticationFlowContext context, String mobileNumber, List<UserModel> users) {
UserModel user = users.get(0);
String otp;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package in.divoc.api.authenticator;

public class ValidationService implements IValidation {
@Override
public boolean validate(String mobileNumber) {
return mobileNumber.length() == 10 || mobileNumber.length() == 14;
}
}

0 comments on commit ab841d7

Please sign in to comment.