diff --git a/.github/workflows/13-backend-incremental-pitest.yml b/.github/workflows/13-backend-incremental-pitest.yml index e3f02ae2..7ca5bbdb 100644 --- a/.github/workflows/13-backend-incremental-pitest.yml +++ b/.github/workflows/13-backend-incremental-pitest.yml @@ -54,7 +54,7 @@ jobs: - name: Build with Maven run: mvn -B test - name: Pitest - run: mvn test org.pitest:pitest-maven:mutationCoverage -DmutationThreshold=100 + run: mvn pitest:mutationCoverage -DmutationThreshold=100 - name: Upload Pitest History to Artifacts if: always() # always upload artifacts, even if tests fail uses: actions/upload-artifact@v3.1.2 diff --git a/.github/workflows/14-backend-pitest.yml b/.github/workflows/14-backend-pitest.yml index e99c7eb7..534a0eb2 100644 --- a/.github/workflows/14-backend-pitest.yml +++ b/.github/workflows/14-backend-pitest.yml @@ -43,7 +43,7 @@ jobs: # main branch changes - name: Pitest - run: mvn test org.pitest:pitest-maven:mutationCoverage -DmutationThreshold=100 + run: mvn pitest:mutationCoverage -DmutationThreshold=100 - name: Upload Pitest History to Artifacts if: always() # always upload artifacts, even if tests fail uses: actions/upload-artifact@v3.1.2 diff --git a/README.md b/README.md index c8f647fe..f0a85bec 100644 --- a/README.md +++ b/README.md @@ -165,12 +165,12 @@ INTEGRATION=true HEADLESS=false mvn test-compile failsafe:integration-test To run a particular integration test (e.g. only `HomePageWebIT.java`) use `-Dit.test=ClassName`, for example: ``` -INTEGRATION=true mvn test-compile failsafe:integration-test -Dit.test=HomePageWebIt +INTEGRATION=true mvn test-compile failsafe:integration-test -Dit.test=HomePageWebIT ``` or to see it run live: ``` -INTEGRATION=true HEADLESS=false mvn test-compile failsafe:integration-test -Dit.test=HomePageWebIt +INTEGRATION=true HEADLESS=false mvn test-compile failsafe:integration-test -Dit.test=HomePageWebIT ``` Integration tests are any methods labelled with `@Test` annotation, that are under the `/src/test/java` hierarchy, and have names starting with `IT` (specifically capital I, capital T). @@ -181,5 +181,4 @@ Unless you want a particular integration test to *also* be run when you type `mv Note that while `mvn test` is typically sufficient to run tests, we have found that if you haven't compiled the test code yet, running `mvn failsafe:integration-test` may not actually run any of the tests. -To run a single integration test (e.g. only `HomePageWebIT.java`) use `-Dit.test=ClassName`, for example: diff --git a/pom.xml b/pom.xml index 97ba0156..070bfa9e 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.springframework.boot spring-boot-starter-parent - 2.6.3 + 3.1.1 @@ -75,7 +75,7 @@ org.springframework.cloud spring-cloud-gateway-mvc - 3.0.1 + 4.1.3 @@ -135,11 +135,12 @@ 2.0.1.Final + org.springdoc - springdoc-openapi-ui - 1.7.0 - + springdoc-openapi-starter-webmvc-ui + 2.5.0 + @@ -157,7 +158,8 @@ 3.0.0-M5 - + @@ -198,6 +200,7 @@ **/${app.packagePath}/controllers/FrontendController.* **/${app.packagePath}/controllers/FrontendProxyController.* **/${app.packagePath}/services/CurrentUserServiceImpl.* + **/${app.packagePath}/services/GrantedAuthoritiesService.* **/${app.packagePath}/ExampleApplication.* **/edu/ucsb/cs156/example/services/wiremock/* @@ -286,12 +289,16 @@ ${app.package}.services.CurrentUserServiceImpl ${app.package}.ExampleApplication ${app.package}.config.SecurityConfig + ${app.package}.config.SpaCsrfTokenRequestHandler + ${app.package}.config.CsrfCookieFilter edu.ucsb.cs156.example.services.wiremock.WiremockService edu.ucsb.cs156.example.services.wiremock.WiremockServiceDummy edu.ucsb.cs156.example.services.wiremock.WiremockServiceImpl + ${app.package}.services.GrantedAuthoritiesService edu.ucsb.cs156.example.web.* + edu.ucsb.cs156.example.integration.* HTML @@ -377,8 +384,8 @@ frontend-maven-plugin 1.12.1 - frontend - ${project.build.directory} + frontend + ${project.build.directory} @@ -409,26 +416,26 @@ - - - maven-antrun-plugin - 3.0.0 - - - generate-resources - - - - - - - - - run - - - - + + + maven-antrun-plugin + 3.0.0 + + + generate-resources + + + + + + + + + run + + + + diff --git a/src/main/java/edu/ucsb/cs156/example/aop/LoggingAspect.java b/src/main/java/edu/ucsb/cs156/example/aop/LoggingAspect.java index 2cdc6acf..15e1a10d 100644 --- a/src/main/java/edu/ucsb/cs156/example/aop/LoggingAspect.java +++ b/src/main/java/edu/ucsb/cs156/example/aop/LoggingAspect.java @@ -1,5 +1,6 @@ package edu.ucsb.cs156.example.aop; +import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; @@ -8,8 +9,6 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import javax.servlet.http.HttpServletRequest; - import java.util.ArrayList; import java.util.Arrays; import java.util.Optional; diff --git a/src/main/java/edu/ucsb/cs156/example/config/SecurityConfig.java b/src/main/java/edu/ucsb/cs156/example/config/SecurityConfig.java index 103397a1..bf281d53 100644 --- a/src/main/java/edu/ucsb/cs156/example/config/SecurityConfig.java +++ b/src/main/java/edu/ucsb/cs156/example/config/SecurityConfig.java @@ -1,88 +1,100 @@ package edu.ucsb.cs156.example.config; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Pattern; - -import javax.servlet.http.HttpServletRequest; - +import edu.ucsb.cs156.example.entities.User; +import edu.ucsb.cs156.example.repositories.UserRepository; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.oauth2.core.user.OAuth2UserAuthority; +import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; +import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler; +import org.springframework.security.web.csrf.CsrfTokenRequestHandler; +import org.springframework.security.web.csrf.XorCsrfTokenRequestAttributeHandler; +import org.springframework.security.web.csrf.CsrfToken; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import org.springframework.security.web.util.matcher.RequestMatcher; - - +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; -import edu.ucsb.cs156.example.entities.User; -import edu.ucsb.cs156.example.repositories.UserRepository; -import lombok.extern.slf4j.Slf4j; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; /** - * The `SecurityConfig` class in Java configures web security with OAuth2 login, CSRF protection, and + * The `SecurityConfig` class in Java configures web security with OAuth2 login, + * CSRF protection, and * role-based authorization based on user email addresses. */ @Configuration @EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) +@EnableMethodSecurity @Slf4j -public class SecurityConfig extends WebSecurityConfigurerAdapter { +public class SecurityConfig { @Value("${app.admin.emails}") - private final List adminEmails = new ArrayList(); + private final List adminEmails = new ArrayList<>(); @Autowired UserRepository userRepository; /** - * The `configure` method in this Java code configures various security settings for an HTTP request, - * including authorization, exception handling, OAuth2 login, CSRF protection, and logout behavior. + * The `filterChain` method in this Java code configures various security + * settings for an HTTP request, + * including authorization, exception handling, OAuth2 login, CSRF protection, + * and logout behavior. * * @param http injected HttpSecurity object (injected by Spring framework) + * // */ - @Override - protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests(authorize -> authorize - .anyRequest().permitAll()) - .exceptionHandling(handlingConfigurer -> handlingConfigurer - .authenticationEntryPoint(new Http403ForbiddenEntryPoint())) + // https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript-spa + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .exceptionHandling(handling -> handling.authenticationEntryPoint(new Http403ForbiddenEntryPoint())) .oauth2Login( oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.userAuthoritiesMapper(this.userAuthoritiesMapper()))) .csrf(csrf -> csrf - .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())) - .logout(logout -> logout - .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) - .logoutSuccessUrl("/")); + .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) + .csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler())) + .addFilterAfter(new CsrfCookieFilter(), BasicAuthenticationFilter.class) + .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) + .logout(logout -> logout.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")); + return http.build(); } /** - * The `configure` method is used to configure web security in Java, specifically ignoring requests + * The `webSecurityCustomizer` method is used to configure web security in Java, + * specifically ignoring requests * to the "/h2-console/**" path. - * - * @param web injected by Spring Framework */ - @Override - public void configure(WebSecurity web) throws Exception { - web.ignoring().antMatchers("/h2-console/**"); + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return web -> web.ignoring().requestMatchers("/h2-console/**"); } private GrantedAuthoritiesMapper userAuthoritiesMapper() { @@ -93,12 +105,12 @@ private GrantedAuthoritiesMapper userAuthoritiesMapper() { authorities.forEach(authority -> { log.info("********** authority={}", authority); mappedAuthorities.add(authority); - if (OAuth2UserAuthority.class.isInstance(authority)) { - OAuth2UserAuthority oauth2UserAuthority = (OAuth2UserAuthority) authority; - + if (authority instanceof OAuth2UserAuthority oauth2UserAuthority) { Map userAttributes = oauth2UserAuthority.getAttributes(); log.info("********** userAttributes={}", userAttributes); + mappedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER")); + String email = (String) userAttributes.get("email"); if (getAdmin(email)) { mappedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); @@ -116,7 +128,8 @@ private GrantedAuthoritiesMapper userAuthoritiesMapper() { } /** - * This method checks if the given email belongs to an admin user either from a predefined + * This method checks if the given email belongs to an admin user either from a + * predefined * list or by querying the user repository. * * @param email email address of the user @@ -129,4 +142,54 @@ public boolean getAdmin(String email) { Optional u = userRepository.findByEmail(email); return u.isPresent() && u.get().getAdmin(); } +} + +final class SpaCsrfTokenRequestHandler extends CsrfTokenRequestAttributeHandler { + private final CsrfTokenRequestHandler delegate = new XorCsrfTokenRequestAttributeHandler(); + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, + Supplier deferredCsrfToken) { + /* + * Always use XorCsrfTokenRequestAttributeHandler to provide BREACH protection + * of + * the CsrfToken when it is rendered in the response body. + */ + this.delegate.handle(request, response, deferredCsrfToken); + } + + @Override + public String resolveCsrfTokenValue(HttpServletRequest request, CsrfToken csrfToken) { + /* + * If the request contains a request header, use + * CsrfTokenRequestAttributeHandler + * to resolve the CsrfToken. This applies when a single-page application + * includes + * the header value automatically, which was obtained via a cookie containing + * the + * raw CsrfToken. + */ + if (StringUtils.hasText(request.getHeader(csrfToken.getHeaderName()))) { + return super.resolveCsrfTokenValue(request, csrfToken); + } + /* + * In all other cases (e.g. if the request contains a request parameter), use + * XorCsrfTokenRequestAttributeHandler to resolve the CsrfToken. This applies + * when a server-side rendered form includes the _csrf request parameter as a + * hidden input. + */ + return this.delegate.resolveCsrfTokenValue(request, csrfToken); + } +} + +final class CsrfCookieFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + CsrfToken csrfToken = (CsrfToken) request.getAttribute("_csrf"); + // Render the token value to a cookie by causing the deferred token to be loaded + csrfToken.getToken(); + filterChain.doFilter(request, response); + } } \ No newline at end of file diff --git a/src/main/java/edu/ucsb/cs156/example/controllers/UserInfoController.java b/src/main/java/edu/ucsb/cs156/example/controllers/UserInfoController.java index 5a34463e..df8bdc9c 100644 --- a/src/main/java/edu/ucsb/cs156/example/controllers/UserInfoController.java +++ b/src/main/java/edu/ucsb/cs156/example/controllers/UserInfoController.java @@ -1,8 +1,6 @@ package edu.ucsb.cs156.example.controllers; -import edu.ucsb.cs156.example.entities.User; import edu.ucsb.cs156.example.models.CurrentUser; -import edu.ucsb.cs156.example.services.CurrentUserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; diff --git a/src/main/java/edu/ucsb/cs156/example/entities/Restaurant.java b/src/main/java/edu/ucsb/cs156/example/entities/Restaurant.java index 196778bc..373bfae3 100644 --- a/src/main/java/edu/ucsb/cs156/example/entities/Restaurant.java +++ b/src/main/java/edu/ucsb/cs156/example/entities/Restaurant.java @@ -1,14 +1,13 @@ package edu.ucsb.cs156.example.entities; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; - -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * This is a JPA entity that represents a restaurant. diff --git a/src/main/java/edu/ucsb/cs156/example/entities/UCSBDate.java b/src/main/java/edu/ucsb/cs156/example/entities/UCSBDate.java index 1769918c..9a8996f5 100644 --- a/src/main/java/edu/ucsb/cs156/example/entities/UCSBDate.java +++ b/src/main/java/edu/ucsb/cs156/example/entities/UCSBDate.java @@ -1,18 +1,17 @@ package edu.ucsb.cs156.example.entities; -import java.time.LocalDateTime; - -import javax.persistence.Entity; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.GeneratedValue; - -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; -/** +/** * This is a JPA entity that represents a UCSBDate, i.e. an entry * that comes from the UCSB API for academic calendar dates. */ @@ -28,6 +27,6 @@ public class UCSBDate { private long id; private String quarterYYYYQ; - private String name; + private String name; private LocalDateTime localDateTime; } \ No newline at end of file diff --git a/src/main/java/edu/ucsb/cs156/example/entities/UCSBDiningCommons.java b/src/main/java/edu/ucsb/cs156/example/entities/UCSBDiningCommons.java index d54ea34d..55810380 100644 --- a/src/main/java/edu/ucsb/cs156/example/entities/UCSBDiningCommons.java +++ b/src/main/java/edu/ucsb/cs156/example/entities/UCSBDiningCommons.java @@ -1,12 +1,11 @@ package edu.ucsb.cs156.example.entities; -import javax.persistence.Entity; -import javax.persistence.Id; - -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; /** * This is a JPA entity that represents a UCSBDiningCommons diff --git a/src/main/java/edu/ucsb/cs156/example/entities/User.java b/src/main/java/edu/ucsb/cs156/example/entities/User.java index 5819f731..61cc13e2 100644 --- a/src/main/java/edu/ucsb/cs156/example/entities/User.java +++ b/src/main/java/edu/ucsb/cs156/example/entities/User.java @@ -1,14 +1,14 @@ package edu.ucsb.cs156.example.entities; -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; -import lombok.AccessLevel; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; +import lombok.Data; +import lombok.NoArgsConstructor; /** * This is a JPA entity that represents a user. diff --git a/src/main/resources/application-integration.properties b/src/main/resources/application-integration.properties index b7f3b013..52d73869 100644 --- a/src/main/resources/application-integration.properties +++ b/src/main/resources/application-integration.properties @@ -16,7 +16,6 @@ spring.security.oauth2.client.registration.my-oauth-provider.client-name=Client spring.security.oauth2.client.registration.my-oauth-provider.provider=my-oauth-provider spring.security.oauth2.client.registration.my-oauth-provider.scope=https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/userinfo.profile spring.security.oauth2.client.registration.my-oauth-provider.redirect-uri=http://localhost:8080/login/oauth2/code/my-oauth-provider -spring.security.oauth2.client.registration.my-oauth-provider.client-authentication-method=basic spring.security.oauth2.client.registration.my-oauth-provider.authorization-grant-type=authorization_code spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=http://localhost:8090/oauth/authorize diff --git a/src/main/resources/application-wiremock.properties b/src/main/resources/application-wiremock.properties index 81ddf1e3..2cce381c 100644 --- a/src/main/resources/application-wiremock.properties +++ b/src/main/resources/application-wiremock.properties @@ -16,7 +16,6 @@ spring.security.oauth2.client.registration.my-oauth-provider.client-name=Client spring.security.oauth2.client.registration.my-oauth-provider.provider=my-oauth-provider spring.security.oauth2.client.registration.my-oauth-provider.scope=https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/userinfo.profile spring.security.oauth2.client.registration.my-oauth-provider.redirect-uri=http://localhost:8080/login/oauth2/code/my-oauth-provider -spring.security.oauth2.client.registration.my-oauth-provider.client-authentication-method=basic spring.security.oauth2.client.registration.my-oauth-provider.authorization-grant-type=authorization_code spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=http://localhost:8090/oauth/authorize diff --git a/src/test/java/edu/ucsb/cs156/example/WebTestCase.java b/src/test/java/edu/ucsb/cs156/example/WebTestCase.java index 7feee284..eb5ba557 100644 --- a/src/test/java/edu/ucsb/cs156/example/WebTestCase.java +++ b/src/test/java/edu/ucsb/cs156/example/WebTestCase.java @@ -1,14 +1,5 @@ package edu.ucsb.cs156.example; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.ActiveProfiles; - import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer; import com.microsoft.playwright.Browser; @@ -16,8 +7,15 @@ import com.microsoft.playwright.BrowserType; import com.microsoft.playwright.Page; import com.microsoft.playwright.Playwright; - import edu.ucsb.cs156.example.services.wiremock.WiremockServiceImpl; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.context.ActiveProfiles; + +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; @ActiveProfiles("integration") public abstract class WebTestCase { diff --git a/src/test/java/edu/ucsb/cs156/example/services/CurrentUserServiceTests.java b/src/test/java/edu/ucsb/cs156/example/services/CurrentUserServiceTests.java index effbc3ab..06539bdc 100644 --- a/src/test/java/edu/ucsb/cs156/example/services/CurrentUserServiceTests.java +++ b/src/test/java/edu/ucsb/cs156/example/services/CurrentUserServiceTests.java @@ -9,19 +9,20 @@ import edu.ucsb.cs156.example.ControllerTestCase; import edu.ucsb.cs156.example.entities.User; +import org.mockito.Answers; class CurrentUserServiceTests extends ControllerTestCase { @Test void test_isLoggedIn_returns_false() { - CurrentUserService currentUserService = mock(CurrentUserService.class); + CurrentUserService currentUserService = mock(CurrentUserService.class, Answers.CALLS_REAL_METHODS); when(currentUserService.getUser()).thenReturn(null); assertFalse(currentUserService.isLoggedIn()); } @Test void test_isLoggedIn_returns_true() { - CurrentUserService currentUserService = mock(CurrentUserService.class); + CurrentUserService currentUserService = mock(CurrentUserService.class, Answers.CALLS_REAL_METHODS); when(currentUserService.getUser()).thenReturn(User.builder().build()); assertTrue(currentUserService.isLoggedIn()); } diff --git a/src/test/java/edu/ucsb/cs156/example/services/GrantedAuthoritiesServiceTests.java b/src/test/java/edu/ucsb/cs156/example/services/GrantedAuthoritiesServiceTests.java deleted file mode 100644 index 24fd6d09..00000000 --- a/src/test/java/edu/ucsb/cs156/example/services/GrantedAuthoritiesServiceTests.java +++ /dev/null @@ -1,44 +0,0 @@ -package edu.ucsb.cs156.example.services; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Collection; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import edu.ucsb.cs156.example.repositories.UserRepository; -import edu.ucsb.cs156.example.testconfig.TestConfig; - -@ExtendWith(SpringExtension.class) -@EnableConfigurationProperties(value = SystemInfoServiceImpl.class) -@Import(TestConfig.class) -@ContextConfiguration -class GrantedAuthoritiesServiceTests { - - @MockBean - UserRepository userRepository; - - @Autowired - GrantedAuthoritiesService grantedAuthoritiesService; - - @WithMockUser(roles = { "USER" }) - @Test - void test_getGrantedAuthorities() { - // act - Collection grantedAuthorities = grantedAuthoritiesService.getGrantedAuthorities(); - - // assert - - assertTrue(grantedAuthorities.size() > 0 ); - } - -} diff --git a/src/test/java/edu/ucsb/cs156/example/testconfig/TestConfig.java b/src/test/java/edu/ucsb/cs156/example/testconfig/TestConfig.java index c9590520..ea96a428 100644 --- a/src/test/java/edu/ucsb/cs156/example/testconfig/TestConfig.java +++ b/src/test/java/edu/ucsb/cs156/example/testconfig/TestConfig.java @@ -1,13 +1,16 @@ package edu.ucsb.cs156.example.testconfig; +import edu.ucsb.cs156.example.config.SecurityConfig; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import edu.ucsb.cs156.example.services.CurrentUserService; import edu.ucsb.cs156.example.services.GrantedAuthoritiesService; +import org.springframework.context.annotation.Import; @TestConfiguration +@Import(SecurityConfig.class) public class TestConfig { @Bean diff --git a/src/test/java/edu/ucsb/cs156/example/web/HomePageWebIT.java b/src/test/java/edu/ucsb/cs156/example/web/HomePageWebIT.java index b3abe7f7..ac61eb40 100644 --- a/src/test/java/edu/ucsb/cs156/example/web/HomePageWebIT.java +++ b/src/test/java/edu/ucsb/cs156/example/web/HomePageWebIT.java @@ -1,15 +1,12 @@ package edu.ucsb.cs156.example.web; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; diff --git a/src/test/java/edu/ucsb/cs156/example/web/SwaggerWebIT.java b/src/test/java/edu/ucsb/cs156/example/web/SwaggerWebIT.java index 2cfa6663..9ce7e5f8 100644 --- a/src/test/java/edu/ucsb/cs156/example/web/SwaggerWebIT.java +++ b/src/test/java/edu/ucsb/cs156/example/web/SwaggerWebIT.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension;