From 813aa85abb84d9a075fa6127043650efe09b9931 Mon Sep 17 00:00:00 2001 From: Jon Chambers Date: Mon, 27 Dec 2021 12:21:06 -0500 Subject: [PATCH] Don't extend `HmacOneTimePasswordGenerator` in `TimeBasedOneTimePasswordGenerator` --- .../TimeBasedOneTimePasswordGenerator.java | 27 ++++++++++++++++--- .../otp/HmacOneTimePasswordGeneratorTest.java | 10 +++---- ...TimeBasedOneTimePasswordGeneratorTest.java | 19 ++++++++----- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java b/src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java index 647bf50..6f5325d 100644 --- a/src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java +++ b/src/main/java/com/eatthepath/otp/TimeBasedOneTimePasswordGenerator.java @@ -35,7 +35,8 @@ * * @author Jon Chambers */ -public class TimeBasedOneTimePasswordGenerator extends HmacOneTimePasswordGenerator { +public class TimeBasedOneTimePasswordGenerator { + private final HmacOneTimePasswordGenerator hotp; private final Duration timeStep; /** @@ -115,7 +116,7 @@ public TimeBasedOneTimePasswordGenerator(final Duration timeStep, final int pass public TimeBasedOneTimePasswordGenerator(final Duration timeStep, final int passwordLength, final String algorithm) throws NoSuchAlgorithmRuntimeException { - super(passwordLength, algorithm); + this.hotp = new HmacOneTimePasswordGenerator(passwordLength, algorithm); this.timeStep = timeStep; } @@ -131,7 +132,7 @@ public TimeBasedOneTimePasswordGenerator(final Duration timeStep, final int pass * @throws InvalidKeyException if the given key is inappropriate for initializing the {@link Mac} for this generator */ public int generateOneTimePassword(final Key key, final Instant timestamp) throws InvalidKeyException { - return this.generateOneTimePassword(key, timestamp.toEpochMilli() / this.timeStep.toMillis()); + return this.hotp.generateOneTimePassword(key, timestamp.toEpochMilli() / this.timeStep.toMillis()); } /** @@ -163,7 +164,7 @@ public String generateOneTimePasswordString(final Key key, final Instant timesta * @throws InvalidKeyException if the given key is inappropriate for initializing the {@link Mac} for this generator */ public String generateOneTimePasswordString(final Key key, final Instant timestamp, final Locale locale) throws InvalidKeyException { - return this.formatOneTimePassword(this.generateOneTimePassword(key, timestamp), locale); + return this.hotp.formatOneTimePassword(this.generateOneTimePassword(key, timestamp), locale); } /** @@ -174,4 +175,22 @@ public String generateOneTimePasswordString(final Key key, final Instant timesta public Duration getTimeStep() { return this.timeStep; } + + /** + * Returns the length, in decimal digits, of passwords produced by this generator. + * + * @return the length, in decimal digits, of passwords produced by this generator + */ + public int getPasswordLength() { + return this.hotp.getPasswordLength(); + } + + /** + * Returns the name of the HMAC algorithm used by this generator. + * + * @return the name of the HMAC algorithm used by this generator + */ + public String getAlgorithm() { + return this.hotp.getAlgorithm(); + } } diff --git a/src/test/java/com/eatthepath/otp/HmacOneTimePasswordGeneratorTest.java b/src/test/java/com/eatthepath/otp/HmacOneTimePasswordGeneratorTest.java index 96ce6bb..1f949a0 100644 --- a/src/test/java/com/eatthepath/otp/HmacOneTimePasswordGeneratorTest.java +++ b/src/test/java/com/eatthepath/otp/HmacOneTimePasswordGeneratorTest.java @@ -76,7 +76,7 @@ void testGetAlgorithm() { @ParameterizedTest @MethodSource("argumentsForTestGenerateOneTimePasswordHotp") void testGenerateOneTimePassword(final int counter, final int expectedOneTimePassword) throws Exception { - assertEquals(expectedOneTimePassword, this.getDefaultGenerator().generateOneTimePassword(HOTP_KEY, counter)); + assertEquals(expectedOneTimePassword, new HmacOneTimePasswordGenerator().generateOneTimePassword(HOTP_KEY, counter)); } @Test @@ -106,7 +106,7 @@ private static Stream argumentsForTestGenerateOneTimePasswordHotp() { @MethodSource("argumentsForTestGenerateOneTimePasswordStringHotp") void testGenerateOneTimePasswordString(final int counter, final String expectedOneTimePassword) throws Exception { Locale.setDefault(Locale.US); - assertEquals(expectedOneTimePassword, this.getDefaultGenerator().generateOneTimePasswordString(HOTP_KEY, counter)); + assertEquals(expectedOneTimePassword, new HmacOneTimePasswordGenerator().generateOneTimePasswordString(HOTP_KEY, counter)); } private static Stream argumentsForTestGenerateOneTimePasswordStringHotp() { @@ -128,7 +128,7 @@ private static Stream argumentsForTestGenerateOneTimePasswordStringHo @MethodSource("argumentsForTestGenerateOneTimePasswordStringLocaleHotp") void testGenerateOneTimePasswordStringLocale(final int counter, final Locale locale, final String expectedOneTimePassword) throws Exception { Locale.setDefault(Locale.US); - assertEquals(expectedOneTimePassword, this.getDefaultGenerator().generateOneTimePasswordString(HOTP_KEY, counter, locale)); + assertEquals(expectedOneTimePassword, new HmacOneTimePasswordGenerator().generateOneTimePasswordString(HOTP_KEY, counter, locale)); } private static Stream argumentsForTestGenerateOneTimePasswordStringLocaleHotp() { @@ -147,8 +147,4 @@ private static Stream argumentsForTestGenerateOneTimePasswordStringLo arguments(9, locale, "५२०४८९") ); } - - protected HmacOneTimePasswordGenerator getDefaultGenerator() { - return new HmacOneTimePasswordGenerator(); - } } diff --git a/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java b/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java index 23e33f4..dcc6cf9 100644 --- a/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java +++ b/src/test/java/com/eatthepath/otp/TimeBasedOneTimePasswordGeneratorTest.java @@ -36,7 +36,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.params.provider.Arguments.arguments; -public class TimeBasedOneTimePasswordGeneratorTest extends HmacOneTimePasswordGeneratorTest { +public class TimeBasedOneTimePasswordGeneratorTest { private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1"; private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256"; @@ -54,17 +54,22 @@ public class TimeBasedOneTimePasswordGeneratorTest extends HmacOneTimePasswordGe new SecretKeySpec("1234567890123456789012345678901234567890123456789012345678901234".getBytes(StandardCharsets.US_ASCII), TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA512); - @Override - protected HmacOneTimePasswordGenerator getDefaultGenerator() { - return new TimeBasedOneTimePasswordGenerator(); + @Test + void testGetPasswordLength() { + final int passwordLength = 7; + assertEquals(passwordLength, new TimeBasedOneTimePasswordGenerator(Duration.ofSeconds(30), passwordLength).getPasswordLength()); + } + + @Test + void testGetAlgorithm() { + final String algorithm = TimeBasedOneTimePasswordGenerator.TOTP_ALGORITHM_HMAC_SHA256; + assertEquals(algorithm, new TimeBasedOneTimePasswordGenerator(Duration.ofSeconds(30), 6, algorithm).getAlgorithm()); } @Test void testGetTimeStep() { final Duration timeStep = Duration.ofSeconds(97); - final TimeBasedOneTimePasswordGenerator totp = new TimeBasedOneTimePasswordGenerator(timeStep); - - assertEquals(timeStep, totp.getTimeStep()); + assertEquals(timeStep, new TimeBasedOneTimePasswordGenerator(timeStep).getTimeStep()); } /**