Skip to content

Commit

Permalink
[CONLUZ-37] Implemented a validation class to stop the app bootstrap …
Browse files Browse the repository at this point in the history
…if required config parameters are not present (#39)
  • Loading branch information
viktorKhan authored Jan 14, 2024
1 parent 754678e commit 95f0e2e
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 8 deletions.
36 changes: 36 additions & 0 deletions src/main/java/org/lucoenergia/conluz/AppConfigCheck.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.lucoenergia.conluz;

import org.lucoenergia.conluz.infrastructure.shared.security.auth.JwtConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class AppConfigCheck implements ApplicationRunner {

private static final Logger LOGGER = LoggerFactory.getLogger(AppConfigCheck.class);

private final JwtConfiguration jwtConfiguration;

public AppConfigCheck(JwtConfiguration jwtConfiguration) {
this.jwtConfiguration = jwtConfiguration;
}

@Override
public void run(ApplicationArguments args) {
isSecretKeyPresent();
}

private void isSecretKeyPresent() {
// Secret key must be present
String secretKey = jwtConfiguration.getSecretKey();
if (secretKey == null || secretKey.isBlank()) {
LOGGER.error("Secret key not found. You must provide a secret key using the parameter {}",
JwtConfiguration.CONLUZ_JWT_SECRET_KEY);
System.exit(1);
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,4 @@ public class ConLuzApplication {
public static void main(String[] args) {
SpringApplication.run(ConLuzApplication.class, args);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ public InvalidTokenException(String token) {
this.token = token;
}

public InvalidTokenException(String token, Throwable ex) {
super(ex);
this.token = token;
}

public String getToken() {
return token;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
Expand Down Expand Up @@ -86,14 +87,22 @@ private boolean isTokenExpired(Token token) {
}

private Key getKey() {
byte[] keyBytes = Decoders.BASE64.decode(jwtConfiguration.getSecretKey());
String secretKey = jwtConfiguration.getSecretKey();
if (secretKey == null || secretKey.isBlank()) {
throw new SecretKeyNotFoundException();
}
byte[] keyBytes = Decoders.BASE64.decode(secretKey);
return Keys.hmacShaKeyFor(keyBytes);
}

private Claims getAllClaims(Token token) {
return Jwts
.parserBuilder().setSigningKey(getKey()).build()
.parseClaimsJws(token.getToken()).getBody();
try {
return Jwts
.parserBuilder().setSigningKey(getKey()).build()
.parseClaimsJws(token.getToken()).getBody();
} catch (MalformedJwtException e) {
throw new InvalidTokenException(token.getToken(), e);
}
}

private <T> T getClaim(Token token, Function<Claims, T> claimsResolver) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
@Configuration
public class JwtConfiguration {

private static final String CONLUZ_JWT_SECRET_KEY = "CONLUZ_JWT_SECRET_KEY";
public static final String CONLUZ_JWT_SECRET_KEY = "CONLUZ_JWT_SECRET_KEY";

@Value("${conluz.security.jwt.expiration-time}")
private Integer expirationTime;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package org.lucoenergia.conluz.infrastructure.shared.security.auth;

public class SecretKeyNotFoundException extends RuntimeException {
}
2 changes: 1 addition & 1 deletion src/main/resources/logback-spring.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</springProfile>

<!-- Production environment -->
<springProfile name="prod">
<springProfile name="prod,production">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.lucoenergia.conluz.domain.admin.user.UserMother;
import org.lucoenergia.conluz.domain.admin.user.create.CreateUserRepository;
import org.lucoenergia.conluz.infrastructure.shared.BaseControllerTest;
import org.lucoenergia.conluz.infrastructure.shared.security.auth.InvalidTokenException;
import org.lucoenergia.conluz.infrastructure.shared.security.auth.JwtAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
Expand Down Expand Up @@ -278,7 +279,7 @@ void testWithWrongToken() {
final String wrongToken = JwtAuthenticationFilter.AUTHORIZATION_HEADER_PREFIX +
"wrong";

Assertions.assertThrows(MalformedJwtException.class,
Assertions.assertThrows(InvalidTokenException.class,
() -> mockMvc.perform(get("/api/v1/users")
.header(HttpHeaders.AUTHORIZATION, wrongToken)
.contentType(MediaType.APPLICATION_JSON)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.lucoenergia.conluz.domain.admin.user.User;
import org.lucoenergia.conluz.domain.admin.user.auth.Token;
import org.lucoenergia.conluz.domain.admin.user.UserMother;
Expand All @@ -15,6 +18,8 @@
@ExtendWith(MockitoExtension.class)
class JwtAuthRepositoryTest {

private final static String SECRET_KEY = "b5f86373ba5d7593f4c6eab57862bf4be76369c1adbe263ae2d50ddae40b8ca2";

@InjectMocks
private JwtAuthRepository repository;

Expand Down Expand Up @@ -50,12 +55,27 @@ void testTokenClaims() {
@Test
void testGetUserIdByInvalidToken() {
String invalidToken = "invalid-token";

Mockito.when(jwtConfiguration.getSecretKey()).thenReturn(SECRET_KEY);

InvalidTokenException exception = Assertions.assertThrows(InvalidTokenException.class,
() -> repository.getUserIdFromToken(Token.of(invalidToken)));

Assertions.assertEquals(invalidToken, exception.getToken());
}

@ParameterizedTest
@ValueSource(strings = {"", " "})
@NullSource
void testMissingSecretKey(String secretKey) {
String invalidToken = "invalid-token";

Mockito.when(jwtConfiguration.getSecretKey()).thenReturn(secretKey);

Assertions.assertThrows(SecretKeyNotFoundException.class,
() -> repository.getUserIdFromToken(Token.of(invalidToken)));
}

private void mockJwtConfig() {
// Mock expiration time and JWT secret key
Mockito.when(jwtConfiguration.getExpirationTime()).thenReturn(30);
Expand Down

0 comments on commit 95f0e2e

Please sign in to comment.