keycloak-memoizeit
Changes
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerClientTest.java 157(+52 -105)
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerTestRealmSetup.java 29(+0 -29)
testsuite/integration-arquillian/tests/base/src/test/resources/dockerClientTest/keycloak-docker-compose-yaml/certs/docker-realm-public-key.pem 17(+0 -17)
testsuite/integration-arquillian/tests/base/src/test/resources/dockerClientTest/keycloak-docker-compose-yaml/certs/localhost.crt 35(+0 -35)
testsuite/integration-arquillian/tests/base/src/test/resources/dockerClientTest/keycloak-docker-compose-yaml/certs/localhost.key 51(+0 -51)
Details
diff --git a/testsuite/integration-arquillian/pom.xml b/testsuite/integration-arquillian/pom.xml
index 674a92f..9c8854c 100644
--- a/testsuite/integration-arquillian/pom.xml
+++ b/testsuite/integration-arquillian/pom.xml
@@ -52,6 +52,7 @@
<version.shrinkwrap.resolvers>2.2.6</version.shrinkwrap.resolvers>
<undertow-embedded.version>1.0.0.Alpha2</undertow-embedded.version>
<version.org.wildfly.extras.creaper>1.6.1</version.org.wildfly.extras.creaper>
+ <testcontainers.version>1.5.1</testcontainers.version>
<!--migration properties-->
<migration.70.version>1.9.8.Final</migration.70.version>
diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml
index 7bffe00..a131f6a 100644
--- a/testsuite/integration-arquillian/tests/base/pom.xml
+++ b/testsuite/integration-arquillian/tests/base/pom.xml
@@ -112,7 +112,7 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
- <version>1.2.1</version>
+ <version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerClientTest.java
index f947d9e..fbc9fe1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerClientTest.java
@@ -4,53 +4,44 @@ import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.common.Profile;
+import org.keycloak.representations.idm.KeysMetadataRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.ProfileAssume;
-import org.keycloak.testsuite.util.WaitUtils;
-import org.rnorth.ducttape.ratelimits.RateLimiterBuilder;
-import org.rnorth.ducttape.unreliables.Unreliables;
-import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.BindMode;
import org.testcontainers.containers.Container;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
-import org.testcontainers.images.builder.ImageFromDockerfile;
-import org.testcontainers.shaded.com.github.dockerjava.api.model.ContainerNetwork;
+import sun.security.provider.X509Factory;
-import java.util.Arrays;
+import java.io.File;
+import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Predicate;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assume.assumeTrue;
-import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
public class DockerClientTest extends AbstractKeycloakTest {
- public static final Logger LOGGER = LoggerFactory.getLogger(DockerClientTest.class);
-
public static final String REALM_ID = "docker-test-realm";
- public static final String AUTH_FLOW = "docker-basic-auth-flow";
public static final String CLIENT_ID = "docker-test-client";
public static final String DOCKER_USER = "docker-user";
public static final String DOCKER_USER_PASSWORD = "password";
- public static final String REGISTRY_HOSTNAME = "registry.localdomain";
+ public static final String REGISTRY_HOSTNAME = "localhost";
public static final Integer REGISTRY_PORT = 5000;
public static final String MINIMUM_DOCKER_VERSION = "1.8.0";
- public static final String IMAGE_NAME = "busybox";
private GenericContainer dockerRegistryContainer = null;
private GenericContainer dockerClientContainer = null;
private static String hostIp;
+ private static String authServerPort;
@BeforeClass
public static void verifyEnvironment() {
@@ -59,7 +50,6 @@ public class DockerClientTest extends AbstractKeycloakTest {
final Optional<DockerVersion> dockerVersion = new DockerHostVersionSupplier().get();
assumeTrue("Could not determine docker version for host machine. It either is not present or accessible to the JVM running the test harness.", dockerVersion.isPresent());
assumeTrue("Docker client on host machine is not a supported version. Please upgrade and try again.", DockerVersion.COMPARATOR.compare(dockerVersion.get(), DockerVersion.parseVersionString(MINIMUM_DOCKER_VERSION)) >= 0);
- LOGGER.debug("Discovered valid docker client on host. version: {}", dockerVersion);
hostIp = System.getProperty("host.ip");
@@ -70,21 +60,13 @@ public class DockerClientTest extends AbstractKeycloakTest {
}
}
Assert.assertNotNull("Could not resolve host machine's IP address for docker adapter, and 'host.ip' system poperty not set. Client will not be able to authenticate against the keycloak server!", hostIp);
+
+ authServerPort = AUTH_SERVER_SSL_REQUIRED ? System.getProperty("auth.server.https.port") : System.getProperty("auth.server.http.port");
}
@Override
public void addTestRealms(final List<RealmRepresentation> testRealms) {
- final RealmRepresentation dockerRealm = loadJson(getClass().getResourceAsStream("/docker-test-realm.json"), RealmRepresentation.class);
-
- /**
- * TODO fix test harness/importer NPEs when attempting to create realm from scratch.
- * Need to fix those, would be preferred to do this programmatically such that we don't have to keep realm elements
- * (I.E. certs, realm url) in sync with a flat file
- *
- * final RealmRepresentation dockerRealm = DockerTestRealmSetup.createRealm(REALM_ID);
- * DockerTestRealmSetup.configureDockerAuthenticationFlow(dockerRealm, AUTH_FLOW);
- */
-
+ final RealmRepresentation dockerRealm = DockerTestRealmSetup.createRealm(REALM_ID);
DockerTestRealmSetup.configureDockerRegistryClient(dockerRealm, CLIENT_ID);
DockerTestRealmSetup.configureUser(dockerRealm, DOCKER_USER, DOCKER_USER_PASSWORD);
@@ -95,106 +77,71 @@ public class DockerClientTest extends AbstractKeycloakTest {
public void beforeAbstractKeycloakTest() throws Exception {
super.beforeAbstractKeycloakTest();
+ // find the realm cert
+ String realmCert = null;
+ List<KeysMetadataRepresentation.KeyMetadataRepresentation> realmKeys = adminClient.realm(REALM_ID).keys().getKeyMetadata().getKeys();
+ for (KeysMetadataRepresentation.KeyMetadataRepresentation key : realmKeys) {
+ if (key.getType().equals("RSA")) {
+ realmCert = key.getCertificate();
+ }
+ }
+ if (realmCert == null) {
+ throw new IllegalStateException("Cannot find public realm cert");
+ }
+
+ // save the cert to a file
+ File tmpCertFile = File.createTempFile("keycloak-docker-realm-cert-", ".pem");
+ tmpCertFile.deleteOnExit();
+ PrintWriter tmpCertWriter = new PrintWriter(tmpCertFile);
+ tmpCertWriter.println(X509Factory.BEGIN_CERT);
+ tmpCertWriter.println(realmCert);
+ tmpCertWriter.println(X509Factory.END_CERT);
+ tmpCertWriter.close();
+
final Map<String, String> environment = new HashMap<>();
environment.put("REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY", "/tmp");
- environment.put("REGISTRY_HTTP_TLS_CERTIFICATE", "/opt/certs/localhost.crt");
- environment.put("REGISTRY_HTTP_TLS_KEY", "/opt/certs/localhost.key");
- environment.put("REGISTRY_AUTH_TOKEN_REALM", "http://" + hostIp + ":8180/auth/realms/docker-test-realm/protocol/docker-v2/auth");
+ environment.put("REGISTRY_AUTH_TOKEN_REALM", "http://" + hostIp + ":" + authServerPort + "/auth/realms/" + REALM_ID + "/protocol/docker-v2/auth");
environment.put("REGISTRY_AUTH_TOKEN_SERVICE", CLIENT_ID);
- environment.put("REGISTRY_AUTH_TOKEN_ISSUER", "http://" + hostIp + ":8180/auth/realms/docker-test-realm");
- environment.put("REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE", "/opt/certs/docker-realm-public-key.pem");
+ environment.put("REGISTRY_AUTH_TOKEN_ISSUER", "http://" + hostIp + ":" + authServerPort + "/auth/realms/" + REALM_ID);
+ environment.put("REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE", "/opt/kc-certs/" + tmpCertFile.getCanonicalFile().getName());
environment.put("INSECURE_REGISTRY", "--insecure-registry " + REGISTRY_HOSTNAME + ":" + REGISTRY_PORT);
String dockerioPrefix = Boolean.parseBoolean(System.getProperty("docker.io-prefix-explicit")) ? "docker.io/" : "";
- // TODO this required me to turn selinux off :(. Add BindMode options for :z and :Z. Make selinux enforcing again!
dockerRegistryContainer = new GenericContainer(dockerioPrefix + "registry:2")
- .withClasspathResourceMapping("dockerClientTest/keycloak-docker-compose-yaml/certs", "/opt/certs", BindMode.READ_ONLY)
+ .withFileSystemBind(tmpCertFile.getCanonicalPath(), "/opt/kc-certs/" + tmpCertFile.getCanonicalFile().getName(), BindMode.READ_ONLY)
.withEnv(environment)
+ .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("dockerRegistryContainer")))
+ .withNetworkMode("host")
.withPrivilegedMode(true);
dockerRegistryContainer.start();
- dockerRegistryContainer.followOutput(new Slf4jLogConsumer(LOGGER));
-
- dockerClientContainer = new GenericContainer(
- new ImageFromDockerfile()
- .withDockerfileFromBuilder(dockerfileBuilder -> {
- dockerfileBuilder.from("centos/systemd:latest")
- .run("yum", "install", "-y", "docker", "iptables", ";", "yum", "clean", "all")
- .cmd("/usr/sbin/init")
- .volume("/sys/fs/cgroup")
- .build();
- })
- )
- .withClasspathResourceMapping("dockerClientTest/keycloak-docker-compose-yaml/certs/localhost.crt", "/opt/docker/certs.d/" + REGISTRY_HOSTNAME + "/localhost.crt", BindMode.READ_ONLY)
- .withClasspathResourceMapping("dockerClientTest/keycloak-docker-compose-yaml/sysconfig_docker", "/etc/sysconfig/docker", BindMode.READ_WRITE)
- .withPrivilegedMode(true);
-
- final Optional<ContainerNetwork> network = dockerRegistryContainer.getContainerInfo().getNetworkSettings().getNetworks().values().stream().findFirst();
- assumeTrue("Could not find a network adapter whereby the docker client container could connect to host!", network.isPresent());
- dockerClientContainer.withExtraHost(REGISTRY_HOSTNAME, network.get().getIpAddress());
+ dockerClientContainer = new GenericContainer(dockerioPrefix + "docker:dind")
+ .withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger("dockerClientContainer")))
+ .withNetworkMode("host")
+ .withPrivilegedMode(true);
dockerClientContainer.start();
- dockerClientContainer.followOutput(new Slf4jLogConsumer(LOGGER));
-
- int i = 0;
- String stdErr = "";
- while (i++ < 30) {
- log.infof("Trying to start docker service; attempt: %d", i);
- stdErr = dockerClientContainer.execInContainer("systemctl", "start", "docker.service").getStderr();
- if (stdErr.isEmpty()) {
- break;
- }
- else {
- log.info("systemctl failed: " + stdErr);
- }
- WaitUtils.pause(1000);
- }
-
- assumeTrue("Cannot start docker service!", stdErr.isEmpty());
-
- log.info("Waiting for docker service...");
- validateDockerStarted();
- log.info("Docker service successfully started");
}
- private void validateDockerStarted() {
- final Callable<Boolean> checkStrategy = () -> {
- try {
- final String commandResult = dockerClientContainer.execInContainer("docker", "ps").getStderr();
- return !commandResult.contains("Cannot connect");
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } catch (Exception e) {
- return false;
- }
- };
+ @Override
+ public void afterAbstractKeycloakTest() {
+ super.afterAbstractKeycloakTest();
- Unreliables.retryUntilTrue(30, TimeUnit.SECONDS, () -> RateLimiterBuilder.newBuilder().withRate(1, TimeUnit.SECONDS).withConstantThroughput().build().getWhenReady(() -> {
- try {
- return checkStrategy.call();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }));
+ pause(5000); // wait for the container logs
+
+ dockerClientContainer.close();
+ dockerRegistryContainer.close();
}
@Test
public void shouldPerformDockerAuthAgainstRegistry() throws Exception {
+ log.info("Starting the attempt for login...");
Container.ExecResult dockerLoginResult = dockerClientContainer.execInContainer("docker", "login", "-u", DOCKER_USER, "-p", DOCKER_USER_PASSWORD, REGISTRY_HOSTNAME + ":" + REGISTRY_PORT);
- printNonEmpties(dockerLoginResult.getStdout(), dockerLoginResult.getStderr());
+ printCommandResult(dockerLoginResult);
assertThat(dockerLoginResult.getStdout(), containsString("Login Succeeded"));
}
- private static void printNonEmpties(final String... results) {
- Arrays.stream(results)
- .forEachOrdered(DockerClientTest::printNonEmpty);
- }
-
- private static void printNonEmpty(final String result) {
- if (nullOrEmpty.negate().test(result)) {
- LOGGER.info(result);
- }
+ private void printCommandResult(Container.ExecResult result) {
+ log.infof("Command executed. Output follows:\nSTDOUT: %s\n---\nSTDERR: %s", result.getStdout(), result.getStderr());
}
-
- public static final Predicate<String> nullOrEmpty = string -> string == null || string.isEmpty();
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerTestRealmSetup.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerTestRealmSetup.java
index 727af1d..6e711f0 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerTestRealmSetup.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerTestRealmSetup.java
@@ -1,10 +1,6 @@
package org.keycloak.testsuite.docker;
-import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.protocol.docker.DockerAuthV2Protocol;
-import org.keycloak.protocol.docker.DockerAuthenticator;
-import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
-import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
@@ -31,31 +27,6 @@ public final class DockerTestRealmSetup {
return createdRealm;
}
- public static void configureDockerAuthenticationFlow(final RealmRepresentation dockerRealm, final String authFlowAlais) {
- final AuthenticationFlowRepresentation dockerBasicAuthFlow = new AuthenticationFlowRepresentation();
- dockerBasicAuthFlow.setId(UUID.randomUUID().toString());
- dockerBasicAuthFlow.setAlias(authFlowAlais);
- dockerBasicAuthFlow.setProviderId("basic-flow");
- dockerBasicAuthFlow.setTopLevel(true);
- dockerBasicAuthFlow.setBuiltIn(false);
-
- final AuthenticationExecutionExportRepresentation dockerBasicAuthExecution = new AuthenticationExecutionExportRepresentation();
- dockerBasicAuthExecution.setAuthenticator(DockerAuthenticator.ID);
- dockerBasicAuthExecution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED.name());
- dockerBasicAuthExecution.setPriority(0);
- dockerBasicAuthExecution.setUserSetupAllowed(false);
- dockerBasicAuthExecution.setAutheticatorFlow(false);
-
- final List<AuthenticationExecutionExportRepresentation> authenticationExecutions = Optional.ofNullable(dockerBasicAuthFlow.getAuthenticationExecutions()).orElse(new ArrayList<>());
- authenticationExecutions.add(dockerBasicAuthExecution);
- dockerBasicAuthFlow.setAuthenticationExecutions(authenticationExecutions);
-
- final List<AuthenticationFlowRepresentation> authenticationFlows = Optional.ofNullable(dockerRealm.getAuthenticationFlows()).orElse(new ArrayList<>());
- authenticationFlows.add(dockerBasicAuthFlow);
- dockerRealm.setAuthenticationFlows(authenticationFlows);
- dockerRealm.setBrowserFlow(dockerBasicAuthFlow.getAlias());
- }
-
public static void configureDockerRegistryClient(final RealmRepresentation dockerRealm, final String clientId) {
final ClientRepresentation dockerClient = new ClientRepresentation();