Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

26 adapt structure of config import #27

Merged
merged 2 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,89 +1,65 @@
package com.cycrilabs.keycloak.configurator.commands.configure.boundary;

import static io.quarkus.arc.ComponentsProvider.LOG;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject;

import org.keycloak.admin.client.Keycloak;

import com.cycrilabs.keycloak.configurator.commands.configure.control.ConfigurationFileStore;
import com.cycrilabs.keycloak.configurator.commands.configure.control.EntityStore;
import com.cycrilabs.keycloak.configurator.commands.configure.entity.ConfigureCommandConfiguration;
import com.cycrilabs.keycloak.configurator.shared.control.JsonUtil;
import com.cycrilabs.keycloak.configurator.shared.control.KeycloakFactory;
import com.cycrilabs.keycloak.configurator.shared.entity.EntityType;

import io.quarkus.logging.Log;

public abstract class AbstractImporter {
/**
* The path separator for the current operating system. This is used to split the file path into
* its parts. This is used in a regular expression, so special characters need to be escaped.
*/
public static final String PATH_SEPARATOR =
Pattern.quote(FileSystems.getDefault().getSeparator());

@Inject
protected ConfigureCommandConfiguration configuration;
protected Keycloak keycloak;
@Inject
protected ConfigurationFileStore configurationFileStore;
protected EntityStore entityStore;

@PostConstruct
public void init() {
keycloak = KeycloakFactory.create(configuration);
}

protected <T> T loadEntity(final Path filepath, final Class<T> dtoClass) {
final String json = loadJsonFromResource(filepath);
return JsonUtil.fromJson(json, dtoClass);
}

private String loadJsonFromResource(final Path filePath) {
try {
return Files.readString(filePath, StandardCharsets.UTF_8);
} catch (final IOException e) {
LOG.errorf("Could not read file {}", filePath);
throw new RuntimeException(e);
}
}

public void runImport(final EntityStore entityStore) {
Log.infof("Executing importer %s.", getClass().getSimpleName());
Log.infof("Executing importer '%s'.", getClass().getSimpleName());
this.entityStore = entityStore;
final List<Path> importFiles = getEntityFilePaths(getEntityDirectory());
for (final Path importFile : importFiles) {

for (final Path importFile : getImportFiles()) {
Log.debugf("Importing file '%s'.", importFile);
importFile(importFile);
}
}

private List<Path> getEntityFilePaths(final String entityDir) {
final String dir = Paths.get(configuration.getConfigDirectory(), entityDir).toString();
try (final Stream<Path> stream = Files.walk(Paths.get(dir))) {
return stream
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".json"))
.toList();
} catch (final IOException e) {
Log.errorf("Could not read directory %s", dir);
return Collections.emptyList();
private List<Path> getImportFiles() {
final List<Path> importFiles = configurationFileStore.getImportFiles(getType());
if (importFiles.isEmpty()) {
Log.infof("No files found for importer '%s'.", getClass().getSimpleName());
}
return importFiles;
}

public int getPriority() {
return getType().getPriority();
}

protected String getEntityDirectory() {
return getType().getDirectory();
}

public abstract EntityType getType();

protected abstract Object importFile(final Path file);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.ErrorRepresentation;

import com.cycrilabs.keycloak.configurator.shared.control.JsonUtil;
import com.cycrilabs.keycloak.configurator.shared.entity.EntityType;

import io.quarkus.logging.Log;
Expand All @@ -22,30 +23,31 @@ public EntityType getType() {

@Override
protected ClientRepresentation importFile(final Path file) {
final ClientRepresentation client = loadEntity(file, ClientRepresentation.class);
final ClientRepresentation client = JsonUtil.loadEntity(file, ClientRepresentation.class);

final String[] fileNameParts = file.toString().split(PATH_SEPARATOR);
final String realmName = fileNameParts[fileNameParts.length - 2];
final String realmName = fileNameParts[fileNameParts.length - 3];

try (final Response response = keycloak.realm(realmName)
.clients()
.create(client)) {
if (response.getStatus() == 409) {
Log.errorf("Could not import client from file: %s",
Log.errorf("Could not import client for realm '%s': %s", realmName,
response.readEntity(ErrorRepresentation.class)
.getErrorMessage());
} else {
Log.infof("Client '%s' imported.", client.getClientId());
Log.infof("Client '%s' imported for realm '%s'.", client.getClientId(), realmName);
}
} catch (final ClientErrorException e) {
Log.errorf("Could not import client from file: %s", e.getMessage());
Log.errorf("Could not import client for realm '%s': %s", realmName, e.getMessage());
}

final ClientRepresentation importedClient = keycloak.realm(realmName)
.clients()
.findByClientId(client.getClientId())
.get(0);
Log.infof("Loaded client role '%s' from server.", importedClient.getClientId());
Log.infof("Loaded client '%s' from realm '%s'.", importedClient.getClientId(),
realmName);
entityStore.addClient(realmName, importedClient);
return importedClient;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.cycrilabs.keycloak.configurator.commands.configure.boundary;

import java.nio.file.Path;
import java.util.Arrays;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.ClientErrorException;

import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;

import com.cycrilabs.keycloak.configurator.shared.control.JsonUtil;
import com.cycrilabs.keycloak.configurator.shared.entity.EntityType;

import io.quarkus.logging.Log;
Expand All @@ -21,10 +23,10 @@ public EntityType getType() {

@Override
protected RoleRepresentation importFile(final Path file) {
final RoleRepresentation role = loadEntity(file, RoleRepresentation.class);
final RoleRepresentation role = JsonUtil.loadEntity(file, RoleRepresentation.class);

final String[] fileNameParts = file.toString().split(PATH_SEPARATOR);
final String realmName = fileNameParts[fileNameParts.length - 3];
final String realmName = fileNameParts[fileNameParts.length - 4];
final String clientId = fileNameParts[fileNameParts.length - 2];
final ClientRepresentation client = entityStore.getClient(realmName, clientId);

Expand All @@ -34,9 +36,11 @@ protected RoleRepresentation importFile(final Path file) {
.get(client.getId())
.roles()
.create(role);
Log.infof("Client role '%s' imported.", role.getName());
} catch (final ClientErrorException e) {
Log.errorf("Could not import client role from file: %s", e.getMessage());
Log.infof("Client role '%s' imported for client '%s' of realm '%s'.", role.getName(),
clientId, realmName);
} catch (final Exception e) {
Log.errorf("Could not import client role for client '%s' of realm '%s': %s", clientId,
realmName, e.getMessage());
}

return keycloak.realm(realmName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.keycloak.representations.idm.ErrorRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;

import com.cycrilabs.keycloak.configurator.shared.control.JsonUtil;
import com.cycrilabs.keycloak.configurator.shared.entity.EntityType;

import io.quarkus.logging.Log;
Expand All @@ -22,30 +23,31 @@ public EntityType getType() {

@Override
protected Object importFile(final Path file) {
final GroupRepresentation group = loadEntity(file, GroupRepresentation.class);
final GroupRepresentation group = JsonUtil.loadEntity(file, GroupRepresentation.class);

final String[] fileNameParts = file.toString().split(PATH_SEPARATOR);
final String realmName = fileNameParts[fileNameParts.length - 2];
final String realmName = fileNameParts[fileNameParts.length - 3];

try (final Response response = keycloak.realm(realmName)
.groups()
.add(group)) {
if (response.getStatus() == 409) {
Log.errorf("Could not import group from file: %s",
Log.errorf("Could not import group for realm '%s': %s", realmName,
response.readEntity(ErrorRepresentation.class)
.getErrorMessage());
} else {
Log.infof("Group '%s' imported.", group.getName());
Log.infof("Group '%s' imported for realm '%s'.", group.getName(), realmName);
}
} catch (final ClientErrorException e) {
Log.errorf("Could not import group from file: %s", e.getMessage());
Log.errorf("Could not import group for realm '%s': %s", realmName, e.getMessage());
}

final GroupRepresentation importedGroup = keycloak.realm(realmName)
.groups()
.query(group.getName())
.get(0);
Log.infof("Loaded imported group '%s' from server.", importedGroup.getName());
Log.infof("Loaded imported group '%s' from realm '%s'.", importedGroup.getName(),
realmName);
return importedGroup;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import org.keycloak.representations.idm.RealmRepresentation;

import com.cycrilabs.keycloak.configurator.shared.control.JsonUtil;
import com.cycrilabs.keycloak.configurator.shared.entity.EntityType;

import io.quarkus.logging.Log;
Expand All @@ -20,7 +21,7 @@ public EntityType getType() {

@Override
protected RealmRepresentation importFile(final Path file) {
final RealmRepresentation realm = loadEntity(file, RealmRepresentation.class);
final RealmRepresentation realm = JsonUtil.loadEntity(file, RealmRepresentation.class);

try {
keycloak.realms()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.cycrilabs.keycloak.configurator.commands.configure.boundary;

import java.nio.file.Path;
import java.util.List;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.ClientErrorException;

import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;

import com.cycrilabs.keycloak.configurator.shared.control.JsonUtil;
import com.cycrilabs.keycloak.configurator.shared.entity.EntityType;

import io.quarkus.logging.Log;
Expand All @@ -20,25 +23,32 @@ public EntityType getType() {

@Override
protected Object importFile(final Path file) {
final RoleRepresentation role = loadEntity(file, RoleRepresentation.class);
final RoleRepresentation role = JsonUtil.loadEntity(file, RoleRepresentation.class);

final String[] fileNameParts = file.toString().split(PATH_SEPARATOR);
final String realmName = fileNameParts[fileNameParts.length - 2];
final String realmName = fileNameParts[fileNameParts.length - 3];

try {
keycloak.realm(realmName)
.roles()
.create(role);
Log.infof("Realm role '%s' imported.", role.getName());
Log.infof("Realm role '%s' imported for realm '%s'.", role.getName(), realmName);
} catch (final ClientErrorException e) {
Log.errorf("Could not import realm role from file: %s", e.getMessage());
Log.errorf("Could not import realm role for realm '%s': %s", realmName, e.getMessage());
}

final RoleRepresentation importedRole = keycloak.realm(realmName)
.roles()
.get(role.getName())
.toRepresentation();
Log.infof("Loaded imported realm role '%s' from server.", importedRole.getName());
return importedRole;
try {
final RoleRepresentation importedRole = keycloak.realm(realmName)
.roles()
.get(role.getName())
.toRepresentation();
Log.infof("Loaded imported realm role '%s' from realm '%s'.", importedRole.getName(),
realmName);
return importedRole;
} catch (final ClientErrorException e) {
Log.errorf("Could not load imported realm role '%s' from realm '%s': %s", role.getName(),
realmName, e.getMessage());
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.keycloak.representations.idm.ErrorRepresentation;
import org.keycloak.representations.idm.UserRepresentation;

import com.cycrilabs.keycloak.configurator.shared.control.JsonUtil;
import com.cycrilabs.keycloak.configurator.shared.entity.EntityType;

import io.quarkus.logging.Log;
Expand All @@ -23,23 +24,24 @@ public EntityType getType() {

@Override
protected Object importFile(final Path file) {
final UserRepresentation user = loadEntity(file, UserRepresentation.class);
final UserRepresentation user = JsonUtil.loadEntity(file, UserRepresentation.class);

final String[] fileNameParts = file.toString().split(PATH_SEPARATOR);
final String realmName = fileNameParts[fileNameParts.length - 2];
final String realmName = fileNameParts[fileNameParts.length - 3];

try (final Response response = keycloak.realm(realmName)
.users()
.create(user)) {
if (response.getStatus() == 409) {
Log.errorf("Could not import user from file: %s",
Log.errorf("Could not import user from file for realm '%s': %s", realmName,
response.readEntity(ErrorRepresentation.class)
.getErrorMessage());
} else {
Log.infof("User '%s' imported.", user.getEmail());
Log.infof("User '%s' imported for realm '%s'.", user.getEmail(), realmName);
}
} catch (final ClientErrorException e) {
Log.errorf("Could not import user from file: %s", e.getMessage());
Log.errorf("Could not import user from file for realm '%s': %s", realmName,
e.getMessage());
}

return loadImportedUser(realmName, user);
Expand All @@ -51,11 +53,12 @@ private UserRepresentation loadImportedUser(final String realmName,
.users()
.search(user.getUsername());
if (searchResult.isEmpty()) {
Log.infof("Could not load imported user '%s' from server.", user.getUsername());
Log.infof("Could not load imported user '%s' from realm '%s'.", user.getUsername(),
realmName);
return null;
}
final UserRepresentation importedUser = searchResult.getFirst();
Log.infof("Loaded imported user '%s' from server.", importedUser.getEmail());
Log.infof("Loaded imported user '%s' from realm '%s'.", importedUser.getEmail(), realmName);
return importedUser;
}
}
Loading
Loading