From 7ceb01e5a51c3885e979348d754fb60122aa9138 Mon Sep 17 00:00:00 2001 From: GavCookCO <99668051+GavCookCO@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:42:40 +0000 Subject: [PATCH] Adding a helper method to check for anonymous sessions (#254) --- .../services/GrantAdvertService.java | 22 ++++--- .../gap/adminbackend/utils/HelperUtils.java | 22 +++++++ .../adminbackend/utils/HelperUtilsTest.java | 65 +++++++++++++++++++ 3 files changed, 99 insertions(+), 10 deletions(-) diff --git a/src/main/java/gov/cabinetoffice/gap/adminbackend/services/GrantAdvertService.java b/src/main/java/gov/cabinetoffice/gap/adminbackend/services/GrantAdvertService.java index c6b12eed..5e2b21be 100644 --- a/src/main/java/gov/cabinetoffice/gap/adminbackend/services/GrantAdvertService.java +++ b/src/main/java/gov/cabinetoffice/gap/adminbackend/services/GrantAdvertService.java @@ -70,19 +70,21 @@ public GrantAdvert save(GrantAdvert advert) { final Authentication auth = SecurityContextHolder.getContext().getAuthentication(); Optional.ofNullable(auth) .ifPresentOrElse(authentication -> { - final AdminSession adminSession = (AdminSession) authentication.getPrincipal(); - final GrantAdmin admin = grantAdminRepository.findByGapUserUserSub(adminSession.getUserSub()) - .orElseThrow(() -> new UserNotFoundException("Could not find an admin with sub " + adminSession.getUserSub())); + if (!HelperUtils.isAnonymousSession()) { + final AdminSession adminSession = (AdminSession) authentication.getPrincipal(); + final GrantAdmin admin = grantAdminRepository.findByGapUserUserSub(adminSession.getUserSub()) + .orElseThrow(() -> new UserNotFoundException("Could not find an admin with sub " + adminSession.getUserSub())); - if (advert.getScheme().getGrantAdmins().contains(admin)) { - final Instant updatedAt = Instant.now(clock); - advert.setLastUpdated(updatedAt); - advert.setLastUpdatedBy(admin); + if (advert.getScheme().getGrantAdmins().contains(admin)) { + final Instant updatedAt = Instant.now(clock); + advert.setLastUpdated(updatedAt); + advert.setLastUpdatedBy(admin); - advert.getScheme().setLastUpdated(updatedAt); - advert.getScheme().setLastUpdatedBy(adminSession.getGrantAdminId()); + advert.getScheme().setLastUpdated(updatedAt); + advert.getScheme().setLastUpdatedBy(adminSession.getGrantAdminId()); - advert.setValidLastUpdated(true); + advert.setValidLastUpdated(true); + } } }, () -> log.warn("Admin session was null. Update must have been performed by a lambda.")); diff --git a/src/main/java/gov/cabinetoffice/gap/adminbackend/utils/HelperUtils.java b/src/main/java/gov/cabinetoffice/gap/adminbackend/utils/HelperUtils.java index 8429da17..818c40be 100644 --- a/src/main/java/gov/cabinetoffice/gap/adminbackend/utils/HelperUtils.java +++ b/src/main/java/gov/cabinetoffice/gap/adminbackend/utils/HelperUtils.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper; import gov.cabinetoffice.gap.adminbackend.exceptions.UnauthorizedException; import gov.cabinetoffice.gap.adminbackend.models.AdminSession; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponentsBuilder; @@ -13,10 +14,14 @@ import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import java.util.Arrays; +import java.util.Collections; import java.util.Objects; +import java.util.Optional; public class HelperUtils { + public static final String ROLE_ANONYMOUS = "ROLE_ANONYMOUS"; + /** * Used to generate a safely encoded URL, incl. any query params This method will * auto-remove any query params where the value is null, to prevent empty request @@ -88,4 +93,21 @@ public static String getJwtFromCookies(final HttpServletRequest request, final S return userServiceToken.getValue(); } + + /** + * Verifies whether a session is anonymous in spring security or not. + * + * Useful method to have because some of our lambdas use encrypted headers to bypass spring security. + * @return + */ + public static boolean isAnonymousSession() { + return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()) + .map(authentication -> authentication.getAuthorities() + .stream() + .map(GrantedAuthority::getAuthority) + .toList()) + .orElse(Collections.emptyList()) + .stream() + .anyMatch(auth -> auth.equals(ROLE_ANONYMOUS)); + } } diff --git a/src/test/java/gov/cabinetoffice/gap/adminbackend/utils/HelperUtilsTest.java b/src/test/java/gov/cabinetoffice/gap/adminbackend/utils/HelperUtilsTest.java index fee2781f..2f386b70 100644 --- a/src/test/java/gov/cabinetoffice/gap/adminbackend/utils/HelperUtilsTest.java +++ b/src/test/java/gov/cabinetoffice/gap/adminbackend/utils/HelperUtilsTest.java @@ -1,15 +1,38 @@ package gov.cabinetoffice.gap.adminbackend.utils; +import gov.cabinetoffice.gap.adminbackend.models.AdminSession; import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import static gov.cabinetoffice.gap.adminbackend.testdata.SchemeTestData.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; class HelperUtilsTest { + @Mock + private Authentication auth; + + @Mock + private SecurityContext context; + @Test void buildUrlWithNoParamsTest() { String builtUrl = HelperUtils.buildUrl("testHost", "testPath", null); @@ -43,4 +66,46 @@ void parseJsonExpectedHappyTest() { + "\",\"contactEmail\":\"" + SAMPLE_SCHEME_CONTACT + "\",\"lastUpdatedByADeletedUser\":false}"); } + @Test + void isAnonymousSession_ReturnsTrueIfAnonymousSession() { + + Authentication auth = Mockito.mock(Authentication.class); + SecurityContext context = mock(SecurityContext.class); + + try (MockedStatic securityContextHolder = Mockito.mockStatic(SecurityContextHolder.class)) { + securityContextHolder.when(SecurityContextHolder::getContext).thenReturn(context); + + final GrantedAuthority role = new SimpleGrantedAuthority("ROLE_ANONYMOUS"); + + when(context.getAuthentication()) + .thenReturn(auth); + + when(auth.getAuthorities()) + .thenReturn((Collection) List.of(role)); + + assertThat(HelperUtils.isAnonymousSession()).isTrue(); + } + } + + @Test + void isAnonymousSession_ReturnsFalseIfIdNotAnonymousSession() { + + Authentication auth = Mockito.mock(Authentication.class); + SecurityContext context = mock(SecurityContext.class); + + try (MockedStatic securityContextHolder = Mockito.mockStatic(SecurityContextHolder.class)) { + securityContextHolder.when(SecurityContextHolder::getContext).thenReturn(context); + + final GrantedAuthority role = new SimpleGrantedAuthority("ROLE_ADMIN"); + + when(context.getAuthentication()) + .thenReturn(auth); + + when(auth.getAuthorities()) + .thenReturn((Collection) List.of(role)); + + assertThat(HelperUtils.isAnonymousSession()).isFalse(); + } + } + } \ No newline at end of file