use of org.keycloak.models.utils.TimeBasedOTP in project keycloak by keycloak.
the class RequiredActionsTest method testOtp.
private void testOtp(String type, String algorithm, int digits, Integer period, Integer counter, String secret) {
switch(algorithm) {
case "SHA1":
algorithm = TimeBasedOTP.HMAC_SHA1;
break;
case "SHA256":
algorithm = TimeBasedOTP.HMAC_SHA256;
break;
case "SHA512":
algorithm = TimeBasedOTP.HMAC_SHA512;
break;
default:
throw new AssertionError("Wrong algorithm type");
}
HmacOTP otpGenerator;
String secretDecoded = new String(Base32.decode(secret));
String code;
switch(type) {
case TOTP:
otpGenerator = new TimeBasedOTP(algorithm, digits, period, 0);
code = ((TimeBasedOTP) otpGenerator).generateTOTP(secretDecoded);
break;
case HOTP:
otpGenerator = new HmacOTP(digits, algorithm, 0);
code = otpGenerator.generateHOTP(secretDecoded, counter);
break;
default:
throw new AssertionError("Wrong OTP type");
}
// fill in the form
otpSetupPage.setTotp(code);
otpSetupPage.submit();
assertLoginSuccessful();
// try the code is working
deleteAllSessionsInTestRealm();
testRealmAccountPage.navigateTo();
testRealmLoginPage.form().login(testUser);
oneTimeCodePage.assertCurrent();
// assertEquals("One-time code", oneTimeCodePage.getTotpLabel());
// bad attempt
oneTimeCodePage.submit();
assertTrue(oneTimeCodePage.feedbackMessage().isError());
assertEquals("[TEST LOCALE] vložen chybný kód", oneTimeCodePage.feedbackMessage().getText());
oneTimeCodePage.sendCode("XXXXXX");
assertTrue(oneTimeCodePage.feedbackMessage().isError());
assertEquals("[TEST LOCALE] vložen chybný kód", oneTimeCodePage.feedbackMessage().getText());
// generate new code
code = type.equals(TOTP) ? ((TimeBasedOTP) otpGenerator).generateTOTP(secretDecoded) : otpGenerator.generateHOTP(secretDecoded, ++counter);
oneTimeCodePage.sendCode(code);
assertLoginSuccessful();
}
use of org.keycloak.models.utils.TimeBasedOTP in project keycloak by keycloak.
the class TotpTest method testTotpLookAround.
/**
* KEYCLOAK-18880
*/
@Test
public void testTotpLookAround() {
int lookAroundWindow = 2;
TimeBasedOTP totp = new TimeBasedOTP("HmacSHA1", 8, 60, lookAroundWindow);
String secret = "dSdmuHLQhkm54oIm0A0S";
String otp = totp.generateTOTP(secret);
for (int i = -lookAroundWindow; i <= lookAroundWindow; i++) {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, i);
totp.setCalendar(calendar);
Assert.assertTrue("Should accept code with skew offset " + i, totp.validateTOTP(otp, secret.getBytes(StandardCharsets.UTF_8)));
}
}
use of org.keycloak.models.utils.TimeBasedOTP in project keycloak by keycloak.
the class OTPCredentialProvider method isValid.
@Override
public boolean isValid(RealmModel realm, UserModel user, CredentialInput credentialInput) {
if (!(credentialInput instanceof UserCredentialModel)) {
logger.debug("Expected instance of UserCredentialModel for CredentialInput");
return false;
}
String challengeResponse = credentialInput.getChallengeResponse();
if (challengeResponse == null) {
return false;
}
if (ObjectUtil.isBlank(credentialInput.getCredentialId())) {
logger.debugf("CredentialId is null when validating credential of user %s", user.getUsername());
return false;
}
CredentialModel credential = getCredentialStore().getStoredCredentialById(realm, user, credentialInput.getCredentialId());
OTPCredentialModel otpCredentialModel = OTPCredentialModel.createFromCredentialModel(credential);
OTPSecretData secretData = otpCredentialModel.getOTPSecretData();
OTPCredentialData credentialData = otpCredentialModel.getOTPCredentialData();
OTPPolicy policy = realm.getOTPPolicy();
if (OTPCredentialModel.HOTP.equals(credentialData.getSubType())) {
HmacOTP validator = new HmacOTP(credentialData.getDigits(), credentialData.getAlgorithm(), policy.getLookAheadWindow());
int counter = validator.validateHOTP(challengeResponse, secretData.getValue(), credentialData.getCounter());
if (counter < 0) {
return false;
}
otpCredentialModel.updateCounter(counter);
getCredentialStore().updateCredential(realm, user, otpCredentialModel);
return true;
} else if (OTPCredentialModel.TOTP.equals(credentialData.getSubType())) {
TimeBasedOTP validator = new TimeBasedOTP(credentialData.getAlgorithm(), credentialData.getDigits(), credentialData.getPeriod(), policy.getLookAheadWindow());
return validator.validateTOTP(challengeResponse, secretData.getValue().getBytes(StandardCharsets.UTF_8));
}
return false;
}
use of org.keycloak.models.utils.TimeBasedOTP in project keycloak by keycloak.
the class RequiredActionTotpSetupTest method setupOtpPolicyChangedTotp8Digits.
@Test
public void setupOtpPolicyChangedTotp8Digits() {
// set policy to 8 digits
RealmRepresentation realmRep = adminClient.realm("test").toRepresentation();
RealmBuilder.edit(realmRep).otpLookAheadWindow(1).otpDigits(8).otpPeriod(30).otpType(OTPCredentialModel.TOTP).otpAlgorithm(HmacOTP.HMAC_SHA1).otpInitialCounter(0);
adminClient.realm("test").update(realmRep);
loginPage.open();
loginPage.login("test-user@localhost", "password");
totpPage.assertCurrent();
String totpSecret = totpPage.getTotpSecret();
TimeBasedOTP timeBased = new TimeBasedOTP(HmacOTP.HMAC_SHA1, 8, 30, 1);
totpPage.configure(timeBased.generateTOTP(totpSecret));
String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent().getDetails().get(Details.CODE_ID);
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
EventRepresentation loginEvent = events.expectLogin().session(sessionId).assertEvent();
oauth.openLogout();
events.expectLogout(loginEvent.getSessionId()).assertEvent();
loginPage.open();
loginPage.login("test-user@localhost", "password");
String src = driver.getPageSource();
String token = timeBased.generateTOTP(totpSecret);
assertEquals(8, token.length());
loginTotpPage.login(token);
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
events.expectLogin().assertEvent();
// Revert
realmRep = adminClient.realm("test").toRepresentation();
RealmBuilder.edit(realmRep).otpDigits(6);
adminClient.realm("test").update(realmRep);
}
use of org.keycloak.models.utils.TimeBasedOTP in project keycloak by keycloak.
the class AppInitiatedActionTotpSetupTest method setupOtpPolicyChangedTotp8Digits.
@Test
public void setupOtpPolicyChangedTotp8Digits() {
// set policy to 8 digits
RealmRepresentation realmRep = adminClient.realm("test").toRepresentation();
RealmBuilder.edit(realmRep).otpLookAheadWindow(1).otpDigits(8).otpPeriod(30).otpType(OTPCredentialModel.TOTP).otpAlgorithm(HmacOTP.HMAC_SHA1).otpInitialCounter(0);
adminClient.realm("test").update(realmRep);
doAIA();
loginPage.login("test-user@localhost", "password");
totpPage.assertCurrent();
String totpSecret = totpPage.getTotpSecret();
TimeBasedOTP timeBased = new TimeBasedOTP(HmacOTP.HMAC_SHA1, 8, 30, 1);
totpPage.configure(timeBased.generateTOTP(totpSecret));
String sessionId = events.expectRequiredAction(EventType.UPDATE_TOTP).assertEvent().getDetails().get(Details.CODE_ID);
assertKcActionStatus(SUCCESS);
EventRepresentation loginEvent = events.expectLogin().session(sessionId).assertEvent();
oauth.openLogout();
events.expectLogout(loginEvent.getSessionId()).assertEvent();
loginPage.open();
loginPage.login("test-user@localhost", "password");
String src = driver.getPageSource();
String token = timeBased.generateTOTP(totpSecret);
assertEquals(8, token.length());
loginTotpPage.login(token);
assertKcActionStatus(null);
events.expectLogin().assertEvent();
// Revert
realmRep = adminClient.realm("test").toRepresentation();
RealmBuilder.edit(realmRep).otpDigits(6);
adminClient.realm("test").update(realmRep);
}
Aggregations