experimental access code for RbacUserEntity
This commit is contained in:
parent
1451e7b661
commit
2abe88eb15
@ -3,7 +3,12 @@ package net.hostsharing.hsadminng.rbac.rbacuser;
|
|||||||
import lombok.*;
|
import lombok.*;
|
||||||
import org.springframework.data.annotation.Immutable;
|
import org.springframework.data.annotation.Immutable;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -16,8 +21,35 @@ import java.util.UUID;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class RbacUserEntity {
|
public class RbacUserEntity {
|
||||||
|
|
||||||
|
private static final int MAX_VALIDITY_DAYS = 21;
|
||||||
|
private static DateTimeFormatter DATE_FORMAT_WITH_FULLHOUR = DateTimeFormatter.ofPattern("MM-dd-yyyy HH");
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
private UUID uuid;
|
private UUID uuid;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
public String generateAccessCode() {
|
||||||
|
return generateAccessCode(LocalDateTime.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValidAccessCode(final String accessCode, final int validityHours) {
|
||||||
|
if (validityHours > 24 * MAX_VALIDITY_DAYS) {
|
||||||
|
throw new IllegalArgumentException("Max validity (%s days) exceeded.".formatted(MAX_VALIDITY_DAYS));
|
||||||
|
}
|
||||||
|
if (generateAccessCode(LocalDateTime.now().minus(validityHours, ChronoUnit.HOURS)).equals(accessCode)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (validityHours < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isValidAccessCode(accessCode, validityHours - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
String generateAccessCode(final LocalDateTime timestamp) {
|
||||||
|
final var compound = name + ":" + uuid + ":" + timestamp.format(DATE_FORMAT_WITH_FULLHOUR);
|
||||||
|
final var code = String.valueOf(1000000 + Math.abs(compound.hashCode()) % 100000);
|
||||||
|
return code.substring(1, 4) + ":" + code.substring(4, 7);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
package net.hostsharing.hsadminng.rbac.rbacuser;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
|
class RbacUserEntityUnitTest {
|
||||||
|
|
||||||
|
RbacUserEntity givenUser = new RbacUserEntity(UUID.randomUUID(), "test@example.org");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generatedAccessCodeMatchesDefinedPattern() {
|
||||||
|
final var givenAccessCode = givenUser.generateAccessCode();
|
||||||
|
|
||||||
|
final var actual = givenAccessCode.matches("[0-9]{3}:[0-9]{3}");
|
||||||
|
|
||||||
|
assertThat(actual).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void freshAccessCodeIsValid() {
|
||||||
|
final var givenAccessCode = givenUser.generateAccessCode();
|
||||||
|
|
||||||
|
final var actual = givenUser.isValidAccessCode(givenAccessCode, 4);
|
||||||
|
|
||||||
|
assertThat(actual).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void recentEnoughAccessCodeIsValid() {
|
||||||
|
final var givenAccessCode = givenUser.generateAccessCode(LocalDateTime.now().minus(4, ChronoUnit.HOURS));
|
||||||
|
|
||||||
|
final var actual = givenUser.isValidAccessCode(givenAccessCode, 4);
|
||||||
|
|
||||||
|
assertThat(actual).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void outdatedEnoughAccessCodeIsNotValid() {
|
||||||
|
final var givenAccessCode = givenUser.generateAccessCode(LocalDateTime.now().minus(5, ChronoUnit.HOURS));
|
||||||
|
|
||||||
|
final var actual = givenUser.isValidAccessCode(givenAccessCode, 4);
|
||||||
|
|
||||||
|
assertThat(actual).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void noExceptionIsThrowIfMaxValidityIsNotExceeded() {
|
||||||
|
final var givenAccessCode = givenUser.generateAccessCode();
|
||||||
|
|
||||||
|
givenUser.isValidAccessCode(givenAccessCode, 24 * 21);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void illegalArgumentExceptionIsThrowIfMaxValidityIsExceeded() {
|
||||||
|
final var givenAccessCode = givenUser.generateAccessCode();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> {
|
||||||
|
givenUser.isValidAccessCode(givenAccessCode, 24 * 21 + 1);
|
||||||
|
})
|
||||||
|
.isInstanceOf(IllegalArgumentException.class)
|
||||||
|
.hasMessage("Max validity (21 days) exceeded.");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user