Pull request #638: RED-4515
Merge in RED/persistence-service from RED-4515 to master * commit '8a0591d4b967b3c7880a4e04584d259b7499af7d': RED-4515: Create schema on createTenant RED-4515: Rename master realm client to redaction as this make configuration much easier RED-4515: Create default user set valid redirect uis RED-4515: Changed swagger back to authorizationCode flow RED-4515: Fixed kc config RED-4515 - kc createRealm RED-4515 - kc createRealm RED-4515 - kc createRealm RED-4515: Create realm on create tenant RED-4515: Create realm on createTenant
This commit is contained in:
commit
48df7bf273
@ -49,6 +49,7 @@ public class HeaderBasedKeycloakRealmResolver implements KeycloakConfigResolver
|
||||
|
||||
var config = MagicConverter.convert(adapterConfig, AdapterConfig.class);
|
||||
config.setRealm(tenant);
|
||||
config.setResource(tenant);
|
||||
|
||||
return KeycloakDeploymentBuilder.build(config);
|
||||
}
|
||||
|
||||
@ -5,8 +5,6 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
|
||||
|
||||
@ -89,6 +89,7 @@ public class KeyCloakRoleManagerService {
|
||||
realm.roles().create(role);
|
||||
|
||||
}
|
||||
|
||||
var applicationRoleResource = realm.roles().get(applicationRole);
|
||||
Set<RoleRepresentation> composites = realm.rolesById()
|
||||
.getClientRoleComposites(applicationRoleResource.toRepresentation().getId(), redactionClient.toRepresentation().getId());
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
package com.iqser.red.service.persistence.management.v1.processor.service;
|
||||
|
||||
import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_ADMIN_ROLE;
|
||||
import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_MANAGER_ROLE;
|
||||
import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_USER_ADMIN_ROLE;
|
||||
import static com.iqser.red.keycloak.commons.roles.ApplicationRoles.RED_USER_ROLE;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -11,15 +17,26 @@ import java.util.stream.Collectors;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.RolesRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.postgresql.util.PSQLException;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.StatementCallback;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.iqser.red.keycloak.commons.KeyCloakAdminClientService;
|
||||
import com.iqser.red.keycloak.commons.KeyCloakSettings;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.InternalServerErrorException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.migration.AsyncMigrationStarterService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.multitenancy.entity.AzureStorageConnectionEntity;
|
||||
@ -46,6 +63,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@EnableConfigurationProperties(LiquibaseProperties.class)
|
||||
public class TenantManagementService {
|
||||
|
||||
private static final Long MAX_WAIT_TIME = 60_000L; // 60 seconds
|
||||
|
||||
private static final Set<String> SUPPORTED_DATABASES = Set.of("postgresql");
|
||||
private static final Set<String> SQL_CONNECTION_ERROR_CODES = Set.of(
|
||||
// connection_exception
|
||||
@ -65,13 +84,19 @@ public class TenantManagementService {
|
||||
private final AsyncMigrationStarterService asyncMigrationStarterService;
|
||||
private final GeneralConfigurationService generalConfigurationService;
|
||||
private final KeyCloakRoleManagerService keyCloakRoleManagerService;
|
||||
private final KeyCloakAdminClientService keycloak;
|
||||
private final KeyCloakSettings keyCloakSettings;
|
||||
|
||||
|
||||
public TenantManagementService(EncryptionDecryptionService encryptionService,
|
||||
@Qualifier("tenantLiquibaseProperties") LiquibaseProperties liquibaseProperties,
|
||||
ResourceLoader resourceLoader,
|
||||
TenantRepository tenantRepository,
|
||||
AsyncMigrationStarterService asyncMigrationStarterService, GeneralConfigurationService generalConfigurationService, KeyCloakRoleManagerService keyCloakRoleManagerService) {
|
||||
AsyncMigrationStarterService asyncMigrationStarterService,
|
||||
GeneralConfigurationService generalConfigurationService,
|
||||
KeyCloakRoleManagerService keyCloakRoleManagerService,
|
||||
KeyCloakAdminClientService keycloak,
|
||||
KeyCloakSettings keyCloakSettings) {
|
||||
|
||||
this.encryptionService = encryptionService;
|
||||
this.liquibaseProperties = liquibaseProperties;
|
||||
@ -80,6 +105,8 @@ public class TenantManagementService {
|
||||
this.asyncMigrationStarterService = asyncMigrationStarterService;
|
||||
this.generalConfigurationService = generalConfigurationService;
|
||||
this.keyCloakRoleManagerService = keyCloakRoleManagerService;
|
||||
this.keycloak = keycloak;
|
||||
this.keyCloakSettings = keyCloakSettings;
|
||||
}
|
||||
|
||||
|
||||
@ -88,7 +115,9 @@ public class TenantManagementService {
|
||||
|
||||
if (tenantRepository.findById(tenantRequest.getTenantId()).isEmpty()) {
|
||||
|
||||
var jdbcUrl = JDBCUtils.buildJdbcUrl(tenantRequest.getDatabaseConnection());
|
||||
createSchema(tenantRequest);
|
||||
|
||||
var jdbcUrl = JDBCUtils.buildJdbcUrlWithSchema(tenantRequest.getDatabaseConnection());
|
||||
validateJdbcUrl(jdbcUrl);
|
||||
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl,
|
||||
@ -145,6 +174,25 @@ public class TenantManagementService {
|
||||
|
||||
tenantRepository.save(tenantEntity);
|
||||
|
||||
createRealm(tenantRequest.getTenantId());
|
||||
|
||||
var waitTime = 0;
|
||||
boolean realmReady;
|
||||
do {
|
||||
realmReady = tryToAccessRealm(tenantRequest.getTenantId());
|
||||
if (realmReady) {
|
||||
break;
|
||||
} else {
|
||||
Thread.sleep(1_000L);
|
||||
waitTime += 1_000L;
|
||||
}
|
||||
|
||||
} while (waitTime < MAX_WAIT_TIME);
|
||||
|
||||
if (!realmReady) {
|
||||
throw new InternalServerErrorException("Failed to create KC realm");
|
||||
}
|
||||
|
||||
generalConfigurationService.initGeneralConfiguration(tenantRequest.getTenantId());
|
||||
keyCloakRoleManagerService.updateRoles(tenantRequest.getTenantId());
|
||||
asyncMigrationStarterService.runForTenant(tenantRequest.getTenantId());
|
||||
@ -155,6 +203,110 @@ public class TenantManagementService {
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void createSchema(TenantRequest tenantRequest){
|
||||
|
||||
var jdbcUrl = JDBCUtils.buildJdbcUrl(tenantRequest.getDatabaseConnection());
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl,
|
||||
tenantRequest.getDatabaseConnection().getUsername(),
|
||||
tenantRequest.getDatabaseConnection().getPassword())) {
|
||||
DataSource tenantDataSource = new SingleConnectionDataSource(connection, false);
|
||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(tenantDataSource);
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE SCHEMA " + tenantRequest.getDatabaseConnection().getSchema()));
|
||||
jdbcTemplate.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT USAGE ON SCHEMA " + tenantRequest.getDatabaseConnection().getSchema() + " TO " + tenantRequest.getDatabaseConnection().getUsername()));
|
||||
} catch (Exception e) {
|
||||
log.info("Could not create schema, ignoring");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean tryToAccessRealm(String tenantId) {
|
||||
|
||||
try {
|
||||
return keycloak.getAdminClient().realms().findAll().stream().anyMatch(r -> r.getRealm().equals(tenantId));
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void createRealm(String tenantId) {
|
||||
|
||||
var redaction = new RealmRepresentation();
|
||||
redaction.setId(tenantId);
|
||||
redaction.setRealm(tenantId);
|
||||
redaction.setEnabled(true);
|
||||
redaction.setLoginTheme("redaction");
|
||||
redaction.setEmailTheme("redaction");
|
||||
redaction.setAccountTheme("redaction");
|
||||
|
||||
var redactionClient = new ClientRepresentation();
|
||||
redactionClient.setEnabled(true);
|
||||
redactionClient.setName("redaction");
|
||||
redactionClient.setClientId("redaction");
|
||||
redactionClient.setStandardFlowEnabled(true);
|
||||
redactionClient.setImplicitFlowEnabled(true);
|
||||
redactionClient.setDirectAccessGrantsEnabled(true);
|
||||
redactionClient.setRedirectUris(List.of("/ui/*"));
|
||||
redactionClient.setPublicClient(true);
|
||||
|
||||
var swaggerClient = new ClientRepresentation();
|
||||
swaggerClient.setEnabled(true);
|
||||
swaggerClient.setName("swagger-ui-client");
|
||||
swaggerClient.setClientId("swagger-ui-client");
|
||||
swaggerClient.setStandardFlowEnabled(true);
|
||||
swaggerClient.setImplicitFlowEnabled(false);
|
||||
swaggerClient.setDirectAccessGrantsEnabled(false);
|
||||
swaggerClient.setServiceAccountsEnabled(true);
|
||||
swaggerClient.setAuthorizationServicesEnabled(true);
|
||||
swaggerClient.setRedirectUris(List.of("/redaction-gateway-v1/*"));
|
||||
|
||||
redaction.setClients(List.of(redactionClient, swaggerClient));
|
||||
var redUserRole = new RoleRepresentation();
|
||||
redUserRole.setComposite(true);
|
||||
redUserRole.setName(RED_USER_ROLE);
|
||||
redUserRole.setContainerId("redaction");
|
||||
|
||||
var redManagerRole = new RoleRepresentation();
|
||||
redManagerRole.setComposite(true);
|
||||
redManagerRole.setName(RED_MANAGER_ROLE);
|
||||
redManagerRole.setContainerId("redaction");
|
||||
|
||||
var redAdminRole = new RoleRepresentation();
|
||||
redAdminRole.setComposite(true);
|
||||
redAdminRole.setName(RED_ADMIN_ROLE);
|
||||
redAdminRole.setContainerId("redaction");
|
||||
|
||||
var redUserAdminRole = new RoleRepresentation();
|
||||
redUserAdminRole.setComposite(true);
|
||||
redUserAdminRole.setName(RED_USER_ADMIN_ROLE);
|
||||
redUserAdminRole.setContainerId("redaction");
|
||||
|
||||
RolesRepresentation rolesRepresentation = new RolesRepresentation();
|
||||
rolesRepresentation.setRealm(List.of(redUserRole, redManagerRole, redAdminRole, redUserAdminRole));
|
||||
redaction.setRoles(rolesRepresentation);
|
||||
|
||||
var credentialRepresentation = new CredentialRepresentation();
|
||||
credentialRepresentation.setType("password");
|
||||
credentialRepresentation.setValue("OsloImWinter!23");
|
||||
|
||||
var defaultUser = new UserRepresentation();
|
||||
defaultUser.setUsername("manageradmin");
|
||||
defaultUser.setCredentials(List.of(credentialRepresentation));
|
||||
defaultUser.setEmailVerified(true);
|
||||
defaultUser.setRealmRoles(List.of(RED_USER_ROLE, RED_MANAGER_ROLE, RED_ADMIN_ROLE, RED_USER_ADMIN_ROLE, "uma_authorization", "offline_access"));
|
||||
|
||||
var clientRoles = new HashMap<String, List<String>>();
|
||||
clientRoles.put("account", List.of("manage-account", "view-profile"));
|
||||
|
||||
defaultUser.setClientRoles(clientRoles);
|
||||
defaultUser.setEnabled(true);
|
||||
redaction.setUsers(List.of(defaultUser));
|
||||
|
||||
keycloak.getAdminClient().realms().create(redaction);
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
private void validateJdbcUrl(String jdbcUrl) {
|
||||
|
||||
@ -173,7 +325,6 @@ public class TenantManagementService {
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void runLiquibase(DataSource dataSource) throws LiquibaseException {
|
||||
|
||||
SpringLiquibase liquibase = getSpringLiquibase(dataSource);
|
||||
|
||||
@ -28,6 +28,23 @@ public class JDBCUtils {
|
||||
|
||||
|
||||
public String buildJdbcUrl(DatabaseConnection databaseConnection){
|
||||
StringBuilder sb = new StringBuilder("jdbc:")
|
||||
.append(databaseConnection.getDriver())
|
||||
.append("://")
|
||||
.append(databaseConnection.getHost())
|
||||
.append(':')
|
||||
.append(databaseConnection.getPort())
|
||||
.append('/')
|
||||
.append(databaseConnection.getDatabase());
|
||||
if(databaseConnection.getParams() != null) {
|
||||
sb.append('?');
|
||||
databaseConnection.getParams().forEach((k, v) -> sb.append('&').append(k).append(v));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public String buildJdbcUrlWithSchema(DatabaseConnection databaseConnection){
|
||||
StringBuilder sb = new StringBuilder("jdbc:")
|
||||
.append(databaseConnection.getDriver())
|
||||
.append("://")
|
||||
|
||||
@ -1,13 +1,23 @@
|
||||
package com.iqser.red.service.peristence.v1.server;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -17,7 +27,11 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.StatementCallback;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.DossierTemplateImportService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.TenantManagementService;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository;
|
||||
import com.iqser.red.service.persistence.management.v1.processor.utils.multitenancy.TenantContext;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.importexport.ImportDossierTemplateRequest;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.DatabaseConnection;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.S3StorageConnection;
|
||||
import com.iqser.red.service.persistence.service.v1.api.shared.model.multitenancy.SearchConnection;
|
||||
@ -70,30 +84,81 @@ public class DevConfiguration {
|
||||
.password("redaction")
|
||||
.build())
|
||||
.searchConnection(SearchConnection.builder()
|
||||
.hosts(Set.of("elasticsearchHost"))
|
||||
.hosts(Set.of("localhost"))
|
||||
.port(9200)
|
||||
.scheme("https")
|
||||
.scheme("http")
|
||||
.username("elastic")
|
||||
.password("changeMe")
|
||||
.numberOfShards("1")
|
||||
.numberOfReplicas("5")
|
||||
.build())
|
||||
.s3StorageConnection(S3StorageConnection.builder()
|
||||
.key("key")
|
||||
.secret("secret")
|
||||
.signerType("signerType")
|
||||
.bucketName("bucketName")
|
||||
.region("eu")
|
||||
.endpoint("endpoint")
|
||||
.key("minioadmin")
|
||||
.secret("minioadmin")
|
||||
.bucketName("redaction")
|
||||
.endpoint("http://localhost:9000")
|
||||
.build())
|
||||
.build();
|
||||
|
||||
tenantManagementService.createTenant(tenantRequest);
|
||||
|
||||
}
|
||||
|
||||
TenantContext.setTenantId("redaction");
|
||||
if(dossierTemplateRepository.count() == 0) {
|
||||
testDossierTemplateImport();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Autowired
|
||||
private DossierTemplateImportService dossierTemplateImportService;
|
||||
|
||||
@Autowired
|
||||
private DossierTemplateRepository dossierTemplateRepository;
|
||||
|
||||
public byte[] pack(String sourceDirPath) throws IOException {
|
||||
|
||||
var bos = new ByteArrayOutputStream();
|
||||
var p = Paths.get(sourceDirPath);
|
||||
try (ZipOutputStream zs = new ZipOutputStream(bos)) {
|
||||
Stream<Path> paths = Files.walk(p);
|
||||
{
|
||||
paths.filter(path -> !Files.isDirectory(path)).forEach(path -> {
|
||||
ZipEntry zipEntry = new ZipEntry(p.relativize(path).toString());
|
||||
try {
|
||||
zs.putNextEntry(zipEntry);
|
||||
Files.copy(path, zs);
|
||||
zs.closeEntry();
|
||||
} catch (IOException e) {
|
||||
System.err.println(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return bos.toByteArray();
|
||||
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void testDossierTemplateImport() {
|
||||
|
||||
var importDir = new File("/Users/timobejan/work/dossier-templates-v2/dev");
|
||||
|
||||
TenantContext.setTenantId("redaction");
|
||||
for (var file : importDir.listFiles()) {
|
||||
if(file.isDirectory()){
|
||||
var archive = pack(file.getAbsolutePath());
|
||||
log.info("Importing file: " + file.getName() + " " + " with size: " + archive.length);
|
||||
var request = new ImportDossierTemplateRequest();
|
||||
request.setArchive(archive);
|
||||
request.setUpdateExistingDossierTemplate(false);
|
||||
request.setUserId("system");
|
||||
dossierTemplateImportService.importDossierTemplate(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public void createSchema(String jdbcUrl, String username, String password) {
|
||||
|
||||
|
||||
@ -60,7 +60,7 @@ keycloak:
|
||||
commons:
|
||||
keycloak:
|
||||
applicationClientId: redaction
|
||||
clientId: redaction-system
|
||||
clientId: redaction
|
||||
clientSecret: G5E1qLU8ZNdDv7HY5BNLPdt5nXdeF7cU
|
||||
realm: redaction
|
||||
serverUrl: http://localhost:8080
|
||||
|
||||
@ -131,7 +131,7 @@ bucket4j:
|
||||
keycloak:
|
||||
sslRequired: none
|
||||
auth-server-url: https://red-staging.iqser.cloud/auth
|
||||
realm: redaction
|
||||
realm: master
|
||||
resource: redaction
|
||||
disableTrustManager: true
|
||||
useResourceRoleMappings: true
|
||||
@ -154,7 +154,7 @@ springdoc:
|
||||
operations-sorter: alpha
|
||||
tags-sorter: alpha
|
||||
oauth:
|
||||
client-id: swagger-ui-client
|
||||
client-id: redaction
|
||||
doc-expansion: none
|
||||
enabled: ${swagger.enabled}
|
||||
config-url: /redaction-gateway-v1/docs/swagger-config
|
||||
|
||||
@ -10,7 +10,6 @@ import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -35,7 +34,7 @@ public class DossierTemplateImportTest extends AbstractPersistenceServerServiceT
|
||||
@Disabled
|
||||
public void testDossierTemplateImport() {
|
||||
|
||||
var importDir = new File("/path/to/git/repo/dossier-templates-v2/dev");
|
||||
var importDir = new File("/Users/timobejan/work/dossier-templates-v2/dev");
|
||||
|
||||
TenantContext.setTenantId("redaction");
|
||||
for (var file : importDir.listFiles()) {
|
||||
|
||||
@ -2,8 +2,6 @@ package com.iqser.red.service.peristence.v1.server.integration.utils;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -16,6 +14,7 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.keycloak.adapters.springboot.KeycloakSpringBootProperties;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.amqp.core.AmqpAdmin;
|
||||
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
||||
@ -36,7 +35,6 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.StatementCallback;
|
||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
@ -102,7 +100,6 @@ import com.iqser.red.storage.commons.StorageAutoConfiguration;
|
||||
import com.iqser.red.storage.commons.service.StorageService;
|
||||
|
||||
import io.micrometer.prometheus.PrometheusMeterRegistry;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@ -120,8 +117,6 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
@MockBean
|
||||
protected RedactionLogMergeService redactionLogMergeService;
|
||||
@MockBean
|
||||
protected KeyCloakAdminClientService keyCloakAdminClientService;
|
||||
@MockBean
|
||||
protected PDFTronClient pdfTronRedactionClient;
|
||||
@Autowired
|
||||
protected ApplicationConfigClient appConfigClient;
|
||||
@ -212,6 +207,8 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
private UserService userService;
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
@Autowired
|
||||
private KeyCloakSettings keyCloakSettings;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
@ -232,12 +229,22 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
|
||||
TenantContext.setTenantId("redaction");
|
||||
|
||||
when(keyCloakAdminClientService.getAdminClient()).thenReturn(KeyCloakTestContainer.getInstance().getKeycloakAdminClient());
|
||||
// when(keyCloakAdminClientService.getAdminClient()).thenReturn(KeyCloakTestContainer.getInstance().getKeycloakAdminClient());
|
||||
|
||||
userService.evictUserCache();
|
||||
var allUsers = userService.getAllUsers();
|
||||
|
||||
if (allUsers.isEmpty()) {
|
||||
if (allUsers.size() == 1) {
|
||||
|
||||
var redactionSystemClient = new ClientRepresentation();
|
||||
redactionSystemClient.setEnabled(true);
|
||||
redactionSystemClient.setName(keyCloakSettings.getClientId());
|
||||
redactionSystemClient.setClientId(keyCloakSettings.getClientId());
|
||||
redactionSystemClient.setSecret(keyCloakSettings.getClientSecret());
|
||||
redactionSystemClient.setDirectAccessGrantsEnabled(true);
|
||||
redactionSystemClient.setServiceAccountsEnabled(true);
|
||||
|
||||
KeyCloakTestContainer.getInstance().getKeycloakAdminClient().realm("redaction").clients().create(redactionSystemClient);
|
||||
|
||||
var admin1 = createUser("manageradmin1@test.com");
|
||||
var admin2 = createUser("manageradmin2@test.com");
|
||||
@ -301,7 +308,6 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
var port = postgreSQLContainerMaster.getJdbcUrl().substring(0, postgreSQLContainerMaster.getJdbcUrl().lastIndexOf('/')).split(":")[3];
|
||||
|
||||
createDatabase("redaction", "redaction");
|
||||
createSchema(jdbcUrl, "redaction", "redaction");
|
||||
|
||||
var tenantRequest = TenantRequest.builder()
|
||||
.tenantId("redaction")
|
||||
@ -349,18 +355,6 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public void createSchema(String jdbcUrl, String username, String password) {
|
||||
|
||||
try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password)) {
|
||||
DataSource tenantDataSource = new SingleConnectionDataSource(connection, false);
|
||||
JdbcTemplate insert = new JdbcTemplate(tenantDataSource);
|
||||
insert.execute((StatementCallback<Boolean>) stmt -> stmt.execute("CREATE SCHEMA myschema"));
|
||||
insert.execute((StatementCallback<Boolean>) stmt -> stmt.execute("GRANT USAGE ON SCHEMA myschema TO " + username));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@AfterEach
|
||||
public void cleanupStorage() {
|
||||
|
||||
@ -432,14 +426,15 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
|
||||
var connectionStringDetails = "?serverTimezone=UTC&cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true";
|
||||
|
||||
var kcInstance = KeyCloakTestContainer.getInstance();
|
||||
|
||||
TestPropertyValues.of("spring.redis.port=" + redisContainer.getFirstMappedPort(),
|
||||
"multitenancy.master.datasource.url=" + postgreSQLContainerMaster.getJdbcUrl() + connectionStringDetails,
|
||||
"multitenancy.master.datasource.username=" + postgreSQLContainerMaster.getUsername(),
|
||||
"multitenancy.master.datasource.password=" + postgreSQLContainerMaster.getPassword()).applyTo(configurableApplicationContext.getEnvironment());
|
||||
"multitenancy.master.datasource.password=" + postgreSQLContainerMaster.getPassword(),
|
||||
"keycloak.auth-server-url=" + kcInstance.getAuthServerUrl(),
|
||||
"commons.keycloak.serverUrl=" + kcInstance.getAuthServerUrl()).applyTo(configurableApplicationContext.getEnvironment());
|
||||
|
||||
var kcInstance = KeyCloakTestContainer.getInstance();
|
||||
|
||||
TestPropertyValues.of("keycloak.auth-server-url=" + kcInstance.getAuthServerUrl());
|
||||
}
|
||||
|
||||
}
|
||||
@ -464,7 +459,7 @@ public abstract class AbstractPersistenceServerServiceTest {
|
||||
|
||||
var instance = KeyCloakTestContainer.getInstance();
|
||||
|
||||
when(cloakAdminClientService.getAdminClient()).thenReturn(instance.getKeycloakAdminClient());
|
||||
// when(cloakAdminClientService.getAdminClient()).thenReturn(instance.getKeycloakAdminClient());
|
||||
|
||||
keycloakSpringBootProperties.setAuthServerUrl(instance.getAuthServerUrl());
|
||||
keyCloakSettings.setServerUrl(instance.getAuthServerUrl());
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
package com.iqser.red.service.peristence.v1.server.integration.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
|
||||
import dasniko.testcontainers.keycloak.KeycloakContainer;
|
||||
|
||||
@ -26,35 +29,34 @@ public class KeyCloakTestContainer {
|
||||
keycloak.start();
|
||||
|
||||
var adminClient = keycloak.getKeycloakAdminClient();
|
||||
var redaction = new RealmRepresentation();
|
||||
redaction.setId("redaction");
|
||||
redaction.setRealm("redaction");
|
||||
redaction.setEnabled(true);
|
||||
adminClient.realms().create(redaction);
|
||||
var redaction = adminClient.realm("master");
|
||||
|
||||
var redactionRealm = adminClient.realm("redaction");
|
||||
var redactionClient = new ClientRepresentation();
|
||||
|
||||
redactionClient.setId("redaction");
|
||||
redactionClient.setEnabled(true);
|
||||
redactionClient.setName("redaction");
|
||||
redactionClient.setSecret("redaction");
|
||||
redactionClient.setServiceAccountsEnabled(true);
|
||||
redactionClient.setDirectAccessGrantsEnabled(true);
|
||||
redactionClient.setStandardFlowEnabled(true);
|
||||
redactionClient.setImplicitFlowEnabled(true);
|
||||
redactionClient.setDirectAccessGrantsEnabled(true);
|
||||
redactionRealm.clients().create(redactionClient);
|
||||
redaction.clients().create(redactionClient);
|
||||
redaction.clients().create(redactionClient);
|
||||
|
||||
RealmResource myRealm = adminClient.realm("master");
|
||||
String userId = myRealm.clients().get("redaction").getServiceAccountUser().getId();
|
||||
UserResource serviceAccountUser = myRealm.users().get(userId);
|
||||
|
||||
ClientRepresentation clientThatOwnsRole = myRealm.clients().findByClientId("master-realm").get(0);
|
||||
|
||||
String clientIdOfRoleOwner = clientThatOwnsRole.getId();
|
||||
|
||||
var redactionSystemClient = new ClientRepresentation();
|
||||
redactionSystemClient.setId("redaction-system");
|
||||
redactionSystemClient.setEnabled(true);
|
||||
redactionSystemClient.setName("redaction-system");
|
||||
redactionSystemClient.setSecret("redaction-system");
|
||||
redactionSystemClient.setDirectAccessGrantsEnabled(true);
|
||||
redactionSystemClient.setStandardFlowEnabled(true);
|
||||
redactionSystemClient.setImplicitFlowEnabled(true);
|
||||
redactionSystemClient.setDirectAccessGrantsEnabled(true);
|
||||
redactionRealm.clients().create(redactionSystemClient);
|
||||
List<RoleRepresentation> roles = new ArrayList<>();
|
||||
roles.addAll(myRealm.clients().get(clientIdOfRoleOwner).roles().list());
|
||||
serviceAccountUser.roles().clientLevel(clientIdOfRoleOwner).add(roles);
|
||||
serviceAccountUser.roles().realmLevel().add(List.of(myRealm.roles().get("create-realm").toRepresentation()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package com.iqser.red.service.peristence.v1.server.integration.utils;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.NotAuthorizedException;
|
||||
|
||||
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
|
||||
@ -48,6 +49,10 @@ public class TokenService {
|
||||
|
||||
try {
|
||||
return tokenClient.tokenManager().getAccessTokenString();
|
||||
} catch (BadRequestException e) {
|
||||
var response = e.getResponse().getEntity();
|
||||
System.out.println(response);
|
||||
return null;
|
||||
} catch (NotAuthorizedException e) {
|
||||
throw new AuthenticationFailedException(e);
|
||||
} finally {
|
||||
|
||||
@ -118,15 +118,15 @@ multitenancy:
|
||||
keycloak:
|
||||
enabled: true
|
||||
sslRequired: none
|
||||
realm: redaction
|
||||
resource: redaction
|
||||
realm: master
|
||||
resource: master
|
||||
disableTrustManager: true
|
||||
useResourceRoleMappings: true
|
||||
|
||||
commons:
|
||||
keycloak:
|
||||
application-client-id: redaction
|
||||
realm: redaction
|
||||
client-id: redaction-system
|
||||
client-secret: redaction-system
|
||||
realm: master
|
||||
client-id: redaction
|
||||
client-secret: redaction
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user