diff --git a/example-microservice/.gitlab-ci.yml b/example-microservice/.gitlab-ci.yml deleted file mode 100644 index 66ed222..0000000 --- a/example-microservice/.gitlab-ci.yml +++ /dev/null @@ -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})%/ - diff --git a/example-microservice/build.gradle b/example-microservice/build.gradle deleted file mode 100644 index 9f324fb..0000000 --- a/example-microservice/build.gradle +++ /dev/null @@ -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 -} diff --git a/example-microservice/settings.gradle b/example-microservice/settings.gradle deleted file mode 100644 index 064b859..0000000 --- a/example-microservice/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'example-microservice' diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/Application.java b/example-microservice/src/main/java/nl/tudelft/sem/template/example/Application.java deleted file mode 100644 index 23a6654..0000000 --- a/example-microservice/src/main/java/nl/tudelft/sem/template/example/Application.java +++ /dev/null @@ -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); - } -} diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/application/.keep b/example-microservice/src/main/java/nl/tudelft/sem/template/example/application/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/AuthManager.java b/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/AuthManager.java deleted file mode 100644 index c02dd72..0000000 --- a/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/AuthManager.java +++ /dev/null @@ -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(); - } -} diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtAuthenticationEntryPoint.java b/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtAuthenticationEntryPoint.java deleted file mode 100644 index 86a6c2d..0000000 --- a/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtAuthenticationEntryPoint.java +++ /dev/null @@ -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. - *

- * 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. - *

- */ -@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()); - } -} \ No newline at end of file diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtRequestFilter.java b/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtRequestFilter.java deleted file mode 100644 index f6726e0..0000000 --- a/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtRequestFilter.java +++ /dev/null @@ -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. - *

- * 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. - *

- */ -@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); - } -} \ No newline at end of file diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtTokenVerifier.java b/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtTokenVerifier.java deleted file mode 100644 index b5e049f..0000000 --- a/example-microservice/src/main/java/nl/tudelft/sem/template/example/authentication/JwtTokenVerifier.java +++ /dev/null @@ -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 getClaimFromToken(String token, Function claimsResolver) { - final Claims claims = getClaims(token); - return claimsResolver.apply(claims); - } - - private Claims getClaims(String token) { - return Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody(); - } -} diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/config/H2Config.java b/example-microservice/src/main/java/nl/tudelft/sem/template/example/config/H2Config.java deleted file mode 100644 index 57326ea..0000000 --- a/example-microservice/src/main/java/nl/tudelft/sem/template/example/config/H2Config.java +++ /dev/null @@ -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; - } -} diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/config/RequestAuthenticationConfig.java b/example-microservice/src/main/java/nl/tudelft/sem/template/example/config/RequestAuthenticationConfig.java deleted file mode 100644 index 770fb46..0000000 --- a/example-microservice/src/main/java/nl/tudelft/sem/template/example/config/RequestAuthenticationConfig.java +++ /dev/null @@ -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); - } - -} diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/controllers/DefaultController.java b/example-microservice/src/main/java/nl/tudelft/sem/template/example/controllers/DefaultController.java deleted file mode 100644 index 7eb77ba..0000000 --- a/example-microservice/src/main/java/nl/tudelft/sem/template/example/controllers/DefaultController.java +++ /dev/null @@ -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. - *

- * This controller shows how you can extract information from the JWT token. - *

- */ -@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 helloWorld() { - return ResponseEntity.ok("Hello " + authManager.getNetId()); - - } - -} diff --git a/example-microservice/src/main/java/nl/tudelft/sem/template/example/domain/.keep b/example-microservice/src/main/java/nl/tudelft/sem/template/example/domain/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/example-microservice/src/main/resources/application-dev.properties b/example-microservice/src/main/resources/application-dev.properties deleted file mode 100644 index 95bf69a..0000000 --- a/example-microservice/src/main/resources/application-dev.properties +++ /dev/null @@ -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 diff --git a/example-microservice/src/main/resources/application.properties b/example-microservice/src/main/resources/application.properties deleted file mode 100644 index 4a39452..0000000 --- a/example-microservice/src/main/resources/application.properties +++ /dev/null @@ -1,5 +0,0 @@ -# Port of the microservice -server.port=8082 - -# Secret for the JWT signing -jwt.secret=exampleSecret diff --git a/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/AuthManagerTests.java b/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/AuthManagerTests.java deleted file mode 100644 index 05b8e07..0000000 --- a/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/AuthManagerTests.java +++ /dev/null @@ -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); - } -} diff --git a/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtAuthenticationEntryPointTests.java b/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtAuthenticationEntryPointTests.java deleted file mode 100644 index 6e395e4..0000000 --- a/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtAuthenticationEntryPointTests.java +++ /dev/null @@ -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); - } -} diff --git a/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtRequestFilterTests.java b/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtRequestFilterTests.java deleted file mode 100644 index f374308..0000000 --- a/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtRequestFilterTests.java +++ /dev/null @@ -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 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 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(); - } -} diff --git a/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtTokenVerifierTests.java b/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtTokenVerifierTests.java deleted file mode 100644 index 5a273df..0000000 --- a/example-microservice/src/test/java/nl/tudelft/sem/template/example/authentication/JwtTokenVerifierTests.java +++ /dev/null @@ -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 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); - } -} diff --git a/example-microservice/src/test/java/nl/tudelft/sem/template/example/integration/ExampleTest.java b/example-microservice/src/test/java/nl/tudelft/sem/template/example/integration/ExampleTest.java deleted file mode 100644 index e778c02..0000000 --- a/example-microservice/src/test/java/nl/tudelft/sem/template/example/integration/ExampleTest.java +++ /dev/null @@ -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"); - - } -} diff --git a/example-microservice/src/test/java/nl/tudelft/sem/template/example/profiles/MockAuthenticationManagerProfile.java b/example-microservice/src/test/java/nl/tudelft/sem/template/example/profiles/MockAuthenticationManagerProfile.java deleted file mode 100644 index 6d3ff38..0000000 --- a/example-microservice/src/test/java/nl/tudelft/sem/template/example/profiles/MockAuthenticationManagerProfile.java +++ /dev/null @@ -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); - } -} - diff --git a/example-microservice/src/test/java/nl/tudelft/sem/template/example/profiles/MockTokenVerifierProfile.java b/example-microservice/src/test/java/nl/tudelft/sem/template/example/profiles/MockTokenVerifierProfile.java deleted file mode 100644 index 4f516a4..0000000 --- a/example-microservice/src/test/java/nl/tudelft/sem/template/example/profiles/MockTokenVerifierProfile.java +++ /dev/null @@ -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); - } -} diff --git a/settings.gradle b/settings.gradle index f46bb63..4fd842f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,3 @@ rootProject.name = 'template' -include 'example-microservice' -include 'order-microservice' \ No newline at end of file +include 'order-microservice'