Compare commits

..

No commits in common. "main" and "1.157.0" have entirely different histories.

10 changed files with 77 additions and 180 deletions

View File

@ -17,6 +17,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.knecon.fforesight.tenantcommons.model.TenantResponse; import com.knecon.fforesight.tenantcommons.model.TenantResponse;
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest; import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse; import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest; import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest; import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
@ -42,7 +43,8 @@ public interface TenantsResource {
@ResponseBody @ResponseBody
@ResponseStatus(value = HttpStatus.NO_CONTENT) @ResponseStatus(value = HttpStatus.NO_CONTENT)
@Operation(summary = "Deletes given tenant", description = "None") @Operation(summary = "Deletes given tenant", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden access, you dont have rights to delete tenants"), @ApiResponse(responseCode = "405", description = "Operation is not allowed."), @ApiResponse(responseCode = "409", description = "Conflict while deleting tenant.")}) @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK"), @ApiResponse(responseCode = "403", description = "Forbidden access, you dont have rights to delete tenants"), @ApiResponse(responseCode = "405", description = "Operation is not allowed."),
@ApiResponse(responseCode = "409", description = "Conflict while deleting tenant.")})
@DeleteMapping(value = TENANTS_TENANT_ID_PATH) @DeleteMapping(value = TENANTS_TENANT_ID_PATH)
void deleteTenant(@PathVariable("tenantId") String tenantId); void deleteTenant(@PathVariable("tenantId") String tenantId);
@ -71,6 +73,12 @@ public interface TenantsResource {
void updateDetails(@PathVariable("tenantId") String tenantId, @RequestBody UpdateDetailsRequest request); void updateDetails(@PathVariable("tenantId") String tenantId, @RequestBody UpdateDetailsRequest request);
@GetMapping(value = TENANTS_PATH + "/simple", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets all existing tenants in a simplified format", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
List<SimpleTenantResponse> getSimpleTenants();
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE) @GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Returns the deployment key for a tenant", description = "None") @Operation(summary = "Returns the deployment key for a tenant", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})

View File

@ -16,6 +16,7 @@ import com.knecon.fforesight.tenantcommons.TenantApplicationType;
import com.knecon.fforesight.tenantcommons.model.TenantResponse; import com.knecon.fforesight.tenantcommons.model.TenantResponse;
import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest; import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse; import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest; import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest; import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
@ -60,6 +61,12 @@ public interface InternalTenantsResource {
TenantResponse updateTenant(@PathVariable("tenantId") String tenantId, @RequestBody UpdateTenantRequest tenantRequest); TenantResponse updateTenant(@PathVariable("tenantId") String tenantId, @RequestBody UpdateTenantRequest tenantRequest);
@GetMapping(value = "/tenants/simple", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets all existing tenant in a simplified format", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
List<SimpleTenantResponse> getSimpleTenants();
@GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE) @GetMapping(value = "/deploymentKey" + TENANT_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Returns the deployment key for a tenant", description = "None") @Operation(summary = "Returns the deployment key for a tenant", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})

View File

@ -22,6 +22,7 @@ import com.knecon.fforesight.tenantcommons.model.UpdateDetailsRequest;
import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource; import com.knecon.fforesight.tenantusermanagement.api.external.PublicResource;
import com.knecon.fforesight.tenantusermanagement.api.external.TenantsResource; import com.knecon.fforesight.tenantusermanagement.api.external.TenantsResource;
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse; import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest; import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest; import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService; import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
@ -76,6 +77,12 @@ public class TenantsController implements TenantsResource, PublicResource {
} }
public List<SimpleTenantResponse> getSimpleTenants() {
return tenantManagementService.getTenants().stream().map(t -> new SimpleTenantResponse(t.getTenantId(), t.getDisplayName(), t.getGuid())).toList();
}
@PreAuthorize("hasAuthority('" + UPDATE_TENANT + "')") @PreAuthorize("hasAuthority('" + UPDATE_TENANT + "')")
public TenantResponse updateTenant(String tenantId, @RequestBody UpdateTenantRequest tenantRequest) { public TenantResponse updateTenant(String tenantId, @RequestBody UpdateTenantRequest tenantRequest) {

View File

@ -16,6 +16,7 @@ import com.knecon.fforesight.tenantusermanagement.api.internal.InternalResource;
import com.knecon.fforesight.tenantusermanagement.api.internal.InternalTenantsResource; import com.knecon.fforesight.tenantusermanagement.api.internal.InternalTenantsResource;
import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest; import com.knecon.fforesight.tenantusermanagement.model.CreateTenantRequest;
import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse; import com.knecon.fforesight.tenantusermanagement.model.DeploymentKeyResponse;
import com.knecon.fforesight.tenantusermanagement.model.SimpleTenantResponse;
import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest; import com.knecon.fforesight.tenantusermanagement.model.UpdateTenantRequest;
import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService; import com.knecon.fforesight.tenantusermanagement.service.DeploymentKeyService;
import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService; import com.knecon.fforesight.tenantusermanagement.service.TenantManagementService;
@ -67,6 +68,12 @@ public class InternalTenantsController implements InternalTenantsResource, Inter
} }
public List<SimpleTenantResponse> getSimpleTenants() {
return tenantManagementService.getTenants().stream().map(t -> new SimpleTenantResponse(t.getTenantId(), t.getDisplayName(), t.getGuid())).toList();
}
public DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId) { public DeploymentKeyResponse getDeploymentKey(@PathVariable(TENANT_ID_PARAM) String tenantId) {
return new DeploymentKeyResponse(deploymentKeyService.getDeploymentKey(tenantId)); return new DeploymentKeyResponse(deploymentKeyService.getDeploymentKey(tenantId));

View File

@ -0,0 +1,23 @@
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
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "Object containing a simplified version of the tenant data.")
public class SimpleTenantResponse {
@Schema(description = "Parameter containing the ID of the tenant.")
private String tenantId;
@Schema(description = "Parameter containing the display name of the tenant.")
private String displayName;
@Schema(description = "Parameter containing the global unique ID of the tenant.")
private String guid;
}

View File

@ -129,7 +129,7 @@ public class UserService {
return getUserByUsername(username); return getUserByUsername(username);
} }
} }
public void checkRankOrderForAssigningRole(Set<String> newRoles, Set<String> currentUserRoles) { public void checkRankOrderForAssigningRole(Set<String> newRoles, Set<String> currentUserRoles) {
@ -239,67 +239,33 @@ public class UserService {
public void validateSufficientRoles(String userId, Set<String> userRoles, Set<String> newRoles, Set<String> currentUserRoles) { public void validateSufficientRoles(String userId, Set<String> userRoles, Set<String> newRoles, Set<String> currentUserRoles) {
var roleMapping = tenantApplicationTypeService.getCurrentProperties().getKcRoleMapping(); var roleMapping = tenantApplicationTypeService.getCurrentProperties().getKcRoleMapping();
var maxRank = currentUserRoles.stream()
int maxCurrentUserRank = currentUserRoles.stream()
.map(r -> roleMapping.getRole(r).getRank()) .map(r -> roleMapping.getRole(r).getRank())
.max(Integer::compare) .max(Integer::compare)
.orElse(-1); .orElse(-1);
var newRolesRank = newRoles.stream()
.map(r -> roleMapping.getRole(r).getRank())
.toList();
var maxNewRolesRank = newRolesRank.stream()
.max(Integer::compare)
.orElse(-1);
Set<String> untouchableRoles = userRoles.stream() var untouchableRoles = userRoles.stream()
.filter(roleMapping::isValidRole) .filter(roleMapping::isValidRole)
.map(roleMapping::getRole) .map(roleMapping::getRole)
.filter(r -> r.getRank() > maxCurrentUserRank && !ApplicationRoles.isKneconRole(r.getName())) .filter(r -> r.getRank() > maxRank || ApplicationRoles.isKneconRole(r.getName()))
.map(KCRole::getName) .map(KCRole::getName)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Set<String> kneconRoles = userRoles.stream() if (maxNewRolesRank > maxRank) {
.filter(roleMapping::isValidRole)
.map(roleMapping::getRole)
.map(KCRole::getName)
.filter(ApplicationRoles::isKneconRole)
.collect(Collectors.toSet());
int maxNewRolesRank = newRoles.stream()
.map(r -> roleMapping.getRole(r).getRank())
.max(Integer::compare)
.orElse(-1);
newRoles.addAll(kneconRoles);
int maxNewRolesRankIncludingKnecon = newRoles.stream()
.map(r -> roleMapping.getRole(r).getRank())
.max(Integer::compare)
.orElse(-1);
ensureNoHigherRankAssigned(maxCurrentUserRank, maxNewRolesRank);
ensureUntouchableRolesPreserved(untouchableRoles, newRoles);
ensureHighestRankNotRemovedFromSelf(userId, maxCurrentUserRank, maxNewRolesRankIncludingKnecon, roleMapping.getMaxRank());
}
private void ensureNoHigherRankAssigned(int maxCurrentUserRank, int maxNewRolesRank) {
if (maxNewRolesRank > maxCurrentUserRank) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot assign this role to that user. Insufficient rights"); throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot assign this role to that user. Insufficient rights");
} }
}
private void ensureUntouchableRolesPreserved(Set<String> untouchableRoles, Set<String> newRoles) {
if (!newRoles.containsAll(untouchableRoles)) { if (!newRoles.containsAll(untouchableRoles)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot modify some roles for this user. Insufficient rights"); throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Cannot modify some roles for this user. Insufficient rights");
} }
}
if (userId.equalsIgnoreCase(KeycloakSecurity.getUserId()) && maxRank.equals(roleMapping.getMaxRank()) && !maxNewRolesRank.equals(maxRank)) {
private void ensureHighestRankNotRemovedFromSelf(String userId, int maxCurrentUserRank, int maxNewRolesRankIncludingKnecon, int overallMaxRank) {
boolean isSelf = userId.equalsIgnoreCase(KeycloakSecurity.getUserId());
boolean isUserHighestRank = maxCurrentUserRank == overallMaxRank;
boolean highestRankRemoved = !Integer.valueOf(maxNewRolesRankIncludingKnecon).equals(maxCurrentUserRank);
if (isSelf && isUserHighestRank && highestRankRemoved) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "Cannot remove highest ranking role from self."); throw new ResponseStatusException(HttpStatus.CONFLICT, "Cannot remove highest ranking role from self.");
} }
} }
@ -689,7 +655,6 @@ public class UserService {
.max(Integer::compare) .max(Integer::compare)
.orElse(-1); .orElse(-1);
var targetRank = userRoles.stream() var targetRank = userRoles.stream()
.filter(ApplicationRoles::isNoKneconRole)
.map(r -> roleMapping.getRole(r).getRank()) .map(r -> roleMapping.getRole(r).getRank())
.max(Integer::compare) .max(Integer::compare)
.orElse(-1); .orElse(-1);

View File

@ -101,7 +101,7 @@ spring:
password: ${REDIS_PASSWORD:} password: ${REDIS_PASSWORD:}
fforesight: fforesight:
keycloak: keycloak:
ignored-endpoints: [ '/actuator/health', '/actuator/health/**', '/tenant-user-management', '/tenant-user-management/', '/internal/**','/tenant-user-management/docs/**','/tenant-user-management/docs','/actuator/prometheus' ] ignored-endpoints: [ '/actuator/health', '/actuator/health/**', '/tenant-user-management', '/tenant-user-management/', '/internal/**','/tenant-user-management/docs/**','/tenant-user-management/docs','/tenant-user-management/tenants/simple' ]
enabled: true enabled: true
springdoc: springdoc:
base-path: '/tenant-user-management' base-path: '/tenant-user-management'
@ -155,7 +155,7 @@ fforesight:
permissions: [ "red-add-dictionary-entry","red-get-similar-images", "red-add-update-dictionary-type", "red-write-dossier-status", "red-read-dossier-status", "red-delete-dictionary-entry", "red-delete-dictionary-type", permissions: [ "red-add-dictionary-entry","red-get-similar-images", "red-add-update-dictionary-type", "red-write-dossier-status", "red-read-dossier-status", "red-delete-dictionary-entry", "red-delete-dictionary-type",
"red-delete-report-template", "red-download-report-template", "red-get-report-templates", "fforesight-manage-user-preferences", "red-read-colors", "red-read-dictionary-types", "red-delete-report-template", "red-download-report-template", "red-get-report-templates", "fforesight-manage-user-preferences", "red-read-colors", "red-read-dictionary-types",
"red-read-digital-signature", "red-read-dossier-attributes", "red-read-dossier-attributes-config", "red-read-dossier-templates", "red-read-file-attributes-config", "red-read-digital-signature", "red-read-dossier-attributes", "red-read-dossier-attributes-config", "red-read-dossier-templates", "red-read-file-attributes-config",
"red-read-legal-basis", "red-get-user-stats","red-read-license-report", "red-read-notification", "red-read-rules", "red-read-data-formats", "fforesight-read-smtp-configuration", "fforesight-read-identity-provider-config", "red-read-versions", "red-read-watermark", "red-read-legal-basis", "red-read-license-report", "red-read-notification", "red-read-rules", "red-read-data-formats", "fforesight-read-smtp-configuration", "fforesight-read-identity-provider-config", "red-read-versions", "red-read-watermark",
"red-reindex", "red-search-audit-log", "red-update-notification", "red-upload-report-template", "red-write-colors", "red-write-digital-signature", "red-write-dossier-attributes-config", "red-reindex", "red-search-audit-log", "red-update-notification", "red-upload-report-template", "red-write-colors", "red-write-digital-signature", "red-write-dossier-attributes-config",
"red-write-dossier-templates", "red-write-file-attributes-config", "fforesight-write-general-configuration", "red-write-legal-basis", "red-write-rules", "red-write-data-formats", "fforesight-write-smtp-configuration", "fforesight-write-identity-provider-config", "red-write-dossier-templates", "red-write-file-attributes-config", "fforesight-write-general-configuration", "red-write-legal-basis", "red-write-rules", "red-write-data-formats", "fforesight-write-smtp-configuration", "fforesight-write-identity-provider-config",
"red-write-watermark", "red-write-app-configuration", "red-manage-acl-permissions", "fforesight-create-tenant", "fforesight-get-tenants", "fforesight-update-tenant", "fforesight-deployment-info" ] "red-write-watermark", "red-write-app-configuration", "red-manage-acl-permissions", "fforesight-create-tenant", "fforesight-get-tenants", "fforesight-update-tenant", "fforesight-deployment-info" ]
@ -175,7 +175,7 @@ fforesight:
set-by-default: false set-by-default: false
rank: 400 rank: 400
permissions: [ "fforesight-manage-user-preferences", "fforesight-read-all-users", "red-read-app-configuration", "fforesight-read-general-configuration", permissions: [ "fforesight-manage-user-preferences", "fforesight-read-all-users", "red-read-app-configuration", "fforesight-read-general-configuration",
"red-read-notification", "red-get-user-stats", "fforesight-read-users", "fforesight-update-my-profile", "red-update-notification", "fforesight-write-users", "red-read-license" ] "red-read-notification", "fforesight-read-users", "fforesight-update-my-profile", "red-update-notification", "fforesight-write-users", "red-read-license" ]
documine: documine:
application-client-id: 'redaction' application-client-id: 'redaction'
application-name: 'Documine' application-name: 'Documine'
@ -230,7 +230,7 @@ fforesight:
- name: RED_USER_ADMIN - name: RED_USER_ADMIN
set-by-default: false set-by-default: false
rank: 400 rank: 400
permissions: [ "fforesight-manage-user-preferences", "fforesight-read-all-users", "red-read-app-configuration", "fforesight-read-general-configuration", permissions: [ "fforesight-manage-user-preferences", "fforesight-read-all-users", "red-read-dossier", "red-read-app-configuration", "fforesight-read-general-configuration",
"red-read-notification", "fforesight-read-users", "fforesight-update-my-profile", "red-update-notification", "fforesight-write-users", "red-read-license" ] "red-read-notification", "fforesight-read-users", "fforesight-update-my-profile", "red-update-notification", "fforesight-write-users", "red-read-license" ]
clarifynd: clarifynd:
application-client-id: 'fforesight' application-client-id: 'fforesight'

View File

@ -17,8 +17,8 @@ public class StartupTest extends AbstractTenantUserManagementIntegrationTest {
@Test @Test
public void testStartup() { public void testStartup() {
var tenants = internalTenantsClient.getTenants(); var simpleTenants = internalTenantsClient.getSimpleTenants();
assertThat(tenants).isNotEmpty(); assertThat(simpleTenants).isNotEmpty();
} }

View File

@ -30,10 +30,8 @@ import com.knecon.fforesight.tenantusermanagement.permissions.ApplicationRoles;
import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties; import com.knecon.fforesight.tenantusermanagement.properties.TenantUserManagementProperties;
import com.knecon.fforesight.tenantusermanagement.service.RealmService; import com.knecon.fforesight.tenantusermanagement.service.RealmService;
import com.knecon.fforesight.tenantusermanagement.service.TenantApplicationTypeService; import com.knecon.fforesight.tenantusermanagement.service.TenantApplicationTypeService;
import com.knecon.fforesight.tenantusermanagement.service.UserService;
import feign.FeignException; import feign.FeignException;
import lombok.NonNull;
import lombok.SneakyThrows; import lombok.SneakyThrows;
public class UserTest extends AbstractTenantUserManagementIntegrationTest { public class UserTest extends AbstractTenantUserManagementIntegrationTest {
@ -50,9 +48,6 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
@Autowired @Autowired
private TenantApplicationTypeService tenantApplicationTypeService; private TenantApplicationTypeService tenantApplicationTypeService;
@Autowired
private UserService userService;
@Test @Test
public void testUsers() { public void testUsers() {
@ -510,11 +505,11 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
tokenService.setUser("admin@knecon.com", "secret"); tokenService.setUser("admin@knecon.com", "secret");
// this should still not be possible // this should still not be possible
e = assertThrows(FeignException.class, () -> userClient.setRoles(onlyKneconUser.getUserId(), allRoles)); e = assertThrows(FeignException.class, () -> userClient.setRoles(onlyKneconUser.getUserId(), allRoles));
assertEquals(404, e.status()); assertEquals(404, e.status());
// and also not this // and also not this
e = assertThrows(FeignException.class, () -> userClient.setRoles(user.getUserId(), allRoles)); e = assertThrows(FeignException.class, () -> userClient.setRoles(user.getUserId(), allRoles));
assertEquals(400, e.status()); assertEquals(400, e.status());
// we can also poll the user // we can also poll the user
@ -593,16 +588,12 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
addRoles(user4.getUserId(), allButKneconRoles); addRoles(user4.getUserId(), allButKneconRoles);
allUsers = userClient.getAllUsers(true); allUsers = userClient.getAllUsers(true);
var user4AfterShenanigansOpt = allUsers.stream() var user4AfterShenanigansOpt = allUsers.stream().filter(u -> u.getUserId().equals(user4.getUserId())).findFirst();
.filter(u -> u.getUserId().equals(user4.getUserId()))
.findFirst();
assertTrue(user4AfterShenanigansOpt.isPresent()); assertTrue(user4AfterShenanigansOpt.isPresent());
user4AfterShenanigansOpt.get().setRoles(new HashSet<>()); user4AfterShenanigansOpt.get().setRoles(new HashSet<>());
assertEquals(user4AfterShenanigansOpt.get(), user4); assertEquals(user4AfterShenanigansOpt.get(), user4);
var stillOnlyKneconUserOpt = allUsers.stream() var stillOnlyKneconUserOpt = allUsers.stream().filter(u -> u.getUserId().equals(onlyKneconUser.getUserId())).findFirst();
.filter(u -> u.getUserId().equals(onlyKneconUser.getUserId()))
.findFirst();
assertTrue(stillOnlyKneconUserOpt.isPresent()); assertTrue(stillOnlyKneconUserOpt.isPresent());
stillOnlyKneconUserOpt.get().setRoles(new HashSet<>()); stillOnlyKneconUserOpt.get().setRoles(new HashSet<>());
assertEquals(stillOnlyKneconUserOpt.get(), onlyKneconUser); assertEquals(stillOnlyKneconUserOpt.get(), onlyKneconUser);
@ -717,113 +708,6 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
} }
@Test
public void testUpdateProfileForUserWithAllRoles() {
TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID);
tokenService.setUser("admin@knecon.com", "secret");
var allRoles = tenantApplicationTypeService.getCurrentProperties().getKcRoleMapping().getAllRoles();
Set<String> allButKneconRoles = allRoles.stream()
.filter(ApplicationRoles::isNoKneconRole)
.collect(Collectors.toSet());
CreateUserRequest createUserRequest = new CreateUserRequest();
createUserRequest.setEmail("all.roles.user@knecon.com");
createUserRequest.setUsername("all.roles.user@knecon.com");
createUserRequest.setFirstName("All");
createUserRequest.setLastName("Roles");
var allRolesuser = userClient.createUser(createUserRequest);
addRoles(allRolesuser.getUserId(), allRoles);
assertThat(allRolesuser).isNotNull();
UpdateProfileRequest updateProfileRequest = UpdateProfileRequest.builder()
.email("all.roles.user@knecon.com")
.firstName("All")
.lastName("NewLastName")
.roles(allButKneconRoles)
.build();
var updatedUser = userClient.updateProfile(allRolesuser.getUserId(), updateProfileRequest);
assertThat(updatedUser).isNotNull();
assertThat(updatedUser.getLastName()).isEqualTo("NewLastName");
tokenService.setUser("test@fforesight.com", "secret");
updateProfileRequest.setLastName("AnotherNewLastName");
updatedUser = userClient.updateProfile(allRolesuser.getUserId(), updateProfileRequest);
assertThat(updatedUser).isNotNull();
assertThat(updatedUser.getLastName()).isEqualTo("AnotherNewLastName");
createUserRequest.setEmail("less.super.user.1@knecon.com");
createUserRequest.setUsername(createUserRequest.getEmail());
createUserRequest.setRoles(Set.of("LESS_SUPER_USER"));
var lessSuperUser = userClient.createUser(createUserRequest);
userClient.resetPassword(lessSuperUser.getUserId(), ResetPasswordRequest.builder().password("Secret@secured!23").build());
tokenService.setUser("less.super.user.1@knecon.com", "Secret@secured!23");
FeignException feignException = assertThrows(FeignException.class, () -> userClient.updateProfile(allRolesuser.getUserId(), updateProfileRequest));
assertEquals(400, feignException.status());
assertTrue(feignException.getMessage().contains("Cannot assign this role to that user. Insufficient rights"));
tokenService.setUser("admin@knecon.com", "secret");
userClient.deleteUser(lessSuperUser.getUserId());
userClient.deleteUser(allRolesuser.getUserId());
}
@Test
public void testDeleteKneconRolesUserAsNormalAdmin() {
TenantContext.setTenantId(AbstractTenantUserManagementIntegrationTest.TEST_TENANT_ID);
tokenService.setUser("admin@knecon.com", "secret");
var allRoles = tenantApplicationTypeService.getCurrentProperties().getKcRoleMapping().getAllRoles();
Set<String> allButKneconRoles = allRoles.stream()
.filter(ApplicationRoles::isNoKneconRole)
.collect(Collectors.toSet());
CreateUserRequest createUserRequest = new CreateUserRequest();
createUserRequest.setEmail("normalAdmin@knecon.com");
createUserRequest.setUsername("normalAdmin@knecon.com");
createUserRequest.setFirstName("Mister");
createUserRequest.setLastName("Admin");
var adminUser = userClient.createUser(createUserRequest);
addRoles(adminUser.getUserId(), allButKneconRoles);
assertThat(adminUser).isNotNull();
createUserRequest = new CreateUserRequest();
createUserRequest.setEmail("kneconAdmin@knecon.com");
createUserRequest.setUsername("kneconAdmin@knecon.com");
createUserRequest.setFirstName("Knecon");
createUserRequest.setLastName("Admin");
var kneconAdminuser = userClient.createUser(createUserRequest);
addRoles(kneconAdminuser.getUserId(), allRoles);
assertThat(kneconAdminuser).isNotNull();
userClient.resetPassword(adminUser.getUserId(), ResetPasswordRequest.builder().password("Secret@secured!23").build());
tokenService.setUser("normalAdmin@knecon.com", "Secret@secured!23");
userClient.deleteUser(kneconAdminuser.getUserId());
List<User> allUsers = userClient.getAllUsers(true);
assertTrue(allUsers.stream()
.noneMatch(u -> u.getUserId().equals(kneconAdminuser.getUserId())));
List<User> unfilteredUsers = userService.getAllUsers();
assertTrue(unfilteredUsers.stream()
.anyMatch(u -> u.getUserId().equals(kneconAdminuser.getUserId())));
tokenService.setUser("admin@knecon.com", "secret");
userClient.deleteUser(adminUser.getUserId());
}
private UsersResource getTenantUsersResource() { private UsersResource getTenantUsersResource() {
return realmService.realm(TenantContext.getTenantId()).users(); return realmService.realm(TenantContext.getTenantId()).users();
@ -846,11 +730,7 @@ public class UserTest extends AbstractTenantUserManagementIntegrationTest {
private void addRoles(String userId, Set<String> roles) { private void addRoles(String userId, Set<String> roles) {
getUserResource(userId).roles() getUserResource(userId).roles().realmLevel().add(roles.stream().map(this::getRoleRepresentation).toList());
.realmLevel()
.add(roles.stream()
.map(this::getRoleRepresentation)
.toList());
} }
} }

View File

@ -90,7 +90,7 @@ spring:
fforesight: fforesight:
keycloak: keycloak:
ignored-endpoints: [ '/actuator/health', '/tenant-user-management','/internal/**','/tenant-user-management/docs/**','/tenant-user-management/docs' ] ignored-endpoints: [ '/actuator/health', '/tenant-user-management','/internal/**','/tenant-user-management/docs/**','/tenant-user-management/docs','/tenant-user-management/tenants/simple' ]
enabled: true enabled: true
springdoc: springdoc:
base-path: '/tenant-user-management' base-path: '/tenant-user-management'