Merge branch 'RED-8491' into 'main'
RED-8491: Hide all KNECON_* roles for any possible access in all endpoints See merge request fforesight/tenant-user-management-service!105
This commit is contained in:
commit
ed86367ab8
@ -1,6 +1,5 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.controller.external;
|
||||
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.DELETE_TENANT;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.READ_ALL_USERS;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.READ_USERS;
|
||||
import static com.knecon.fforesight.tenantusermanagement.permissions.UserManagementPermissions.UPDATE_MY_PROFILE;
|
||||
@ -26,6 +25,7 @@ import com.knecon.fforesight.tenantusermanagement.model.ResetPasswordRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateMyProfileRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateProfileRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.User;
|
||||
import com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles;
|
||||
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
|
||||
import com.knecon.fforesight.tenantusermanagement.service.UserService;
|
||||
|
||||
@ -41,9 +41,6 @@ public class UserController implements UserResource, PublicResource {
|
||||
private final UserService userService;
|
||||
private final TenantUserManagementProperties tenantUserManagementProperties;
|
||||
|
||||
private static final String KNECON_ADMIN_ROLE = "KNECON_ADMIN";
|
||||
private static final String KNECON_SUPPORT_ROLE = "KNECON_SUPPORT";
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('" + READ_USERS + "')")
|
||||
@ -76,7 +73,7 @@ public class UserController implements UserResource, PublicResource {
|
||||
.filter(user -> {
|
||||
Set<String> filteredRoles = user.getRoles()
|
||||
.stream()
|
||||
.filter(role -> !role.equals(KNECON_ADMIN_ROLE) && !role.equals(KNECON_SUPPORT_ROLE))
|
||||
.filter(ApplicationRoles::isNoKneconRole)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (filteredRoles.isEmpty()) {
|
||||
@ -142,7 +139,7 @@ public class UserController implements UserResource, PublicResource {
|
||||
|
||||
Set<String> filteredRoles = user.getRoles()
|
||||
.stream()
|
||||
.filter(role -> !role.equals(KNECON_ADMIN_ROLE) && !role.equals(KNECON_SUPPORT_ROLE))
|
||||
.filter(ApplicationRoles::isNoKneconRole)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (filteredRoles.isEmpty()) {
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package com.knecon.fforesight.tenantusermanagement.permissions;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public final class ApplicationRoles {
|
||||
|
||||
public static final String KNECON_ADMIN_ROLE = "KNECON_ADMIN";
|
||||
public static final String KNECON_SUPPORT_ROLE = "KNECON_SUPPORT";
|
||||
|
||||
private static final Set<String> KNECON_ROLES = Set.of(KNECON_ADMIN_ROLE, KNECON_SUPPORT_ROLE);
|
||||
|
||||
public static boolean isNoKneconRole(String role) {
|
||||
|
||||
return !KNECON_ROLES.contains(role);
|
||||
}
|
||||
|
||||
public static boolean isKneconRole(String role) {
|
||||
|
||||
return KNECON_ROLES.contains(role);
|
||||
}
|
||||
|
||||
}
|
||||
@ -39,6 +39,7 @@ import com.knecon.fforesight.tenantusermanagement.model.ResetPasswordRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateMyProfileRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateProfileRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.User;
|
||||
import com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles;
|
||||
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
|
||||
|
||||
import io.micrometer.common.util.StringUtils;
|
||||
@ -78,7 +79,7 @@ public class UserService {
|
||||
|
||||
String username = StringUtils.isEmpty(user.getUsername()) ? user.getEmail() : user.getUsername();
|
||||
if (!this.getTenantUsersResource().search(username, true).isEmpty() || !this.getTenantUsersResource().searchByEmail(user.getEmail(), true).isEmpty()) {
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "User with this username or email address already exists");
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Requested username or email address not available");
|
||||
}
|
||||
|
||||
if (!EmailValidator.getInstance().isValid(user.getEmail())) {
|
||||
@ -165,9 +166,13 @@ public class UserService {
|
||||
|
||||
var currentUserRoles = this.getUserRoles(KeycloakSecurity.getUserId());
|
||||
|
||||
var userWithNewRoles = setRoles(userId, roles, currentUserRoles);
|
||||
if (!userId.equalsIgnoreCase(KeycloakSecurity.getUserId()) && roles.stream()
|
||||
.anyMatch(ApplicationRoles::isKneconRole) && currentUserRoles.stream()
|
||||
.noneMatch(ApplicationRoles::isKneconRole)) {
|
||||
throw new NotFoundException("User with id: " + userId + " does not exist");
|
||||
}
|
||||
|
||||
return userWithNewRoles;
|
||||
return setRoles(userId, roles, currentUserRoles);
|
||||
}
|
||||
|
||||
|
||||
@ -176,7 +181,9 @@ public class UserService {
|
||||
|
||||
var allRoles = tenantUserManagementProperties.getKcRoleMapping().getAllRoles();
|
||||
newRoles.forEach(role -> {
|
||||
if (!allRoles.contains(role)) {
|
||||
|
||||
if (!allRoles.contains(role) || ApplicationRoles.isKneconRole(role) && currentUserRoles.stream()
|
||||
.noneMatch(ApplicationRoles::isKneconRole)) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid role: " + role);
|
||||
}
|
||||
});
|
||||
@ -236,7 +243,7 @@ public class UserService {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot modify some roles for this user. Insufficient rights");
|
||||
}
|
||||
|
||||
if (userId.equals(KeycloakSecurity.getUserId()) && maxRank.equals(roleMapping.getMaxRank()) && !maxNewRolesRank.equals(maxRank)) {
|
||||
if (userId.equalsIgnoreCase(KeycloakSecurity.getUserId()) && maxRank.equals(roleMapping.getMaxRank()) && !maxNewRolesRank.equals(maxRank)) {
|
||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "Cannot remove highest ranking role from self.");
|
||||
}
|
||||
}
|
||||
@ -412,10 +419,12 @@ public class UserService {
|
||||
return;
|
||||
}
|
||||
|
||||
var executionValid = isExecutionRankValid(KeycloakSecurity.getUserId(), userId);
|
||||
var status = validateExecution(KeycloakSecurity.getUserId(), userId);
|
||||
|
||||
if (!executionValid) {
|
||||
if (status.equals(ValidationStatus.FORBIDDEN)) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "It is not allowed to delete a user with higher ranking roles");
|
||||
} else if (status.equals(ValidationStatus.INVALID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var userResource = getUserResource(userId);
|
||||
@ -434,6 +443,11 @@ public class UserService {
|
||||
var user = this.getUserResource(userId);
|
||||
var userRepresentation = user.toRepresentation();
|
||||
|
||||
if (getRoles(userId).stream()
|
||||
.anyMatch(ApplicationRoles::isKneconRole)) {
|
||||
throw new NotFoundException("User with id: " + userId + " does not exist");
|
||||
}
|
||||
|
||||
if (userRepresentation.getFederatedIdentities() != null && !userRepresentation.getFederatedIdentities().isEmpty() && !updateProfileRequest.getEmail()
|
||||
.equals(userRepresentation.getEmail())) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "It is not allowed to change the email from a federated identity");
|
||||
@ -462,10 +476,14 @@ public class UserService {
|
||||
|
||||
public User activateProfile(String userId, boolean isActive) {
|
||||
|
||||
var executionValid = isExecutionRankValid(KeycloakSecurity.getUserId(), userId);
|
||||
if (!userId.equalsIgnoreCase(KeycloakSecurity.getUserId())) {
|
||||
var status = validateExecution(KeycloakSecurity.getUserId(), userId);
|
||||
|
||||
if (!executionValid) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "It is not allowed to activate/deactivate a user with higher ranking roles");
|
||||
if (status.equals(ValidationStatus.FORBIDDEN)) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "It is not allowed to activate/deactivate a user with higher ranking roles");
|
||||
} else if (status.equals(ValidationStatus.INVALID)) {
|
||||
throw new NotFoundException("User with id: " + userId + " does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
var user = this.getUserResource(userId);
|
||||
@ -491,10 +509,14 @@ public class UserService {
|
||||
|
||||
public void resetPassword(String userId, ResetPasswordRequest resetPasswordRequest) {
|
||||
|
||||
var executionValid = isExecutionRankValid(KeycloakSecurity.getUserId(), userId);
|
||||
if (!userId.equalsIgnoreCase(KeycloakSecurity.getUserId())) {
|
||||
var status = validateExecution(KeycloakSecurity.getUserId(), userId);
|
||||
|
||||
if (!executionValid) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "It is not allowed to reset the password of a user with higher ranking roles");
|
||||
if (status.equals(ValidationStatus.FORBIDDEN)) {
|
||||
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "It is not allowed to reset the password of a user with higher ranking roles");
|
||||
} else if (status.equals(ValidationStatus.INVALID)) {
|
||||
throw new NotFoundException("User with id: " + userId + " does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
@ -542,13 +564,24 @@ public class UserService {
|
||||
}
|
||||
|
||||
|
||||
private boolean isExecutionRankValid(String executingUserId, String targetUserId) {
|
||||
private enum ValidationStatus {
|
||||
ALLOWED,
|
||||
FORBIDDEN,
|
||||
INVALID
|
||||
}
|
||||
|
||||
|
||||
private ValidationStatus validateExecution(String executingUserId, String targetUserId) {
|
||||
|
||||
var currentUserResource = getUserResource(executingUserId);
|
||||
var currentRoles = getRoles(currentUserResource.toRepresentation().getId());
|
||||
|
||||
var userRoles = getRoles(targetUserId);
|
||||
|
||||
if (currentRoles.stream()
|
||||
.anyMatch(ApplicationRoles::isKneconRole)) {
|
||||
return ValidationStatus.INVALID;
|
||||
}
|
||||
|
||||
var roleMapping = tenantUserManagementProperties.getKcRoleMapping();
|
||||
var maxRank = currentRoles.stream()
|
||||
.map(r -> roleMapping.getRole(r).getRank())
|
||||
@ -559,8 +592,11 @@ public class UserService {
|
||||
.max(Integer::compare)
|
||||
.orElse(-1);
|
||||
|
||||
return targetRank <= maxRank;
|
||||
|
||||
if (targetRank <= maxRank) {
|
||||
return ValidationStatus.ALLOWED;
|
||||
} else {
|
||||
return ValidationStatus.FORBIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -30,6 +30,44 @@ fforesight:
|
||||
- 'fforesight-write-smtp-configuration'
|
||||
- 'fforesight-read-identity-provider-config'
|
||||
- 'fforesight-write-identity-provider-config'
|
||||
- name: KNECON_ADMIN
|
||||
set-by-default: true
|
||||
rank: 1000
|
||||
permissions:
|
||||
- 'fforesight-read-general-configuration'
|
||||
- 'fforesight-write-general-configuration'
|
||||
- 'fforesight-manage-user-preferences'
|
||||
- 'fforesight-read-users'
|
||||
- 'fforesight-read-all-users'
|
||||
- 'fforesight-write-users'
|
||||
- 'fforesight-update-my-profile'
|
||||
- 'fforesight-create-tenant'
|
||||
- 'fforesight-get-tenants'
|
||||
- 'fforesight-update-tenant'
|
||||
- 'fforesight-deployment-info'
|
||||
- 'fforesight-read-smtp-configuration'
|
||||
- 'fforesight-write-smtp-configuration'
|
||||
- 'fforesight-read-identity-provider-config'
|
||||
- 'fforesight-write-identity-provider-config'
|
||||
- name: KNECON_SUPPORT
|
||||
set-by-default: true
|
||||
rank: 1000
|
||||
permissions:
|
||||
- 'fforesight-read-general-configuration'
|
||||
- 'fforesight-write-general-configuration'
|
||||
- 'fforesight-manage-user-preferences'
|
||||
- 'fforesight-read-users'
|
||||
- 'fforesight-read-all-users'
|
||||
- 'fforesight-write-users'
|
||||
- 'fforesight-update-my-profile'
|
||||
- 'fforesight-create-tenant'
|
||||
- 'fforesight-get-tenants'
|
||||
- 'fforesight-update-tenant'
|
||||
- 'fforesight-deployment-info'
|
||||
- 'fforesight-read-smtp-configuration'
|
||||
- 'fforesight-write-smtp-configuration'
|
||||
- 'fforesight-read-identity-provider-config'
|
||||
- 'fforesight-write-identity-provider-config'
|
||||
application-name: "redaction"
|
||||
springdoc:
|
||||
auth-server-url: http://localhost:8080
|
||||
|
||||
@ -10,6 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -21,6 +22,8 @@ import com.knecon.fforesight.tenantusermanagement.model.CreateUserRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.ResetPasswordRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateMyProfileRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.UpdateProfileRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.User;
|
||||
import com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles;
|
||||
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
|
||||
|
||||
import feign.FeignException;
|
||||
@ -42,33 +45,41 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
||||
tokenService.setUser("test@fforesight.com", "secret");
|
||||
|
||||
var allUsers = userClient.getAllUsers(true);
|
||||
var testUserFound = allUsers.stream().anyMatch(u -> u.getEmail().equalsIgnoreCase("test@fforesight.com"));
|
||||
var testUserFound = allUsers.stream()
|
||||
.anyMatch(u -> u.getEmail().equalsIgnoreCase("test@fforesight.com"));
|
||||
assertThat(allUsers).isNotEmpty();
|
||||
assertThat(testUserFound).isTrue();
|
||||
|
||||
allUsers = userClient.getApplicationSpecificUsers(true);
|
||||
testUserFound = allUsers.stream().anyMatch(u -> u.getEmail().equalsIgnoreCase("test@fforesight.com"));
|
||||
testUserFound = allUsers.stream()
|
||||
.anyMatch(u -> u.getEmail().equalsIgnoreCase("test@fforesight.com"));
|
||||
assertThat(allUsers).isNotEmpty();
|
||||
assertThat(testUserFound).isTrue();
|
||||
|
||||
var testUserId = allUsers.iterator().next().getUserId();
|
||||
var testUser = userClient.getUserById(testUserId);
|
||||
var optionalUser = allUsers.stream().filter(user -> user.getUsername().equalsIgnoreCase("test@fforesight.com")).findFirst();
|
||||
assert(optionalUser.isPresent());
|
||||
var testUser = userClient.getUserById(optionalUser.get().getUserId());
|
||||
assertThat(testUser).isNotNull();
|
||||
|
||||
testUser = userClient.updateMyProfile(UpdateMyProfileRequest.builder()
|
||||
.email("test@fforesight.com")
|
||||
.firstName("updateTestFirstName")
|
||||
.lastName("updateTestLastName")
|
||||
.build());
|
||||
.email("test@fforesight.com")
|
||||
.firstName("updateTestFirstName")
|
||||
.lastName("updateTestLastName")
|
||||
.build());
|
||||
assertThat(testUser.getLastName()).isEqualTo("updateTestLastName");
|
||||
assertThat(testUser.getFirstName()).isEqualTo("updateTestFirstName");
|
||||
|
||||
|
||||
Set<String> allButKneconRoles = tenantUserManagementProperties.getKcRoleMapping().getAllRoles().stream()
|
||||
.filter(ApplicationRoles::isNoKneconRole)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
CreateUserRequest createUserRequest = new CreateUserRequest();
|
||||
createUserRequest.setEmail("test.new.user@knecon.com");
|
||||
createUserRequest.setFirstName("Test");
|
||||
createUserRequest.setLastName("New User");
|
||||
createUserRequest.setUsername(createUserRequest.getEmail());
|
||||
createUserRequest.setRoles(tenantUserManagementProperties.getKcRoleMapping().getAllRoles());
|
||||
createUserRequest.setRoles(allButKneconRoles);
|
||||
var createdUser = userClient.createUser(createUserRequest);
|
||||
|
||||
allUsers = userClient.getAllUsers(true);
|
||||
@ -84,13 +95,14 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
||||
assertThat(createdUser.getRoles()).isEmpty();
|
||||
|
||||
createdUser = userClient.updateProfile(createdUser.getUserId(),
|
||||
UpdateProfileRequest.builder()
|
||||
.email("test.new.user@knecon.com")
|
||||
.firstName("update test")
|
||||
.lastName("update test")
|
||||
.roles(tenantUserManagementProperties.getKcRoleMapping().getAllRoles())
|
||||
.build());
|
||||
assertThat(createdUser.getRoles()).containsExactly(tenantUserManagementProperties.getKcRoleMapping().getAllRoles().toArray(new String[0]));
|
||||
UpdateProfileRequest.builder()
|
||||
.email("test.new.user@knecon.com")
|
||||
.firstName("update test")
|
||||
.lastName("update test")
|
||||
.roles(allButKneconRoles)
|
||||
.build());
|
||||
assertThat(createdUser.getRoles()).containsExactly(allButKneconRoles
|
||||
.toArray(new String[0]));
|
||||
|
||||
userClient.deleteUsers(List.of(createdUser.getUserId()));
|
||||
|
||||
@ -133,7 +145,10 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
||||
userClient.resetPassword(createdUser2.getUserId(), ResetPasswordRequest.builder().password("Secret@secured!2345").build());
|
||||
|
||||
var allUsers = userClient.getAllUsers(true);
|
||||
var initialSuperUser = allUsers.stream().filter(u -> u.getEmail().equalsIgnoreCase("test@fforesight.com")).findAny().get();
|
||||
var initialSuperUser = allUsers.stream()
|
||||
.filter(u -> u.getEmail().equalsIgnoreCase("test@fforesight.com"))
|
||||
.findAny()
|
||||
.get();
|
||||
try {
|
||||
//reset password as less-super-user for super-user
|
||||
userClient.resetPassword(initialSuperUser.getUserId(), ResetPasswordRequest.builder().password("ShouldNotWork@123").build());
|
||||
@ -223,6 +238,7 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
||||
TenantContext.clear();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
public void testActivateUserWithSameRole() {
|
||||
@ -283,13 +299,16 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
||||
public void testCreateUserWithExistingUser() {
|
||||
|
||||
TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID);
|
||||
Set<String> allButKneconRoles = tenantUserManagementProperties.getKcRoleMapping().getAllRoles().stream()
|
||||
.filter(ApplicationRoles::isNoKneconRole)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
var createUserRequest = new CreateUserRequest();
|
||||
createUserRequest.setEmail("existinguser@knecon.com");
|
||||
createUserRequest.setFirstName("Existing");
|
||||
createUserRequest.setLastName("User");
|
||||
createUserRequest.setUsername("ExistingUser");
|
||||
createUserRequest.setRoles(tenantUserManagementProperties.getKcRoleMapping().getAllRoles());
|
||||
createUserRequest.setRoles(allButKneconRoles);
|
||||
userClient.createUser(createUserRequest);
|
||||
|
||||
var createUserRequest2 = new CreateUserRequest();
|
||||
@ -297,46 +316,187 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
|
||||
createUserRequest2.setFirstName("New");
|
||||
createUserRequest2.setLastName("User");
|
||||
createUserRequest2.setUsername("NewUser");
|
||||
createUserRequest2.setRoles(tenantUserManagementProperties.getKcRoleMapping().getAllRoles());
|
||||
createUserRequest2.setRoles(allButKneconRoles);
|
||||
|
||||
FeignException e = assertThrows(FeignException.class, () -> userClient.createUser(createUserRequest2));
|
||||
assertEquals(409, e.status());
|
||||
assertEquals(400, e.status());
|
||||
|
||||
var createUserRequest3 = new CreateUserRequest();
|
||||
createUserRequest3.setEmail("newuser@knecon.com");
|
||||
createUserRequest3.setFirstName("New");
|
||||
createUserRequest3.setLastName("User");
|
||||
createUserRequest3.setUsername("ExistingUser");
|
||||
createUserRequest3.setRoles(tenantUserManagementProperties.getKcRoleMapping().getAllRoles());
|
||||
createUserRequest3.setRoles(allButKneconRoles);
|
||||
|
||||
e = assertThrows(FeignException.class, () -> userClient.createUser(createUserRequest3));
|
||||
assertEquals(409, e.status());
|
||||
assertEquals(400, e.status());
|
||||
|
||||
var createUserRequest4 = new CreateUserRequest();
|
||||
createUserRequest4.setEmail("existinguser@knecon.com");
|
||||
createUserRequest4.setFirstName("New");
|
||||
createUserRequest4.setLastName("User");
|
||||
createUserRequest4.setUsername("ExistingUser");
|
||||
createUserRequest4.setRoles(tenantUserManagementProperties.getKcRoleMapping().getAllRoles());
|
||||
createUserRequest4.setRoles(allButKneconRoles);
|
||||
|
||||
e = assertThrows(FeignException.class, () -> userClient.createUser(createUserRequest4));
|
||||
assertEquals(409, e.status());
|
||||
assertEquals(400, e.status());
|
||||
|
||||
var createUserRequest5 = new CreateUserRequest();
|
||||
createUserRequest5.setEmail("anotherexistinguser@knecon.com");
|
||||
createUserRequest5.setFirstName("Another existing");
|
||||
createUserRequest5.setLastName("User");
|
||||
createUserRequest5.setRoles(tenantUserManagementProperties.getKcRoleMapping().getAllRoles());
|
||||
createUserRequest5.setRoles(allButKneconRoles);
|
||||
userClient.createUser(createUserRequest5);
|
||||
|
||||
var createUserRequest6 = new CreateUserRequest();
|
||||
createUserRequest6.setEmail("anotherexistinguser@knecon.com");
|
||||
createUserRequest6.setFirstName("Another new");
|
||||
createUserRequest6.setLastName("User");
|
||||
createUserRequest6.setRoles(tenantUserManagementProperties.getKcRoleMapping().getAllRoles());
|
||||
createUserRequest6.setRoles(allButKneconRoles);
|
||||
|
||||
e = assertThrows(FeignException.class, () -> userClient.createUser(createUserRequest6));
|
||||
assertEquals(409, e.status());
|
||||
assertEquals(400, e.status());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testHiddenKneconRoles() {
|
||||
|
||||
// set context and user
|
||||
TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID);
|
||||
tokenService.setUser("admin@knecon.com", "secret");
|
||||
|
||||
// different role sets and subsets
|
||||
var allRoles = tenantUserManagementProperties.getKcRoleMapping().getAllRoles();
|
||||
Set<String> allButKneconRoles = allRoles.stream()
|
||||
.filter(ApplicationRoles::isNoKneconRole)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<String> onlyKneconRoles = allRoles.stream()
|
||||
.filter(ApplicationRoles::isKneconRole)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
var sizeBefore = userClient.getAllUsers(true).size();
|
||||
|
||||
// create several users with different roles for testing
|
||||
var createUserRequest = new CreateUserRequest();
|
||||
createUserRequest.setEmail("allroles@knecon.com");
|
||||
createUserRequest.setFirstName("All");
|
||||
createUserRequest.setLastName("Roles");
|
||||
createUserRequest.setUsername("AllRoles");
|
||||
createUserRequest.setRoles(allRoles);
|
||||
User user = userClient.createUser(createUserRequest);
|
||||
|
||||
var createUserRequest2 = new CreateUserRequest();
|
||||
createUserRequest2.setEmail("nokneconroles@notknecon.com");
|
||||
createUserRequest2.setFirstName("No Knecon");
|
||||
createUserRequest2.setLastName("Roles");
|
||||
createUserRequest2.setUsername("NoKneconRoles");
|
||||
createUserRequest2.setRoles(allButKneconRoles);
|
||||
User noKneconUser = userClient.createUser(createUserRequest2);
|
||||
|
||||
var createUserRequest3 = new CreateUserRequest();
|
||||
createUserRequest3.setEmail("onlykneconroles@notknecon.com");
|
||||
createUserRequest3.setFirstName("Only Knecon");
|
||||
createUserRequest3.setLastName("Roles");
|
||||
createUserRequest3.setUsername("OnlyKneconRoles");
|
||||
createUserRequest3.setRoles(onlyKneconRoles);
|
||||
User onlyKneconUser = userClient.createUser(createUserRequest3);
|
||||
|
||||
var allUsers = userClient.getAllUsers(true);
|
||||
// one role is completely hidden
|
||||
assertEquals(allUsers.size(), sizeBefore + 2);
|
||||
|
||||
// no knecon roles are visible
|
||||
assertEquals(allUsers.stream().filter(u -> u.getRoles().stream().anyMatch(ApplicationRoles::isKneconRole)).count(), 0);
|
||||
|
||||
// we can get this user because of other roles being present
|
||||
userClient.getUserById(noKneconUser.getUserId());
|
||||
|
||||
// but not this one as he only has knecon roles
|
||||
var e = assertThrows(FeignException.class, () -> userClient.getUserById(onlyKneconUser.getUserId()));
|
||||
assertEquals(404, e.status());
|
||||
|
||||
// switch token to the user without knecon roles
|
||||
tokenService.setUser("test@fforesight.com", "secret");
|
||||
|
||||
// create another dummy user with only SUPER_USER
|
||||
var redUserAdminUserRequest = new CreateUserRequest();
|
||||
redUserAdminUserRequest.setEmail("red-user-admin@knecon.com");
|
||||
redUserAdminUserRequest.setUsername(redUserAdminUserRequest.getEmail());
|
||||
redUserAdminUserRequest.setRoles(Set.of("SUPER_USER"));
|
||||
var redUserAdmin = userClient.createUser(redUserAdminUserRequest);
|
||||
|
||||
// reset password for authentication
|
||||
userClient.resetPassword(redUserAdmin.getUserId(), ResetPasswordRequest.builder().password("Secret@secured!23").build());
|
||||
|
||||
// authenticate with the newly created user
|
||||
tokenService.setUser("red-user-admin@knecon.com", "Secret@secured!23");
|
||||
|
||||
// we should not be able to set roles of this user at all as it is not visible to us resulting in a 404
|
||||
e = assertThrows(FeignException.class, () -> userClient.setRoles(user.getUserId(), onlyKneconRoles));
|
||||
assertEquals(404, e.status());
|
||||
|
||||
// we should not be able to assign ourselves a knecon role as it is not visible to us
|
||||
e = assertThrows(FeignException.class, () -> userClient.setRoles(redUserAdmin.getUserId(), allRoles));
|
||||
assertEquals(400, e.status());
|
||||
|
||||
// authenticate as knecon admin again
|
||||
tokenService.setUser("admin@knecon.com", "secret");
|
||||
|
||||
// this should be possible because we now have knecon roles
|
||||
userClient.setRoles(onlyKneconUser.getUserId(), allRoles);
|
||||
assertEquals(userClient.getUserById(onlyKneconUser.getUserId()).getRoles().size(), 2);
|
||||
|
||||
// and this as well
|
||||
userClient.setRoles(user.getUserId(), allRoles);
|
||||
|
||||
// we can also poll the user
|
||||
userClient.getUserById(user.getUserId());
|
||||
|
||||
// back to having no rights
|
||||
tokenService.setUser("red-user-admin@knecon.com", "Secret@secured!23");
|
||||
|
||||
// we can not call update profile
|
||||
e = assertThrows(FeignException.class, () -> userClient.updateProfile(user.getUserId(), new UpdateProfileRequest()));
|
||||
assertEquals(404, e.status());
|
||||
|
||||
// or reset password as it is forbidden (higher rights)
|
||||
e = assertThrows(FeignException.class, () -> userClient.resetPassword(user.getUserId(), new ResetPasswordRequest()));
|
||||
assertEquals(403, e.status());
|
||||
|
||||
// now as a knecon admin again
|
||||
tokenService.setUser("admin@knecon.com", "secret");
|
||||
|
||||
// we can also not see another knecon account and change their password
|
||||
e = assertThrows(FeignException.class, () -> userClient.resetPassword(user.getUserId(), new ResetPasswordRequest()));
|
||||
assertEquals(404, e.status());
|
||||
|
||||
// or activate the profile
|
||||
e = assertThrows(FeignException.class, () -> userClient.activateProfile(user.getUserId(), true));
|
||||
assertEquals(404, e.status());
|
||||
|
||||
// we create a new user with all roles
|
||||
var createUserRequest4 = new CreateUserRequest();
|
||||
createUserRequest4.setEmail("allroles2@knecon.com");
|
||||
createUserRequest4.setFirstName("All");
|
||||
createUserRequest4.setLastName("Roles2");
|
||||
createUserRequest4.setUsername("AllRoles2");
|
||||
createUserRequest4.setRoles(allRoles);
|
||||
User user4 = userClient.createUser(createUserRequest4);
|
||||
|
||||
// we attempt to delete it
|
||||
userClient.deleteUser(user4.getUserId());
|
||||
|
||||
// and again using the bulk call
|
||||
userClient.deleteUsers(List.of(user4.getUserId()));
|
||||
|
||||
// user should still be present despite deletes as it as a knecon user
|
||||
assertEquals(allUsers.size(), sizeBefore + 2);
|
||||
// and should not have changed
|
||||
var user5 = userClient.getUserById(user4.getUserId());
|
||||
assertEquals(user4, user5);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import com.knecon.fforesight.tenantusermanagement.api.internal.InternalTenantsRe
|
||||
import com.knecon.fforesight.tenantusermanagement.model.SearchConnectionRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantRequest;
|
||||
import com.knecon.fforesight.tenantusermanagement.model.TenantUser;
|
||||
import com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles;
|
||||
import com.knecon.fforesight.tenantusermanagement.testcontainers.MongoDBTestContainer;
|
||||
import com.knecon.fforesight.tenantusermanagement.testcontainers.SpringPostgreSQLTestContainer;
|
||||
|
||||
@ -57,7 +58,18 @@ public class TestTenantService {
|
||||
.tenantId(testTenantId)
|
||||
.displayName(testTenantId)
|
||||
.guid(UUID.randomUUID().toString())
|
||||
.defaultUsers(List.of(TenantUser.builder().roles(Set.of("SUPER_USER")).username("test@fforesight.com").password("secret").email("test@fforesight.com").build()))
|
||||
.defaultUsers(List.of(TenantUser.builder()
|
||||
.roles(Set.of("SUPER_USER"))
|
||||
.username("test@fforesight.com")
|
||||
.password("secret")
|
||||
.email("test@fforesight.com")
|
||||
.build(),
|
||||
TenantUser.builder()
|
||||
.roles(Set.of(ApplicationRoles.KNECON_ADMIN_ROLE, ApplicationRoles.KNECON_SUPPORT_ROLE))
|
||||
.username("admin@knecon.com")
|
||||
.password("secret")
|
||||
.email("admin@knecon.com")
|
||||
.build()))
|
||||
.databaseConnection(DatabaseConnection.builder()
|
||||
.driver("postgresql")
|
||||
.host(SpringPostgreSQLTestContainer.getInstance().getHost())
|
||||
|
||||
@ -144,6 +144,44 @@ fforesight:
|
||||
- 'fforesight-write-smtp-configuration'
|
||||
- 'fforesight-read-identity-provider-config'
|
||||
- 'fforesight-write-identity-provider-config'
|
||||
- name: KNECON_ADMIN
|
||||
set-by-default: true
|
||||
rank: 1000
|
||||
permissions:
|
||||
- 'fforesight-read-general-configuration'
|
||||
- 'fforesight-write-general-configuration'
|
||||
- 'fforesight-manage-user-preferences'
|
||||
- 'fforesight-read-users'
|
||||
- 'fforesight-read-all-users'
|
||||
- 'fforesight-write-users'
|
||||
- 'fforesight-update-my-profile'
|
||||
- 'fforesight-create-tenant'
|
||||
- 'fforesight-get-tenants'
|
||||
- 'fforesight-update-tenant'
|
||||
- 'fforesight-deployment-info'
|
||||
- 'fforesight-read-smtp-configuration'
|
||||
- 'fforesight-write-smtp-configuration'
|
||||
- 'fforesight-read-identity-provider-config'
|
||||
- 'fforesight-write-identity-provider-config'
|
||||
- name: KNECON_SUPPORT
|
||||
set-by-default: true
|
||||
rank: 1000
|
||||
permissions:
|
||||
- 'fforesight-read-general-configuration'
|
||||
- 'fforesight-write-general-configuration'
|
||||
- 'fforesight-manage-user-preferences'
|
||||
- 'fforesight-read-users'
|
||||
- 'fforesight-read-all-users'
|
||||
- 'fforesight-write-users'
|
||||
- 'fforesight-update-my-profile'
|
||||
- 'fforesight-create-tenant'
|
||||
- 'fforesight-get-tenants'
|
||||
- 'fforesight-update-tenant'
|
||||
- 'fforesight-deployment-info'
|
||||
- 'fforesight-read-smtp-configuration'
|
||||
- 'fforesight-write-smtp-configuration'
|
||||
- 'fforesight-read-identity-provider-config'
|
||||
- 'fforesight-write-identity-provider-config'
|
||||
access-token-life-span: 86400
|
||||
application-name: tenant-user-management
|
||||
application-client-id: tenant-user-management
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user