Removed the example-microservice.

Signed-off-by: kvanmaasdam <K.vanMaasdam@student.tudelft.nl>
This commit is contained in:
kvanmaasdam 2024-01-11 08:28:02 +01:00
parent 4b22198c04
commit 72ee9aa06f
No known key found for this signature in database
23 changed files with 1 additions and 1036 deletions

View file

@ -1,69 +0,0 @@
image: gradle:6.7-jdk15
stages:
- build
- staticAnalysis
- test
variables:
# Disable the Gradle daemon to ensure isolated runs of the CI pipeline.
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
# Default build cache settings to extend from
.build_cached:
cache:
key: "gradle-build"
paths:
# Only cache the gradle directory, as we do not use a shared cache
- .gradle/
policy: pull
build-example-microservice:
extends:
- .build_cached
needs:
- gradle_build
dependencies:
- gradle_build
stage: build
script:
gradle example-microservice:assemble example-microservice:testClasses
checkStyle-example-microservice:
extends:
- .build_cached
needs:
- gradle_build
dependencies:
- gradle_build
stage: staticAnalysis
script:
gradle example-microservice:checkstyleMain example-microservice:checkStyleTest
allow_failure: true
PMD-example-microservice:
extends:
- .build_cached
needs:
- gradle_build
dependencies:
- gradle_build
stage: staticAnalysis
script:
gradle example-microservice:pmdMain
allow_failure: true
test-example-microservice:
extends:
- .build_cached
needs:
- gradle_build
dependencies:
- gradle_build
stage: test
script:
- gradle example-microservice:test example-microservice:jacocoTestReport
- cat example-microservice/build/reports/jacoco/test/html/index.html | grep -Po "Total.*?([0-9]{1,3})%"
coverage: /([0-9]{1,3})%/

View file

@ -1,121 +0,0 @@
buildscript {
repositories {
mavenCentral()
//Needed only for SNAPSHOT versions
//maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
dependencies {
classpath 'info.solidsoft.gradle.pitest:gradle-pitest-plugin:1.5.2'
}
}
plugins {
id 'org.springframework.boot' version '2.4.13'
id 'io.spring.dependency-management' version '1.1.4'
id 'java'
// Test coverage
id 'jacoco'
// Code style
id 'checkstyle'
// PMD
id 'pmd'
// PITest
id 'info.solidsoft.pitest' version '1.5.2'
}
group = 'nl.tudelft.cse.sem.template'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 15
targetCompatibility = 15
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.24'
annotationProcessor 'org.projectlombok:lombok:1.18.24'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
// https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt
implementation 'io.jsonwebtoken:jjwt:0.9.1'
// Local test database (in-memory)
implementation 'com.h2database:h2'
developmentOnly 'org.hibernate:hibernate-entitymanager'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testImplementation('org.junit.jupiter:junit-jupiter:5.8.2')
testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.12.4'
testImplementation('org.assertj:assertj-core:3.23.1')
}
test {
useJUnitPlatform()
jacoco {
enabled = true
includes = ['nl.tudelft.sem.template.*']
excludes = []
}
}
repositories {
mavenCentral()
}
jacoco {
toolVersion = "0.8.7" // Use the desired version of JaCoCo
}
jacocoTestCoverageVerification() {
dependsOn test
violationRules {
rule {
enabled = true
element = 'CLASS'
includes = ['nl.tudelft.sem.template.*']
limit {
counter = 'BRANCH'
value = 'COVEREDRATIO'
minimum = 0.0
}
}
}
}
checkstyle {
toolVersion "10.12.5"
configFile = file("${rootDir}/config/checkstyle/checkstyle.xml")
ignoreFailures = false
maxErrors = 0
maxWarnings = 0
}
pmd {
incrementalAnalysis = true
sourceSets = [sourceSets.main]
}
apply plugin: 'info.solidsoft.pitest'
pitest {
//adds dependency to org.pitest:pitest-junit5-plugin and sets "testPlugin" to "junit5"
junit5PluginVersion = '0.12'
targetClasses = ['nl.tudelft.sem.template.*'] //by default "${project.group}.*"
pitestVersion = '1.5.1' //not needed when a default PIT version should be used
threads = 4
outputFormats = ['XML', 'HTML']
timestampedReports = false
}

View file

@ -1 +0,0 @@
rootProject.name = 'example-microservice'

View file

@ -1,14 +0,0 @@
package nl.tudelft.sem.template.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Example microservice application.
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View file

@ -1,19 +0,0 @@
package nl.tudelft.sem.template.example.authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
/**
* Authentication Manager.
*/
@Component
public class AuthManager {
/**
* Interfaces with spring security to get the name of the user in the current context.
*
* @return The name of the user.
*/
public String getNetId() {
return SecurityContextHolder.getContext().getAuthentication().getName();
}
}

View file

@ -1,30 +0,0 @@
package nl.tudelft.sem.template.example.authentication;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
/**
* Authentication entry point for JWT security.
* <p>
* The authentication entry point is called when an unauthenticated client tries to access a protected resource.
* This JWT authentication entry point returns a response indicating the request was unauthorized.
* </p>
*/
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException)
throws IOException, ServletException {
// Return an unauthorized response code
response.addHeader(JwtRequestFilter.WWW_AUTHENTICATE_HEADER, JwtRequestFilter.AUTHORIZATION_AUTH_SCHEME);
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
}
}

View file

@ -1,91 +0,0 @@
package nl.tudelft.sem.template.example.authentication;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import java.io.IOException;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Request filter for JWT security.
* <p>
* The request filter is called once for each request and makes it possible to modify the request
* before it reaches the application. If an authorization header is present in the request,
* the filter will validate it and authenticate the token.
* </p>
*/
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
public static final String AUTHORIZATION_HEADER = "Authorization";
public static final String WWW_AUTHENTICATE_HEADER = "WWW-Authenticate";
public static final String AUTHORIZATION_AUTH_SCHEME = "Bearer";
private final transient JwtTokenVerifier jwtTokenVerifier;
@Autowired
public JwtRequestFilter(JwtTokenVerifier jwtTokenVerifier) {
this.jwtTokenVerifier = jwtTokenVerifier;
}
/**
* This filter will verify and authenticate a JWT token if a valid authorization header is set.
*
* @param request The current request we are handling.
* @param response The current response we are building.
* @param filterChain The next link in the filter chain.
* @throws ServletException Exception.
* @throws IOException Exception
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Get authorization header
String authorizationHeader = request.getHeader(AUTHORIZATION_HEADER);
// Check if an authorization header is set
if (authorizationHeader != null) {
String[] directives = authorizationHeader.split(" ");
// Check for the correct auth scheme
if (directives.length == 2 && directives[0].equals(AUTHORIZATION_AUTH_SCHEME)) {
String token = directives[1];
try {
if (jwtTokenVerifier.validateToken(token)) {
String netId = jwtTokenVerifier.getNetIdFromToken(token);
var authenticationToken = new UsernamePasswordAuthenticationToken(
netId,
null, List.of() // no credentials and no authorities
);
authenticationToken.setDetails(new WebAuthenticationDetailsSource()
.buildDetails(request));
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the
// Spring Security Configurations successfully.
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
} catch (ExpiredJwtException e) {
System.err.println("JWT token has expired.");
} catch (IllegalArgumentException | JwtException e) {
System.err.println("Unable to parse JWT token");
}
}
System.err.println("Invalid authorization header");
}
filterChain.doFilter(request, response);
}
}

View file

@ -1,46 +0,0 @@
package nl.tudelft.sem.template.example.authentication;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import java.util.Date;
import java.util.function.Function;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* Verifies the JWT token in the request for validity.
*/
@Component
public class JwtTokenVerifier {
@Value("${jwt.secret}") // automatically loads jwt.secret from resources/application.properties
private transient String jwtSecret;
/**
* Validate the JWT token for expiration.
*/
public boolean validateToken(String token) {
return !isTokenExpired(token);
}
public String getNetIdFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getClaims(token);
return claimsResolver.apply(claims);
}
private Claims getClaims(String token) {
return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
}
}

View file

@ -1,45 +0,0 @@
package nl.tudelft.sem.template.example.config;
import javax.sql.DataSource;
import lombok.Getter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* The H2 config.
*/
@Configuration
@EnableJpaRepositories("nl.tudelft.sem.template.example.domain")
@PropertySource("classpath:application-dev.properties")
@EnableTransactionManagement
public class H2Config {
@Getter
private final Environment environment;
public H2Config(Environment environment) {
this.environment = environment;
}
/**
* Set up the connection to the database.
*
* @return The data source.
*/
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getProperty("jdbc.url"));
dataSource.setUsername(environment.getProperty("jdbc.user"));
dataSource.setPassword(environment.getProperty("jdbc.pass"));
return dataSource;
}
}

View file

@ -1,37 +0,0 @@
package nl.tudelft.sem.template.example.config;
import nl.tudelft.sem.template.example.authentication.JwtAuthenticationEntryPoint;
import nl.tudelft.sem.template.example.authentication.JwtRequestFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/**
* The type Web security config.
*/
@Configuration
public class RequestAuthenticationConfig extends WebSecurityConfigurerAdapter {
private final transient JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private final transient JwtRequestFilter jwtRequestFilter;
public RequestAuthenticationConfig(JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint,
JwtRequestFilter jwtRequestFilter) {
this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
this.jwtRequestFilter = jwtRequestFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}

View file

@ -1,41 +0,0 @@
package nl.tudelft.sem.template.example.controllers;
import nl.tudelft.sem.template.example.authentication.AuthManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Hello World example controller.
* <p>
* This controller shows how you can extract information from the JWT token.
* </p>
*/
@RestController
public class DefaultController {
private final transient AuthManager authManager;
/**
* Instantiates a new controller.
*
* @param authManager Spring Security component used to authenticate and authorize the user
*/
@Autowired
public DefaultController(AuthManager authManager) {
this.authManager = authManager;
}
/**
* Gets example by id.
*
* @return the example found in the database with the given id
*/
@GetMapping("/hello")
public ResponseEntity<String> helloWorld() {
return ResponseEntity.ok("Hello " + authManager.getNetId());
}
}

View file

@ -1,8 +0,0 @@
# Database configuration
jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:./example-microservice/example;DB_CLOSE_ON_EXIT=FALSE
# Hibernate configuration
spring.jpa.hibernate.ddl-auto=create-drop
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create

View file

@ -1,5 +0,0 @@
# Port of the microservice
server.port=8082
# Secret for the JWT signing
jwt.secret=exampleSecret

View file

@ -1,38 +0,0 @@
package nl.tudelft.sem.template.example.authentication;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* Tests for the AuthManager class.
*/
public class AuthManagerTests {
private transient AuthManager authManager;
@BeforeEach
public void setup() {
authManager = new AuthManager();
}
@Test
public void getNetidTest() {
// Arrange
String expected = "user123";
var authenticationToken = new UsernamePasswordAuthenticationToken(
expected,
null, List.of() // no credentials and no authorities
);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
// Act
String actual = authManager.getNetId();
// Assert
assertThat(actual).isEqualTo(expected);
}
}

View file

@ -1,51 +0,0 @@
package nl.tudelft.sem.template.example.authentication;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
/**
* Tests for the JwtAuthenticationEntryPoint class.
*/
public class JwtAuthenticationEntryPointTests {
private transient JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private transient HttpServletRequest mockRequest;
private transient HttpServletResponse mockResponse;
private transient AuthenticationException dummyAuthenticationException;
/**
* Set up mocks.
*/
@BeforeEach
public void setup() {
mockRequest = Mockito.mock(HttpServletRequest.class);
mockResponse = Mockito.mock(HttpServletResponse.class);
dummyAuthenticationException = Mockito.mock(AuthenticationException.class);
jwtAuthenticationEntryPoint = new JwtAuthenticationEntryPoint();
}
@Test
public void commenceTest() throws ServletException, IOException {
// Act
jwtAuthenticationEntryPoint.commence(mockRequest, mockResponse, dummyAuthenticationException);
// Assert
verifyNoInteractions(mockRequest);
verify(mockResponse).addHeader(JwtRequestFilter.WWW_AUTHENTICATE_HEADER,
JwtRequestFilter.AUTHORIZATION_AUTH_SCHEME);
verify(mockResponse).sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
verifyNoMoreInteractions(mockResponse);
}
}

View file

@ -1,171 +0,0 @@
package nl.tudelft.sem.template.example.authentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import java.io.IOException;
import java.util.stream.Stream;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.Mockito;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* Tests for the JwtRequestFilter class.
*/
public class JwtRequestFilterTests {
private transient JwtRequestFilter jwtRequestFilter;
private transient HttpServletRequest mockRequest;
private transient HttpServletResponse mockResponse;
private transient FilterChain mockFilterChain;
private transient JwtTokenVerifier mockJwtTokenVerifier;
/**
* Set up mocks.
*/
@BeforeEach
public void setup() {
mockRequest = Mockito.mock(HttpServletRequest.class);
mockResponse = Mockito.mock(HttpServletResponse.class);
mockFilterChain = Mockito.mock(FilterChain.class);
mockJwtTokenVerifier = Mockito.mock(JwtTokenVerifier.class);
jwtRequestFilter = new JwtRequestFilter(mockJwtTokenVerifier);
SecurityContextHolder.getContext().setAuthentication(null);
}
@AfterEach
public void assertChainContinues() throws ServletException, IOException {
verify(mockFilterChain).doFilter(mockRequest, mockResponse);
verifyNoMoreInteractions(mockFilterChain);
}
@Test
public void correctToken() throws ServletException, IOException {
// Arrange
String token = "randomtoken123";
String user = "user123";
when(mockRequest.getHeader("Authorization")).thenReturn("Bearer " + token);
when(mockJwtTokenVerifier.validateToken(token)).thenReturn(true);
when(mockJwtTokenVerifier.getNetIdFromToken(token)).thenReturn(user);
// Act
jwtRequestFilter.doFilterInternal(mockRequest, mockResponse, mockFilterChain);
// Assert
assertThat(SecurityContextHolder.getContext().getAuthentication().getName())
.isEqualTo(user);
}
@Test
public void invalidToken() throws ServletException, IOException {
// Arrange
String token = "randomtoken123";
String user = "user123";
when(mockRequest.getHeader("Authorization")).thenReturn("Bearer " + token);
when(mockJwtTokenVerifier.validateToken(token)).thenReturn(false);
when(mockJwtTokenVerifier.getNetIdFromToken(token)).thenReturn(user);
// Act
jwtRequestFilter.doFilterInternal(mockRequest, mockResponse, mockFilterChain);
// Assert
assertThat(SecurityContextHolder.getContext().getAuthentication())
.isNull();
}
/**
* Parameterized test for various token verification exceptions.
*
* @param throwable the exception to be tested
*/
@ParameterizedTest
@MethodSource("tokenVerificationExceptionGenerator")
public void tokenVerificationException(Class<? extends Throwable> throwable)
throws ServletException, IOException {
// Arrange
String token = "randomtoken123";
String user = "user123";
when(mockRequest.getHeader("Authorization")).thenReturn("Bearer " + token);
when(mockJwtTokenVerifier.validateToken(token)).thenThrow(throwable);
when(mockJwtTokenVerifier.getNetIdFromToken(token)).thenReturn(user);
// Act
jwtRequestFilter.doFilterInternal(mockRequest, mockResponse, mockFilterChain);
// Assert
assertThat(SecurityContextHolder.getContext().getAuthentication())
.isNull();
}
private static Stream<Arguments> tokenVerificationExceptionGenerator() {
return Stream.of(
Arguments.of(ExpiredJwtException.class),
Arguments.of(IllegalArgumentException.class),
Arguments.of(JwtException.class)
);
}
@Test
public void nullToken() throws ServletException, IOException {
// Arrange
when(mockRequest.getHeader("Authorization")).thenReturn(null);
// Act
jwtRequestFilter.doFilterInternal(mockRequest, mockResponse, mockFilterChain);
// Assert
assertThat(SecurityContextHolder.getContext().getAuthentication())
.isNull();
}
@Test
public void invalidPrefix() throws ServletException, IOException {
// Arrange
String token = "randomtoken123";
String user = "user123";
when(mockRequest.getHeader("Authorization")).thenReturn("Bearer1 " + token);
when(mockJwtTokenVerifier.validateToken(token)).thenReturn(true);
when(mockJwtTokenVerifier.getNetIdFromToken(token)).thenReturn(user);
// Act
jwtRequestFilter.doFilterInternal(mockRequest, mockResponse, mockFilterChain);
// Assert
assertThat(SecurityContextHolder.getContext().getAuthentication())
.isNull();
}
@Test
public void noPrefix() throws ServletException, IOException {
// Arrange
String token = "randomtoken123";
String user = "user123";
when(mockRequest.getHeader("Authorization")).thenReturn(token);
when(mockJwtTokenVerifier.validateToken(token)).thenReturn(true);
when(mockJwtTokenVerifier.getNetIdFromToken(token)).thenReturn(user);
// Act
jwtRequestFilter.doFilterInternal(mockRequest, mockResponse, mockFilterChain);
// Assert
assertThat(SecurityContextHolder.getContext().getAuthentication())
.isNull();
}
}

View file

@ -1,110 +0,0 @@
package nl.tudelft.sem.template.example.authentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.assertj.core.api.ThrowableAssert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
* Tests for the JwtTokenVerifier class.
*/
public class JwtTokenVerifierTests {
private transient JwtTokenVerifier jwtTokenVerifier;
private final String secret = "testSecret123";
@BeforeEach
public void setup() throws NoSuchFieldException, IllegalAccessException {
jwtTokenVerifier = new JwtTokenVerifier();
this.injectSecret(secret);
}
@Test
public void validateNonExpiredToken() {
// Arrange
String token = generateToken(secret, "user123", -10_000_000, 10_000_000);
// Act
boolean actual = jwtTokenVerifier.validateToken(token);
// Assert
assertThat(actual).isTrue();
}
@Test
public void validateExpiredToken() {
// Arrange
String token = generateToken(secret, "user123", -10_000_000, -5_000_000);
// Act
ThrowableAssert.ThrowingCallable action = () -> jwtTokenVerifier.validateToken(token);
// Assert
assertThatExceptionOfType(ExpiredJwtException.class)
.isThrownBy(action);
}
@Test
public void validateTokenIncorrectSignature() {
// Arrange
String token = generateToken("incorrectSecret", "user123", -10_000_000, 10_000_000);
// Act
ThrowableAssert.ThrowingCallable action = () -> jwtTokenVerifier.validateToken(token);
// Assert
assertThatExceptionOfType(SignatureException.class)
.isThrownBy(action);
}
@Test
public void validateMalformedToken() {
// Arrange
String token = "malformedtoken";
// Act
ThrowableAssert.ThrowingCallable action = () -> jwtTokenVerifier.validateToken(token);
// Assert
assertThatExceptionOfType(MalformedJwtException.class)
.isThrownBy(action);
}
@Test
public void parseNetid() {
// Arrange
String expected = "user123";
String token = generateToken(secret, expected, -10_000_000, 10_000_000);
// Act
String actual = jwtTokenVerifier.getNetIdFromToken(token);
// Assert
assertThat(actual).isEqualTo(expected);
}
private String generateToken(String jwtSecret, String netid, long issuanceOffset, long expirationOffset) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder().setClaims(claims).setSubject(netid)
.setIssuedAt(new Date(System.currentTimeMillis() + issuanceOffset))
.setExpiration(new Date(System.currentTimeMillis() + expirationOffset))
.signWith(SignatureAlgorithm.HS512, jwtSecret).compact();
}
private void injectSecret(String secret) throws NoSuchFieldException, IllegalAccessException {
Field declaredField = jwtTokenVerifier.getClass().getDeclaredField("jwtSecret");
declaredField.setAccessible(true);
declaredField.set(jwtTokenVerifier, secret);
}
}

View file

@ -1,66 +0,0 @@
package nl.tudelft.sem.template.example.integration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import nl.tudelft.sem.template.example.authentication.AuthManager;
import nl.tudelft.sem.template.example.authentication.JwtTokenVerifier;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
/**
* Integration tests for the example microservice.
*/
@SpringBootTest
@ExtendWith(SpringExtension.class)
// activate profiles to have spring use mocks during auto-injection of certain beans.
@ActiveProfiles({"test", "mockTokenVerifier", "mockAuthenticationManager"})
//@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
@AutoConfigureMockMvc
public class ExampleTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private transient JwtTokenVerifier mockJwtTokenVerifier;
@Autowired
private transient AuthManager mockAuthenticationManager;
@Test
public void helloWorld() throws Exception {
// Arrange
// Notice how some custom parts of authorisation need to be mocked.
// Otherwise, the integration test would never be able to authorise as the authorisation server is offline.
when(mockAuthenticationManager.getNetId()).thenReturn("ExampleUser");
when(mockJwtTokenVerifier.validateToken(anyString())).thenReturn(true);
when(mockJwtTokenVerifier.getNetIdFromToken(anyString())).thenReturn("ExampleUser");
// Act
// Still include Bearer token as AuthFilter itself is not mocked
ResultActions result = mockMvc.perform(get("/hello")
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer MockedToken"));
// Assert
result.andExpect(status().isOk());
String response = result.andReturn().getResponse().getContentAsString();
assertThat(response).isEqualTo("Hello ExampleUser");
}
}

View file

@ -1,36 +0,0 @@
package nl.tudelft.sem.template.example.profiles;
import nl.tudelft.sem.template.example.authentication.AuthManager;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
/**
* A configuration profile to allow injection of a mock AuthenticationManager.
* A configuration can be used to define beans to be used during injection.
* When this profile is active spring dependency injection will use this class to look for bean methods.
* It will then prioritise these beans due to their @Primary tag.
* In this case we return a mock to allow for more testability.
* .
* The profile tag will give a name to this configuration.
* With the tag applied the profile will be inactive by default unless activated.
* When the profile is active its bean will be used when looking for Beans to auto-inject.
*/
@Profile("mockAuthenticationManager")
@Configuration
public class MockAuthenticationManagerProfile {
/**
* Mocks the AuthenticationManager.
*
* @return A mocked AuthenticationManager.
*/
@Bean
@Primary // marks this bean as the first bean to use when trying to inject an AuthenticationManager
public AuthManager getMockAuthenticationManager() {
return Mockito.mock(AuthManager.class);
}
}

View file

@ -1,35 +0,0 @@
package nl.tudelft.sem.template.example.profiles;
import nl.tudelft.sem.template.example.authentication.JwtTokenVerifier;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
/**
* A configuration profile to allow injection of a mock TokenVerifier.
* A configuration can be used to define beans to be used during injection.
* When this profile is active spring dependency injection will use this class to look for bean methods.
* It will then prioritise these beans due to their @Primary tag.
* In this case we return a mock to allow for more testability.
* .
* The profile tag will give a name to this configuration.
* With the tag applied the profile will be inactive by default unless activated.
* When the profile is active its bean will be used when looking for Beans to auto-inject.
*/
@Profile("mockTokenVerifier")
@Configuration
public class MockTokenVerifierProfile {
/**
* Mocks the TokenVerifier.
*
* @return A mocked TokenVerifier.
*/
@Bean
@Primary // marks this bean as the first bean to use when trying to inject an AuthenticationManager
public JwtTokenVerifier getMockTokenVerifier() {
return Mockito.mock(JwtTokenVerifier.class);
}
}

View file

@ -1,4 +1,3 @@
rootProject.name = 'template'
include 'example-microservice'
include 'order-microservice'
include 'order-microservice'