diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/common/install-features.sh b/testsuite/integration-arquillian/servers/app-server/karaf/common/install-features.sh index d094ff4c7d..b8cba84bed 100755 --- a/testsuite/integration-arquillian/servers/app-server/karaf/common/install-features.sh +++ b/testsuite/integration-arquillian/servers/app-server/karaf/common/install-features.sh @@ -23,7 +23,7 @@ do fi if "$UPDATE_CONFIG" == "true"; then - echo "Updating Config - org.ops4j.pax.url.mvn" + echo "Updating Config" ./client $CLIENT_AUTH -f update-config.cli if [ $? -ne 0 ]; then RESULT=1; @@ -36,6 +36,14 @@ do ./client $CLIENT_AUTH -f install-features.cli if [ $? -ne 0 ]; then RESULT=1; fi + if "$UPDATE_CONFIG" == "true"; then + echo "Updating Config - Keycloak authentication" + ./client $CLIENT_AUTH -f update-config-auth.cli + if [ $? -ne 0 ]; then + RESULT=1; + fi + fi + ./stop rm -rf ../data/log rm -rf ../data/tmp diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/pom.xml b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/pom.xml index 80dfc56b92..a048eeab20 100644 --- a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/pom.xml +++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/pom.xml @@ -32,7 +32,7 @@ fuse63 org.jboss.fuse - jboss-fuse-full + jboss-fuse-karaf ${fuse63.version} jboss-fuse-${fuse63.version} -u admin -p admin diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-direct-access.json b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-direct-access.json new file mode 100644 index 0000000000..2441134231 --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-direct-access.json @@ -0,0 +1,9 @@ +{ + "realm": "demo", + "resource": "ssh-jmx-admin-client", + "ssl-required" : "external", + "auth-server-url" : "http://localhost:8080/auth", + "credentials": { + "secret": "password" + } +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-hawtio-client.json b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-hawtio-client.json new file mode 100644 index 0000000000..64d0d57885 --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-hawtio-client.json @@ -0,0 +1,7 @@ +{ + "realm" : "demo", + "resource" : "hawtio-client", + "auth-server-url" : "http://localhost:8080/auth", + "ssl-required" : "external", + "public-client" : true +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-hawtio.json b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-hawtio.json new file mode 100644 index 0000000000..36daac064a --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/keycloak-hawtio.json @@ -0,0 +1,9 @@ +{ + "realm" : "demo", + "resource" : "jaas", + "bearer-only" : true, + "auth-server-url" : "http://localhost:8080/auth", + "ssl-required" : "external", + "use-resource-role-mappings": false, + "principal-attribute": "preferred_username" +} \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/update-config-auth.cli b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/update-config-auth.cli new file mode 100644 index 0000000000..2c3bc66080 --- /dev/null +++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/update-config-auth.cli @@ -0,0 +1,8 @@ +config:edit org.apache.karaf.shell +config:propset sshRealm keycloak +config:update +system-property -p hawtio.roles admin,user +system-property -p hawtio.keycloakEnabled true +system-property -p hawtio.realm keycloak +system-property -p hawtio.keycloakClientConfig \$\{karaf.base\}/etc/keycloak-hawtio-client.json +system-property -p hawtio.rolePrincipalClasses org.keycloak.adapters.jaas.RolePrincipal,org.apache.karaf.jaas.boot.principal.RolePrincipal diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/update-config.cli b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/update-config.cli index d6a425a0f7..9a319403ba 100644 --- a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/update-config.cli +++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/src/main/resources/update-config.cli @@ -3,3 +3,8 @@ config:propset org.ops4j.pax.url.mvn.localRepository ${maven.repo.local} config:propset org.ops4j.pax.url.mvn.settings ${maven.local.settings} config:propappend org.ops4j.pax.url.mvn.repositories ${repositories} config:update +config:edit jmx.acl.org.apache.karaf.security.jmx +config:propappend list* viewer +config:propappend set* jmxAdmin +config:propappend * jmxAdmin,admin +config:update \ No newline at end of file diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/pom.xml b/testsuite/integration-arquillian/servers/app-server/karaf/pom.xml index ecff21a47c..b717b3d3bc 100644 --- a/testsuite/integration-arquillian/servers/app-server/karaf/pom.xml +++ b/testsuite/integration-arquillian/servers/app-server/karaf/pom.xml @@ -117,6 +117,7 @@ install-features.cli update-config.cli + update-config-auth.cli true @@ -124,7 +125,7 @@ - copy-users-properties + copy-configs process-resources copy-resources @@ -137,6 +138,9 @@ src/main/resources users.properties + keycloak-direct-access.json + keycloak-hawtio-client.json + keycloak-hawtio.json diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml index 198c0aaf9f..58050ddd90 100644 --- a/testsuite/integration-arquillian/tests/base/pom.xml +++ b/testsuite/integration-arquillian/tests/base/pom.xml @@ -81,6 +81,26 @@ greenmail compile + + org.jboss.arquillian.container + arquillian-container-karaf-managed + 2.1.0.CR18 + + + org.jboss.arquillian.container + arquillian-container-osgi + 2.1.0.CR18 + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.enterprise + provided + diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java index c9a9d89f9f..310a3bc464 100644 --- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/KeycloakArquillianExtension.java @@ -17,6 +17,7 @@ package org.keycloak.testsuite.arquillian; +import org.jboss.arquillian.container.spi.client.container.DeployableContainer; import org.jboss.arquillian.container.test.impl.enricher.resource.URLResourceProvider; import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor; import org.jboss.arquillian.container.test.spi.client.deployment.DeploymentScenarioGenerator; @@ -26,6 +27,7 @@ import org.jboss.arquillian.graphene.location.CustomizableURLResourceProvider; import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider; import org.jboss.arquillian.test.spi.execution.TestExecutionDecider; import org.keycloak.testsuite.arquillian.h2.H2TestEnricher; +import org.keycloak.testsuite.arquillian.karaf.CustomKarafContainer; import org.keycloak.testsuite.arquillian.migration.MigrationTestExecutionDecider; import org.keycloak.testsuite.arquillian.provider.AdminClientProvider; import org.keycloak.testsuite.arquillian.provider.OAuthClientProvider; @@ -51,10 +53,10 @@ public class KeycloakArquillianExtension implements LoadableExtension { builder .service(DeploymentScenarioGenerator.class, DeploymentTargetModifier.class) .service(ApplicationArchiveProcessor.class, DeploymentArchiveProcessor.class) + .service(DeployableContainer.class, CustomKarafContainer.class) .observer(AuthServerTestEnricher.class) .observer(AppServerTestEnricher.class) .observer(H2TestEnricher.class); - builder .service(TestExecutionDecider.class, MigrationTestExecutionDecider.class); diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/karaf/CustomKarafContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/karaf/CustomKarafContainer.java new file mode 100644 index 0000000000..46f43a3201 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/karaf/CustomKarafContainer.java @@ -0,0 +1,231 @@ +package org.keycloak.testsuite.arquillian.karaf; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.jboss.arquillian.container.osgi.jmx.JMXDeployableContainer; +import org.jboss.arquillian.container.osgi.jmx.ObjectNameFactory; +import org.jboss.arquillian.container.osgi.karaf.managed.KarafManagedContainerConfiguration; +import org.jboss.arquillian.container.spi.client.container.LifecycleException; +import org.osgi.jmx.framework.BundleStateMBean; +import org.osgi.jmx.framework.FrameworkMBean; +import org.osgi.jmx.framework.ServiceStateMBean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * KarafManagedDeployableContainer + * + * @author thomas.diesler@jboss.com + */ +public class CustomKarafContainer extends JMXDeployableContainer { + + static final Logger _logger = LoggerFactory.getLogger(CustomKarafContainer.class.getPackage().getName()); + + private KarafManagedContainerConfiguration config; + private Process process; + + @Override + public Class getConfigurationClass() { + @SuppressWarnings("unchecked") + Class clazz = (Class) KarafManagedContainerConfiguration.class; + return clazz; + } + + @Override + public void setup(T config) { + super.setup(config); + this.config = config; + } + + @Override + public void start() throws LifecycleException { + + // Try to connect to an already running server + MBeanServerConnection mbeanServer = null; + try { + mbeanServer = getMBeanServerConnection(500, TimeUnit.MILLISECONDS); + } catch (TimeoutException ex) { + // ignore + } + + if (mbeanServer != null && !config.isAllowConnectingToRunningServer()) { + throw new LifecycleException( + "The server is already running! Managed containers does not support connecting to running server instances due to the " + + "possible harmful effect of connecting to the wrong server. Please stop server before running or change to another type of container.\n" + + "To disable this check and allow Arquillian to connect to a running server, set allowConnectingToRunningServer to true in the container configuration"); + } + + // Start the Karaf process + if (mbeanServer == null) { + String karafHome = config.getKarafHome(); + if (karafHome == null) + throw new IllegalStateException("karafHome cannot be null"); + + File karafHomeDir = new File(karafHome).getAbsoluteFile(); + if (!karafHomeDir.isDirectory()) + throw new IllegalStateException("Not a valid Karaf home dir: " + karafHomeDir); + + String java = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"; + _logger.info(String.format("Using java: %s", java)); + + List cmd = new ArrayList(); + cmd.add(java); + + // JavaVM args + String javaArgs = config.getJavaVmArguments(); + if (!javaArgs.contains("-Xmx")) { + javaArgs = KarafManagedContainerConfiguration.DEFAULT_JAVAVM_ARGUMENTS + " " + javaArgs; + } + cmd.addAll(Arrays.asList(javaArgs.split("\\s"))); + + // Karaf properties + cmd.add("-Dkaraf.home=" + karafHomeDir); + cmd.add("-Dkaraf.base=" + karafHomeDir); + cmd.add("-Dkaraf.etc=" + karafHomeDir + "/etc"); + cmd.add("-Dkaraf.data=" + karafHomeDir + "/data"); + cmd.add("-Dkaraf.instances=" + karafHomeDir + "/instances"); + cmd.add("-Dkaraf.startLocalConsole=false"); + cmd.add("-Dkaraf.startRemoteShell=true"); + + // Java properties + cmd.add("-Djava.io.tmpdir=" + new File(karafHomeDir, "data/tmp")); + cmd.add("-Djava.util.logging.config.file=" + new File(karafHomeDir, "etc/java.util.logging.properties")); + cmd.add("-Djava.endorsed.dirs=" + new File(karafHomeDir, "lib/endorsed")); + + // Classpath + StringBuilder classPath = new StringBuilder(); + File karafLibDir = new File(karafHomeDir, "lib"); + String[] libs = karafLibDir.list(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.startsWith("karaf"); + } + }); + for (String lib : libs) { + String separator = classPath.length() > 0 ? File.pathSeparator : ""; + classPath.append(separator).append(new File(karafHomeDir, "lib/" + lib)); + } + cmd.add("-classpath"); + cmd.add(classPath.toString()); + + // Main class + cmd.add("org.apache.karaf.main.Main"); + + // Output the startup command + StringBuffer cmdstr = new StringBuffer(); + for (String tok : cmd) { + cmdstr.append(tok).append(" "); + } + _logger.debug("Starting Karaf with: {}", cmdstr); + + try { + ProcessBuilder processBuilder = new ProcessBuilder(cmd); + processBuilder.directory(karafHomeDir); + processBuilder.redirectErrorStream(true); + process = processBuilder.start(); + new Thread(new ConsoleConsumer()).start(); + } catch (Exception ex) { + throw new LifecycleException("Cannot start managed Karaf container", ex); + } + + // Get the MBeanServerConnection + try { + mbeanServer = getMBeanServerConnection(30, TimeUnit.SECONDS); + } catch (Exception ex) { + destroyKarafProcess(); + throw new LifecycleException("Cannot obtain MBean server connection", ex); + } + } + + mbeanServerInstance.set(mbeanServer); + + try { + // Get the FrameworkMBean + ObjectName oname = ObjectNameFactory.create("osgi.core:type=framework,*"); + frameworkMBean = getMBeanProxy(mbeanServer, oname, FrameworkMBean.class, 30, TimeUnit.SECONDS); + + // Get the BundleStateMBean + oname = ObjectNameFactory.create("osgi.core:type=bundleState,*"); + bundleStateMBean = getMBeanProxy(mbeanServer, oname, BundleStateMBean.class, 30, TimeUnit.SECONDS); + + // Get the BundleStateMBean + oname = ObjectNameFactory.create("osgi.core:type=serviceState,*"); + serviceStateMBean = getMBeanProxy(mbeanServer, oname, ServiceStateMBean.class, 30, TimeUnit.SECONDS); + + // Install the arquillian bundle to become active + installArquillianBundle(); + + // Await the arquillian bundle to become active + awaitArquillianBundleActive(30, TimeUnit.SECONDS); + + // Await the beginning start level + Integer beginningStartLevel = config.getKarafBeginningStartLevel(); + if (beginningStartLevel != null) + awaitBeginningStartLevel(beginningStartLevel, 30, TimeUnit.SECONDS); + + // Await bootsrap complete services + awaitBootstrapCompleteServices(); + + } catch (RuntimeException rte) { + destroyKarafProcess(); + throw rte; + } catch (Exception ex) { + destroyKarafProcess(); + throw new LifecycleException("Cannot start Karaf container", ex); + } + } + + @Override + public void stop() throws LifecycleException { + super.stop(); + destroyKarafProcess(); + } + + private void destroyKarafProcess() throws LifecycleException { + if (process != null) { + process.destroy(); + try { + process.waitFor(); + } catch (InterruptedException e) { + throw new LifecycleException("Cannot start Karaf container", e); + } + } + } + + /** + * Runnable that consumes the output of the process. If nothing consumes the output the AS will hang on some platforms + * + * @author Stuart Douglas + */ + private class ConsoleConsumer implements Runnable { + + @Override + public void run() { + final InputStream stream = process.getInputStream(); + final boolean writeOutput = config.isOutputToConsole(); + try { + byte[] buf = new byte[32]; + int num; + // Do not try reading a line cos it considers '\r' end of line + while ((num = stream.read(buf)) != -1) { + if (writeOutput) + System.out.write(buf, 0, num); + } + } catch (IOException ignored) { + } + } + } + + +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseAdminAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseAdminAdapterTest.java new file mode 100644 index 0000000000..3cc9b38701 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseAdminAdapterTest.java @@ -0,0 +1,258 @@ +package org.keycloak.testsuite.adapter.example; + +import static org.junit.Assert.assertTrue; +import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO; +import static org.keycloak.testsuite.util.IOUtil.loadRealm; +import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlDoesntStartWith; +import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.apache.sshd.client.SshClient; +import org.apache.sshd.client.channel.ClientChannel; +import org.apache.sshd.client.channel.ClientChannelEvent; +import org.apache.sshd.client.future.ConnectFuture; +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.client.session.ClientSession.ClientSessionEvent; +import org.jboss.arquillian.graphene.page.Page; +import org.junit.Assert; +import org.junit.Test; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest; +import org.keycloak.testsuite.adapter.page.HawtioPage; + +public abstract class AbstractFuseAdminAdapterTest extends AbstractExampleAdapterTest { + + @Page + private HawtioPage hawtioPage; + + private SshClient client; + + private ClientChannel channel; + + private ClientSession session; + + enum Result { OK, NOT_FOUND, NO_CREDENTIALS, NO_ROLES }; + + @Override + public void addAdapterTestRealms(List testRealms) { + RealmRepresentation fuseRealm = loadRealm(new File(EXAMPLES_HOME_DIR + "/fuse/demorealm.json")); + testRealms.add(fuseRealm); + } + + @Override + public void setDefaultPageUriParameters() { + super.setDefaultPageUriParameters(); + testRealmPage.setAuthRealm(DEMO); + testRealmLoginPage.setAuthRealm(DEMO); + } + + @Test + public void hawtioLoginTest() throws Exception { + hawtioPage.navigateTo(); + testRealmLoginPage.form().login("user", "invalid-password"); + assertCurrentUrlDoesntStartWith(hawtioPage); + + testRealmLoginPage.form().login("invalid-user", "password"); + assertCurrentUrlDoesntStartWith(hawtioPage); + + testRealmLoginPage.form().login("root", "password"); + assertCurrentUrlStartsWith(hawtioPage.getDriver(), hawtioPage.toString() + "/welcome"); + hawtioPage.logout(); + assertCurrentUrlStartsWith(testRealmLoginPage); + + hawtioPage.navigateTo(); + testRealmLoginPage.form().login("mary", "password"); + assertTrue(!driver.getPageSource().contains("welcome")); + } + + + + @Test + public void sshLoginTest() throws Exception { + assertCommand("mary", "password", "shell:date", Result.NO_ROLES); + assertCommand("john", "password", "shell:info", Result.NO_CREDENTIALS); + assertCommand("john", "password", "shell:date", Result.OK); + assertCommand("root", "password", "shell:info", Result.OK); + } + + @Test + public void jmxLoginTest() throws Exception { + setJMXAuthentication("keycloak", "password"); + ObjectName mbean = new ObjectName("org.apache.karaf:type=config,name=root"); + //invalid credentials + try { + getJMXConnector("mary", "password1").getMBeanServerConnection(); + Assert.fail(); + } catch (SecurityException se) {} + //no role + MBeanServerConnection connection = getJMXConnector("mary", "password").getMBeanServerConnection(); + assertJmxInvoke(false, connection, mbean, "listProperties", new Object [] {""}, new String [] {String.class.getName()}); + assertJmxInvoke(false, connection, mbean, "setProperty", new Object [] {"", "x", "y"}, new String [] {String.class.getName(), String.class.getName(), String.class.getName()}); + //read only role + connection = getJMXConnector("john", "password").getMBeanServerConnection(); + assertJmxInvoke(true, connection, mbean, "listProperties", new Object [] {""}, new String [] {String.class.getName()}); + assertJmxInvoke(false, connection, mbean, "setProperty", new Object [] {"", "x", "y"}, new String [] {String.class.getName(), String.class.getName(), String.class.getName()}); + //read write role + connection = getJMXConnector("root", "password").getMBeanServerConnection(); + assertJmxInvoke(true, connection, mbean, "listProperties", new Object [] {""}, new String [] {String.class.getName()}); + assertJmxInvoke(true, connection, mbean, "setProperty", new Object [] {"", "x", "y"}, new String [] {String.class.getName(), String.class.getName(), String.class.getName()}); + setJMXAuthentication("karaf", "admin"); + } + + private String assertCommand(String user, String password, String command, Result result) throws Exception, IOException { + if (!command.endsWith("\n")) + command += "\n"; + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + OutputStream pipe = openSshChannel(user, password, out, out); + pipe.write(command.getBytes()); + pipe.flush(); + + closeSshChannel(pipe); + String output = new String(out.toByteArray()); + + switch(result) { + case OK: + Assert.assertFalse("Should not contain 'Insufficient credentials' or 'Command not found': " + output, + output.contains("Insufficient credentials") || output.contains("Command not found")); + break; + case NOT_FOUND: + Assert.assertTrue("Should contain 'Command not found': " + output, + output.contains("Command not found")); + break; + case NO_CREDENTIALS: + Assert.assertTrue("Should contain 'Insufficient credentials': " + output, + output.contains("Insufficient credentials")); + break; + case NO_ROLES: + Assert.assertTrue("Should contain 'Current user has no associated roles': " + output, + output.contains("Current user has no associated roles")); + break; + default: + Assert.fail("Unexpected enum value: " + result); + } + return output; + } + + private OutputStream openSshChannel(String username, String password, OutputStream ... outputs) throws Exception { + client = SshClient.setUpDefaultClient(); + client.start(); + ConnectFuture future = client.connect(username, "localhost", 8101); + future.await(); + session = future.getSession(); + + Set ret = EnumSet.of(ClientSessionEvent.WAIT_AUTH); + while (ret.contains(ClientSessionEvent.WAIT_AUTH)) { + session.addPasswordIdentity(password); + session.auth().verify(); + ret = session.waitFor(EnumSet.of(ClientSessionEvent.WAIT_AUTH, ClientSessionEvent.CLOSED, ClientSessionEvent.AUTHED), 0); + } + if (ret.contains(ClientSessionEvent.CLOSED)) { + throw new Exception("Could not open SSH channel"); + } + channel = session.createChannel("shell"); + PipedOutputStream pipe = new PipedOutputStream(); + channel.setIn(new PipedInputStream(pipe)); + + OutputStream out; + if (outputs.length >= 1) { + out = outputs[0]; + } else { + out = new ByteArrayOutputStream(); + } + channel.setOut(out); + + OutputStream err; + if (outputs.length >= 2) { + err = outputs[1]; + } else { + err = new ByteArrayOutputStream(); + } + channel.setErr(err); + channel.open(); + + return pipe; + } + + private void setJMXAuthentication(String realm, String password) throws Exception { + assertCommand("admin", "password", "config:edit org.apache.karaf.management; config:propset jmxRealm " + realm + "; config:update", Result.OK); + getMBeanServerConnection(10000, TimeUnit.MILLISECONDS, "admin", password); + } + + private void closeSshChannel(OutputStream pipe) throws IOException { + pipe.write("logout\n".getBytes()); + pipe.flush(); + + channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), 0); + session.close(true); + client.stop(); + + client = null; + channel = null; + session = null; + } + + private Object assertJmxInvoke(boolean expectSuccess, MBeanServerConnection connection, ObjectName mbean, String method, + Object[] params, String[] signature) throws InstanceNotFoundException, MBeanException, ReflectionException, IOException { + try { + Object result = connection.invoke(mbean, method, params, signature); + assertTrue(expectSuccess); + return result; + } catch (SecurityException se) { + assertTrue(!expectSuccess); + return null; + } + } + + private MBeanServerConnection getMBeanServerConnection(long timeout, final TimeUnit unit, String username, String password) throws Exception { + Exception lastException = null; + long timeoutMillis = System.currentTimeMillis() + unit.toMillis(timeout); + while (System.currentTimeMillis() < timeoutMillis) { + try { + return getJMXConnector(username, password).getMBeanServerConnection(); + } catch (Exception ex) { + lastException = ex; + Thread.sleep(500); + ex.printStackTrace(); + } + } + TimeoutException timeoutException = new TimeoutException(); + timeoutException.initCause(lastException); + throw timeoutException; + } + + private JMXConnector getJMXConnector(String userName, String password) throws Exception { + JMXServiceURL url = new JMXServiceURL(getJmxServiceUrl()); + String[] credentials = new String[] { userName, password }; + Map env = Collections.singletonMap(JMXConnector.CREDENTIALS, credentials); + JMXConnector connector = JMXConnectorFactory.connect(url, env); + return connector; + } + + private String getJmxServiceUrl() throws Exception { + return "service:jmx:rmi://localhost:44444/jndi/rmi://localhost:1099/karaf-root"; + } + +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java index b0583fb70a..f21a48c27b 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractFuseExampleAdapterTest.java @@ -59,7 +59,7 @@ public abstract class AbstractFuseExampleAdapterTest extends AbstractExampleAdap @Override public void addAdapterTestRealms(List testRealms) { - RealmRepresentation fuseRealm = loadRealm(new File(EXAMPLES_HOME_DIR + "/fuse/testrealm.json")); + RealmRepresentation fuseRealm = loadRealm(new File(EXAMPLES_HOME_DIR + "/fuse/demorealm.json")); testRealms.add(fuseRealm); } diff --git a/testsuite/integration-arquillian/tests/other/adapters/karaf/common/xslt/arquillian.xsl b/testsuite/integration-arquillian/tests/other/adapters/karaf/common/xslt/arquillian.xsl index 9c8f2a622f..9c1b6ebb9e 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/karaf/common/xslt/arquillian.xsl +++ b/testsuite/integration-arquillian/tests/other/adapters/karaf/common/xslt/arquillian.xsl @@ -31,21 +31,19 @@ true - org.jboss.arquillian.container.osgi.karaf.managed.KarafManagedDeployableContainer - + + org.keycloak.testsuite.arquillian.karaf.CustomKarafContainer false ${app.server.home} ${app.server.java.home} - -agentlib:jdwp=transport=dt_socket,address=5005,server=y,suspend=n ${adapter.test.props} service:jmx:rmi://127.0.0.1:44444/jndi/rmi://127.0.0.1:1099/karaf-root ${app.server.management.user} - ${app.server.management.password} + ${app.server.management.password} - diff --git a/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/src/test/java/org/keycloak/testsuite/adapter/example/Fuse63AdminAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/src/test/java/org/keycloak/testsuite/adapter/example/Fuse63AdminAdapterTest.java new file mode 100644 index 0000000000..90f80d4817 --- /dev/null +++ b/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/src/test/java/org/keycloak/testsuite/adapter/example/Fuse63AdminAdapterTest.java @@ -0,0 +1,8 @@ +package org.keycloak.testsuite.adapter.example; + +import org.keycloak.testsuite.arquillian.annotation.AppServerContainer; + +@AppServerContainer("app-server-fuse63") +public class Fuse63AdminAdapterTest extends AbstractFuseAdminAdapterTest { + +} diff --git a/testsuite/integration-arquillian/tests/other/adapters/karaf/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/karaf/pom.xml index 70e4a2cdef..c930dec56b 100644 --- a/testsuite/integration-arquillian/tests/other/adapters/karaf/pom.xml +++ b/testsuite/integration-arquillian/tests/other/adapters/karaf/pom.xml @@ -86,7 +86,12 @@ org.apache.karaf org.apache.karaf.client 3.0.3 - + + + org.apache.sshd + sshd-core + 1.2.0 + diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml index 642087dfe6..5c6a03f720 100755 --- a/testsuite/integration-arquillian/tests/pom.xml +++ b/testsuite/integration-arquillian/tests/pom.xml @@ -719,6 +719,12 @@ compile + + org.apache.sshd + sshd-core + 1.2.0 + + com.icegreen