use of org.keycloak.models.credential.OTPCredentialModel in project keycloak by keycloak.
the class CredentialHelper method createOTPCredential.
/**
* Create OTP credential either in userStorage or local storage (Keycloak DB)
*
* @return true if credential was successfully created either in the user storage or Keycloak DB. False if error happened (EG. during HOTP validation)
*/
public static boolean createOTPCredential(KeycloakSession session, RealmModel realm, UserModel user, String totpCode, OTPCredentialModel credentialModel) {
CredentialProvider otpCredentialProvider = session.getProvider(CredentialProvider.class, "keycloak-otp");
String totpSecret = credentialModel.getOTPSecretData().getValue();
UserCredentialModel otpUserCredential = new UserCredentialModel("", realm.getOTPPolicy().getType(), totpSecret);
boolean userStorageCreated = session.userCredentialManager().updateCredential(realm, user, otpUserCredential);
String credentialId = null;
if (userStorageCreated) {
logger.debugf("Created OTP credential for user '%s' in the user storage", user.getUsername());
} else {
CredentialModel createdCredential = otpCredentialProvider.createCredential(realm, user, credentialModel);
credentialId = createdCredential.getId();
}
// If the type is HOTP, call verify once to consume the OTP used for registration and increase the counter.
UserCredentialModel credential = new UserCredentialModel(credentialId, otpCredentialProvider.getType(), totpCode);
return session.userCredentialManager().isValid(realm, user, credential);
}
use of org.keycloak.models.credential.OTPCredentialModel in project keycloak by keycloak.
the class OTPFormAuthenticator method validateOTP.
public void validateOTP(AuthenticationFlowContext context) {
MultivaluedMap<String, String> inputData = context.getHttpRequest().getDecodedFormParameters();
String otp = inputData.getFirst("otp");
String credentialId = inputData.getFirst("selectedCredentialId");
if (credentialId == null || credentialId.isEmpty()) {
OTPCredentialModel defaultOtpCredential = getCredentialProvider(context.getSession()).getDefaultCredential(context.getSession(), context.getRealm(), context.getUser());
credentialId = defaultOtpCredential == null ? "" : defaultOtpCredential.getId();
}
context.getEvent().detail(Details.SELECTED_CREDENTIAL_ID, credentialId);
context.form().setAttribute(SELECTED_OTP_CREDENTIAL_ID, credentialId);
UserModel userModel = context.getUser();
if (!enabledUser(context, userModel)) {
// error in context is set in enabledUser/isDisabledByBruteForce
return;
}
if (otp == null) {
Response challengeResponse = challenge(context, null);
context.challenge(challengeResponse);
return;
}
boolean valid = context.getSession().userCredentialManager().isValid(context.getRealm(), context.getUser(), new UserCredentialModel(credentialId, getCredentialProvider(context.getSession()).getType(), otp));
if (!valid) {
context.getEvent().user(userModel).error(Errors.INVALID_USER_CREDENTIALS);
Response challengeResponse = challenge(context, Messages.INVALID_TOTP, Validation.FIELD_OTP_CODE);
context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS, challengeResponse);
return;
}
context.success();
}
use of org.keycloak.models.credential.OTPCredentialModel in project keycloak by keycloak.
the class BasicAuthOTPAuthenticator method checkOtp.
private boolean checkOtp(AuthenticationFlowContext context, String otp) {
OTPCredentialModel preferredCredential = getCredentialProvider(context.getSession()).getDefaultCredential(context.getSession(), context.getRealm(), context.getUser());
boolean valid = getCredentialProvider(context.getSession()).isValid(context.getRealm(), context.getUser(), new UserCredentialModel(preferredCredential.getId(), getCredentialProvider(context.getSession()).getType(), otp));
if (!valid) {
context.getEvent().user(context.getUser()).error(Errors.INVALID_USER_CREDENTIALS);
if (context.getExecution().isRequired()) {
Response challengeResponse = challenge(context, Messages.INVALID_TOTP, Validation.FIELD_OTP_CODE);
context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS, challengeResponse);
} else {
context.attempted();
}
return false;
}
return true;
}
use of org.keycloak.models.credential.OTPCredentialModel in project keycloak by keycloak.
the class CredentialModelBackwardsCompatibilityTest method testCredentialModelOTP.
@Test
public void testCredentialModelOTP() {
CredentialModel otp = OTPCredentialModel.createTOTP("456123", 6, 30, "someAlg");
Assert.assertEquals("456123", otp.getValue());
Assert.assertEquals(6, otp.getDigits());
Assert.assertEquals(30, otp.getPeriod());
Assert.assertEquals("someAlg", otp.getAlgorithm());
// Change something and assert it is changed
otp.setValue("789789");
Assert.assertEquals("789789", otp.getValue());
// Test clone
OTPCredentialModel cloned = OTPCredentialModel.createFromCredentialModel(otp);
Assert.assertEquals("789789", cloned.getOTPSecretData().getValue());
Assert.assertEquals(6, cloned.getOTPCredentialData().getDigits());
Assert.assertEquals("someAlg", cloned.getOTPCredentialData().getAlgorithm());
}
use of org.keycloak.models.credential.OTPCredentialModel in project keycloak by keycloak.
the class UpdateTotp method processAction.
@Override
public void processAction(RequiredActionContext context) {
EventBuilder event = context.getEvent();
event.event(EventType.UPDATE_TOTP);
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
String challengeResponse = formData.getFirst("totp");
String totpSecret = formData.getFirst("totpSecret");
String mode = formData.getFirst("mode");
String userLabel = formData.getFirst("userLabel");
OTPPolicy policy = context.getRealm().getOTPPolicy();
OTPCredentialModel credentialModel = OTPCredentialModel.createFromPolicy(context.getRealm(), totpSecret, userLabel);
if (Validation.isBlank(challengeResponse)) {
Response challenge = context.form().setAttribute("mode", mode).addError(new FormMessage(Validation.FIELD_OTP_CODE, Messages.MISSING_TOTP)).createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
return;
} else if (!validateOTPCredential(context, challengeResponse, credentialModel, policy)) {
Response challenge = context.form().setAttribute("mode", mode).addError(new FormMessage(Validation.FIELD_OTP_CODE, Messages.INVALID_TOTP)).createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
return;
}
OTPCredentialProvider otpCredentialProvider = (OTPCredentialProvider) context.getSession().getProvider(CredentialProvider.class, "keycloak-otp");
final Stream<CredentialModel> otpCredentials = (otpCredentialProvider.isConfiguredFor(context.getRealm(), context.getUser())) ? context.getSession().userCredentialManager().getStoredCredentialsByTypeStream(context.getRealm(), context.getUser(), OTPCredentialModel.TYPE) : Stream.empty();
if (otpCredentials.count() >= 1 && Validation.isBlank(userLabel)) {
Response challenge = context.form().setAttribute("mode", mode).addError(new FormMessage(Validation.FIELD_OTP_LABEL, Messages.MISSING_TOTP_DEVICE_NAME)).createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
return;
}
if (!CredentialHelper.createOTPCredential(context.getSession(), context.getRealm(), context.getUser(), challengeResponse, credentialModel)) {
Response challenge = context.form().setAttribute("mode", mode).addError(new FormMessage(Validation.FIELD_OTP_CODE, Messages.INVALID_TOTP)).createResponse(UserModel.RequiredAction.CONFIGURE_TOTP);
context.challenge(challenge);
return;
}
context.success();
}
Aggregations