diff --git a/sugoi-api-core/src/main/java/fr/insee/sugoi/core/model/Right.java b/sugoi-api-core/src/main/java/fr/insee/sugoi/core/model/Right.java new file mode 100644 index 00000000..6bb2eef8 --- /dev/null +++ b/sugoi-api-core/src/main/java/fr/insee/sugoi/core/model/Right.java @@ -0,0 +1,61 @@ +/* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package fr.insee.sugoi.core.model; + +public class Right { + + private String realm = ""; + private String userStorage = ""; + private String application = ""; + + public String getRealm() { + return realm; + } + + public void setRealm(String realm) { + this.realm = realm; + } + + public String getUserStorage() { + return userStorage; + } + + public void setUserStorage(String userStorage) { + this.userStorage = userStorage; + } + + public String getApplication() { + return application; + } + + public void setApplication(String application) { + this.application = application; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + if (realm.equals("")) { + sb.append("*_*"); + } else { + sb.append(realm); + if (!userStorage.equals("")) { + sb.append("_" + userStorage); + } + } + if (!application.equals("")) { + sb.append("\\" + getApplication()); + } + return sb.toString().toUpperCase(); + } +} diff --git a/sugoi-api-core/src/main/java/fr/insee/sugoi/core/service/PermissionService.java b/sugoi-api-core/src/main/java/fr/insee/sugoi/core/service/PermissionService.java index 420bcb2c..e6f04db3 100644 --- a/sugoi-api-core/src/main/java/fr/insee/sugoi/core/service/PermissionService.java +++ b/sugoi-api-core/src/main/java/fr/insee/sugoi/core/service/PermissionService.java @@ -13,33 +13,28 @@ */ package fr.insee.sugoi.core.service; -import fr.insee.sugoi.core.model.SugoiUser; import java.util.List; public interface PermissionService { - public boolean isReader(SugoiUser sugoiUser, String realm, String userStorage); + public boolean isReader(List roles, String realmName, String usName); - public boolean isPasswordManager(SugoiUser sugoiUser, String realm, String userStorage); + public boolean isPasswordManager(List roles, String realmName, String usName); - public boolean isApplicationManager( - SugoiUser sugoiUser, String realm, String userStorage, String application); + public boolean isApplicationManager(List roles, String realmName, String appName); - public boolean isWriter(SugoiUser sugoiUser, String realm, String userStorage); + public boolean isWriter(List roles, String realmName, String usName); - public boolean isAdmin(SugoiUser sugoiUser); + public boolean isAdmin(List roles); public boolean isValidAttributeAccordingAttributePattern( - SugoiUser sugoiUser, String realm, String storage, String pattern, String attribute); + List roles, String realm, String storage, String pattern, String attribute); - public List getUserRealmReader(SugoiUser sugoiUser); + public List getReaderRoles(List roles); - public List getUserRealmWriter(SugoiUser sugoiUser); + public List getWriterRoles(List roles); - public List getUserRealmPasswordManager(SugoiUser sugoiUser); + public List getPasswordManagerRoles(List roles); - public List getUserRealmAppManager(SugoiUser sugoiUser); - - public List getAllowedAttributePattern( - SugoiUser sugoiUser, String realm, String storage, String pattern); + public List getAppManagerRoles(List roles); } diff --git a/sugoi-api-core/src/main/java/fr/insee/sugoi/core/service/impl/PermissionServiceImpl.java b/sugoi-api-core/src/main/java/fr/insee/sugoi/core/service/impl/PermissionServiceImpl.java index 3f9dcaaf..e5f5fa69 100644 --- a/sugoi-api-core/src/main/java/fr/insee/sugoi/core/service/impl/PermissionServiceImpl.java +++ b/sugoi-api-core/src/main/java/fr/insee/sugoi/core/service/impl/PermissionServiceImpl.java @@ -13,12 +13,11 @@ */ package fr.insee.sugoi.core.service.impl; -import fr.insee.sugoi.core.model.SugoiUser; +import fr.insee.sugoi.core.model.Right; import fr.insee.sugoi.core.service.PermissionService; -import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.Optional; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -49,182 +48,141 @@ public class PermissionServiceImpl implements PermissionService { public static final Logger logger = LoggerFactory.getLogger(PermissionServiceImpl.class); - @Override - public boolean isReader(SugoiUser sugoiUser, String realm, String userStorage) { - List searchRoleList = - getSearchRoleList(sugoiUser, realm, userStorage, null, regexpReaderList); - return checkIfUserGetRoles(sugoiUser, searchRoleList) - || isWriter(sugoiUser, realm, userStorage); + public boolean isReader(List roles, String realmName, String usName) { + return areUserRolesInValidRoles(regexpReaderList, roles, realmName, usName, null) + || isPasswordManager(roles, realmName, usName) + || isWriter(roles, realmName, usName); } - @Override - public boolean isPasswordManager(SugoiUser sugoiUser, String realm, String userStorage) { - List searchRoleList = - getSearchRoleList(sugoiUser, realm, userStorage, null, passwordManagerRoleList); - return checkIfUserGetRoles(sugoiUser, searchRoleList); + public boolean isPasswordManager(List roles, String realmName, String usName) { + return areUserRolesInValidRoles(passwordManagerRoleList, roles, realmName, usName, null) + || isWriter(roles, realmName, usName); } - @Override - public boolean isApplicationManager( - SugoiUser sugoiUser, String realm, String userStorage, String application) { - List searchRoleList = - getSearchRoleList(sugoiUser, realm, userStorage, application, applicationManagerRoleList); - return checkIfUserGetRoles(sugoiUser, searchRoleList) && isReader(sugoiUser, realm, null); + public boolean isApplicationManager(List roles, String realmName, String appName) { + return (areUserRolesInValidRoles(applicationManagerRoleList, roles, realmName, null, appName) + && isReader(roles, realmName, null)) + || isWriter(roles, realmName, null); } - @Override - public boolean isWriter(SugoiUser sugoiUser, String realm, String userStorage) { - List searchRoleList = - getSearchRoleList(sugoiUser, realm, userStorage, null, regexpWriterList); - return checkIfUserGetRoles(sugoiUser, searchRoleList) || isAdmin(sugoiUser); + public boolean isWriter(List roles, String realmName, String usName) { + return areUserRolesInValidRoles(regexpWriterList, roles, realmName, usName, null) + || isAdmin(roles); } - @Override - public boolean isAdmin(SugoiUser sugoiUser) { - return checkIfUserGetRoles(sugoiUser, adminRoleList); + public boolean isAdmin(List roles) { + return areUserRolesInValidRoles(adminRoleList, roles, null, null, null); } - private boolean checkIfUserGetRoles(SugoiUser sugoiUser, List rolesSearch) { - logger.debug("Checking if user {} is in : {}", sugoiUser.getName(), rolesSearch); - List roles = - sugoiUser.getRoles().stream().map(String::toUpperCase).collect(Collectors.toList()); - logger.debug("User roles: {}", roles); - for (String roleSearch : rolesSearch) { - logger.trace(roleSearch); - if (roles.contains(roleSearch.toUpperCase())) { - return true; - } - for (String role : roles) { - if (role.toUpperCase().matches(roleSearch.replace("*", ".*").toUpperCase())) { - return true; - } - } - } - return false; + public boolean isValidAttributeAccordingAttributePattern( + List roles, String realm, String storage, String pattern, String attribute) { + return getAllowedAttributePattern(roles, realm, storage, pattern).stream() + .anyMatch(allowedPattern -> attribute.toUpperCase().matches(allowedPattern)); } - @Override - public List getUserRealmReader(SugoiUser sugoiUser) { - return getUserRightList(sugoiUser, regexpReaderList); + public List getReaderRoles(List roles) { + return getStringRightsFromRegexList(roles, regexpReaderList); } - @Override - public List getUserRealmWriter(SugoiUser sugoiUser) { - return getUserRightList(sugoiUser, regexpWriterList); + public List getWriterRoles(List roles) { + return getStringRightsFromRegexList(roles, regexpWriterList); } - @Override - public List getUserRealmPasswordManager(SugoiUser sugoiUser) { - return getUserRightList(sugoiUser, passwordManagerRoleList); + public List getPasswordManagerRoles(List roles) { + return getStringRightsFromRegexList(roles, passwordManagerRoleList); } - @Override - public List getUserRealmAppManager(SugoiUser sugoiUser) { - return getUserRightList(sugoiUser, applicationManagerRoleList); + public List getAppManagerRoles(List roles) { + return getStringRightsFromRegexList(roles, applicationManagerRoleList); } - private List getUserRightList(SugoiUser sugoiUser, List regexpListToSearch) { - List searchRoleList = - getSearchRoleList( - sugoiUser, - "(?.*)", - "(?.*)", - "(?.*)", - regexpListToSearch) - .stream() - .map(String::toUpperCase) - .collect(Collectors.toList()); - List roles = - sugoiUser.getRoles().stream() - .map(String::toUpperCase) - .map( - role -> { - for (String searchRole : searchRoleList) { - Pattern p = Pattern.compile(searchRole); - Matcher m = p.matcher(role); - if (m.matches()) { - String realm = ""; - String userStorage = ""; - String application = ""; - try { - realm = m.group("REALM"); - } catch (Exception e) { - } - try { - userStorage = "_" + m.group("USERSTORAGE"); - } catch (Exception e) { - } - try { - if (m.group("APPLICATION") != null) { - if (realm.equals("")) { - realm = "*"; - userStorage = "_*"; - } - application = "\\" + m.group("APPLICATION"); - } - } catch (Exception e) { - } - String res = realm + userStorage + application; - return res; - } - } - return null; - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - return roles; + private List getAllowedAttributePattern( + List roles, String realm, String storage, String pattern) { + return getRightsFromRegexList(roles, applicationManagerRoleList).stream() + .map(appRight -> getPatternFromRegex(pattern, realm, storage, appRight.getApplication())) + .map(Pattern::pattern) + .collect(Collectors.toList()); } - private List getSearchRoleList( - SugoiUser sugoiUser, - String realm, - String userStorage, - String application, - List regexpList) { - Map valueMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - valueMap.put("realm", realm.toUpperCase()); - if (userStorage != null) { - valueMap.put("userStorage", userStorage.toUpperCase()); - } - if (application != null) { - valueMap.put("application", application); - } - return regexpList.stream() - .map(regexp -> StrSubstitutor.replace(regexp, valueMap, "$(", ")")) + private static List getStringRightsFromRegexList( + List roles, List applicationManagerRoleList) { + return getRightsFromRegexList(roles, applicationManagerRoleList).stream() + .map(Right::toString) .collect(Collectors.toList()); } - @Override - public List getAllowedAttributePattern( - SugoiUser sugoiUser, String realm, String storage, String pattern) { - List appRightsOfUser = - getUserRealmAppManager(sugoiUser).stream() - .map(app -> app.split("\\\\")[1]) + private static List getRightsFromRegexList(List roles, List regexpList) { + List validPatterns = + regexpList.stream() + .map(PermissionServiceImpl::createCatchingPattern) .collect(Collectors.toList()); - // Look for regexp of attribute value allowed - List regexpAttributesAllowed = new ArrayList<>(); - for (String appRight : appRightsOfUser) { - Map valueMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); - valueMap.put("application", appRight); - valueMap.put("realm", realm); - valueMap.put("storage", storage); - regexpAttributesAllowed.add( - StrSubstitutor.replace(pattern, valueMap, "$(", ")").toUpperCase()); + return roles.stream() + .map(role -> transformRoleToRight(role, validPatterns)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toList()); + } + + /** + * Create a pattern from the regexp used to retrieve realm, userstorage and application from any + * roles matching it via transformRoleToRight. + * + * @param regexp a String defining the form of a valid role (ex: READER_$(realm)_$(userstorage)) + * @return the catching pattern form this regexp (ex : READER_(?.*_(?.*))) + */ + private static Pattern createCatchingPattern(String regexp) { + return getPatternFromRegex(regexp, "(?.*)", "(?.*)", "(?.*)"); + } + + private static boolean areUserRolesInValidRoles( + List regexpList, + List userRoles, + String realmName, + String usName, + String appName) { + logger.debug("Checking if user is in : {}", regexpList); + return regexpList.stream() + .map(regexp -> getPatternFromRegex(regexp, realmName, usName, appName)) + .anyMatch( + validPattern -> + userRoles.stream() + .anyMatch(userRole -> validPattern.matcher(userRole.toUpperCase()).matches())); + } + + private static Pattern getPatternFromRegex( + String regexp, String realmName, String usName, String appName) { + Map valueMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + if (realmName != null) { + valueMap.put("realm", realmName.toUpperCase()); } - return regexpAttributesAllowed; + if (usName != null) { + valueMap.put("userStorage", usName.toUpperCase()); + } + if (appName != null) { + valueMap.put("application", appName.toUpperCase()); + } + return Pattern.compile( + StrSubstitutor.replace(regexp, valueMap, "$(", ")").replace("*", ".*"), + Pattern.CASE_INSENSITIVE); } - @Override - public boolean isValidAttributeAccordingAttributePattern( - SugoiUser sugoiUser, String realm, String storage, String pattern, String attribute) { - List regexpAttributesAllowed = - getAllowedAttributePattern(sugoiUser, realm, storage, pattern); - // Check if attribute match with allowed pattern - for (String regexpAttributeAllowed : regexpAttributesAllowed) { - if (attribute.toUpperCase().matches(regexpAttributeAllowed)) { - return true; + private static Optional transformRoleToRight(String role, List patterns) { + for (Pattern p : patterns) { + Matcher m = p.matcher(role); + if (m.matches()) { + Right right = new Right(); + if (p.pattern().contains("?")) { + right.setRealm(m.group("REALM")); + } + if (p.pattern().contains("?")) { + right.setUserStorage(m.group("USERSTORAGE")); + } + if (p.pattern().contains("?")) { + right.setApplication(m.group("APPLICATION")); + } + return Optional.of(right); } } - return false; + return Optional.empty(); } } diff --git a/sugoi-api-core/src/test/java/fr/insee/sugoi/core/service/PermissionServiceTests.java b/sugoi-api-core/src/test/java/fr/insee/sugoi/core/service/PermissionServiceTests.java index c04a048b..2578af1b 100644 --- a/sugoi-api-core/src/test/java/fr/insee/sugoi/core/service/PermissionServiceTests.java +++ b/sugoi-api-core/src/test/java/fr/insee/sugoi/core/service/PermissionServiceTests.java @@ -15,18 +15,11 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.fail; -import fr.insee.sugoi.core.configuration.GlobalKeysConfig; -import fr.insee.sugoi.core.model.SugoiUser; import fr.insee.sugoi.core.realm.RealmProvider; import fr.insee.sugoi.core.service.impl.PermissionServiceImpl; -import fr.insee.sugoi.model.Realm; import java.util.List; -import java.util.Optional; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -40,121 +33,160 @@ public class PermissionServiceTests { @Autowired PermissionService permissions; - private Realm realm; - - @BeforeEach - public void setup() { - realm = new Realm(); - realm.setName("test"); - realm.addProperty(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_PATTERNS_LIST, "(.*)_$(application)"); - realm.addProperty(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_KEYS_LIST, "my-attribute-key"); - } - @Test public void testAdminRegexp() { - SugoiUser sugoiUser = new SugoiUser("admin", List.of("role_Admin_Sugoi")); - assertThat("User is admin", permissions.isAdmin(sugoiUser), is(true)); + assertThat("User is admin", permissions.isAdmin(List.of("role_Admin_Sugoi"))); + assertThat("User on sugoii is not admin", !permissions.isAdmin(List.of("role_Admin_Sugoii"))); } @Test public void testReaderRegexp() { - SugoiUser sugoiUser = new SugoiUser("reader_realm1", List.of("role_Reader_realm1_sugoi")); + List readerRoles = List.of("role_Reader_realm1_sugoi"); - assertThat("User can read realm1", permissions.isReader(sugoiUser, "realm1", ""), is(true)); + assertThat("User can read realm1", permissions.isReader(readerRoles, "realm1", ""), is(true)); assertThat( - "User cannot write realm1", permissions.isWriter(sugoiUser, "realm1", ""), is(false)); - assertThat("User cannot read realm2", permissions.isReader(sugoiUser, "realm2", ""), is(false)); + "User cannot write realm1", permissions.isWriter(readerRoles, "realm1", ""), is(false)); + assertThat( + "User cannot read realm2", permissions.isReader(readerRoles, "realm2", ""), is(false)); } @Test public void testWriterRegexp() { - SugoiUser sugoiUser = new SugoiUser("writer_realm1", List.of("role_Writer_realm1_sugoi")); - assertThat("User can read realm1", permissions.isReader(sugoiUser, "realm1", ""), is(true)); - assertThat("User can write realm1", permissions.isWriter(sugoiUser, "realm1", ""), is(true)); - assertThat("User cannot read realm2", permissions.isReader(sugoiUser, "realm2", ""), is(false)); + List writerRoles = List.of("role_Writer_realm1_sugoi"); + assertThat("User can read realm1", permissions.isReader(writerRoles, "realm1", ""), is(true)); + assertThat("User can write realm1", permissions.isWriter(writerRoles, "realm1", ""), is(true)); + assertThat( + "User cannot read realm2", permissions.isReader(writerRoles, "realm2", ""), is(false)); } @Test public void testUserStorageNull() { - try { - SugoiUser sugoiUser = new SugoiUser("writer_realm1", List.of("role_Writer_realm1_sugoi")); - assertThat( - "No nullPointerException", permissions.isReader(sugoiUser, "realm1", null), is(true)); - } catch (Exception e) { - fail(); - } + List writerRoles = List.of("role_Writer_realm1_sugoi"); + assertThat( + "No nullPointerException", permissions.isReader(writerRoles, "realm1", null), is(true)); } @Test public void testAppManager() { - try { - SugoiUser sugoiUser = - new SugoiUser( - "appmanager_realm1_appli1", - List.of("role_Asi_realm1_appli1", "role_reader_realm1_sugoi")); - assertThat( - "user is app manager for appli1 in realm1", - permissions.isApplicationManager(sugoiUser, "realm1", null, "appli1"), - is(true)); - assertThat( - "user is reader in realm1", permissions.isReader(sugoiUser, "realm1", null), is(true)); - } catch (Exception e) { - fail(); - } + List appRoles = List.of("role_Asi_realm1_appli1", "role_reader_realm1_sugoi"); + assertThat( + "user is app manager for appli1 in realm1", + permissions.isApplicationManager(appRoles, "realm1", "appli1"), + is(true)); + assertThat( + "user is reader in realm1", permissions.isReader(appRoles, "realm1", null), is(true)); } @Test public void testAppManagerWithoutRealmInRoleName() { - try { - SugoiUser sugoiUser = - new SugoiUser( - "appmanager_appli1", List.of("role_Asi_appli1", "role_reader_realm1_sugoi")); - assertThat( - "user is app manager for appli1 in realm1", - permissions.isApplicationManager(sugoiUser, "realm1", null, "appli1"), - is(true)); - assertThat( - "user is reader in realm1", permissions.isReader(sugoiUser, "realm1", null), is(true)); - assertThat( - "user is app manager for appli1 in realm2", - permissions.isApplicationManager(sugoiUser, "realm2", null, "appli1"), - is(false)); - assertThat( - "user is reader in realm2", permissions.isReader(sugoiUser, "realm2", null), is(false)); - - } catch (Exception e) { - fail(); - } + List withoutRealmRoles = List.of("role_Asi_appli1", "role_reader_realm1_sugoi"); + assertThat( + "user is app manager for appli1 in realm1", + permissions.isApplicationManager(withoutRealmRoles, "realm1", "appli1"), + is(true)); + assertThat( + "user is reader in realm1", + permissions.isReader(withoutRealmRoles, "realm1", null), + is(true)); + assertThat( + "user is app manager for appli1 in realm2", + permissions.isApplicationManager(withoutRealmRoles, "realm2", "appli1"), + is(false)); + assertThat( + "user is reader in realm2", + permissions.isReader(withoutRealmRoles, "realm2", null), + is(false)); } @Test public void testAdminWildcard() { - SugoiUser sugoiUser = new SugoiUser("admin_wildcard", List.of("role_nimportequoi_admin")); - try { - assertThat("user is admin sugoi", permissions.isAdmin(sugoiUser), is(true)); - } catch (Exception e) { - fail(); - } + List adminWildcardRole = List.of("role_nimportequoi_admin"); + assertThat("user is admin sugoi", permissions.isAdmin(adminWildcardRole), is(true)); } @Test public void testgetAllowedAttributePattern() { - try { - Mockito.when(realmProvider.load(Mockito.any())).thenReturn(Optional.of(realm)); - SugoiUser sugoiUser = - new SugoiUser("admin_wildcard", List.of("role_ASI_realm1_app1", "role_ASI_app2")); - List allowedAttributesPattern = - permissions.getAllowedAttributePattern( - sugoiUser, - "toto", - "tata", - realm - .getProperties() - .get(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_KEYS_LIST) - .split(",")[0]); - assertThat("allowed Attributes Pattern", allowedAttributesPattern.size(), is(2)); - } catch (Exception e) { - fail(); - } + List roles = List.of("role_ASI_realm1_app1", "role_ASI_app2"); + assertThat( + "Toto_app1 should be accepted according to the pattern", + permissions.isValidAttributeAccordingAttributePattern( + roles, "realm1", null, "(.*)_$(application)", "toto_app1")); + assertThat( + "Toto_app2 should be denied", + !permissions.isValidAttributeAccordingAttributePattern( + roles, "realm1", null, "(.*)_$(application)", "toto_app3")); + } + + @Test + public void testGetReaderRole() { + List roles = + List.of( + "role_toto_titi", + "role_Reader_realm2", + "role_Reader_realm1_sugoi", + "role_Reader_realm3_sugoi"); + List readableRealm = permissions.getReaderRoles(roles); + assertThat("There should only be 2 valid reader roles", 2, is(readableRealm.size())); + assertThat("should contain realm1", readableRealm.contains("REALM1")); + assertThat("should contain realm3", readableRealm.contains("REALM3")); + } + + @Test + public void testGetWriterRole() { + List roles = + List.of( + "role_toto_titi", + "role_Reader_realm2", + "role_Writer_realm1_sugoi", + "role_Reader_realm3_sugoi"); + List writableRealm = permissions.getWriterRoles(roles); + assertThat("There should only be 1 valid writer role", 1, is(writableRealm.size())); + assertThat("should contain realm1", writableRealm.contains("REALM1")); + } + + @Test + public void testGetAppManagerRole() { + List roles = List.of("role_ASI_realm1_appli", "role_ASI_appli2"); + List appManagerRealms = permissions.getAppManagerRoles(roles); + assertThat("There should only be 2 valid appmanager roles", 2, is(appManagerRealms.size())); + assertThat( + "should contain realm and appli when application scoped", + appManagerRealms.contains("REALM1\\APPLI")); + assertThat("can contain only application", appManagerRealms.contains("*_*\\APPLI2")); + } + + @Test + public void testGetPasswordManagerRole() { + List roles = + List.of( + "role_passwordmanager_toto_sugoi", + "role_passwordmanager_realm1_tata_sugoi", + "role_Writer_realm2_sugoi"); + List passwordManagerRealms = permissions.getPasswordManagerRoles(roles); + assertThat( + "There should only be 2 valid passwordmanager role", 2, is(passwordManagerRealms.size())); + assertThat("should contain realm1 us tata", passwordManagerRealms.contains("REALM1_TATA")); + assertThat("should contain toto", passwordManagerRealms.contains("TOTO")); + } + + @Test + public void testIsPasswordManager() { + List roles = + List.of( + "role_passwordmanager_toto_sugoi", + "role_passwordmanager_realm1_tata_sugoi", + "role_Writer_realm2_sugoi"); + assertThat( + "Should have the password manager permission with null us", + permissions.isPasswordManager(roles, "toto", null)); + assertThat( + "Should have the password manager permission with tata us", + permissions.isPasswordManager(roles, "realm1", "tata")); + assertThat( + "Should not have the password manager permission with null us", + !permissions.isPasswordManager(roles, "realm1", null)); + assertThat( + "Should not have the password manager permission with default us", + !permissions.isPasswordManager(roles, "realm1", "default")); } } diff --git a/sugoi-api-core/src/test/resources/permissions/test-regexp-permissions.properties b/sugoi-api-core/src/test/resources/permissions/test-regexp-permissions.properties index e9214247..349bba46 100644 --- a/sugoi-api-core/src/test/resources/permissions/test-regexp-permissions.properties +++ b/sugoi-api-core/src/test/resources/permissions/test-regexp-permissions.properties @@ -2,6 +2,7 @@ fr.insee.sugoi.api.regexp.role.writer=ROLE_WRITER_$(realm)_SUGOI fr.insee.sugoi.api.regexp.role.reader=ROLE_READER_$(realm)_SUGOI fr.insee.sugoi.api.regexp.role.admin=ROLE_ADMIN_SUGOI, ROLE_*_Admin +fr.insee.sugoi.api.regexp.role.password.manager=ROLE_PASSWORDMANAGER_$(realm)_$(userstorage)_SUGOI,ROLE_PASSWORDMANAGER_$(realm)_SUGOI fr.insee.sugoi.api.regexp.role.application.manager=ROLE_ASI_$(realm)_$(application), ROLE_ASI_$(application) logging.level.fr.insee.sugoi=trace \ No newline at end of file diff --git a/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/controller/AppManagedUserAttributeController.java b/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/controller/AppManagedUserAttributeController.java index a1795b3b..83d49d20 100644 --- a/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/controller/AppManagedUserAttributeController.java +++ b/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/controller/AppManagedUserAttributeController.java @@ -39,6 +39,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -90,12 +91,12 @@ public class AppManagedUserAttributeController { description = "Invalid combinaison of id between body and path", content = {@Content(mediaType = "application/json")}) }) - public ResponseEntity addUserAttributesManagedByApp( + public ResponseEntity addUserAttributesManagedByApp( @Parameter( description = "Name of the realm where the operation will be made", required = true) @PathVariable("realm") - String realm, + String realmName, @Parameter( description = "Name of the userstorage where the operation will be made", required = true) @@ -124,87 +125,31 @@ public ResponseEntity addUserAttributesManagedByApp( .map(GrantedAuthority::getAuthority) .map(String::toUpperCase) .collect(Collectors.toList()); - SugoiUser sugoiUser = new SugoiUser(authentication.getName(), roles); - Realm _realm = configService.getRealm(realm); - List attributes_allowed = - Arrays.asList( - _realm - .getProperties() - .get(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_KEYS_LIST) - .toUpperCase() - .split(",")); - try { - if (attributes_allowed.contains(attributeKey.toUpperCase())) { - - if (permissionService.isWriter(sugoiUser, realm, storage)) { - ProviderResponse response = - userService.addAppManagedAttribute( - realm, - storage, - id, - attributeKey, - attributeValue, - new ProviderRequest( - new SugoiUser( - authentication.getName(), - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList())), - isAsynchronous, - null, - isUrgent)); - return ResponseEntity.status(Utils.convertStatusTHttpStatus(response, false, true)) - .header("X-SUGOI-TRANSACTION-ID", response.getRequestId()) - .header("X-SUGOI-REQUEST-STATUS", response.getStatus().toString()) - .build(); - } else { - String pattern_of_attribute = - _realm - .getProperties() - .get(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_PATTERNS_LIST) - .toUpperCase() - .split(",")[attributes_allowed.indexOf(attributeKey.toUpperCase())]; - if (permissionService.isValidAttributeAccordingAttributePattern( - sugoiUser, realm, storage, pattern_of_attribute, attributeValue)) { - ProviderResponse response = - userService.addAppManagedAttribute( - realm, - storage, - id, - attributeKey, - attributeValue, - new ProviderRequest( - new SugoiUser( - authentication.getName(), - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList())), - isAsynchronous, - null, - isUrgent)); - return ResponseEntity.status(Utils.convertStatusTHttpStatus(response, false, true)) - .header("X-SUGOI-REQUEST-STATUS", response.getStatus().toString()) - .header("X-SUGOI-TRANSACTION-ID", response.getRequestId()) - .build(); - } - - // If no match found then app cannot managed attribute or attribute doesn't math - // with allowed pattern - throw new AppCannotManagedAttributeException( - "Cannot add attribute to user: attribute doesn't match with pattern"); - } - } - } catch (Exception e) { - if (e instanceof AppCannotManagedAttributeException) { - throw e; - } - throw new AppCannotManagedAttributeException( - "Cannot add attribute to user: app cannot managed attributes " + attributeKey); + Realm realm = configService.getRealm(realmName); + String patternOfAttribute = getPatternOfAttribute(realm, attributeKey); + if (permissionService.isWriter(roles, realmName, storage) + || permissionService.isValidAttributeAccordingAttributePattern( + roles, realmName, storage, patternOfAttribute, attributeValue)) { + ProviderResponse response = + userService.addAppManagedAttribute( + realmName, + storage, + id, + attributeKey, + attributeValue, + new ProviderRequest( + new SugoiUser(authentication.getName(), roles), isAsynchronous, null, isUrgent)); + return ResponseEntity.status(Utils.convertStatusTHttpStatus(response, false, true)) + .header("X-SUGOI-TRANSACTION-ID", response.getRequestId()) + .header("X-SUGOI-REQUEST-STATUS", response.getStatus().toString()) + .build(); + } else { + throw new AccessDeniedException( + "Not allowed to add appmanagedattribute " + + attributeKey + + " . Attribute should match pattern : " + + patternOfAttribute); } - throw new AppCannotManagedAttributeException( - "Cannot add attribute to user: app cannot managed attributes " + attributeKey); } @DeleteMapping( @@ -233,12 +178,12 @@ public ResponseEntity addUserAttributesManagedByApp( description = "Invalid combinaison of id between body and path", content = {@Content(mediaType = "application/json")}) }) - public ResponseEntity deleteUserAttributesManagedByApp( + public ResponseEntity deleteUserAttributesManagedByApp( @Parameter( description = "Name of the realm where the operation will be made", required = true) @PathVariable("realm") - String realm, + String realmName, @Parameter( description = "Name of the userstorage where the operation will be made", required = true) @@ -267,87 +212,34 @@ public ResponseEntity deleteUserAttributesManagedByApp( .map(GrantedAuthority::getAuthority) .map(String::toUpperCase) .collect(Collectors.toList()); - SugoiUser sugoiUser = new SugoiUser(authentication.getName(), roles); - Realm _realm = configService.getRealm(realm); - List attributes_allowed = - Arrays.asList( - _realm - .getProperties() - .get(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_KEYS_LIST) - .toUpperCase() - .split(",")); - try { - if (attributes_allowed.contains(attributeKey.toUpperCase())) { - - if (permissionService.isWriter(sugoiUser, realm, storage)) { - ProviderResponse response = - userService.deleteAppManagedAttribute( - realm, - storage, - id, - attributeKey, - attributeValue, - new ProviderRequest( - new SugoiUser( - authentication.getName(), - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList())), - isAsynchronous, - transactionId, - isUrgent)); - return ResponseEntity.status(Utils.convertStatusTHttpStatus(response, false, true)) - .header("X-SUGOI-REQUEST-STATUS", response.getStatus().toString()) - .header("X-SUGOI-TRANSACTION-ID", response.getRequestId()) - .build(); - } else { - String pattern_of_attribute = - _realm - .getProperties() - .get(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_PATTERNS_LIST) - .toUpperCase() - .split(",")[attributes_allowed.indexOf(attributeKey.toUpperCase())]; - if (permissionService.isValidAttributeAccordingAttributePattern( - sugoiUser, realm, storage, pattern_of_attribute, attributeValue)) { - ProviderResponse response = - userService.deleteAppManagedAttribute( - realm, - storage, - id, - attributeKey, - attributeValue, - new ProviderRequest( - new SugoiUser( - authentication.getName(), - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList())), - isAsynchronous, - transactionId, - isUrgent)); - return ResponseEntity.status(Utils.convertStatusTHttpStatus(response, false, true)) - .header("X-SUGOI-REQUEST-STATUS", response.getStatus().toString()) - .header("X-SUGOI-TRANSACTION-ID", response.getRequestId()) - .build(); - } - - // If no match found then app cannot managed attribute or attribute doesn't math - // with allowed pattern - throw new AppCannotManagedAttributeException( - "Cannot delete attribute to user: attribute doesn't match with pattern"); - } - } - } catch (Exception e) { - if (e instanceof AppCannotManagedAttributeException) { - throw e; - } - throw new AppCannotManagedAttributeException( - "Cannot add delete to user: app cannot managed attributes " + attributeKey); + Realm realm = configService.getRealm(realmName); + String patternOfAttribute = getPatternOfAttribute(realm, attributeKey); + if (permissionService.isWriter(roles, realmName, storage) + || permissionService.isValidAttributeAccordingAttributePattern( + roles, realmName, storage, patternOfAttribute, attributeValue)) { + ProviderResponse response = + userService.deleteAppManagedAttribute( + realmName, + storage, + id, + attributeKey, + attributeValue, + new ProviderRequest( + new SugoiUser(authentication.getName(), roles), + isAsynchronous, + transactionId, + isUrgent)); + return ResponseEntity.status(Utils.convertStatusTHttpStatus(response, false, true)) + .header("X-SUGOI-REQUEST-STATUS", response.getStatus().toString()) + .header("X-SUGOI-TRANSACTION-ID", response.getRequestId()) + .build(); + } else { + throw new AccessDeniedException( + "Not allowed to delete appmanagedattribute " + + attributeKey + + " . Attribute should match pattern : " + + patternOfAttribute); } - throw new AppCannotManagedAttributeException( - "Cannot add delete to user: app cannot managed attributes " + attributeKey); } @PatchMapping( @@ -376,7 +268,7 @@ public ResponseEntity deleteUserAttributesManagedByApp( description = "Invalid combinaison of id between body and path", content = {@Content(mediaType = "application/json")}) }) - public ResponseEntity addUserAttributesManagedByApp( + public ResponseEntity addUserAttributesManagedByApp( @Parameter( description = "Name of the realm where the operation will be made", required = true) @@ -401,10 +293,13 @@ public ResponseEntity addUserAttributesManagedByApp( String transactionId, Authentication authentication) { - User foundUser = userService.findById(realm, null, id); return addUserAttributesManagedByApp( realm, - (String) foundUser.getMetadatas().get(GlobalKeysConfig.USERSTORAGE.getName()), + (String) + userService + .findById(realm, null, id) + .getMetadatas() + .get(GlobalKeysConfig.USERSTORAGE.getName()), id, attributeKey, attributeValue, @@ -465,10 +360,13 @@ public ResponseEntity deleteUserAttributesManagedByApp( String transactionId, Authentication authentication) { - User foundUser = userService.findById(realm, null, id); return deleteUserAttributesManagedByApp( realm, - (String) foundUser.getMetadatas().get(GlobalKeysConfig.USERSTORAGE.getName()), + (String) + userService + .findById(realm, null, id) + .getMetadatas() + .get(GlobalKeysConfig.USERSTORAGE.getName()), id, attributeKey, attributeValue, @@ -477,4 +375,37 @@ public ResponseEntity deleteUserAttributesManagedByApp( transactionId, authentication); } + + /** + * Each attributes allowed have an authorized pattern in the pattern config at the same place + * there are in the attribute managed config. If the attribute exists, return this pattern to be + * checked for user permissions. + * + * @param realm where the config will be fetched + * @param attributeKey attribute the user wants to update + * @throws AppCannotManagedAttributeException if the attribute is not an app managed attribute + * @return the authorized pattern for the attribute + */ + private String getPatternOfAttribute(Realm realm, String attributeKey) { + List attributesAllowed = getAttributesAllowed(realm); + if (attributesAllowed.contains(attributeKey.toUpperCase())) { + return realm + .getProperties() + .get(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_PATTERNS_LIST) + .toUpperCase() + .split(",")[attributesAllowed.indexOf(attributeKey.toUpperCase())]; + } else { + throw new AppCannotManagedAttributeException( + "Cannot add delete to user: " + attributeKey + " is not an app managed attribute"); + } + } + + private List getAttributesAllowed(Realm realm) { + return Arrays.asList( + realm + .getProperties() + .get(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_KEYS_LIST) + .toUpperCase() + .split(",")); + } } diff --git a/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/controller/WhoAmi.java b/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/controller/WhoAmi.java index 71f23b45..87122618 100644 --- a/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/controller/WhoAmi.java +++ b/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/controller/WhoAmi.java @@ -13,7 +13,6 @@ */ package fr.insee.sugoi.services.controller; -import fr.insee.sugoi.core.model.SugoiUser; import fr.insee.sugoi.core.service.PermissionService; import fr.insee.sugoi.services.view.WhoamiView; import io.swagger.v3.oas.annotations.Operation; @@ -60,14 +59,13 @@ public WhoamiView whoami() { .map(GrantedAuthority::getAuthority) .map(String::toUpperCase) .collect(Collectors.toList()); - SugoiUser sugoiUser = new SugoiUser(authentication.getName(), roles); WhoamiView res = new WhoamiView(); res.setId(authentication.getName()); - res.setPasswordRealm(permissionService.getUserRealmPasswordManager(sugoiUser)); - res.setReaderRealm(permissionService.getUserRealmReader(sugoiUser)); - res.setWriterRealm(permissionService.getUserRealmWriter(sugoiUser)); - res.setAppManager(permissionService.getUserRealmAppManager(sugoiUser)); - res.setIsAdmin(permissionService.isAdmin(sugoiUser)); + res.setPasswordRealm(permissionService.getPasswordManagerRoles(roles)); + res.setReaderRealm(permissionService.getReaderRoles(roles)); + res.setWriterRealm(permissionService.getWriterRoles(roles)); + res.setAppManager(permissionService.getAppManagerRoles(roles)); + res.setIsAdmin(permissionService.isAdmin(roles)); return res; } } diff --git a/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/decider/AuthorizeMethodDecider.java b/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/decider/AuthorizeMethodDecider.java index 39c1b81b..403e2aef 100644 --- a/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/decider/AuthorizeMethodDecider.java +++ b/sugoi-api-rest-services/src/main/java/fr/insee/sugoi/services/decider/AuthorizeMethodDecider.java @@ -15,7 +15,6 @@ import fr.insee.sugoi.core.model.SugoiUser; import fr.insee.sugoi.core.service.PermissionService; -import java.util.List; import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,17 +37,13 @@ public class AuthorizeMethodDecider { public boolean isReader(String realm, String userStorage) { if (enable) { - logger.info("Check if user is reader on realm {} and userStorage {}", realm, userStorage); - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - List roles = - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList()); - SugoiUser sugoiUser = new SugoiUser(authentication.getName(), roles); - return permissionService.isReader(sugoiUser, realm, userStorage) - || permissionService.isWriter(sugoiUser, realm, userStorage) - || permissionService.isPasswordManager(sugoiUser, realm, userStorage); + SugoiUser user = getCurrentSugoiUser(); + logger.info( + "Check if user {} is reader on realm {} and userStorage {}", + user.getName(), + realm, + userStorage); + return permissionService.isReader(user.getRoles(), realm, userStorage); } logger.warn("PreAuthorize on request is disabled, can cause security problem"); return true; @@ -56,16 +51,9 @@ public boolean isReader(String realm, String userStorage) { public boolean isAppManager(String realm, String application) { if (enable) { - logger.info("Check if user is at least reader on realm {}", realm); - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - List roles = - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList()); - SugoiUser sugoiUser = new SugoiUser(authentication.getName(), roles); - return permissionService.isApplicationManager(sugoiUser, realm, null, application) - || permissionService.isWriter(sugoiUser, realm, null); + SugoiUser user = getCurrentSugoiUser(); + logger.info("Check if {} user is at least reader on realm {}", user.getName(), realm); + return permissionService.isApplicationManager(user.getRoles(), realm, application); } logger.warn("PreAuthorize on request is disabled, can cause security problem"); return true; @@ -73,17 +61,13 @@ public boolean isAppManager(String realm, String application) { public boolean isPasswordManager(String realm, String userStorage) { if (enable) { + SugoiUser user = getCurrentSugoiUser(); logger.info( - "Check if user is at least reader on realm {} and userStorage {}", realm, userStorage); - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - List roles = - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList()); - SugoiUser sugoiUser = new SugoiUser(authentication.getName(), roles); - return permissionService.isPasswordManager(sugoiUser, realm, userStorage) - || permissionService.isWriter(sugoiUser, realm, userStorage); + "Check if user {} is at least reader on realm {} and userStorage {}", + user.getName(), + realm, + userStorage); + return permissionService.isPasswordManager(user.getRoles(), realm, userStorage); } logger.warn("PreAuthorize on request is disabled, can cause security problem"); return true; @@ -91,16 +75,13 @@ public boolean isPasswordManager(String realm, String userStorage) { public boolean isWriter(String realm, String userStorage) { if (enable) { + SugoiUser user = getCurrentSugoiUser(); logger.info( - "Check if user is at least writer on realm {} and userStorage {}", realm, userStorage); - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - List roles = - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList()); - SugoiUser sugoiUser = new SugoiUser(authentication.getName(), roles); - return permissionService.isWriter(sugoiUser, realm, userStorage); + "Check if user {} is at least writer on realm {} and userStorage {}", + user.getName(), + realm, + userStorage); + return permissionService.isWriter(user.getRoles(), realm, userStorage); } logger.warn("PreAuthorize on request is disabled, can cause security problem"); return true; @@ -108,17 +89,21 @@ public boolean isWriter(String realm, String userStorage) { public boolean isAdmin() { if (enable) { - logger.info("Check if user is admin"); - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - List roles = - authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .map(String::toUpperCase) - .collect(Collectors.toList()); - SugoiUser sugoiUser = new SugoiUser(authentication.getName(), roles); - return permissionService.isAdmin(sugoiUser); + SugoiUser user = getCurrentSugoiUser(); + logger.info("Check if user {} is admin", user.getName()); + return permissionService.isAdmin(user.getRoles()); } logger.warn("PreAuthorize on request is disabled, can cause security problem"); return true; } + + private SugoiUser getCurrentSugoiUser() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + return new SugoiUser( + authentication.getName(), + authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .map(String::toUpperCase) + .collect(Collectors.toList())); + } } diff --git a/sugoi-api-rest-services/src/test/java/fr/insee/sugoi/services/controller/AppManagedUserAttributeControllerTest.java b/sugoi-api-rest-services/src/test/java/fr/insee/sugoi/services/controller/AppManagedUserAttributeControllerTest.java index ed8b3726..c556b8ce 100644 --- a/sugoi-api-rest-services/src/test/java/fr/insee/sugoi/services/controller/AppManagedUserAttributeControllerTest.java +++ b/sugoi-api-rest-services/src/test/java/fr/insee/sugoi/services/controller/AppManagedUserAttributeControllerTest.java @@ -15,20 +15,18 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.fail; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import com.fasterxml.jackson.databind.ObjectMapper; import fr.insee.sugoi.commons.services.controller.technics.SugoiAdviceController; +import fr.insee.sugoi.commons.services.view.ErrorView; import fr.insee.sugoi.core.configuration.GlobalKeysConfig; import fr.insee.sugoi.core.model.ProviderResponse; import fr.insee.sugoi.core.model.ProviderResponse.ProviderResponseStatus; import fr.insee.sugoi.core.service.ConfigService; -import fr.insee.sugoi.core.service.PermissionService; import fr.insee.sugoi.core.service.UserService; +import fr.insee.sugoi.core.service.impl.PermissionServiceImpl; import fr.insee.sugoi.model.Realm; -import fr.insee.sugoi.model.User; -import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -45,7 +43,11 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; @SpringBootTest( - classes = {AppManagedUserAttributeController.class, SugoiAdviceController.class}, + classes = { + AppManagedUserAttributeController.class, + SugoiAdviceController.class, + PermissionServiceImpl.class + }, properties = "spring.config.location=classpath:/permissions/test-regexp-permissions.properties") @AutoConfigureMockMvc @EnableWebMvc @@ -54,189 +56,97 @@ public class AppManagedUserAttributeControllerTest { @MockBean private UserService userService; - @MockBean private PermissionService permissionService; - @MockBean private ConfigService configService; ObjectMapper objectMapper = new ObjectMapper(); - Realm realm; - User user; @BeforeEach public void setup() { - realm = new Realm(); + Realm realm = new Realm(); realm.setName("test"); realm.addProperty(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_PATTERNS_LIST, "(.*)_$(application)"); realm.addProperty(GlobalKeysConfig.APP_MANAGED_ATTRIBUTE_KEYS_LIST, "my-attribute-key"); + Mockito.when(configService.getRealm(Mockito.anyString())).thenReturn(realm); + Mockito.doReturn(new ProviderResponse("", "requestId", ProviderResponseStatus.OK, null, null)) + .when(userService) + .addAppManagedAttribute( + Mockito.any(), + Mockito.any(), + Mockito.any(), + Mockito.any(), + Mockito.any(), + Mockito.any()); } @Test - @WithMockUser(username = "reader_realm1", roles = "ADMIN_SUGOI") - public void get200WhenAddCorrectAttributes() { - try { - - Mockito.when(configService.getRealm(Mockito.anyString())).thenReturn(realm); - Mockito.when(permissionService.getUserRealmAppManager(Mockito.any())) - .thenReturn(List.of("*\\appA", "*\\appB")); - Mockito.doReturn(true) - .when(permissionService) - .isWriter(Mockito.any(), Mockito.anyString(), Mockito.anyString()); - Mockito.doReturn(new ProviderResponse("", "requestId", ProviderResponseStatus.OK, null, null)) - .when(userService) - .addAppManagedAttribute( - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any()); - RequestBuilder requestBuilder = - MockMvcRequestBuilders.patch( - "/realms/domaine1/storages/test/users/Toto/my-attribute-key/prop_role_appA") - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON) - .with(csrf()); - MockHttpServletResponse response = mockMvc.perform(requestBuilder).andReturn().getResponse(); - - assertThat("Response must be 200 OK", response.getStatus(), is(204)); - - } catch (Exception e) { - e.printStackTrace(); - fail(); - } + @WithMockUser(roles = "ADMIN_SUGOI") + public void get200WhenAddCorrectAttributesWhenAdminOrWriter() throws Exception { + MockHttpServletResponse response = + createPatchRequestFromUrl( + "/realms/domaine1/storages/test/users/Toto/my-attribute-key/prop_role_appA"); + assertThat("Response must be 204 ACCEPTED", response.getStatus(), is(204)); } @Test - @WithMockUser - public void get200WhenAddCorrectAttributesWhenAdminOrWriter() { - try { - - Mockito.when(configService.getRealm(Mockito.anyString())).thenReturn(realm); - Mockito.doReturn(true) - .when(permissionService) - .isWriter(Mockito.any(), Mockito.anyString(), Mockito.anyString()); - Mockito.doReturn(new ProviderResponse("", "requestId", ProviderResponseStatus.OK, null, null)) - .when(userService) - .addAppManagedAttribute( - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any()); - RequestBuilder requestBuilder = - MockMvcRequestBuilders.patch( - "/realms/domaine1/storages/test/users/Toto/my-attribute-key/prop_role_appA") - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON) - .with(csrf()); - MockHttpServletResponse response = mockMvc.perform(requestBuilder).andReturn().getResponse(); - - assertThat("Response must be 200 OK", response.getStatus(), is(204)); - - } catch (Exception e) { - e.printStackTrace(); - fail(); - } + @WithMockUser(roles = "ASI_appA") + public void get200WhenAddCorrectAttributesWhenAppManager() throws Exception { + MockHttpServletResponse response = + createPatchRequestFromUrl( + "/realms/domaine1/storages/test/users/Toto/my-attribute-key/prop_role_appA"); + assertThat("Response must be 204 ACCEPTED", response.getStatus(), is(204)); } @Test - @WithMockUser(username = "reader_realm1", roles = "ASI_SUGOI") - public void get200WhenAddCorrectAttributesWhenAppManager() { - try { - - Mockito.when( - permissionService.isWriter(Mockito.any(), Mockito.anyString(), Mockito.anyString())) - .thenReturn(false); - Mockito.doReturn(true) - .when(permissionService) - .isValidAttributeAccordingAttributePattern( - Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()); - Mockito.doReturn(new ProviderResponse("", "requestId", ProviderResponseStatus.OK, null, null)) - .when(userService) - .addAppManagedAttribute( - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any(), - Mockito.any()); - Mockito.when(configService.getRealm(Mockito.anyString())).thenReturn(realm); - Mockito.when( - permissionService.getAllowedAttributePattern( - Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.anyString())) - .thenReturn(List.of("(.*)_appA", "(.*)_appB")); - RequestBuilder requestBuilder = - MockMvcRequestBuilders.patch( - "/realms/domaine1/storages/test/users/Toto/my-attribute-key/prop_role_appA") - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON) - .with(csrf()); - MockHttpServletResponse response = mockMvc.perform(requestBuilder).andReturn().getResponse(); - - assertThat("Response must be 200 OK", response.getStatus(), is(204)); - - } catch (Exception e) { - e.printStackTrace(); - fail(); - } + @WithMockUser(roles = "ASI_appA") + public void get403WhenTryToAddValidAttributeWithBadPattern() throws Exception { + MockHttpServletResponse response = + createPatchRequestFromUrl( + "/realms/domaine1/storages/test/users/Toto/my-attribute-key/appA_toto"); + assertThat("Response must be 403", response.getStatus(), is(403)); + assertThat( + "Message should be access denied and give the pattern", + getMessageFromErrorView(response), + is( + "Not allowed to add appmanagedattribute my-attribute-key . Attribute should match pattern : (.*)_$(APPLICATION)")); } @Test - @WithMockUser(username = "reader_realm1", roles = "ASI_SUGOI") - public void get403WhenAddIncorrectAttributes() { - try { - - Mockito.when( - permissionService.isWriter(Mockito.any(), Mockito.anyString(), Mockito.anyString())) - .thenReturn(false); - Mockito.when(configService.getRealm(Mockito.anyString())).thenReturn(realm); - Mockito.when( - permissionService.getAllowedAttributePattern( - Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.anyString())) - .thenReturn(List.of("(.*)_appA", "(.*)_appB")); - RequestBuilder requestBuilder = - MockMvcRequestBuilders.patch( - "/realms/domaine1/storages/test/users/Toto/my-attribute-key2/prop_role_appA") - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON) - .with(csrf()); - MockHttpServletResponse response = mockMvc.perform(requestBuilder).andReturn().getResponse(); - - assertThat("Response must be 403", response.getStatus(), is(403)); - - } catch (Exception e) { - e.printStackTrace(); - fail(); - } + @WithMockUser(roles = "ASI_SUGOI") + public void get403WhenAddIncorrectAttributes() throws Exception { + MockHttpServletResponse response = + createPatchRequestFromUrl( + "/realms/domaine1/storages/test/users/Toto/my-attribute-key2/prop_role_appA"); + assertThat("Response must be 403", response.getStatus(), is(403)); + assertThat( + "Message should be not an app managed attribute", + getMessageFromErrorView(response), + is("Cannot add delete to user: my-attribute-key2 is not an app managed attribute")); } @Test - @WithMockUser(username = "reader_realm1", roles = "ASI_SUGOI") - public void get403WhenNoRightIncorrectAttributes() { - try { - - Mockito.when( - permissionService.isWriter(Mockito.any(), Mockito.anyString(), Mockito.anyString())) - .thenReturn(false); - Mockito.when(configService.getRealm(Mockito.anyString())).thenReturn(realm); - Mockito.when( - permissionService.getAllowedAttributePattern( - Mockito.any(), Mockito.anyString(), Mockito.any(), Mockito.anyString())) - .thenReturn(List.of("(.*)_sugoi")); - RequestBuilder requestBuilder = - MockMvcRequestBuilders.patch( - "/realms/domaine1/storages/test/users/Toto/my-attribute-key/prop_role_appA") - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.APPLICATION_JSON) - .with(csrf()); - MockHttpServletResponse response = mockMvc.perform(requestBuilder).andReturn().getResponse(); + @WithMockUser(roles = "ASI_SUGOI") + public void get403WhenNoRightIncorrectAttributes() throws Exception { + MockHttpServletResponse response = + createPatchRequestFromUrl( + "/realms/domaine1/storages/test/users/Toto/my-attribute-key/prop_role_appA"); + assertThat("Response must be 403", response.getStatus(), is(403)); + assertThat( + "Message should be access denied and give the pattern", + getMessageFromErrorView(response), + is( + "Not allowed to add appmanagedattribute my-attribute-key . Attribute should match pattern : (.*)_$(APPLICATION)")); + } - assertThat("Response must be 403", response.getStatus(), is(403)); + private MockHttpServletResponse createPatchRequestFromUrl(String url) throws Exception { + RequestBuilder requestBuilder = + MockMvcRequestBuilders.patch(url) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .with(csrf()); + return mockMvc.perform(requestBuilder).andReturn().getResponse(); + } - } catch (Exception e) { - e.printStackTrace(); - fail(); - } + private String getMessageFromErrorView(MockHttpServletResponse response) throws Exception { + return objectMapper.readValue(response.getContentAsString(), ErrorView.class).getMessage(); } }