Search in sources :

Example 6 with TimeBasedOTP

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();
}
Also used : HmacOTP(org.keycloak.models.utils.HmacOTP) TimeBasedOTP(org.keycloak.models.utils.TimeBasedOTP)

Example 7 with TimeBasedOTP

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)));
    }
}
Also used : TimeBasedOTP(org.keycloak.models.utils.TimeBasedOTP) Calendar(java.util.Calendar) Test(org.junit.Test)

Example 8 with TimeBasedOTP

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;
}
Also used : OTPSecretData(org.keycloak.models.credential.dto.OTPSecretData) HmacOTP(org.keycloak.models.utils.HmacOTP) UserCredentialModel(org.keycloak.models.UserCredentialModel) OTPCredentialModel(org.keycloak.models.credential.OTPCredentialModel) TimeBasedOTP(org.keycloak.models.utils.TimeBasedOTP) OTPCredentialData(org.keycloak.models.credential.dto.OTPCredentialData) OTPCredentialModel(org.keycloak.models.credential.OTPCredentialModel) OTPPolicy(org.keycloak.models.OTPPolicy) UserCredentialModel(org.keycloak.models.UserCredentialModel)

Example 9 with TimeBasedOTP

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);
}
Also used : TimeBasedOTP(org.keycloak.models.utils.TimeBasedOTP) RealmRepresentation(org.keycloak.representations.idm.RealmRepresentation) EventRepresentation(org.keycloak.representations.idm.EventRepresentation) Test(org.junit.Test) AbstractTestRealmKeycloakTest(org.keycloak.testsuite.AbstractTestRealmKeycloakTest)

Example 10 with TimeBasedOTP

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);
}
Also used : TimeBasedOTP(org.keycloak.models.utils.TimeBasedOTP) RealmRepresentation(org.keycloak.representations.idm.RealmRepresentation) EventRepresentation(org.keycloak.representations.idm.EventRepresentation) Test(org.junit.Test)

Aggregations

TimeBasedOTP (org.keycloak.models.utils.TimeBasedOTP)10 Test (org.junit.Test)5 RealmRepresentation (org.keycloak.representations.idm.RealmRepresentation)3 UserCredentialModel (org.keycloak.models.UserCredentialModel)2 HmacOTP (org.keycloak.models.utils.HmacOTP)2 EventRepresentation (org.keycloak.representations.idm.EventRepresentation)2 AbstractTestRealmKeycloakTest (org.keycloak.testsuite.AbstractTestRealmKeycloakTest)2 IOException (java.io.IOException)1 Calendar (java.util.Calendar)1 Matchers.containsString (org.hamcrest.Matchers.containsString)1 Before (org.junit.Before)1 CredentialModel (org.keycloak.credential.CredentialModel)1 PasswordHashProvider (org.keycloak.credential.hash.PasswordHashProvider)1 OTPPolicy (org.keycloak.models.OTPPolicy)1 PasswordPolicy (org.keycloak.models.PasswordPolicy)1 OTPCredentialModel (org.keycloak.models.credential.OTPCredentialModel)1 PasswordUserCredentialModel (org.keycloak.models.credential.PasswordUserCredentialModel)1 OTPCredentialData (org.keycloak.models.credential.dto.OTPCredentialData)1 OTPSecretData (org.keycloak.models.credential.dto.OTPSecretData)1 AccessToken (org.keycloak.representations.AccessToken)1