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:
Dominique Eiflaender 2023-03-24 15:43:06 +01:00
commit 48df7bf273
13 changed files with 304 additions and 70 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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());

View File

@ -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);

View File

@ -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("://")

View File

@ -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) {

View File

@ -60,7 +60,7 @@ keycloak:
commons:
keycloak:
applicationClientId: redaction
clientId: redaction-system
clientId: redaction
clientSecret: G5E1qLU8ZNdDv7HY5BNLPdt5nXdeF7cU
realm: redaction
serverUrl: http://localhost:8080

View File

@ -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

View File

@ -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()) {

View File

@ -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());

View File

@ -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()));
}

View File

@ -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 {

View File

@ -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