Skip to content

Commit

Permalink
Add validation Endpoint for token
Browse files Browse the repository at this point in the history
add IT Tests for new Endpoint
add UnitTests for new ServiceMethod used for validation
add ValidateTokenCommand
add properties-maven-plugin to read secret.env and set needed SECRET_JWT_HASH as envVariable
edit README.md

issue #58
  • Loading branch information
alekszivko committed Feb 28, 2025
1 parent 1f1211d commit 6422261
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 1 deletion.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ e.g
or any other wildfly location

## secret.env

The project/application needs a secret.env file with the following variables set in order for authentication and tests to work

```
SECRET_ADMIN_NAME
SECRET_JWT_HASH
SECRET_DEFAULT_PW
```

For convenience the [plugin](https://plugins.jetbrains.com/plugin/7861-envfile) is recommended for reading the secret.env when tests are executed via IntelliJ

## Build Project and deploy application

- *In order for all used relative paths to work
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.gepardec.rest.model.command.AuthCredentialCommand;
import com.gepardec.rest.model.command.CreateUserCommand;
import com.gepardec.rest.model.command.ValidateTokenCommand;
import io.github.cdimascio.dotenv.Dotenv;
import io.restassured.RestAssured;
import io.restassured.filter.log.LogDetail;
Expand Down Expand Up @@ -95,4 +96,53 @@ public void createTestUserWithAuthHeader() {
.path("token");
usedUserTokens.add(token);
}

@Test
public void ensureValidateTokenForInvalidTokenReturnsUnauthorized() {
ValidateTokenCommand validateTokenCommand = new ValidateTokenCommand("aksldfjalsdfjalskdjfaksdl.asdfasddfasdf.asdfsadff");
with().when()
.contentType("application/json")
.body(validateTokenCommand)
.post("/auth/validate")
.then()
.statusCode(401);
}

@Test
public void ensureValidateTokenForNotProvidedOrNullTokenReturnsUnauthorized() {
ValidateTokenCommand validateTokenCommand = new ValidateTokenCommand(null);
with().when()
.contentType("application/json")
.body(validateTokenCommand)
.post("/auth/validate")
.then()
.statusCode(401);
}

@Test
public void ensureValidateTokenForValidTokenReturns200Ok() {
//Login to get valid token
String authHeader = with().when()
.contentType("application/json")
.body(new AuthCredentialCommand(SECRET_ADMIN_NAME, SECRET_DEFAULT_PW))
.headers("Content-Type", ContentType.JSON,
"Accept", ContentType.JSON)
.request("POST", "/auth/login")
.then()
.statusCode(200)
.extract()
.header("Authorization");

var token = authHeader.replace("Bearer ", "");


//Validate token
ValidateTokenCommand validateTokenCommand = new ValidateTokenCommand(token);
with().when()
.contentType("application/json")
.body(validateTokenCommand)
.post("/auth/validate")
.then()
.statusCode(200);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.gepardec.rest.api;

import com.gepardec.rest.model.command.AuthCredentialCommand;
import com.gepardec.rest.model.command.ValidateTokenCommand;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
Expand All @@ -16,4 +17,8 @@ public interface AuthResource {
@POST
@Path("/login")
Response login(AuthCredentialCommand authCredentialCommand);

@POST
@Path("/validate")
Response validateToken(ValidateTokenCommand token);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.gepardec.core.services.AuthService;
import com.gepardec.rest.api.AuthResource;
import com.gepardec.rest.model.command.AuthCredentialCommand;
import com.gepardec.rest.model.command.ValidateTokenCommand;
import com.gepardec.rest.model.mapper.AuthCredentialRestMapper;
import com.gepardec.security.JwtUtil;
import jakarta.enterprise.context.RequestScoped;
Expand Down Expand Up @@ -36,4 +37,11 @@ public Response login(AuthCredentialCommand authCredentialCommand) {
return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid credentials").build();
}
}

@Override
public Response validateToken(ValidateTokenCommand tokenCmd) {
if (tokenCmd.token() != null && authService.isTokenValid(tokenCmd.token())) return Response.ok().build();

return Response.status(Response.Status.UNAUTHORIZED).entity("Invalid token").build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.gepardec.rest.model.command;

public record ValidateTokenCommand(String token) {

}
29 changes: 29 additions & 0 deletions gamertrack-domain/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<quiet>true</quiet>
<files>
<file>${project.parent.basedir}/secret.env</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<configuration>
<environmentVariables>
<SECRET_JWT_HASH>${SECRET_JWT_HASH}</SECRET_JWT_HASH>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
public interface AuthService {
boolean authenticate(AuthCredential credential);
boolean createDefaultUserIfNotExists();
boolean isTokenValid(String token);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import com.gepardec.model.AuthCredential;
import com.gepardec.security.JwtUtil;
import io.github.cdimascio.dotenv.Dotenv;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
Expand Down Expand Up @@ -78,4 +80,16 @@ public boolean createDefaultUserIfNotExists() {
return false; //user was not created
}
}

@Override
public boolean isTokenValid(String token) {
boolean isValid = false;
try {
Jwts.parser().setSigningKey(jwtUtil.generateKey()).build().parseClaimsJws(token);
isValid = true;
} catch (JwtException e) {
log.error("Token validation failed {}", e.getMessage());
}
return isValid;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

Expand All @@ -29,6 +29,7 @@ public class AuthServiceImplTest {
@Mock
TokenService tokenService;


@Test
void ensureCreateDefaultUserIfNotExistsCreatesDefaultUser() {
when(authRepository.findByUsername(any())).thenReturn(Optional.empty());
Expand Down Expand Up @@ -68,4 +69,22 @@ void ensureAuthenticateReturnsTrueWhenCredentialsCorrect() {
assertEquals(authService.authenticate(new AuthCredential("admin", "CorrectPW")), true);
}

@Test
void ensureIsTokenValidReturnsFalseIfTokenIsNull() {
assertFalse(authService.isTokenValid(null));
}

@Test
void ensureIsTokenValidReturnsFalseIfTokenIsInvalid() {
assertFalse(authService.isTokenValid("invalidToken.shouldNotWork.shouldBeFalse"));
}

@Test
void ensureIsTokenValidReturnsTrueIfTokenIsValid() {
when(jwtUtil.generateToken(any())).thenCallRealMethod();
when(jwtUtil.generateKey()).thenCallRealMethod();


assertTrue(authService.isTokenValid(jwtUtil.generateToken("AnyUser")));
}
}

0 comments on commit 6422261

Please sign in to comment.