diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/ResetPasswordRequest.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/ResetPasswordRequest.java index 6b199ef..9148fd0 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/model/ResetPasswordRequest.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/model/ResetPasswordRequest.java @@ -1,9 +1,15 @@ package com.knecon.fforesight.tenantusermanagement.model; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@NoArgsConstructor +@AllArgsConstructor +@Builder @Schema(description = "Object containing the request to reset a password.") public class ResetPasswordRequest { diff --git a/src/main/java/com/knecon/fforesight/tenantusermanagement/service/UserService.java b/src/main/java/com/knecon/fforesight/tenantusermanagement/service/UserService.java index 799fd2a..bed48df 100644 --- a/src/main/java/com/knecon/fforesight/tenantusermanagement/service/UserService.java +++ b/src/main/java/com/knecon/fforesight/tenantusermanagement/service/UserService.java @@ -14,16 +14,6 @@ import javax.ws.rs.NotAuthorizedException; import javax.ws.rs.NotFoundException; import javax.ws.rs.core.Response; -import org.apache.commons.validator.routines.EmailValidator; -import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; -import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; -import org.keycloak.OAuth2Constants; -import org.keycloak.admin.client.KeycloakBuilder; -import org.keycloak.admin.client.resource.UserResource; -import org.keycloak.admin.client.resource.UsersResource; -import org.keycloak.representations.idm.CredentialRepresentation; -import org.keycloak.representations.idm.RoleRepresentation; -import org.keycloak.representations.idm.UserRepresentation; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.CacheEvict; @@ -46,10 +36,19 @@ 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.properties.TenantUserManagementProperties; - import io.micrometer.common.util.StringUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.validator.routines.EmailValidator; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; +import org.keycloak.OAuth2Constants; +import org.keycloak.admin.client.KeycloakBuilder; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.admin.client.resource.UsersResource; +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.UserRepresentation; @Slf4j @Service @@ -127,16 +126,6 @@ public class UserService { } - private void sendResetPasswordEmail(String userId) { - - try { - this.getTenantUsersResource().get(userId).executeActionsEmail(Collections.singletonList("UPDATE_PASSWORD"), 86400); - } catch (Exception e) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to send email.", e); - } - } - - @CacheEvict(value = "${commons.keycloak.userCache}", allEntries = true, beforeInvocation = true) public User setRoles(String userId, Set newRoles, Set currentUserRoles) { @@ -200,31 +189,12 @@ public class UserService { } - private RoleRepresentation getRoleRepresentation(String role) { - - RoleRepresentation realmRole; - try { - realmRole = realmService.realm(TenantContext.getTenantId()).roles().get(role).toRepresentation(); - } catch (NotFoundException e) { - log.warn("The realm role {} is not found.", role); - throw new NotFoundException("The realm role " + role + " is not found.", e); - } - return realmRole; - } - - public Optional getUserById(String userId) { return userListingService.getAllUsers(TenantContext.getTenantId()).stream().filter(u -> u.getUserId().equalsIgnoreCase(userId)).findAny(); } - public List getUsersByIds(Collection userIds) { - - return userListingService.getAllUsers(TenantContext.getTenantId()).stream().filter(u -> userIds.contains(u.getUserId())).collect(Collectors.toList()); - } - - @CacheEvict(value = "${commons.keycloak.userCache}", allEntries = true, beforeInvocation = true) public User updateMyProfile(UpdateMyProfileRequest updateProfileRequest) { @@ -366,20 +336,14 @@ public class UserService { throw new ResponseStatusException(HttpStatus.CONFLICT, "Cannot delete self"); } - var currentUserResource = getUserResource(KeycloakSecurity.getUserId()); - var currentRoles = getRoles(currentUserResource.toRepresentation().getId()); + var executionValid = isExecutionRankValid(KeycloakSecurity.getUserId(), userId); - var userResource = getUserResource(userId); - var userRoles = getRoles(userId); - - var roleMapping = tenantUserManagementProperties.getKcRoleMapping(); - var maxRank = currentRoles.stream().map(r -> roleMapping.getRole(r).getRank()).max(Integer::compare).orElse(-1); - var toDeleteUserMaxRank = userRoles.stream().map(r -> roleMapping.getRole(r).getRank()).max(Integer::compare).orElse(-1); - - if (toDeleteUserMaxRank > maxRank) { + if (!executionValid) { throw new ResponseStatusException(HttpStatus.FORBIDDEN, "It is not allowed to delete a user with higher ranking roles"); } + var userResource = getUserResource(userId); + var userToBeRemoved = getUserByUsername(userResource.toRepresentation().getUsername()); userResource.remove(); @@ -443,12 +407,19 @@ public class UserService { public void resetPassword(String userId, ResetPasswordRequest resetPasswordRequest) { + var executionValid = isExecutionRankValid(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"); + } + try { CredentialRepresentation request = new CredentialRepresentation(); request.setType(CredentialRepresentation.PASSWORD); request.setTemporary(resetPasswordRequest.isTemporary()); request.setValue(resetPasswordRequest.getPassword()); realmService.realm(TenantContext.getTenantId()).users().get(userId).resetPassword(request); + log.info("User {} resetted password for user {}", KeycloakSecurity.getUserId(), userId); } catch (Exception e) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Could not reset password. It does not match the password policy.", e); } @@ -460,4 +431,43 @@ public class UserService { return userListingService.getAllUsers(TenantContext.getTenantId()); } + + private RoleRepresentation getRoleRepresentation(String role) { + + RoleRepresentation realmRole; + try { + realmRole = realmService.realm(TenantContext.getTenantId()).roles().get(role).toRepresentation(); + } catch (NotFoundException e) { + log.warn("The realm role {} is not found.", role); + throw new NotFoundException("The realm role " + role + " is not found.", e); + } + return realmRole; + } + + + private void sendResetPasswordEmail(String userId) { + + try { + this.getTenantUsersResource().get(userId).executeActionsEmail(Collections.singletonList("UPDATE_PASSWORD"), 86400); + } catch (Exception e) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Failed to send email.", e); + } + } + + + private boolean isExecutionRankValid(String executingUserId, String targetUserId) { + + var currentUserResource = getUserResource(executingUserId); + var currentRoles = getRoles(currentUserResource.toRepresentation().getId()); + + var userRoles = getRoles(targetUserId); + + var roleMapping = tenantUserManagementProperties.getKcRoleMapping(); + var maxRank = currentRoles.stream().map(r -> roleMapping.getRole(r).getRank()).max(Integer::compare).orElse(-1); + var targetRank = userRoles.stream().map(r -> roleMapping.getRole(r).getRank()).max(Integer::compare).orElse(-1); + + return targetRank <= maxRank; + + } + } diff --git a/src/test/java/com/knecon/fforesight/AbstractTenantUserManagementIntegrationTest.java b/src/test/java/com/knecon/fforesight/AbstractTenantUserManagementIntegrationTest.java index 74f1827..8280b82 100644 --- a/src/test/java/com/knecon/fforesight/AbstractTenantUserManagementIntegrationTest.java +++ b/src/test/java/com/knecon/fforesight/AbstractTenantUserManagementIntegrationTest.java @@ -1,7 +1,5 @@ package com.knecon.fforesight; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -17,7 +15,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.testcontainers.containers.GenericContainer; import com.knecon.fforesight.feigntestclients.external.TenantsClient; import com.knecon.fforesight.feigntestclients.internal.InternalTenantsClient; @@ -27,9 +24,11 @@ import com.knecon.fforesight.testcontainers.MinioTestContainer; import com.knecon.fforesight.testcontainers.RedisTestContainer; import com.knecon.fforesight.testcontainers.SpringPostgreSQLTestContainer; import com.knecon.fforesight.utils.TestTenantService; - +import com.knecon.fforesight.utils.TokenService; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(SpringExtension.class) @EnableFeignClients(basePackageClasses = {TenantsClient.class, InternalTenantsClient.class}) @@ -38,17 +37,14 @@ import lombok.extern.slf4j.Slf4j; @SpringBootTest(classes = TenantUserManagementServiceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) public class AbstractTenantUserManagementIntegrationTest { + public final static String TEST_TENANT_ID = "test-tenant-fforesight"; + public static int minioPort; @MockBean protected RabbitTemplate rabbitTemplate; - @Autowired protected TestTenantService testTenantService; - - public final static String TEST_TENANT_ID = "test-tenant-fforesight"; - - private static GenericContainer minioServer; - - public static int minioPort; + @Autowired + protected TokenService tokenService; @BeforeEach diff --git a/src/test/java/com/knecon/fforesight/feigntestclients/external/GeneralSettingsClient.java b/src/test/java/com/knecon/fforesight/feigntestclients/external/GeneralSettingsClient.java index 8e86ee5..da41a0b 100644 --- a/src/test/java/com/knecon/fforesight/feigntestclients/external/GeneralSettingsClient.java +++ b/src/test/java/com/knecon/fforesight/feigntestclients/external/GeneralSettingsClient.java @@ -4,7 +4,7 @@ import org.springframework.cloud.openfeign.FeignClient; import com.knecon.fforesight.tenantusermanagement.api.external.GeneralSettingsResource; -@FeignClient(name = "GeneralSettingsClient", url = "http://localhost:${server.port}" ,path = "${fforesight.tenant-user-management.base-path:}") +@FeignClient(name = "GeneralSettingsClient", url = "http://localhost:${server.port}", path = "${fforesight.tenant-user-management.base-path:}") public interface GeneralSettingsClient extends GeneralSettingsResource { } diff --git a/src/test/java/com/knecon/fforesight/feigntestclients/external/SMTPConfigurationClient.java b/src/test/java/com/knecon/fforesight/feigntestclients/external/SMTPConfigurationClient.java index e950fe4..b312e31 100644 --- a/src/test/java/com/knecon/fforesight/feigntestclients/external/SMTPConfigurationClient.java +++ b/src/test/java/com/knecon/fforesight/feigntestclients/external/SMTPConfigurationClient.java @@ -4,7 +4,7 @@ import org.springframework.cloud.openfeign.FeignClient; import com.knecon.fforesight.tenantusermanagement.api.external.SMTPConfigurationResource; -@FeignClient(name = "SMTPConfigurationClient", url = "http://localhost:${server.port}",path = "${fforesight.tenant-user-management.base-path:}") +@FeignClient(name = "SMTPConfigurationClient", url = "http://localhost:${server.port}", path = "${fforesight.tenant-user-management.base-path:}") public interface SMTPConfigurationClient extends SMTPConfigurationResource { } diff --git a/src/test/java/com/knecon/fforesight/feigntestclients/external/TenantsClient.java b/src/test/java/com/knecon/fforesight/feigntestclients/external/TenantsClient.java index 72bf207..aabd6c8 100644 --- a/src/test/java/com/knecon/fforesight/feigntestclients/external/TenantsClient.java +++ b/src/test/java/com/knecon/fforesight/feigntestclients/external/TenantsClient.java @@ -4,7 +4,7 @@ import org.springframework.cloud.openfeign.FeignClient; import com.knecon.fforesight.tenantusermanagement.api.external.TenantsResource; -@FeignClient(name = "TenantsClient", url = "http://localhost:${server.port}",path = "${fforesight.tenant-user-management.base-path:}") +@FeignClient(name = "TenantsClient", url = "http://localhost:${server.port}", path = "${fforesight.tenant-user-management.base-path:}") public interface TenantsClient extends TenantsResource { } diff --git a/src/test/java/com/knecon/fforesight/feigntestclients/external/UserClient.java b/src/test/java/com/knecon/fforesight/feigntestclients/external/UserClient.java index 8f3b617..90d2cc0 100644 --- a/src/test/java/com/knecon/fforesight/feigntestclients/external/UserClient.java +++ b/src/test/java/com/knecon/fforesight/feigntestclients/external/UserClient.java @@ -4,7 +4,7 @@ import org.springframework.cloud.openfeign.FeignClient; import com.knecon.fforesight.tenantusermanagement.api.external.UserResource; -@FeignClient(name = "UserClient", url = "http://localhost:${server.port}",path = "${fforesight.tenant-user-management.base-path:}") +@FeignClient(name = "UserClient", url = "http://localhost:${server.port}", path = "${fforesight.tenant-user-management.base-path:}") public interface UserClient extends UserResource { } diff --git a/src/test/java/com/knecon/fforesight/testcontainers/KeyCloakTestContainer.java b/src/test/java/com/knecon/fforesight/testcontainers/KeyCloakTestContainer.java index 5b3f097..8a06122 100644 --- a/src/test/java/com/knecon/fforesight/testcontainers/KeyCloakTestContainer.java +++ b/src/test/java/com/knecon/fforesight/testcontainers/KeyCloakTestContainer.java @@ -3,13 +3,12 @@ package com.knecon.fforesight.testcontainers; import java.util.ArrayList; import java.util.List; +import dasniko.testcontainers.keycloak.KeycloakContainer; import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.UserResource; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.RoleRepresentation; -import dasniko.testcontainers.keycloak.KeycloakContainer; - public final class KeyCloakTestContainer { private static final String IMAGE_VERSION = "quay.io/keycloak/keycloak:21.0.0"; diff --git a/src/test/java/com/knecon/fforesight/testcontainers/MinioTestContainer.java b/src/test/java/com/knecon/fforesight/testcontainers/MinioTestContainer.java index fc9e082..841d93d 100644 --- a/src/test/java/com/knecon/fforesight/testcontainers/MinioTestContainer.java +++ b/src/test/java/com/knecon/fforesight/testcontainers/MinioTestContainer.java @@ -8,6 +8,7 @@ public final class MinioTestContainer extends GenericContainer smtpConfigurationClient.testSMTPConfiguration(smtpConfiguration)).hasMessageContaining("Couldn't connect to host, port: test.knecon.com, 25; timeout 10000"); - - TenantContext.clear(); - } private SMTPConfiguration provideTestSMTPConfiguration() { @@ -70,4 +59,17 @@ public class SMTPConfigurationTest extends AbstractTenantUserManagementIntegrati } + @Test + public void testSMTPConnection() { + + TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID); + + SMTPConfiguration smtpConfiguration = provideTestSMTPConfiguration(); + + assertThatThrownBy(() -> smtpConfigurationClient.testSMTPConfiguration(smtpConfiguration)).hasMessageContaining( + "Couldn't connect to host, port: test.knecon.com, 25; timeout 10000"); + + TenantContext.clear(); + } + } diff --git a/src/test/java/com/knecon/fforesight/tests/StartupTest.java b/src/test/java/com/knecon/fforesight/tests/StartupTest.java index 7981de0..6c4a4a9 100644 --- a/src/test/java/com/knecon/fforesight/tests/StartupTest.java +++ b/src/test/java/com/knecon/fforesight/tests/StartupTest.java @@ -2,11 +2,11 @@ package com.knecon.fforesight.tests; import static org.assertj.core.api.Assertions.assertThat; -import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import com.knecon.fforesight.AbstractTenantUserManagementIntegrationTest; import com.knecon.fforesight.feigntestclients.internal.InternalTenantsClient; +import org.junit.jupiter.api.Test; public class StartupTest extends AbstractTenantUserManagementIntegrationTest { diff --git a/src/test/java/com/knecon/fforesight/tests/TenantsTest.java b/src/test/java/com/knecon/fforesight/tests/TenantsTest.java index caac7b9..0e0040c 100644 --- a/src/test/java/com/knecon/fforesight/tests/TenantsTest.java +++ b/src/test/java/com/knecon/fforesight/tests/TenantsTest.java @@ -6,12 +6,10 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Map; import java.util.Set; -import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import com.knecon.fforesight.AbstractTenantUserManagementIntegrationTest; import com.knecon.fforesight.feigntestclients.external.TenantsClient; -import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; import com.knecon.fforesight.tenantcommons.TenantContext; import com.knecon.fforesight.tenantcommons.model.AzureStorageConnection; import com.knecon.fforesight.tenantcommons.model.DatabaseConnection; @@ -19,29 +17,22 @@ import com.knecon.fforesight.tenantcommons.model.S3StorageConnection; import com.knecon.fforesight.tenantcommons.model.SearchConnection; import com.knecon.fforesight.tenantusermanagement.model.SearchConnectionRequest; import com.knecon.fforesight.tenantusermanagement.model.TenantRequest; -import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties; import com.knecon.fforesight.tenantusermanagement.service.RealmService; import com.knecon.fforesight.utils.TestTenantService; - import feign.FeignException; +import org.junit.jupiter.api.Test; import software.amazon.awssdk.regions.Region; public class TenantsTest extends AbstractTenantUserManagementIntegrationTest { + private static final String PASSWORD = "**********"; @Autowired private TenantsClient tenantsClient; - @Autowired private TestTenantService testTenantService; - - @Autowired - private EncryptionDecryptionService encryptionService; - @Autowired private RealmService realmService; - private static final String PASSWORD = "**********"; - @Test public void testCreateNewTenant() { @@ -68,6 +59,7 @@ public class TenantsTest extends AbstractTenantUserManagementIntegrationTest { @Test public void testUpdateTenant() { + String tenantId = "new_tenant"; testTenantService.createTestTenantIfNotExists(tenantId, minioPort); TenantContext.setTenantId(tenantId); @@ -131,6 +123,21 @@ public class TenantsTest extends AbstractTenantUserManagementIntegrationTest { } + private SearchConnection convert(SearchConnectionRequest sc, String tenantId) { + + return SearchConnection.builder() + .hosts(sc.getHosts()) + .port(sc.getPort()) + .scheme(sc.getScheme()) + .username(sc.getUsername()) + .password(sc.getPassword()) + .numberOfShards(sc.getNumberOfShards()) + .numberOfReplicas(sc.getNumberOfReplicas()) + .indexPrefix("fforesight_" + tenantId) + .build(); + } + + @Test public void testUpdateTenantWithIncorrectS3Storage() { @@ -253,17 +260,4 @@ public class TenantsTest extends AbstractTenantUserManagementIntegrationTest { TenantContext.clear(); } - - private SearchConnection convert(SearchConnectionRequest sc, String tenantId) { - return SearchConnection.builder() - .hosts(sc.getHosts()) - .port(sc.getPort()) - .scheme(sc.getScheme()) - .username(sc.getUsername()) - .password(sc.getPassword()) - .numberOfShards(sc.getNumberOfShards()) - .numberOfReplicas(sc.getNumberOfReplicas()) - .indexPrefix("fforesight_" + tenantId) - .build(); - } } diff --git a/src/test/java/com/knecon/fforesight/tests/UserPreferenceTest.java b/src/test/java/com/knecon/fforesight/tests/UserPreferenceTest.java index 85d770b..60ce651 100644 --- a/src/test/java/com/knecon/fforesight/tests/UserPreferenceTest.java +++ b/src/test/java/com/knecon/fforesight/tests/UserPreferenceTest.java @@ -4,29 +4,30 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.List; -import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import com.knecon.fforesight.AbstractTenantUserManagementIntegrationTest; import com.knecon.fforesight.feigntestclients.external.UserPreferenceClient; import com.knecon.fforesight.tenantcommons.TenantContext; +import org.junit.jupiter.api.Test; public class UserPreferenceTest extends AbstractTenantUserManagementIntegrationTest { @Autowired private UserPreferenceClient userPreferenceClient; + @Test - public void testUserPreferences(){ + public void testUserPreferences() { TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID); var allMyAttributes = userPreferenceClient.getAllUserAttributes(); assertThat(allMyAttributes).isEmpty(); - userPreferenceClient.setAttribute("test", List.of("1","2","3")); + userPreferenceClient.setAttribute("test", List.of("1", "2", "3")); allMyAttributes = userPreferenceClient.getAllUserAttributes(); - assertThat(allMyAttributes).hasEntrySatisfying("test", k -> assertThat(k).containsExactly("1","2","3")); + assertThat(allMyAttributes).hasEntrySatisfying("test", k -> assertThat(k).containsExactly("1", "2", "3")); userPreferenceClient.deleteAttribute("test"); diff --git a/src/test/java/com/knecon/fforesight/tests/UserTest.java b/src/test/java/com/knecon/fforesight/tests/UserTest.java index 48319e7..aa59134 100644 --- a/src/test/java/com/knecon/fforesight/tests/UserTest.java +++ b/src/test/java/com/knecon/fforesight/tests/UserTest.java @@ -1,20 +1,25 @@ package com.knecon.fforesight.tests; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; import java.util.HashSet; import java.util.List; +import java.util.Set; -import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import com.knecon.fforesight.AbstractTenantUserManagementIntegrationTest; import com.knecon.fforesight.feigntestclients.external.UserClient; import com.knecon.fforesight.tenantcommons.TenantContext; 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.properties.TenantUserManagementProperties; +import feign.FeignException; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; public class UserTest extends AbstractTenantUserManagementIntegrationTest { @@ -44,7 +49,8 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest { var testUser = userClient.getUserById(testUserId); assertThat(testUser).isNotNull(); - testUser = userClient.updateMyProfile(UpdateMyProfileRequest.builder().email("test@fforesight.com").firstName("updateTestFirstName").lastName("updateTestLastName").build()); + testUser = + userClient.updateMyProfile(UpdateMyProfileRequest.builder().email("test@fforesight.com").firstName("updateTestFirstName").lastName("updateTestLastName").build()); assertThat(testUser.getLastName()).isEqualTo("updateTestLastName"); assertThat(testUser.getFirstName()).isEqualTo("updateTestFirstName"); @@ -69,7 +75,12 @@ 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()); + 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])); userClient.deleteUsers(List.of(createdUser.getUserId())); @@ -78,4 +89,49 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest { assertThat(allUsers).hasSize(1); } + + @Test + @SneakyThrows + public void testResetPassword() { + + testTenantService.createTestTenantIfNotExists("test-password-reset", minioPort); + TenantContext.setTenantId("test-password-reset"); + + var createUserRequest = new CreateUserRequest(); + createUserRequest.setEmail("less.super.user.1@knecon.com"); + createUserRequest.setUsername(createUserRequest.getEmail()); + createUserRequest.setRoles(Set.of("LESS_SUPER_USER")); + var createdUser1 = userClient.createUser(createUserRequest); + + createUserRequest = new CreateUserRequest(); + createUserRequest.setEmail("less.super.user.2@knecon.com"); + createUserRequest.setUsername(createUserRequest.getEmail()); + createUserRequest.setRoles(Set.of("LESS_SUPER_USER")); + var createdUser2 = userClient.createUser(createUserRequest); + + //reset password as super-user for less-super-user + userClient.resetPassword(createdUser1.getUserId(), ResetPasswordRequest.builder().password("Secret@secured!23").build()); + + //reset password as super-user for less-super-user + userClient.resetPassword(createdUser2.getUserId(), ResetPasswordRequest.builder().password("Secret@secured!23").build()); + + //authenticate as less-super-user + tokenService.setUser("less.super.user.1@knecon.com", "Secret@secured!23"); + + //reset password as less-super-user for less-super-user + 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(); + try { + //reset password as less-super-user for super-user + userClient.resetPassword(initialSuperUser.getUserId(), ResetPasswordRequest.builder().password("ShouldNotWork@123").build()); + fail("Should not be allowed to reset password of higher ranking user"); + } catch (FeignException e) { + // forbidden to reset password of higher ranking user + assertThat(e.status()).isEqualTo(403); + } + + } + } diff --git a/src/test/java/com/knecon/fforesight/utils/TenantSyncUtils.java b/src/test/java/com/knecon/fforesight/utils/TenantSyncUtils.java index f058134..32ee25e 100644 --- a/src/test/java/com/knecon/fforesight/utils/TenantSyncUtils.java +++ b/src/test/java/com/knecon/fforesight/utils/TenantSyncUtils.java @@ -4,13 +4,6 @@ import static org.mockito.Mockito.when; import java.util.concurrent.TimeUnit; -import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; -import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.keycloak.OAuth2Constants; -import org.keycloak.admin.client.KeycloakBuilder; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -26,6 +19,11 @@ import com.knecon.fforesight.feigntestclients.internal.InternalTenantsClient; import com.knecon.fforesight.tenantusermanagement.TenantUserManagementServiceApplication; import com.knecon.fforesight.tenantusermanagement.service.KeyCloakRoleManagerService; import com.knecon.fforesight.tenantusermanagement.service.RealmService; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; +import org.junit.jupiter.api.extension.ExtendWith; +import org.keycloak.OAuth2Constants; +import org.keycloak.admin.client.KeycloakBuilder; @ActiveProfiles(profiles = "taas") @ExtendWith(SpringExtension.class) @@ -49,7 +47,7 @@ public class TenantSyncUtils { KeyCloakRoleManagerService keyCloakRoleManagerService; -// @Test + // @Test // @Disabled public void syncTenant() { diff --git a/src/test/java/com/knecon/fforesight/utils/TestTenantService.java b/src/test/java/com/knecon/fforesight/utils/TestTenantService.java index 9152ae4..258680d 100644 --- a/src/test/java/com/knecon/fforesight/utils/TestTenantService.java +++ b/src/test/java/com/knecon/fforesight/utils/TestTenantService.java @@ -12,13 +12,11 @@ import com.knecon.fforesight.feigntestclients.external.TenantsClient; import com.knecon.fforesight.tenantcommons.TenantContext; import com.knecon.fforesight.tenantcommons.model.DatabaseConnection; import com.knecon.fforesight.tenantcommons.model.S3StorageConnection; -import com.knecon.fforesight.tenantcommons.model.SearchConnection; import com.knecon.fforesight.tenantusermanagement.api.internal.InternalTenantsResource; 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.testcontainers.SpringPostgreSQLTestContainer; - import lombok.RequiredArgsConstructor; import software.amazon.awssdk.regions.Region; @@ -46,19 +44,6 @@ public class TestTenantService { } - public void createTestTenantWithoutStorageIfNotExist(String testTenantId) { - - try { - var tenantExists = internalTenantsResource.getTenant(testTenantId); - assertThat(tenantExists.getGuid()).isNotBlank(); - - } catch (Exception e) { - // not found - createUser(testTenantId, 0, false); - } - } - - private void createUser(String testTenantId, int actualPort, boolean withStorage) { // not found TenantRequest tenantRequest; @@ -106,4 +91,17 @@ public class TestTenantService { assertThat(tenant.getGuid()).isNotBlank(); } + + public void createTestTenantWithoutStorageIfNotExist(String testTenantId) { + + try { + var tenantExists = internalTenantsResource.getTenant(testTenantId); + assertThat(tenantExists.getGuid()).isNotBlank(); + + } catch (Exception e) { + // not found + createUser(testTenantId, 0, false); + } + } + } diff --git a/src/test/java/com/knecon/fforesight/utils/TokenService.java b/src/test/java/com/knecon/fforesight/utils/TokenService.java index b3f6b40..8d4ebbb 100644 --- a/src/test/java/com/knecon/fforesight/utils/TokenService.java +++ b/src/test/java/com/knecon/fforesight/utils/TokenService.java @@ -6,19 +6,18 @@ import java.util.concurrent.TimeUnit; import javax.ws.rs.BadRequestException; -import org.apache.commons.io.IOUtils; -import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; -import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; -import org.keycloak.OAuth2Constants; -import org.keycloak.admin.client.KeycloakBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.knecon.fforesight.tenantcommons.TenantContext; import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties; - import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; +import org.keycloak.OAuth2Constants; +import org.keycloak.admin.client.KeycloakBuilder; @Slf4j @Service @@ -30,6 +29,7 @@ public class TokenService { private String password; private String accessToken; + @SuppressWarnings("PMD") public void setUser(String username, String password) { @@ -42,7 +42,7 @@ public class TokenService { @SneakyThrows public String getToken() { - if(TenantContext.getTenantId() == null){ + if (TenantContext.getTenantId() == null) { return null; } @@ -67,9 +67,9 @@ public class TokenService { try { accessToken = tokenClient.tokenManager().getAccessTokenString(); return accessToken; - }catch (BadRequestException e){ + } catch (BadRequestException e) { var response = IOUtils.toString(new InputStreamReader((InputStream) e.getResponse().getEntity())); - log.warn("Exception getting token: {}",response, e); + log.warn("Exception getting token: {}", response, e); throw e; } finally { tokenClient.close(); diff --git a/src/test/resources/application.yaml b/src/test/resources/application.yaml index 8507335..c38e340 100644 --- a/src/test/resources/application.yaml +++ b/src/test/resources/application.yaml @@ -123,6 +123,23 @@ fforesight: - 'fforesight-deployment-info' - 'fforesight-read-smtp-configuration' - 'fforesight-write-smtp-configuration' + - name: LESS_SUPER_USER + set-by-default: true + rank: 10 + 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' access-token-life-span: 86400 application-name: tenant-user-management application-client-id: tenant-user-management