mirror of
https://github.com/keycloak/keycloak.git
synced 2026-05-08 08:01:18 -05:00
+2
-2
@@ -30,11 +30,11 @@ public class CredentialValidation {
|
||||
TimeBasedOTP validator = new TimeBasedOTP(credentialModel.getOTPCredentialData().getAlgorithm(),
|
||||
credentialModel.getOTPCredentialData().getDigits(), credentialModel.getOTPCredentialData().getPeriod(),
|
||||
lookAheadWindow);
|
||||
return validator.validateTOTP(token, credentialModel.getOTPSecretData().getValue().getBytes());
|
||||
return validator.validateTOTP(token, credentialModel.getDecodedSecret());
|
||||
} else {
|
||||
HmacOTP validator = new HmacOTP(credentialModel.getOTPCredentialData().getDigits(),
|
||||
credentialModel.getOTPCredentialData().getAlgorithm(), lookAheadWindow);
|
||||
int c = validator.validateHOTP(token, credentialModel.getOTPSecretData().getValue(),
|
||||
int c = validator.validateHOTP(token, credentialModel.getDecodedSecret(),
|
||||
credentialModel.getOTPCredentialData().getCounter());
|
||||
return c > -1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -230,7 +230,7 @@ public class RepresentationToModel {
|
||||
cred.setSecretData("{\"value\":\"" + cred.getHashedSaltedValue() + "\",\"salt\":\"" + cred.getSalt() + "\"}");
|
||||
cred.setPriority(10);
|
||||
} else if (OTPCredentialModel.TOTP.equals(cred.getType()) || OTPCredentialModel.HOTP.equals(cred.getType())) {
|
||||
OTPCredentialData credentialData = new OTPCredentialData(cred.getType(), cred.getDigits(), cred.getCounter(), cred.getPeriod(), cred.getAlgorithm());
|
||||
OTPCredentialData credentialData = new OTPCredentialData(cred.getType(), cred.getDigits(), cred.getCounter(), cred.getPeriod(), cred.getAlgorithm(), null);
|
||||
OTPSecretData secretData = new OTPSecretData(cred.getHashedSaltedValue());
|
||||
cred.setCredentialData(JsonSerialization.writeValueAsString(credentialData));
|
||||
cred.setSecretData(JsonSerialization.writeValueAsString(secretData));
|
||||
|
||||
@@ -54,7 +54,7 @@ public class TimeBasedOTP extends HmacOTP {
|
||||
*
|
||||
* @param secretKey the secret key to derive the token from.
|
||||
*/
|
||||
public String generateTOTP(String secretKey) {
|
||||
public String generateTOTP(byte[] secretKey) {
|
||||
long T = this.clock.getCurrentInterval();
|
||||
|
||||
String steps = Long.toHexString(T).toUpperCase();
|
||||
@@ -67,6 +67,10 @@ public class TimeBasedOTP extends HmacOTP {
|
||||
return generateOTP(secretKey, steps, this.numberDigits, this.algorithm);
|
||||
}
|
||||
|
||||
public String generateTOTP(String secretKey) {
|
||||
return generateTOTP(secretKey.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Validates a token using a secret key.</p>
|
||||
*
|
||||
@@ -88,7 +92,7 @@ public class TimeBasedOTP extends HmacOTP {
|
||||
steps = "0" + steps;
|
||||
}
|
||||
|
||||
String candidate = generateOTP(new String(secret), steps, this.numberDigits, this.algorithm);
|
||||
String candidate = generateOTP(secret, steps, this.numberDigits, this.algorithm);
|
||||
|
||||
if (candidate.equals(token)) {
|
||||
return true;
|
||||
|
||||
@@ -18,6 +18,9 @@ package org.keycloak.models;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.models.credential.OTPCredentialModel;
|
||||
import org.keycloak.models.credential.OTPCredentialModel.SecretEncoding;
|
||||
import org.keycloak.models.utils.Base32;
|
||||
import org.keycloak.models.utils.TimeBasedOTP;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -55,4 +58,32 @@ public class TotpTest {
|
||||
Assert.assertTrue("Should accept code with skew offset " + i,totp.validateTOTP(otp, secret.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBase32EncodedSecret() {
|
||||
TimeBasedOTP totp = new TimeBasedOTP("HmacSHA1", 8, 60, 1);
|
||||
String rawSecret = "JNSVMMTEKZCUGSKJIVGHMNSQOZBDA5JT";
|
||||
String otp = totp.generateTOTP(Base32.decode(rawSecret));
|
||||
OTPCredentialModel credentialModel = OTPCredentialModel.createTOTP(rawSecret, 8, 30, "HmacSHA1");
|
||||
|
||||
Assert.assertFalse(totp.validateTOTP(otp, credentialModel.getDecodedSecret()));
|
||||
|
||||
OTPCredentialModel encodedCredential = OTPCredentialModel.createTOTP(rawSecret, 8, 30, "HmacSHA1", SecretEncoding.BASE32.name());
|
||||
|
||||
Assert.assertTrue(totp.validateTOTP(otp, encodedCredential.getDecodedSecret()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBase32BinaryEncodedSecret() {
|
||||
TimeBasedOTP totp = new TimeBasedOTP("HmacSHA1", 8, 60, 1);
|
||||
String rawSecret = "CDLYAYRJ73ORTU4PUWWATWSYQCP4H2QL";
|
||||
String otp = totp.generateTOTP(Base32.decode(rawSecret));
|
||||
OTPCredentialModel credentialModel = OTPCredentialModel.createTOTP(rawSecret, 8, 30, "HmacSHA1");
|
||||
|
||||
Assert.assertFalse(totp.validateTOTP(otp, credentialModel.getDecodedSecret()));
|
||||
|
||||
OTPCredentialModel encodedCredential = OTPCredentialModel.createTOTP(rawSecret, 8, 30, "HmacSHA1", SecretEncoding.BASE32.name());
|
||||
|
||||
Assert.assertTrue(totp.validateTOTP(otp, encodedCredential.getDecodedSecret()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user