Skip to content

Commit

Permalink
Upgrade keycloak to version 18.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
pablo gonzalez granados committed Jun 23, 2022
1 parent f081952 commit a16b950
Show file tree
Hide file tree
Showing 22 changed files with 434 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import io.quarkus.test.bootstrap.KeycloakService;
import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.services.Container;
import io.quarkus.test.services.KeycloakContainer;

public abstract class BaseSecurityResourceIT {

Expand All @@ -17,9 +17,8 @@ public abstract class BaseSecurityResourceIT {
static final String CLIENT_SECRET_DEFAULT = "test-application-client-secret";
static final String NORMAL_USER = "test-normal-user";

@Container(image = "quay.io/keycloak/keycloak:16.1.0", expectedLog = "Admin console listening", port = 8080)
static final KeycloakService keycloak = new KeycloakService("/keycloak-realm.json", REALM_DEFAULT);

@KeycloakContainer(command = { "start-dev --import-realm" })
static KeycloakService keycloak = new KeycloakService("/keycloak-realm.json", REALM_DEFAULT);
private AuthzClient authzClient;

protected abstract RestService getApp();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class OpenShiftUsingCustomTemplateResourceIT {
private static final String CLIENT_ID_DEFAULT = "test-application-client";
private static final String CLIENT_SECRET_DEFAULT = "test-application-client-secret";

@Container(image = "quay.io/keycloak/keycloak:16.1.0", expectedLog = "Admin console listening", port = 8080)
@Container(image = "quay.io/keycloak/keycloak:18.0.0", expectedLog = "started", port = 8080)
static final KeycloakService customkeycloak = new KeycloakService("/keycloak-realm.json", REALM_DEFAULT);

@QuarkusApplication
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

@QuarkusScenario
public class SecurityResourceIT extends BaseSecurityResourceIT {

@QuarkusApplication
static final RestService app = new RestService()
.withProperty("quarkus.oidc.auth-server-url", () -> keycloak.getRealmUrl())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ items:
- name: latest
from:
kind: DockerImage
name: quay.io/keycloak/keycloak:16.1.0
name: quay.io/keycloak/keycloak:18.0.0
- apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
Expand All @@ -31,6 +31,7 @@ items:
spec:
containers:
- name: keycloak
args: [ "start-dev", "--import-realm"]
env:
- name: X509_CA_BUNDLE
value: /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt
Expand Down
33 changes: 32 additions & 1 deletion examples/keycloak/src/test/resources/keycloak-realm.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,38 @@
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": true,
"clientAuthenticatorType": "client-secret",
"secret": "test-application-client-secret"
"secret": "test-application-client-secret",
"protocolMappers": [
{
"id": "f17f8d5f-2327-4e0b-8001-48a7706be252",
"name": "realm roles",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-realm-role-mapper",
"consentRequired": false,
"config": {
"user.attribute": "foo",
"access.token.claim": "true",
"claim.name": "realm_access.roles",
"jsonType.label": "String",
"multivalued": "true"
}
},
{
"id": "0e0f1e8d-60f9-4435-b753-136d70e56af8",
"name": "username",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-property-mapper",
"consentRequired": false,
"config": {
"userinfo.token.claim": "true",
"user.attribute": "username",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "preferred_username",
"jsonType.label": "String"
}
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import static io.quarkus.test.bootstrap.BaseService.SERVICE_STARTUP_TIMEOUT;
import static io.quarkus.test.bootstrap.BaseService.SERVICE_STARTUP_TIMEOUT_DEFAULT;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_PREFIX;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_WITH_DESTINATION_PREFIX;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_WITH_DESTINATION_PREFIX_MATCHER;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_WITH_DESTINATION_SPLIT_CHAR;
import static io.quarkus.test.utils.PropertiesUtils.SECRET_PREFIX;

import java.nio.file.Files;
Expand Down Expand Up @@ -116,29 +119,46 @@ private Map<String, String> resolveProperties() {
Map<String, String> properties = new HashMap<>();
for (Entry<String, String> entry : context.getOwner().getProperties().entrySet()) {
String value = entry.getValue();

if (isResource(entry.getValue())) {
value = entry.getValue().replace(RESOURCE_PREFIX, StringUtils.EMPTY);
addFileToContainer(value);
addFileToContainer(value, value);
} else if (isResourceWithDestinationPath(entry.getValue())) {
value = entry.getValue().replace(RESOURCE_WITH_DESTINATION_PREFIX, StringUtils.EMPTY);
if (!value.matches(RESOURCE_WITH_DESTINATION_PREFIX_MATCHER)) {
String errorMsg = String.format("Unexpected %s format. Expected destinationPath|fileName but found %s",
RESOURCE_WITH_DESTINATION_PREFIX, value);
throw new RuntimeException(errorMsg);
}

String destinationPath = value.split(RESOURCE_WITH_DESTINATION_SPLIT_CHAR)[0];
String fileName = value.split(RESOURCE_WITH_DESTINATION_SPLIT_CHAR)[1];
addFileToContainer(destinationPath, fileName);
} else if (isSecret(entry.getValue())) {
value = entry.getValue().replace(SECRET_PREFIX, StringUtils.EMPTY);
addFileToContainer(value);
addFileToContainer(value, value);
}

properties.put(entry.getKey(), value);
}
return properties;
}

private void addFileToContainer(String filePath) {
if (Files.exists(Path.of(TARGET, filePath))) {
private void addFileToContainer(String destinationPath, String hostFilePath) {
String containerFullPath = destinationPath + hostFilePath;
if (Files.exists(Path.of(TARGET, hostFilePath))) {
// Mount file if it's a file
innerContainer.withCopyFileToContainer(MountableFile.forHostPath(Path.of(TARGET, filePath)), filePath);
innerContainer.withCopyFileToContainer(MountableFile.forHostPath(Path.of(TARGET, hostFilePath)), containerFullPath);
} else {
// then file is in the classpath
innerContainer.withClasspathResourceMapping(filePath, filePath, BindMode.READ_ONLY);
innerContainer.withClasspathResourceMapping(hostFilePath, containerFullPath, BindMode.READ_ONLY);
}
}

private boolean isResourceWithDestinationPath(String key) {
return key.startsWith(RESOURCE_WITH_DESTINATION_PREFIX);
}

private boolean isResource(String key) {
return key.startsWith(RESOURCE_PREFIX);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
public final class PropertiesUtils {

public static final String RESOURCE_PREFIX = "resource::/";
public static final String RESOURCE_WITH_DESTINATION_PREFIX = "resource_with_destination::";
public static final String RESOURCE_WITH_DESTINATION_SPLIT_CHAR = "\\|";
public static final String RESOURCE_WITH_DESTINATION_PREFIX_MATCHER = ".*" + RESOURCE_WITH_DESTINATION_SPLIT_CHAR + ".*";
public static final String SECRET_PREFIX = "secret::/";
public static final Path TARGET = Path.of("target");
public static final String SLASH = "/";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package io.quarkus.test.bootstrap.inject;

import static io.quarkus.test.model.CustomVolume.VolumeType.CONFIG_MAP;
import static io.quarkus.test.model.CustomVolume.VolumeType.SECRET;
import static io.quarkus.test.utils.AwaitilityUtils.AwaitilitySettings;
import static io.quarkus.test.utils.AwaitilityUtils.untilIsNotNull;
import static io.quarkus.test.utils.AwaitilityUtils.untilIsTrue;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_PREFIX;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_WITH_DESTINATION_PREFIX;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_WITH_DESTINATION_PREFIX_MATCHER;
import static io.quarkus.test.utils.PropertiesUtils.RESOURCE_WITH_DESTINATION_SPLIT_CHAR;
import static io.quarkus.test.utils.PropertiesUtils.SECRET_PREFIX;
import static io.quarkus.test.utils.PropertiesUtils.SLASH;
import static io.quarkus.test.utils.PropertiesUtils.TARGET;
Expand Down Expand Up @@ -33,16 +38,13 @@

import io.fabric8.knative.client.KnativeClient;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesList;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder;
import io.fabric8.kubernetes.api.model.Volume;
import io.fabric8.kubernetes.api.model.VolumeBuilder;
import io.fabric8.kubernetes.api.model.VolumeMount;
import io.fabric8.kubernetes.api.model.VolumeMountBuilder;
import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.client.dsl.PodResource;
Expand All @@ -62,6 +64,7 @@
import io.quarkus.test.bootstrap.Service;
import io.quarkus.test.configuration.PropertyLookup;
import io.quarkus.test.logging.Log;
import io.quarkus.test.model.CustomVolume;
import io.quarkus.test.services.operator.model.CustomResourceStatus;
import io.quarkus.test.utils.AwaitilityUtils;
import io.quarkus.test.utils.Command;
Expand Down Expand Up @@ -630,67 +633,85 @@ private EnvVar getEnvVarByKey(String key, Container container) {

private Map<String, String> enrichProperties(Map<String, String> properties, DeploymentConfig dc) {
// mount path x volume
Map<String, Volume> volumes = new HashMap<>();
Map<String, CustomVolume> volumes = new HashMap<>();

Map<String, String> output = new HashMap<>();
for (Entry<String, String> entry : properties.entrySet()) {
String value = entry.getValue();
if (isResource(entry.getValue())) {
String propertyValue = entry.getValue();
if (isResource(propertyValue)) {
String path = entry.getValue().replace(RESOURCE_PREFIX, StringUtils.EMPTY);
String mountPath = getMountPath(path);
String filename = getFileName(path);
String configMapName = normalizeName(mountPath);
String configMapName = normalizeConfigMapName(mountPath);

// Update config map
createOrUpdateConfigMap(configMapName, filename, getFileContent(path));

// Add the volume
if (!volumes.containsKey(mountPath)) {
Volume volume = new VolumeBuilder()
.withName(configMapName)
.withConfigMap(new ConfigMapVolumeSourceBuilder().withName(configMapName).build())
.build();
volumes.put(mountPath, volume);
volumes.put(mountPath, new CustomVolume(configMapName, "", CONFIG_MAP));
}

value = mountPath + SLASH + filename;
} else if (isSecret(entry.getValue())) {
propertyValue = mountPath + SLASH + filename;
} else if (isResourceWithDestinationPath(propertyValue)) {
String path = propertyValue.replace(RESOURCE_WITH_DESTINATION_PREFIX, StringUtils.EMPTY);
if (!propertyValue.matches(RESOURCE_WITH_DESTINATION_PREFIX_MATCHER)) {
String errorMsg = String.format("Unexpected %s format. Expected destinationPath|fileName but found %s",
RESOURCE_WITH_DESTINATION_PREFIX, propertyValue);
throw new RuntimeException(errorMsg);
}

String mountPath = path.split(RESOURCE_WITH_DESTINATION_SPLIT_CHAR)[0];
String fileName = path.split(RESOURCE_WITH_DESTINATION_SPLIT_CHAR)[1];
String fileNameNormalized = getFileName(fileName);
String configMapName = normalizeConfigMapName(mountPath);

// Update config map
createOrUpdateConfigMap(configMapName, fileNameNormalized, getFileContent(fileName));
propertyValue = mountPath + SLASH + fileNameNormalized;
// Add the volume
if (!volumes.containsKey(mountPath)) {
volumes.put(propertyValue, new CustomVolume(configMapName, fileNameNormalized, CONFIG_MAP));
}
} else if (isSecret(propertyValue)) {
String path = entry.getValue().replace(SECRET_PREFIX, StringUtils.EMPTY);
String mountPath = getMountPath(path);
String filename = getFileName(path);
String secretName = normalizeName(path);
String secretName = normalizeConfigMapName(path);

// Push secret file
doCreateSecretFromFile(secretName, getFilePath(path));
volumes.put(mountPath, volumes.put(mountPath, new CustomVolume(secretName, "", SECRET)));

// Add the volume
Volume volume = new VolumeBuilder()
.withName(secretName)
.withSecret(new SecretVolumeSourceBuilder()
.withSecretName(secretName)
.build())
.build();
volumes.put(mountPath, volume);

value = mountPath + SLASH + filename;
propertyValue = mountPath + SLASH + filename;
}

output.put(entry.getKey(), value);
output.put(entry.getKey(), propertyValue);
}

for (Entry<String, Volume> volume : volumes.entrySet()) {
dc.getSpec().getTemplate().getSpec().getVolumes().add(volume.getValue());
for (Entry<String, CustomVolume> volume : volumes.entrySet()) {
dc.getSpec().getTemplate().getSpec().getVolumes().add(volume.getValue().getVolume());

// Configure all the containers to map the volume
dc.getSpec().getTemplate().getSpec().getContainers()
.forEach(container -> container.getVolumeMounts()
.add(new VolumeMountBuilder().withName(volume.getValue().getName())
.withReadOnly(true).withMountPath(volume.getKey()).build()));
.add(createVolumeMount(volume)));
}

return output;
}

private VolumeMount createVolumeMount(Entry<String, CustomVolume> volume) {
VolumeMountBuilder volumeMountBuilder = new VolumeMountBuilder().withName(volume.getValue().getName())
.withReadOnly(true).withMountPath(volume.getKey());

if (!volume.getValue().getSubFolderRegExp().isEmpty()) {
volumeMountBuilder.withSubPathExpr(volume.getValue().getSubFolderRegExp());
}

return volumeMountBuilder.build();
}

private void createOrUpdateConfigMap(String configMapName, String key, String value) {
if (client.configMaps().withName(configMapName).get() != null) {
// update existing config map by adding new file
Expand Down Expand Up @@ -752,12 +773,16 @@ private String getFilePath(String path) {
return path;
}

private String normalizeName(String name) {
private String normalizeConfigMapName(String name) {
return StringUtils.removeStart(name, SLASH)
.replaceAll(Pattern.quote("."), "-")
.replaceAll(SLASH, "-");
}

private boolean isResourceWithDestinationPath(String key) {
return key.startsWith(RESOURCE_WITH_DESTINATION_PREFIX);
}

private boolean isResource(String key) {
return key.startsWith(RESOURCE_PREFIX);
}
Expand Down Expand Up @@ -828,5 +853,4 @@ private String generateRandomProjectName() {
.collect(() -> new StringBuilder("ts-"), StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
}

}
Loading

0 comments on commit a16b950

Please sign in to comment.