diff --git a/src/main/java/uk/ac/ox/ctl/lti13/security/oauth2/client/lti/web/OptimisticAuthorizationRequestRepository.java b/src/main/java/uk/ac/ox/ctl/lti13/security/oauth2/client/lti/web/OptimisticAuthorizationRequestRepository.java index e391d3b..574ba7b 100644 --- a/src/main/java/uk/ac/ox/ctl/lti13/security/oauth2/client/lti/web/OptimisticAuthorizationRequestRepository.java +++ b/src/main/java/uk/ac/ox/ctl/lti13/security/oauth2/client/lti/web/OptimisticAuthorizationRequestRepository.java @@ -8,8 +8,10 @@ import jakarta.servlet.http.HttpServletResponse; /** - * Checks to see if we already have a valid HTTP Session containing a token, if so we store details of the login - * in the HTTP Session, otherwise we use store based on the state. + * Checks whether a valid HTTP session already contains a token. If so, we store the login details in the HTTP session; + * otherwise, we use state-based storage. When debugging on the client, if login uses the session then step 3 returns + * an HTTP 302 redirect to the tool. If login uses LTI storage in the browser, then step 3 returns HTTP 200 and + * JavaScript performs the redirect. */ public class OptimisticAuthorizationRequestRepository implements AuthorizationRequestRepository { @@ -48,9 +50,10 @@ public void setWorkingSession(HttpServletRequest request, HttpServletResponse re cookie.setHttpOnly(true); cookie.setSecure(true); cookie.setPath("/"); + cookie.setAttribute("SameSite", "None"); // Set the cookie for 1 year. // TODO This should be configurable. - cookie.setMaxAge(60 * 60 * 24 * 356); + cookie.setMaxAge(60 * 60 * 24 * 365); response.addCookie(cookie); // Mark the current request as having a working session. request.setAttribute(ATTRIBUTE_NAME, true); diff --git a/src/test/java/uk/ac/ox/ctl/lti13/stateful/Lti13Step3Test.java b/src/test/java/uk/ac/ox/ctl/lti13/stateful/Lti13Step3Test.java index b8af27e..56a95eb 100644 --- a/src/test/java/uk/ac/ox/ctl/lti13/stateful/Lti13Step3Test.java +++ b/src/test/java/uk/ac/ox/ctl/lti13/stateful/Lti13Step3Test.java @@ -52,6 +52,9 @@ import java.util.HashMap; import java.util.Map; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -202,7 +205,16 @@ public void testStep3SignedTokenNoCookie() throws Exception { .thenReturn(new ResponseEntity<>(jwkSet().toString(), HttpStatus.OK)); mockMvc.perform(post("/lti/login").param("id_token", createJWT(claims)).param("state", "state")) .andExpect(status().is3xxRedirection()) - .andExpect(cookie().exists("WORKING_COOKIES")); + .andExpect(cookie().exists("WORKING_COOKIES")) + .andExpect(result -> { + Cookie cookie = result.getResponse().getCookie("WORKING_COOKIES"); + assertNotNull(cookie); + assertEquals("true", cookie.getValue()); + assertEquals("/", cookie.getPath()); + assertTrue(cookie.getSecure()); + assertTrue(cookie.isHttpOnly()); + assertEquals("None", cookie.getAttribute("SameSite")); + }); } @Test