diff --git a/autograde-service/src/main/java/ch/epfl/autograde/auth/token/ShareSecretAuthentication.java b/autograde-service/src/main/java/ch/epfl/autograde/auth/token/ShareSecretAuthentication.java index 25d1693044c98ec1a922bc94ab22bbf3717650a7..0a4e357bcd1b1530e9a20f45dfeb09a317c745d2 100644 --- a/autograde-service/src/main/java/ch/epfl/autograde/auth/token/ShareSecretAuthentication.java +++ b/autograde-service/src/main/java/ch/epfl/autograde/auth/token/ShareSecretAuthentication.java @@ -49,7 +49,7 @@ public final class ShareSecretAuthentication implements Authentication { @Override public Object getPrincipal() { - return null; + return this; } @Override diff --git a/autograde-service/src/main/java/ch/epfl/autograde/config/SecurityConfig.java b/autograde-service/src/main/java/ch/epfl/autograde/config/SecurityConfig.java index dfcd2b73a3d9689d9dd17a3a8977b6cef72318df..a2b28a20ce016cf9e812abdb08204cf53f5baf83 100644 --- a/autograde-service/src/main/java/ch/epfl/autograde/config/SecurityConfig.java +++ b/autograde-service/src/main/java/ch/epfl/autograde/config/SecurityConfig.java @@ -59,10 +59,10 @@ public class SecurityConfig { .requestCache(RequestCacheConfigurer::disable) .rememberMe(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> { - auth.requestMatchers("/api/v1/ping/no-auth").permitAll(); - auth.requestMatchers("/api/v1/ping/auth").authenticated(); - // By default, request authentication to access any end point - auth.anyRequest().authenticated(); + // Do not enforce authentication for ping + auth.requestMatchers("/api/v1/ping").permitAll(); + // By default, request authentication to access any end point + auth.anyRequest().authenticated(); }) .build(); } diff --git a/autograde-service/src/main/java/ch/epfl/autograde/controller/api/v1/PingController.java b/autograde-service/src/main/java/ch/epfl/autograde/controller/api/v1/PingController.java index a8f56ac2edee71d21188dd705e24094c88dc9ca7..9d538186a711669e7fa4b5e229f003a0895153a9 100644 --- a/autograde-service/src/main/java/ch/epfl/autograde/controller/api/v1/PingController.java +++ b/autograde-service/src/main/java/ch/epfl/autograde/controller/api/v1/PingController.java @@ -4,6 +4,8 @@ import ch.epfl.autograde.model.response.PingResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -11,13 +13,13 @@ import org.springframework.web.bind.annotation.RestController; import java.util.Date; import static java.time.Instant.now; +import static java.util.Objects.nonNull; /** * REST Controller to ping the service * * @author Hamza REMMAL (hamza.remmal@epfl.ch) * @since 1.0.0 - * @version 1.0.0 */ @Slf4j @RestController @@ -26,36 +28,19 @@ import static java.time.Instant.now; public final class PingController { /** - * REST Endpoint to ping the service without authenticated - * @since 1.0.0 + * REST Endpoint to ping the service + * @since 1.3.0 * @return * <ul> * <li>{@link HttpStatus.OK} if the request is successful</li> * </ul> */ - @GetMapping("/no-auth") - public PingResponse ping_without_auth() { - log.info("Received a ping from an unauthenticated source"); + @GetMapping(consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public PingResponse ping(Authentication authentication) { + log.info("API Service received a ping"); return new PingResponse( Date.from(now()), - false - ); - } - - /** - * REST Endpoint to ping the service when authenticated - * @since 1.0.0 - * @return - * <ul> - * <li>{@link HttpStatus.OK} if the request is successful</li> - * </ul> - */ - @GetMapping("/auth") - public PingResponse ping_with_auth() { - log.info("Received a ping from an authenticated source"); - return new PingResponse( - Date.from(now()), - true + nonNull(authentication) && authentication.isAuthenticated() ); } diff --git a/autograde-service/src/test/java/ch/epfl/autograde/controller/api/v1/PingControllerTest.java b/autograde-service/src/test/java/ch/epfl/autograde/controller/api/v1/PingControllerTest.java index 5fef758a27cab30e09feb8e4a5a37408f540a8cb..572d31c8ca691b2b34ea76e5f38414d361d467f9 100644 --- a/autograde-service/src/test/java/ch/epfl/autograde/controller/api/v1/PingControllerTest.java +++ b/autograde-service/src/test/java/ch/epfl/autograde/controller/api/v1/PingControllerTest.java @@ -5,6 +5,8 @@ import org.junit.jupiter.api.Test; 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.HttpHeaders; +import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -13,10 +15,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. /** * Test class for the {@link PingController} API. * <p> - * This class verifies the behaviour of the ping endpoints provided by the API: + * This class verifies the behaviour of the ping endpoint provided by the API: * <ul> - * <li>{@code /api/v1/ping/no-auth} - A public endpoint accessible without authentication.</li> - * <li>{@code /api/v1/ping/auth} - A protected endpoint requiring shared secret authentication.</li> + * <li>{@code /api/v1/ping} - An endpoint accessible without authentication.</li> * </ul> * It uses Spring Boot's {@link MockMvc} for testing HTTP requests and responses, * and the {@link WithSharedSecretAuthentication} annotation to simulate requests @@ -32,78 +33,59 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @SpringBootTest public final class PingControllerTest { - /** The endpoint to perform a non-authenticated ping */ - private final static String NO_AUTH_END_POINT = "/api/v1/ping/no-auth"; + /** The endpoint to perform a ping */ + private final static String PING_END_POINT = "/api/v1/ping"; - /** The endpoint to perform an authenticated ping */ - private final static String AUTH_END_POINT = "/api/v1/ping/auth"; + @Autowired + private MockMvc mockMvc; - @Autowired - private MockMvc mockMvc; + /** + * If <b>not</b> authenticated with the shared secret, the request to `/api/v1/ping` + * should be <b>successful</b> + * <p> + * The following test will verify that: + * <ul> + * <li>The HTTP Status is {@link org.springframework.http.HttpStatus.OK}</li> + * <li>The {@link HttpHeaders.CONTENT_TYPE} is {@link MediaType.APPLICATION_JSON}</li> + * <li>The request will not generate cookies</li> + * <li>The {@code $.auth} field in the response's body is {@code false}</li> + * </ul> + */ + @Test + void successPingWithoutKey() throws Exception { + mockMvc.perform(get(PING_END_POINT)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + header().doesNotExist(HttpHeaders.SET_COOKIE), + jsonPath("$.auth").value(false) + ); + } - /** - * If <b>not</b> authenticated with the shared secret, the request to `/api/v1/ping/no-auth` - * should be <b>successful</b> - * <p> - * The following test will verify that: - * <ul> - * <li>The HTTP Status is {@link org.springframework.http.HttpStatus.OK}</li> - * </ul> - */ - @Test - void successPingNoAuthWithoutKey() throws Exception { - mockMvc.perform(get(NO_AUTH_END_POINT)) - .andExpect(status().isOk()); - } + /** + * If authenticated with the shared secret, the request to `/api/v1/ping` + * should be <b>successful</b> + * <p> + * The following test will verify that: + * <ul> + * <li>The HTTP Status is {@link org.springframework.http.HttpStatus.OK}</li> + * <li>The {@link HttpHeaders.CONTENT_TYPE} is {@link MediaType.APPLICATION_JSON}</li> + * <li>The request will not generate cookies</li> + * <li>The {@code $.auth} field in the response's body is {@code true}</li> + * </ul> + */ + @Test + @WithSharedSecretAuthentication + void successPingWithKey() throws Exception { + mockMvc.perform(get(PING_END_POINT)) + .andExpectAll( + status().isOk(), + content().contentType(MediaType.APPLICATION_JSON), + header().doesNotExist(HttpHeaders.SET_COOKIE), + jsonPath("$.auth").value(true) + ); + } - /** - * If authenticated with the shared secret, the request to `/api/v1/ping/no-auth` - * should be <b>successful</b> - * <p> - * The following test will verify that: - * <ul> - * <li>The HTTP Status is {@link org.springframework.http.HttpStatus.OK}</li> - * </ul> - */ - @Test - @WithSharedSecretAuthentication - void successPingNoAuthWithKey() throws Exception { - mockMvc.perform(get(NO_AUTH_END_POINT)) - .andExpect(status().isOk()); - } - - /** - * If <b>not</b> authenticated with the shared secret, the request to `/api/v1/ping/auth` - * should be <b>fail</b> - * <p> - * The following test will verify that: - * <ul> - * <li>The HTTP Status is {@link org.springframework.http.HttpStatus.UNAUTHORIZED}</li> - * </ul> - */ - @Test - void failPingAuthWithoutKey() throws Exception { - mockMvc.perform(get(AUTH_END_POINT)) - .andExpect(status().isUnauthorized()) - ; - } - - /** - * If authenticated with the shared secret, the request to `/api/v1/ping/auth` - * should be <b>successful</b> - * <p> - * The following test will verify that: - * <ul> - * <li>The HTTP Status is {@link org.springframework.http.HttpStatus.OK}</li> - * </ul> - */ - @Test - @WithSharedSecretAuthentication - void successPingAuthWithKey() throws Exception { - mockMvc.perform(get(AUTH_END_POINT)) - .andExpect(status().isOk()); - } - - // TODO: We need to test authorization here when we implement it + // TODO: We need to test authorization here when we implement it }