From c9a1f2cd952b62cd693525b0f10da8e4611e7cc7 Mon Sep 17 00:00:00 2001
From: Felix Reichenbach <felix.reichenbach@mgm-tp.com>
Date: Thu, 16 Jan 2025 15:20:24 +0100
Subject: [PATCH] OZG-6986 dont show configurations Link on missing permission

---
 .../de/ozgcloud/admin/RootModelAssembler.java |   6 +-
 .../admin/common/user/CurrentUserHelper.java  |  14 +-
 .../admin/common/user/CurrentUserService.java |   4 +
 .../ozgcloud/admin/common/user/UserRole.java  |   4 +
 .../admin/RootModelAssemblerTest.java         |  57 ++++++--
 .../common/user/CurrentUserHelperTest.java    | 130 ++++++++++++------
 .../common/user/CurrentUserServiceTest.java   |  41 ++++--
 7 files changed, 189 insertions(+), 67 deletions(-)

diff --git a/src/main/java/de/ozgcloud/admin/RootModelAssembler.java b/src/main/java/de/ozgcloud/admin/RootModelAssembler.java
index 4feced27..3b564cf3 100644
--- a/src/main/java/de/ozgcloud/admin/RootModelAssembler.java
+++ b/src/main/java/de/ozgcloud/admin/RootModelAssembler.java
@@ -33,6 +33,7 @@ import org.springframework.hateoas.server.RepresentationModelAssembler;
 import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
 import org.springframework.stereotype.Component;
 
+import de.ozgcloud.admin.common.user.CurrentUserService;
 import lombok.RequiredArgsConstructor;
 
 @Component
@@ -41,6 +42,7 @@ public class RootModelAssembler implements RepresentationModelAssembler<Root, En
 	static final String REL_CONFIGURATION = "configuration";
 
 	private final RepositoryRestProperties restProperties;
+	private final CurrentUserService currentUserService;
 
 	@Override
 	public EntityModel<Root> toModel(Root root) {
@@ -52,7 +54,9 @@ public class RootModelAssembler implements RepresentationModelAssembler<Root, En
 		List<Link> links = new ArrayList<>();
 		var rootLinkBuilder = WebMvcLinkBuilder.linkTo(RootController.class);
 		links.add(rootLinkBuilder.withSelfRel());
-		links.add(buildConfigLink());
+		if (currentUserService.hasConfigurationPermission()) {
+			links.add(buildConfigLink());
+		}
 		return links;
 	}
 
diff --git a/src/main/java/de/ozgcloud/admin/common/user/CurrentUserHelper.java b/src/main/java/de/ozgcloud/admin/common/user/CurrentUserHelper.java
index b4fd2c45..123ecc4d 100644
--- a/src/main/java/de/ozgcloud/admin/common/user/CurrentUserHelper.java
+++ b/src/main/java/de/ozgcloud/admin/common/user/CurrentUserHelper.java
@@ -26,9 +26,10 @@ package de.ozgcloud.admin.common.user;
 import java.util.Collection;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
-import org.apache.commons.lang3.StringUtils;
 import org.springframework.security.authentication.AuthenticationTrustResolver;
 import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
 import org.springframework.security.core.Authentication;
@@ -46,20 +47,25 @@ class CurrentUserHelper {
 	private static final Predicate<Authentication> IS_TRUSTED = auth -> !TRUST_RESOLVER.isAnonymous(auth);
 
 	public static boolean hasRole(String role) {
+		return hasAnyRole(Set.of(role));
+	}
+
+	public static boolean hasAnyRole(Set<String> roles) {
 		var auth = getAuthentication();
 
 		if ((Objects.isNull(auth)) || (Objects.isNull(auth.getPrincipal()))) {
 			return false;
 		}
 
-		return containsRole(auth.getAuthorities(), role);
+		return containsAnyRole(auth.getAuthorities(), roles);
 	}
 
-	static boolean containsRole(Collection<? extends GrantedAuthority> authorities, String role) {
+	static boolean containsAnyRole(Collection<? extends GrantedAuthority> authorities, Set<String> roles) {
 		if (Objects.isNull(authorities)) {
 			return false;
 		}
-		return authorities.stream().anyMatch(a -> StringUtils.equalsIgnoreCase(addRolePrefixIfMissing(role), a.getAuthority()));
+		var rolesWithPrefix = roles.stream().map(CurrentUserHelper::addRolePrefixIfMissing).collect(Collectors.toSet());
+		return authorities.stream().anyMatch(a -> rolesWithPrefix.contains(a.getAuthority()));
 	}
 
 	static String addRolePrefixIfMissing(String roleToCheck) {
diff --git a/src/main/java/de/ozgcloud/admin/common/user/CurrentUserService.java b/src/main/java/de/ozgcloud/admin/common/user/CurrentUserService.java
index fc045ec0..0959eafe 100644
--- a/src/main/java/de/ozgcloud/admin/common/user/CurrentUserService.java
+++ b/src/main/java/de/ozgcloud/admin/common/user/CurrentUserService.java
@@ -30,4 +30,8 @@ public class CurrentUserService {
 	public boolean hasRole(String role) {
 		return CurrentUserHelper.hasRole(role);
 	}
+
+	public boolean hasConfigurationPermission() {
+		return CurrentUserHelper.hasAnyRole(UserRole.CONFIGURATION_ROLES);
+	}
 }
diff --git a/src/main/java/de/ozgcloud/admin/common/user/UserRole.java b/src/main/java/de/ozgcloud/admin/common/user/UserRole.java
index 8c28ea3e..391e3f5a 100644
--- a/src/main/java/de/ozgcloud/admin/common/user/UserRole.java
+++ b/src/main/java/de/ozgcloud/admin/common/user/UserRole.java
@@ -23,6 +23,8 @@
  */
 package de.ozgcloud.admin.common.user;
 
+import java.util.Set;
+
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 
@@ -30,4 +32,6 @@ import lombok.NoArgsConstructor;
 public class UserRole {
 	public static final String DATENBEAUFTRAGUNG = "DATENBEAUFTRAGUNG";
 	public static final String ADMIN_ADMIN = "ADMIN_ADMIN";
+
+	public static final Set<String> CONFIGURATION_ROLES = Set.of(ADMIN_ADMIN, DATENBEAUFTRAGUNG);
 }
diff --git a/src/test/java/de/ozgcloud/admin/RootModelAssemblerTest.java b/src/test/java/de/ozgcloud/admin/RootModelAssemblerTest.java
index 5c4ed0d6..bcd7e27a 100644
--- a/src/test/java/de/ozgcloud/admin/RootModelAssemblerTest.java
+++ b/src/test/java/de/ozgcloud/admin/RootModelAssemblerTest.java
@@ -25,6 +25,7 @@ package de.ozgcloud.admin;
 
 import static de.ozgcloud.admin.RootModelAssembler.*;
 import static org.assertj.core.api.Assertions.*;
+import static org.mockito.Mockito.*;
 
 import java.util.List;
 
@@ -34,34 +35,38 @@ import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.Spy;
 import org.springframework.boot.autoconfigure.data.rest.RepositoryRestProperties;
 import org.springframework.hateoas.Link;
 
+import de.ozgcloud.admin.common.user.CurrentUserService;
+
 class RootModelAssemblerTest {
 
 	private static final String BASE_PATH = "/api/base";
+
 	@Spy
 	@InjectMocks
 	private RootModelAssembler modelAssembler;
 
 	@Mock
 	private RepositoryRestProperties restProperties;
+	@Mock
+	private CurrentUserService currentUserService;
 
 	@DisplayName("Entity Model")
 	@Nested
 	class TestEntityModel {
 		@BeforeEach
 		void beforeEach() {
-			Mockito.when(restProperties.getBasePath()).thenReturn(BASE_PATH);
+			when(restProperties.getBasePath()).thenReturn(BASE_PATH);
 		}
 
 		@Test
 		void shouldHaveRoot() {
 			var givenRoot = RootTestFactory.create();
 			List<Link> links = List.of();
-			Mockito.when(modelAssembler.buildRootModelLinks()).thenReturn(links);
+			when(modelAssembler.buildRootModelLinks()).thenReturn(links);
 
 			var resultRoot = modelAssembler.toModel(givenRoot).getContent();
 
@@ -71,7 +76,7 @@ class RootModelAssemblerTest {
 		@Test
 		void shouldHaveLinks() {
 			List<Link> links = List.of(Link.of(RootController.PATH));
-			Mockito.when(modelAssembler.buildRootModelLinks()).thenReturn(links);
+			when(modelAssembler.buildRootModelLinks()).thenReturn(links);
 
 			var modelLinks = modelAssembler.toModel(RootTestFactory.create()).getLinks();
 
@@ -84,14 +89,46 @@ class RootModelAssemblerTest {
 	class TestBuildRootModelLinks {
 
 		@Test
-		void shouldHaveHrefToBasePathIfAuthorized() {
-			Mockito.when(restProperties.getBasePath()).thenReturn(BASE_PATH);
+		void shouldCheckConfigurationPermission() {
+			modelAssembler.buildRootModelLinks();
+
+			verify(currentUserService).hasConfigurationPermission();
+		}
+
+		@Nested
+		class TestOnHasConfigurationPermission {
+
+			@BeforeEach
+			void hasConfigurationPermission() {
+				when(currentUserService.hasConfigurationPermission()).thenReturn(true);
+				when(restProperties.getBasePath()).thenReturn(BASE_PATH);
+			}
+
+			@Test
+			void shouldHaveHrefToConfiguration() {
+				var links = modelAssembler.buildRootModelLinks();
+
+				assertThat(links).containsExactly(
+						Link.of(RootController.PATH),
+						Link.of(BASE_PATH, REL_CONFIGURATION));
+			}
+		}
+
+		@Nested
+		class TestOnNotHasConfigurationPermission {
+
+			@BeforeEach
+			void hasNotConfigurationPermission() {
+				when(currentUserService.hasConfigurationPermission()).thenReturn(false);
+			}
 
-			List<Link> links = modelAssembler.buildRootModelLinks();
+			@Test
+			void shouldHaveOnlySelfLink() {
+				var links = modelAssembler.buildRootModelLinks();
 
-			assertThat(links).containsExactly(
-					Link.of(RootController.PATH),
-					Link.of(BASE_PATH, REL_CONFIGURATION));
+				assertThat(links).containsExactly(
+						Link.of(RootController.PATH));
+			}
 		}
 
 	}
diff --git a/src/test/java/de/ozgcloud/admin/common/user/CurrentUserHelperTest.java b/src/test/java/de/ozgcloud/admin/common/user/CurrentUserHelperTest.java
index 46780c05..1c171505 100644
--- a/src/test/java/de/ozgcloud/admin/common/user/CurrentUserHelperTest.java
+++ b/src/test/java/de/ozgcloud/admin/common/user/CurrentUserHelperTest.java
@@ -24,9 +24,11 @@
 package de.ozgcloud.admin.common.user;
 
 import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
 
-import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -35,7 +37,6 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.Mock;
 import org.mockito.MockedStatic;
-import org.mockito.Mockito;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -43,23 +44,58 @@ import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.User;
 
+import com.thedeanda.lorem.LoremIpsum;
+
 class CurrentUserHelperTest {
 	@DisplayName("Has role")
 	@Nested
 	class TestHasRole {
 		@Mock
-		private final Authentication mockAuthentication = Mockito.mock(Authentication.class);
+		private Authentication mockAuthentication;
+		@Mock
+		private User mockPrincipal;
+
+		private final String role = LoremIpsum.getInstance().getWords(1);
+
+		@Test
+		void shouldCallHasAnyRole() {
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class, CALLS_REAL_METHODS)) {
+				mockUserHelper.when(() -> CurrentUserHelper.hasAnyRole(any())).thenReturn(false);
+
+				CurrentUserHelper.hasRole(role);
+
+				mockUserHelper.verify(() -> CurrentUserHelper.hasAnyRole(Set.of(role)));
+			}
+		}
+
+		@ParameterizedTest
+		@ValueSource(booleans = { false, true })
+		void shouldReturnValue(boolean hasRole) {
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class, CALLS_REAL_METHODS)) {
+				mockUserHelper.when(() -> CurrentUserHelper.hasAnyRole(any())).thenReturn(hasRole);
+
+				var result = CurrentUserHelper.hasRole(UserRole.ADMIN_ADMIN);
+
+				assertThat(result).isEqualTo(hasRole);
+			}
+		}
+	}
+
+	@Nested
+	class TestHasAnyRole {
+		@Mock
+		private Authentication mockAuthentication;
 		@Mock
-		private final User mockPrincipal = Mockito.mock(User.class);
+		private User mockPrincipal;
+
+		private final Set<String> roles = Set.of(LoremIpsum.getInstance().getWords(1));
 
 		@Test
 		void shouldReturnFalseOnMissingAuthentication() {
-			try (MockedStatic<CurrentUserHelper> mockUserHelper = Mockito.mockStatic(
-					CurrentUserHelper.class,
-					Mockito.CALLS_REAL_METHODS)) {
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class)) {
 				mockUserHelper.when(CurrentUserHelper::getAuthentication).thenReturn(null);
 
-				boolean hasRole = CurrentUserHelper.hasRole(UserRole.ADMIN_ADMIN);
+				boolean hasRole = CurrentUserHelper.hasAnyRole(roles);
 
 				assertThat(hasRole).isFalse();
 			}
@@ -67,66 +103,72 @@ class CurrentUserHelperTest {
 
 		@Test
 		void shouldReturnFalseOnMissingPrincipal() {
-			Mockito.when(mockAuthentication.getPrincipal()).thenReturn(null);
-			try (MockedStatic<CurrentUserHelper> mockUserHelper = Mockito.mockStatic(
-					CurrentUserHelper.class,
-					Mockito.CALLS_REAL_METHODS)) {
+			when(mockAuthentication.getPrincipal()).thenReturn(null);
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class, CALLS_REAL_METHODS)) {
 				mockUserHelper.when(CurrentUserHelper::getAuthentication).thenReturn(mockAuthentication);
 
-				boolean hasRole = CurrentUserHelper.hasRole(UserRole.ADMIN_ADMIN);
+				boolean hasRole = CurrentUserHelper.hasAnyRole(roles);
 
 				assertThat(hasRole).isFalse();
 			}
 		}
 
+		@Test
+		void shouldCallContainsAnyRole() {
+			when(mockAuthentication.getPrincipal()).thenReturn(mockPrincipal);
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class, CALLS_REAL_METHODS)) {
+				mockUserHelper.when(CurrentUserHelper::getAuthentication).thenReturn(mockAuthentication);
+
+				CurrentUserHelper.hasAnyRole(roles);
+
+				mockUserHelper.verify(() -> CurrentUserHelper.containsAnyRole(mockAuthentication.getAuthorities(), roles));
+			}
+		}
+
 		@ParameterizedTest
-		@ValueSource(booleans = {false, true})
-		void shouldReturnValue(boolean containsRoleValue) {
-			Mockito.when(mockAuthentication.getPrincipal()).thenReturn(mockPrincipal);
-			List<GrantedAuthority> authorities = List.of();
-			Mockito.<Collection<? extends GrantedAuthority>>when(mockAuthentication.getAuthorities()).thenReturn(authorities);
-
-			try (MockedStatic<CurrentUserHelper> mockUserHelper = Mockito.mockStatic(
-					CurrentUserHelper.class,
-					Mockito.CALLS_REAL_METHODS)) {
+		@ValueSource(booleans = { false, true })
+		void shouldReturnValue(boolean hasRole) {
+			when(mockAuthentication.getPrincipal()).thenReturn(mockPrincipal);
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class, CALLS_REAL_METHODS)) {
 				mockUserHelper.when(CurrentUserHelper::getAuthentication).thenReturn(mockAuthentication);
-				mockUserHelper.when(() -> CurrentUserHelper.containsRole(Mockito.anyList(), Mockito.anyString()))
-						.thenReturn(containsRoleValue);
+				mockUserHelper.when(() -> CurrentUserHelper.containsAnyRole(any(), any())).thenReturn(hasRole);
 
-				boolean hasRole = CurrentUserHelper.hasRole(UserRole.ADMIN_ADMIN);
+				var result = CurrentUserHelper.hasAnyRole(roles);
 
-				mockUserHelper.verify(() -> CurrentUserHelper.containsRole(mockAuthentication.getAuthorities(), UserRole.ADMIN_ADMIN));
-				assertThat(hasRole).isEqualTo(containsRoleValue);
+				assertThat(result).isEqualTo(hasRole);
 			}
 		}
 	}
 
-	@DisplayName("Contains role")
 	@Nested
-	class TestContainsRole {
+	class TestContainsAnyRole {
 		@Test
-		void shouldNotContainRoleIfAuthoritiesIsNull() {
-			boolean containsRole = CurrentUserHelper.containsRole(null, UserRole.ADMIN_ADMIN);
+		void shouldReturnFalseIfAuthoritiesIsNull() {
+			boolean containsRole = CurrentUserHelper.containsAnyRole(null, Set.of(LoremIpsum.getInstance().getWords(1)));
 
 			assertThat(containsRole).isFalse();
 		}
 
 		@Test
-		void shouldNotContainRole() {
+		void shouldFalseOnNoMatchingRole() {
+			var userRole = LoremIpsum.getInstance().getWords(1);
+			var rolesToCheck = Set.of(LoremIpsum.getInstance().getWords(1), LoremIpsum.getInstance().getWords(1));
 			List<GrantedAuthority> authorities = List.of(
-					new SimpleGrantedAuthority(CurrentUserHelper.ROLE_PREFIX + "OTHER"));
+					new SimpleGrantedAuthority(CurrentUserHelper.ROLE_PREFIX + userRole));
 
-			boolean containsRole = CurrentUserHelper.containsRole(authorities, UserRole.ADMIN_ADMIN);
+			boolean containsRole = CurrentUserHelper.containsAnyRole(authorities, rolesToCheck);
 
 			assertThat(containsRole).isFalse();
 		}
 
 		@Test
-		void shouldContainRole() {
-			Collection<? extends GrantedAuthority> authorities = List.of(
-					new SimpleGrantedAuthority(CurrentUserHelper.ROLE_PREFIX + UserRole.ADMIN_ADMIN));
+		void shouldReturnTrueOnMatchingRole() {
+			var userRole = LoremIpsum.getInstance().getWords(1);
+			var rolesToCheck = Set.of(LoremIpsum.getInstance().getWords(1), userRole);
+			List<GrantedAuthority> authorities = List.of(
+					new SimpleGrantedAuthority(CurrentUserHelper.ROLE_PREFIX + userRole));
 
-			boolean containsRole = CurrentUserHelper.containsRole(authorities, UserRole.ADMIN_ADMIN);
+			boolean containsRole = CurrentUserHelper.containsAnyRole(authorities, rolesToCheck);
 
 			assertThat(containsRole).isTrue();
 		}
@@ -166,13 +208,13 @@ class CurrentUserHelperTest {
 	@Nested
 	class TestGetAuthentication {
 		@Mock
-		private final SecurityContext mockSecurityContext = Mockito.mock(SecurityContext.class);
+		private final SecurityContext mockSecurityContext = mock(SecurityContext.class);
 
 		@Test
 		void shouldThrowIfNoAuthenticatedUser() {
-			Mockito.when(mockSecurityContext.getAuthentication()).thenReturn(null);
+			when(mockSecurityContext.getAuthentication()).thenReturn(null);
 
-			try (MockedStatic<SecurityContextHolder> contextHolder = Mockito.mockStatic(SecurityContextHolder.class)) {
+			try (MockedStatic<SecurityContextHolder> contextHolder = mockStatic(SecurityContextHolder.class)) {
 				contextHolder.when(SecurityContextHolder::getContext).thenReturn(mockSecurityContext);
 
 				assertThatIllegalStateException()
@@ -183,10 +225,10 @@ class CurrentUserHelperTest {
 
 		@Test
 		void shouldPassAuthentication() {
-			Authentication mockAuthentication = Mockito.mock(Authentication.class);
-			Mockito.when(mockSecurityContext.getAuthentication()).thenReturn(mockAuthentication);
+			Authentication mockAuthentication = mock(Authentication.class);
+			when(mockSecurityContext.getAuthentication()).thenReturn(mockAuthentication);
 
-			try (MockedStatic<SecurityContextHolder> contextHolder = Mockito.mockStatic(SecurityContextHolder.class)) {
+			try (MockedStatic<SecurityContextHolder> contextHolder = mockStatic(SecurityContextHolder.class)) {
 				contextHolder.when(SecurityContextHolder::getContext).thenReturn(mockSecurityContext);
 
 				Authentication authentication = CurrentUserHelper.getAuthentication();
diff --git a/src/test/java/de/ozgcloud/admin/common/user/CurrentUserServiceTest.java b/src/test/java/de/ozgcloud/admin/common/user/CurrentUserServiceTest.java
index 09f51324..0627188e 100644
--- a/src/test/java/de/ozgcloud/admin/common/user/CurrentUserServiceTest.java
+++ b/src/test/java/de/ozgcloud/admin/common/user/CurrentUserServiceTest.java
@@ -23,14 +23,16 @@
  */
 package de.ozgcloud.admin.common.user;
 
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.MockedStatic;
-import org.mockito.Mockito;
-
-import static org.assertj.core.api.Assertions.assertThat;
 
 class CurrentUserServiceTest {
 	private final CurrentUserService currentUserService = new CurrentUserService();
@@ -39,12 +41,10 @@ class CurrentUserServiceTest {
 	@Nested
 	class TestHasRole {
 		@ParameterizedTest
-		@ValueSource(booleans = {false, true})
+		@ValueSource(booleans = { false, true })
 		void shouldReturnValue(boolean hasRoleValue) {
-			try (MockedStatic<CurrentUserHelper> mockUserHelper = Mockito.mockStatic(
-					CurrentUserHelper.class)
-			){
-				mockUserHelper.when(() -> CurrentUserHelper.hasRole(Mockito.anyString()))
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class)) {
+				mockUserHelper.when(() -> CurrentUserHelper.hasRole(anyString()))
 						.thenReturn(hasRoleValue);
 
 				boolean hasRole = currentUserService.hasRole(UserRole.ADMIN_ADMIN);
@@ -54,4 +54,29 @@ class CurrentUserServiceTest {
 			}
 		}
 	}
+
+	@Nested
+	class TestHasConfigurationPermission {
+
+		@Test
+		void shouldCallCurrentUserHelper() {
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class)) {
+				currentUserService.hasConfigurationPermission();
+
+				mockUserHelper.verify(() -> CurrentUserHelper.hasAnyRole(UserRole.CONFIGURATION_ROLES));
+			}
+		}
+
+		@ParameterizedTest
+		@ValueSource(booleans = { false, true })
+		void shouldReturnValue(boolean hasConfigurationPermission) {
+			try (MockedStatic<CurrentUserHelper> mockUserHelper = mockStatic(CurrentUserHelper.class)) {
+				mockUserHelper.when(() -> CurrentUserHelper.hasAnyRole(any())).thenReturn(hasConfigurationPermission);
+
+				var result = currentUserService.hasConfigurationPermission();
+
+				assertThat(result).isEqualTo(hasConfigurationPermission);
+			}
+		}
+	}
 }
-- 
GitLab