changeset 259:5704bdfab65e

Add basic Keycloak integration tests This adds a test suite that verifies basic security auth with Keycloak works as expected. By default the test suite is skipped. The integration tests can be run by setting the maven property '-Dmaven.ktest.skip=false'. The test suite expects a Keycloak server available at 127.0.0.1:31000 configured with users. Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-July/024326.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-August/024727.html Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024924.html
author Jie Kang <jkang@redhat.com>
date Thu, 14 Sep 2017 10:23:32 -0400
parents e73a052c5901
children 8453ba17aa0f
files pom.xml server/src/main/java/com/redhat/thermostat/gateway/server/Start.java services/jvms/src/main/java/com/redhat/thermostat/gateway/service/jvms/http/JvmsHttpHandler.java tests/keycloak-integration-tests/pom.xml tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/cpu/JvmCpuServiceKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/gc/JvmGcServiceKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/io/JvmIoServiceKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/memory/JvmMemoryServiceKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvms/JvmsServiceKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/system/cpu/SystemCpuKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/system/memory/SystemMemoryKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/system/network/SystemNetworkKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/systems/SystemInfoKeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/keycloak/BasicKeycloakIntegrationTestSuite.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/keycloak/KeycloakIntegrationTest.java tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/keycloak/MongoKeycloakIntegrationTest.java tests/pom.xml tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/EndpointDefinition.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/HttpRequestUtil.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/MongodTestUtil.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/DefaultKeycloakUsers.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/KeycloakAccessToken.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/KeycloakServerCredentials.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/KeycloakTestConfigurationFactory.java tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/KeycloakUserCredentials.java
diffstat 25 files changed, 1925 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/pom.xml	Wed Sep 13 18:45:37 2017 +0200
+++ b/pom.xml	Thu Sep 14 10:23:32 2017 -0400
@@ -77,8 +77,10 @@
 
         <license.skip>false</license.skip>
 
+        <!-- True to skip integration tests. Default to false -->
         <maven.itest.skip>false</maven.itest.skip>
-
+        <!-- True to skip keycloak integration tests. Default to true -->
+        <maven.ktest.skip>true</maven.ktest.skip>
         <!-- Intentionally empty. See java-7 profile -->
         <surefire.argline></surefire.argline>
     </properties>
--- a/server/src/main/java/com/redhat/thermostat/gateway/server/Start.java	Wed Sep 13 18:45:37 2017 +0200
+++ b/server/src/main/java/com/redhat/thermostat/gateway/server/Start.java	Thu Sep 14 10:23:32 2017 -0400
@@ -49,16 +49,22 @@
 
     private Server server = null;
     private AbstractLifeCycle.AbstractLifeCycleListener listener = null;
+    private final ConfigurationFactory factory;
 
     public Start() {
+        this(null, new ConfigurationFactory());
     }
 
     public Start(AbstractLifeCycle.AbstractLifeCycleListener listener) {
+        this(listener, new ConfigurationFactory());
+    }
+
+    public Start(AbstractLifeCycle.AbstractLifeCycleListener listener, ConfigurationFactory factory) {
         this.listener = listener;
+        this.factory = factory;
     }
 
     public void run() {
-        ConfigurationFactory factory = new ConfigurationFactory();
         CoreServerBuilder serverBuilder = new CoreServerBuilder();
         setServerConfig(serverBuilder, factory);
         setServiceBuilder(serverBuilder, factory);
--- a/services/jvms/src/main/java/com/redhat/thermostat/gateway/service/jvms/http/JvmsHttpHandler.java	Wed Sep 13 18:45:37 2017 +0200
+++ b/services/jvms/src/main/java/com/redhat/thermostat/gateway/service/jvms/http/JvmsHttpHandler.java	Thu Sep 14 10:23:32 2017 -0400
@@ -103,9 +103,15 @@
                                 @Context HttpServletRequest httpServletRequest
     ) {
         try {
-            ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
-            String message = mongoStorageHandler.getJvmInfos(storage.getDatabase().getCollection(collectionName), systemId, limit, offset, sort, queries, includes, excludes);
-            return Response.status(Response.Status.OK).entity(message).build();
+            RealmAuthorizer realmAuthorizer = (RealmAuthorizer) httpServletRequest.getAttribute(RealmAuthorizer.class.getName());
+
+            if (realmAuthorizer.readable()) {
+                ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);
+                String message = mongoStorageHandler.getJvmInfos(storage.getDatabase().getCollection(collectionName), systemId, limit, offset, sort, queries, includes, excludes);
+                return Response.status(Response.Status.OK).entity(message).build();
+            } else {
+                return Response.status(Response.Status.FORBIDDEN).build();
+            }
         } catch (Exception e) {
             return exceptionHandler.generateResponseForException(e);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/pom.xml	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Copyright 2012-2017 Red Hat, Inc.
+
+ This file is part of Thermostat.
+
+ Thermostat is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ Thermostat is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Thermostat; see the file COPYING.  If not see
+ <http://www.gnu.org/licenses/>.
+
+ Linking this code with other modules is making a combined work
+ based on this code.  Thus, the terms and conditions of the GNU
+ General Public License cover the whole combination.
+
+ As a special exception, the copyright holders of this code give
+ you permission to link this code with independent modules to
+ produce an executable, regardless of the license terms of these
+ independent modules, and to copy and distribute the resulting
+ executable under terms of your choice, provided that you also
+ meet, for each linked independent module, the terms and conditions
+ of the license of that module.  An independent module is a module
+ which is not derived from or based on this code.  If you modify
+ this code, you may extend this exception to your version of the
+ library, but you are not obligated to do so.  If you do not wish
+ to do so, delete this exception statement from your version.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.redhat.thermostat</groupId>
+        <artifactId>thermostat-web-gateway-tests</artifactId>
+        <version>1.99.12-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>thermostat-web-gateway-tests-keycloak-integration</artifactId>
+
+    <packaging>jar</packaging>
+
+    <name>Thermostat Web Gateway Keycloak Integration Tests</name>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <configuration>
+                            <redirectTestOutputToFile>true</redirectTestOutputToFile>
+                            <skipITs>${maven.ktest.skip}</skipITs>
+                            <environmentVariables>
+                                <THERMOSTAT_GATEWAY_HOME>${project.build.directory}/../../../distribution/target/image</THERMOSTAT_GATEWAY_HOME>
+                            </environmentVariables>
+                            <includes>
+                                <include>**/*Test.java</include>
+                            </includes>
+                        </configuration>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                    <environmentVariables>
+                        <!--
+                        intellij can use this variable when running tests within IDE,
+                        but cannot draw it from the maven-failsafe declaration. Having
+                        it also declared here allows developers to run integration
+                        tests from IDE with less hassle
+                        -->
+                        <THERMOSTAT_GATEWAY_HOME>${project.build.directory}/../../../distribution/target/image</THERMOSTAT_GATEWAY_HOME>
+                    </environmentVariables>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>3.0.2</version>
+                <configuration>
+                    <skipIfEmpty>true</skipIfEmpty>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>test-jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <!-- Thermostat Web Gateway dependencies -->
+        <dependency>
+            <groupId>com.redhat.thermostat</groupId>
+            <artifactId>thermostat-web-gateway-distribution</artifactId>
+            <version>${project.version}</version>
+            <type>pom</type>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>com.redhat.thermostat</groupId>
+            <artifactId>thermostat-web-gateway-tests-utils</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>${junit.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-client</artifactId>
+            <version>${jetty.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/cpu/JvmCpuServiceKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.jvm.cpu;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class JvmCpuServiceKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "jvm-cpu";
+    private static final String versionNumber = "0.0.1";
+
+    private static final String postData = "[{\"item\":1}]";
+
+    public JvmCpuServiceKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, serviceName);
+    }
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1/jvms/jid1", postData));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/gc/JvmGcServiceKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.jvm.gc;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class JvmGcServiceKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "jvm-gc";
+    private static final String versionNumber = "0.0.3";
+
+    private static final String postData =
+            "[{\"timeStamp\":{\"$numberLong\":\"1501016408311\"}, \"collectorName\":\"PSScavenge\",\"runCount\":{\"$numberLong\":\"2\"},\"wallTimeInMicros\":{\"$numberLong\":\"15435\"}}]";
+    private static final String putData = "{\"set\":{\"a\":\"b\"}}";
+
+    public JvmGcServiceKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, serviceName);
+    }
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1/jvms/jid1", postData));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/systems/sid1/jvms/jid1", putData));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/io/JvmIoServiceKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.jvm.io;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class JvmIoServiceKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "jvm-io";
+    private static final String versionNumber = "0.0.1";
+
+    private static final String postData = "[{\"item\":1}]";
+    private static final String putData = "{\"set\":{\"a\":\"b\"}}";
+
+    public JvmIoServiceKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, serviceName);
+    }
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1/jvms/jid1", postData));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/systems/sid1/jvms/jid1", putData));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvm/memory/JvmMemoryServiceKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.jvm.memory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class JvmMemoryServiceKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "jvm-memory";
+    private static final String versionNumber = "0.0.3";
+
+    private static final String postData =
+            "[{\"timeStamp\":{\"$numberLong\":\"1501104816287\"},\"metaspaceMaxCapacity\":{\"$numberLong\":\"1094713344\"},\"metaspaceMinCapacity\":{\"$numberLong\":\"0\"},\"metaspaceCapacity\":{\"$numberLong\":\"21807104\"},\"metaspaceUsed\":{\"$numberLong\":\"19997080\"},\"generations\":[{\"name\":\"new\",\"capacity\":{\"$numberLong\":\"149422080\"},\"maxCapacity\":{\"$numberLong\":\"1369964544\"},\"collector\":\"PSScavenge\",\"spaces\":[{\"index\":0,\"name\":\"eden\",\"capacity\":{\"$numberLong\":\"65011712\"},\"maxCapacity\":{\"$numberLong\":\"1368915968\"},\"used\":{\"$numberLong\":\"10296232\"}},{\"index\":1,\"name\":\"s0\",\"capacity\":{\"$numberLong\":\"8912896\"},\"maxCapacity\":{\"$numberLong\":\"456654848\"},\"used\":{\"$numberLong\":\"0\"}},{\"index\":2,\"name\":\"s1\",\"capacity\":{\"$numberLong\":\"10485760\"},\"maxCapacity\":{\"$numberLong\":\"456654848\"},\"used\":{\"$numberLong\":\"0\"}}]},{\"name\":\"old\",\"capacity\":{\"$numberLong\":\"73924608\"},\"maxCapacity\":{\"$numberLong\":\"2740453376\"},\"collector\":\"PSParallelCompact\",\"spaces\":[{\"index\":0,\"name\":\"old\",\"capacity\":{\"$numberLong\":\"73924608\"},\"maxCapacity\":{\"$numberLong\":\"2740453376\"},\"used\":{\"$numberLong\":\"8617920\"}}]}]}]";
+    private static final String putData = "{\"set\":{\"a\":\"b\"}}";
+
+    public JvmMemoryServiceKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, serviceName);
+    }
+
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1/jvms/jid1", postData));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/systems/sid1/jvms/jid1", putData));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/jvms/JvmsServiceKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.jvms;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class JvmsServiceKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "jvms";
+    private static final String collectionName = "jvm-info";
+    private static final String versionNumber = "0.0.1";
+
+    private static final String postData = "[{\"item\":1}]";
+    private static final String putData = "{\"set\":{\"a\":\"b\"}}";
+    private static final String putTimestampData = "[\"jid1\"]";
+
+    public JvmsServiceKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, collectionName);
+    }
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/tree", EndpointDefinition.NO_BODY));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1", postData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/systems/sid1/jvms/jid1", putData));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/update/systems/sid1/ts/1", putTimestampData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1/jvms/jid1", EndpointDefinition.NO_BODY));
+
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/system/cpu/SystemCpuKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.system.cpu;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class SystemCpuKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "system-cpu";
+    private static final String collectionName = "cpu-info";
+    private static final String versionNumber = "0.0.1";
+
+    private static final String postData =
+            "[{\"perProcessorUsage\":[34.008833148242424,25.00649496194296,40.010391939108736,48.01247032693048,48.01247032693048,22.005715566509807,46.01195072997505,31.00805375280927],\"timeStamp\":{\"$numberLong\":\"1501102486960\"}}]";
+    private static final String putData = "{\"set\":{\"a\":\"b\"}}";
+
+    public SystemCpuKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, collectionName);
+    }
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1", EndpointDefinition.NO_BODY));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1", postData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/systems/sid1", putData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1", EndpointDefinition.NO_BODY));
+
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/system/memory/SystemMemoryKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.system.memory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class SystemMemoryKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "system-memory";
+    private static final String collectionName = "memory-info";
+    private static final String versionNumber = "0.0.1";
+
+    private static final String postData = "[{\"timeStamp\":{\"$numberLong\":\"1501102496901\"},\"total\":{\"$numberLong\":\"16437342208\"},\"free\":{\"$numberLong\":\"4479225856\"},\"buffers\":{\"$numberLong\":\"1158586368\"},\"cached\":{\"$numberLong\":\"4019306496\"},\"swapTotal\":{\"$numberLong\":\"8254386176\"},\"swapFree\":{\"$numberLong\":\"8254386176\"},\"commitLimit\":{\"$numberLong\":\"16473055232\"}}]";
+    private static final String putData = "{\"set\":{\"a\":\"b\"}}";
+
+    public SystemMemoryKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, collectionName);
+    }
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1", EndpointDefinition.NO_BODY));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1", postData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/systems/sid1", putData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1", EndpointDefinition.NO_BODY));
+
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/system/network/SystemNetworkKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.system.network;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class SystemNetworkKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "system-network";
+    private static final String collectionName = "network-info";
+    private static final String versionNumber = "0.0.1";
+
+    private static final String postData = "[{\"agentId\":\"a06056f2-46bb-418f-9c07-35ebf2d67726\",\"timeStamp\":{\"$numberLong\":\"1501164373711\"},\"interfaces\":[{\"interfaceName\":\"veth1dd73a4\",\"displayName\":\"veth1dd73a4\",\"ip6Addr\":\"fe80:0:0:0:89f:deff:fe8a:da94%veth1dd73a4\"},{\"interfaceName\":\"virbr3\",\"displayName\":\"virbr3\",\"ip4Addr\":\"192.168.102.1\"},{\"interfaceName\":\"virbr0\",\"displayName\":\"virbr0\",\"ip4Addr\":\"192.168.124.1\"},{\"interfaceName\":\"virbr1\",\"displayName\":\"virbr1\",\"ip4Addr\":\"192.168.100.1\"},{\"interfaceName\":\"virbr2\",\"displayName\":\"virbr2\",\"ip4Addr\":\"192.168.101.1\"},{\"interfaceName\":\"docker0\",\"displayName\":\"docker0\",\"ip4Addr\":\"172.17.0.1\",\"ip6Addr\":\"fe80:0:0:0:42:bfff:feff:1d42%docker0\"},{\"interfaceName\":\"wlp3s0\",\"displayName\":\"wlp3s0\",\"ip4Addr\":\"10.193.245.52\",\"ip6Addr\":\"fe80:0:0:0:922e:1cff:fe29:365%wlp3s0\"},{\"interfaceName\":\"enp0s25\",\"displayName\":\"enp0s25\",\"ip4Addr\":\"10.15.17.134\",\"ip6Addr\":\"fe80:0:0:0:56ee:75ff:fe97:634e%enp0s25\"},{\"interfaceName\":\"lo\",\"displayName\":\"lo\",\"ip4Addr\":\"127.0.0.1\",\"ip6Addr\":\"0:0:0:0:0:0:0:1%lo\"}]}]";
+    private static final String putData = "{\"set\":{\"a\":\"b\"}}";
+
+    public SystemNetworkKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, collectionName);
+    }
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1", EndpointDefinition.NO_BODY));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1", postData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/systems/sid1", putData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1", EndpointDefinition.NO_BODY));
+
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/service/systems/SystemInfoKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.service.systems;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+import com.redhat.thermostat.gateway.tests.keycloak.BasicKeycloakIntegrationTestSuite;
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+
+public class SystemInfoKeycloakIntegrationTest extends BasicKeycloakIntegrationTestSuite {
+    private static final String serviceName = "systems";
+    private static final String collectionName = "system-info";
+    private static final String versionNumber = "0.0.1";
+
+    private static final String postData = "[{\"agentId\":\"aid1\",\"hostname\":\"localhost.localdomain\",\"timeStamp\":{\"$numberLong\":\"1501102486031\"},\"osName\":\"Fedora 24 (Workstation Edition)\",\"osKernel\":\"Linux 4.11.10-100.fc24.x86_64\",\"cpuModel\":\"Intel(R) Core(TM) i7-4810MQ CPU @ 2.80GHz\",\"cpuCount\":8,\"totalMemory\":{\"$numberLong\":\"16437342208\"}}]";
+    private static final String putData = "{\"set\":{\"a\":\"b\"}}";
+
+    public SystemInfoKeycloakIntegrationTest() {
+        super(serviceName, versionNumber, collectionName);
+    }
+
+    @Override
+    protected List<EndpointDefinition> getEndpointList() {
+        List<EndpointDefinition> endpointDefinitions = new ArrayList<>();
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/", EndpointDefinition.NO_BODY));
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.GET, "/systems/sid1", EndpointDefinition.NO_BODY));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.POST, "/systems/sid1", postData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.PUT, "/systems/sid1", putData));
+
+        endpointDefinitions.add(new EndpointDefinition(HttpMethod.DELETE, "/systems/sid1", EndpointDefinition.NO_BODY));
+
+        return endpointDefinitions;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/keycloak/BasicKeycloakIntegrationTestSuite.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.keycloak;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpMethod;
+import org.junit.Test;
+
+import com.redhat.thermostat.gateway.tests.utils.EndpointDefinition;
+import com.redhat.thermostat.gateway.tests.utils.keycloak.DefaultKeycloakUsers;
+import com.redhat.thermostat.gateway.tests.utils.keycloak.KeycloakUserCredentials;
+
+public abstract class BasicKeycloakIntegrationTestSuite extends MongoKeycloakIntegrationTest {
+
+    private static final String jsonFormat = "application/json";
+
+    private final List<EndpointDefinition> getList = new ArrayList<>();
+    private final List<EndpointDefinition> postList = new ArrayList<>();
+    private final List<EndpointDefinition> putList = new ArrayList<>();
+    private final List<EndpointDefinition> deleteList = new ArrayList<>();
+
+    public BasicKeycloakIntegrationTestSuite(String serviceName, String versionNumber, String collectionName) {
+        super(serviceName + "/" + versionNumber, collectionName);
+        buildMethodLists(getEndpointList());
+    }
+
+    protected void buildMethodLists(List<EndpointDefinition> endpointList) {
+        for (EndpointDefinition endpoint : endpointList) {
+            switch (endpoint.getMethod()) {
+                case GET:
+                    getList.add(endpoint);
+                    break;
+                case POST:
+                    postList.add(endpoint);
+                    break;
+                case PUT:
+                    putList.add(endpoint);
+                    break;
+                case DELETE:
+                    deleteList.add(endpoint);
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    protected abstract List<EndpointDefinition> getEndpointList();
+
+    @Test
+    public void testGetUnauthenticated() throws InterruptedException, ExecutionException, TimeoutException {
+        verifyEndpointsWhenUnauthenticated(getList);
+    }
+
+    @Test
+    public void testPostUnauthenticated() throws InterruptedException, ExecutionException, TimeoutException {
+        verifyEndpointsWhenUnauthenticated(postList);
+    }
+
+    @Test
+    public void testPutUnauthenticated() throws InterruptedException, ExecutionException, TimeoutException {
+        verifyEndpointsWhenUnauthenticated(putList);
+    }
+
+    @Test
+    public void testDeleteUnauthenticated() throws InterruptedException, ExecutionException, TimeoutException {
+        verifyEndpointsWhenUnauthenticated(deleteList);
+    }
+
+    @Test
+    public void testGetAuthorized() throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpointsWhenAuthorized(getList, DefaultKeycloakUsers.USER_A.getCredentials());
+    }
+
+    @Test
+    public void testGetUnauthorized() throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpointsWhenUnauthorized(getList, DefaultKeycloakUsers.USER_B.getCredentials());
+    }
+
+    @Test
+    public void testPostAuthorized() throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpointsWhenAuthorized(postList, DefaultKeycloakUsers.USER_B.getCredentials());
+    }
+
+    @Test
+    public void testPostUnauthorized() throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpointsWhenUnauthorized(postList, DefaultKeycloakUsers.USER_C.getCredentials());
+    }
+
+    @Test
+    public void testPutAuthorized() throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpointsWhenAuthorized(putList, DefaultKeycloakUsers.USER_C.getCredentials());
+    }
+
+    @Test
+    public void testPutUnauthorized() throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpointsWhenUnauthorized(putList, DefaultKeycloakUsers.USER_D.getCredentials());
+    }
+
+    @Test
+    public void testDeleteAuthorized() throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpointsWhenAuthorized(deleteList, DefaultKeycloakUsers.USER_D.getCredentials());
+    }
+
+    @Test
+    public void testDeleteUnauthorized() throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpointsWhenUnauthorized(deleteList, DefaultKeycloakUsers.USER_A.getCredentials());
+    }
+
+    private void verifyEndpointsWhenUnauthenticated(List<EndpointDefinition> endpoints) throws InterruptedException, ExecutionException, TimeoutException {
+        for (EndpointDefinition endpoint : endpoints) {
+            ContentResponse response = httpRequestUtil.buildRequest(baseResourceUrl + endpoint.getEndpointUrl(), endpoint.getMethod()).send();
+
+            verifyResponse(endpoint, response, 401);
+            assertEquals(401, response.getStatus());
+        }
+    }
+
+    private void verifyEndpointsWhenAuthorized(List<EndpointDefinition> endpoints, KeycloakUserCredentials keycloakUserCredentials) throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpoints(endpoints, keycloakUserCredentials, 200);
+    }
+
+    private void verifyEndpointsWhenUnauthorized(List<EndpointDefinition> endpoints, KeycloakUserCredentials keycloakUserCredentials) throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        verifyEndpoints(endpoints, keycloakUserCredentials, 403);
+    }
+
+    private void verifyEndpoints(List<EndpointDefinition> endpoints, KeycloakUserCredentials keycloakUserCredentials, int expectedStatus) throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        for (EndpointDefinition endpoint : endpoints) {
+            HttpMethod method = endpoint.getMethod();
+            Request request = httpRequestUtil.buildRequest(baseResourceUrl + endpoint.getEndpointUrl(), method);
+            if (method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT)) {
+                request = request.content(new StringContentProvider(endpoint.getBody()), jsonFormat);
+            }
+
+            ContentResponse response = httpRequestUtil.sendKeycloakHttpRequest(request, keycloakUserCredentials);
+
+            verifyResponse(endpoint, response, expectedStatus);
+        }
+    }
+
+    private void verifyResponse(EndpointDefinition endpoint, ContentResponse response, int expectedStatus) {
+        if (expectedStatus != response.getStatus()) {
+            System.out.println("Endpoint: " + endpoint.getMethod() + " : " + endpoint.getEndpointUrl());
+            System.out.println("Expected Status: " + expectedStatus);
+            System.out.println("Actual Status: " + response.getStatus());
+        }
+        assertEquals(endpoint.getEndpointUrl(), expectedStatus, response.getStatus());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/keycloak/KeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.keycloak;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.CountDownLatch;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.util.component.AbstractLifeCycle;
+import org.eclipse.jetty.util.component.LifeCycle;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import com.redhat.thermostat.gateway.common.core.config.Configuration;
+import com.redhat.thermostat.gateway.common.core.config.ConfigurationFactory;
+import com.redhat.thermostat.gateway.common.core.config.GatewayHomeRetriever;
+import com.redhat.thermostat.gateway.common.core.config.GlobalConfiguration;
+import com.redhat.thermostat.gateway.server.Start;
+import com.redhat.thermostat.gateway.tests.utils.HttpRequestUtil;
+import com.redhat.thermostat.gateway.tests.utils.keycloak.KeycloakTestConfigurationFactory;
+
+public class KeycloakIntegrationTest {
+    private static final ConfigurationFactory factory;
+
+    protected static HttpRequestUtil httpRequestUtil;
+    protected static HttpClient client;
+    protected static String gatewayUrl;
+
+    protected static final Path distributionImage;
+
+    static {
+        String distDir = new GatewayHomeRetriever().getGatewayHome();
+        distributionImage = Paths.get(distDir);
+        factory = new KeycloakTestConfigurationFactory();
+        String scheme;
+        if (isTLSEnabled()) {
+            scheme = "https";
+        } else {
+            scheme = "http";
+        }
+        gatewayUrl = scheme + "://127.0.0.1:" + KeycloakTestConfigurationFactory.TEST_PORT;
+    }
+
+    protected String baseResourceUrl;
+
+    public KeycloakIntegrationTest(String serviceUrl) {
+        this.baseResourceUrl = gatewayUrl + "/" + serviceUrl;
+    }
+
+    @BeforeClass
+    public static void beforeClassIntegrationTest() throws Exception {
+        client = createAndStartHttpClient();
+        httpRequestUtil = new HttpRequestUtil(client);
+        startServer();
+    }
+
+    public static HttpClient createAndStartHttpClient() throws Exception {
+        final HttpClient client;
+        if (isTLSEnabled()) {
+            SslContextFactory sslFactory = new SslContextFactory();
+            sslFactory.setTrustAll(true);
+            client = new HttpClient(sslFactory);
+        } else {
+            client = new HttpClient();
+        }
+        client.start();
+        return client;
+    }
+
+    private static boolean isTLSEnabled() {
+        Configuration config = factory.createGlobalConfiguration();
+        return Boolean.parseBoolean((String)config.asMap().get(GlobalConfiguration.ConfigurationKey.WITH_TLS.name()));
+    }
+
+    private static Thread serverThread = null;
+    private static Start serverObject = null;
+
+    private static class StartListener extends AbstractLifeCycle.AbstractLifeCycleListener {
+
+        private final CountDownLatch latch;
+        private Throwable cause = null;
+        private boolean failed = false;
+
+        StartListener(CountDownLatch cdl) {
+            this.latch = cdl;
+        }
+
+        @Override
+        public void lifeCycleStarted(LifeCycle event) {
+            super.lifeCycleStarted(event);
+            latch.countDown();
+        }
+
+        @Override
+        public void lifeCycleFailure(LifeCycle event, Throwable cause) {
+            this.failed = true;
+            this.cause = cause;
+            this.latch.countDown();
+        }
+
+        boolean hasFailed() {
+            return failed;
+        }
+
+        Throwable getCause() {
+            return this.cause;
+        }
+    }
+
+    private static void startServer() throws IOException, InterruptedException {
+
+        if (serverThread == null) {
+
+            final CountDownLatch contextStartedLatch = new CountDownLatch(1);
+
+            final StartListener listener = new StartListener(contextStartedLatch);
+
+            serverObject = new Start(listener, factory);
+            serverThread = new Thread(new Runnable() {
+                @Override
+                public void run() {
+                    serverObject.run();
+                }
+            });
+            serverThread.start();
+
+            // wait for Jetty is up and running?
+            contextStartedLatch.await();
+            if (listener.hasFailed()) {
+                throw new IllegalStateException(listener.getCause());
+            }
+        }
+    }
+
+    private static void stopServer() throws Exception {
+        if (serverThread != null) {
+            Thread st = serverThread;
+            synchronized (serverThread) {
+                serverThread = null;
+                serverObject.stopServer();
+                st.join();
+                serverObject = null;
+            }
+        }
+    }
+
+    @AfterClass
+    public static void afterClassIntegrationTest() throws Exception {
+        client.stop();
+        stopServer();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/keycloak-integration-tests/src/test/java/com/redhat/thermostat/gateway/tests/keycloak/MongoKeycloakIntegrationTest.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.keycloak;
+
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Objects;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+
+import com.redhat.thermostat.gateway.tests.utils.MongodTestUtil;
+import com.redhat.thermostat.gateway.tests.utils.keycloak.KeycloakTestConfigurationFactory;
+
+public class MongoKeycloakIntegrationTest extends KeycloakIntegrationTest {
+
+    protected static final MongodTestUtil mongodTestUtil = new MongodTestUtil(KeycloakTestConfigurationFactory.MONGOD_TEST_PORT);
+
+    protected String collectionName;
+
+    public MongoKeycloakIntegrationTest(String serviceUrl, String collectionName) {
+        super(serviceUrl);
+        this.collectionName = Objects.requireNonNull(collectionName);
+    }
+
+    @BeforeClass
+    public static void beforeClassMongoIntegrationTest() throws Exception {
+        mongodTestUtil.startMongod();
+        if (!mongodTestUtil.isConnectedToDatabase()) {
+            fail("Unable to start mongodb database, port in use");
+        }
+        setupMongoCredentials();
+    }
+
+    @Before
+    public void beforeIntegrationTest() {
+        mongodTestUtil.dropCollection(collectionName);
+    }
+
+    private static void setupMongoCredentials() throws IOException, InterruptedException {
+        Path mongoSetup = distributionImage.resolve("etc/mongo-dev-setup.js");
+
+        ProcessBuilder processBuilder = new ProcessBuilder().command("mongo", mongodTestUtil.listenAddress, mongoSetup.toAbsolutePath().toString());
+        Process mongoProcess = processBuilder.start();
+        mongoProcess.waitFor();
+    }
+
+    @AfterClass
+    public static void afterClassMongoIntegrationTest() throws Exception {
+        mongodTestUtil.stopMongod();
+    }
+}
--- a/tests/pom.xml	Wed Sep 13 18:45:37 2017 +0200
+++ b/tests/pom.xml	Thu Sep 14 10:23:32 2017 -0400
@@ -51,6 +51,7 @@
 
     <modules>
         <module>integration-tests</module>
+        <module>keycloak-integration-tests</module>
         <module>test-utils</module>
     </modules>
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/EndpointDefinition.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.utils;
+
+import org.eclipse.jetty.http.HttpMethod;
+
+public class EndpointDefinition {
+    public static final String NO_BODY = null;
+
+    private final HttpMethod method;
+    private final String endpointUrl;
+    private final String body;
+
+    public EndpointDefinition(HttpMethod method, String endpointUrl, String body) {
+        this.method = method;
+        this.endpointUrl = endpointUrl;
+        this.body = body;
+    }
+
+    public String getEndpointUrl() {
+        return endpointUrl;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public HttpMethod getMethod() {
+        return method;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/HttpRequestUtil.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.utils;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.api.Request;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.redhat.thermostat.gateway.tests.utils.keycloak.KeycloakAccessToken;
+import com.redhat.thermostat.gateway.tests.utils.keycloak.KeycloakUserCredentials;
+
+public class HttpRequestUtil {
+    /**
+     * GET request type.
+     */
+    public static final String GET = HttpMethod.GET.asString();
+    /**
+     * PUT request type.
+     */
+    public static final String PUT = HttpMethod.PUT.asString();
+    /**
+     * POST request type.
+     */
+    public static final String POST = HttpMethod.POST.asString();
+    /**
+     * DELETE request type.
+     */
+    public static final String DELETE = HttpMethod.DELETE.asString();
+
+    private static final String KEYCLOAK_TOKEN_SERVICE = "/auth/realms/__REALM__/protocol/openid-connect/token";
+    private static final String KEYCLOAK_CONTENT_TYPE = "application/x-www-form-urlencoded";
+
+    // Static to reuse credentials between tests as much as possible
+    private static final Map<KeycloakUserCredentials, KeycloakAccessToken> tokenMap = new HashMap<>();
+
+    private HttpClient client;
+    private Gson gson = new GsonBuilder().create();
+
+    public HttpRequestUtil(HttpClient client) {
+        this.client = client;
+    }
+
+    public Request buildRequest(String url, HttpMethod method) {
+        return client.newRequest(url).method(method);
+    }
+
+    public ContentResponse sendKeycloakHttpRequest(Request request, KeycloakUserCredentials credentials) throws InterruptedException, ExecutionException, TimeoutException, IOException {
+        request.header("Authorization", "Bearer " + getAccessToken(credentials));
+        return request.send();
+    }
+
+    private String getAccessToken(KeycloakUserCredentials credentials) throws IOException {
+        if (!tokenMap.containsKey(credentials)) {
+            KeycloakAccessToken keycloakAccessToken = acquireKeycloakToken(credentials);
+            if (keycloakAccessToken != null) {
+                tokenMap.put(credentials, keycloakAccessToken);
+                return keycloakAccessToken.getAccessToken();
+            } else {
+                throw new IOException("Unable to acquire Keycloak token. Is Keycloak server running?");
+            }
+        }
+
+        KeycloakAccessToken keycloakAccessToken = tokenMap.get(credentials);
+        if (isKeycloakTokenExpired(keycloakAccessToken)) {
+            keycloakAccessToken = refreshKeycloakToken(credentials, keycloakAccessToken);
+
+            if (keycloakAccessToken == null) {
+                keycloakAccessToken = acquireKeycloakToken(credentials);
+            }
+
+            tokenMap.put(credentials, keycloakAccessToken);
+
+            if (keycloakAccessToken == null) {
+                throw new IOException("Keycloak token expired and attempt to refresh and reacquire Keycloak token failed.");
+            }
+
+        }
+        return keycloakAccessToken.getAccessToken();
+    }
+
+    private boolean isKeycloakTokenExpired(KeycloakAccessToken keycloakAccessToken) {
+        return System.nanoTime() > TimeUnit.NANOSECONDS.convert(keycloakAccessToken.getExpiresIn(), TimeUnit.SECONDS) + keycloakAccessToken.getAcquireTime();
+    }
+
+    private KeycloakAccessToken acquireKeycloakToken(KeycloakUserCredentials credentials) {
+        return requestKeycloakToken(getKeycloakAccessPayload(credentials), credentials);
+    }
+
+    private KeycloakAccessToken refreshKeycloakToken(KeycloakUserCredentials credentials, KeycloakAccessToken keycloakAccessToken) {
+        return requestKeycloakToken(getKeycloakRefreshPayload(credentials, keycloakAccessToken), credentials);
+    }
+
+    private KeycloakAccessToken requestKeycloakToken(String payload, KeycloakUserCredentials credentials) {
+        String keycloakUrl = credentials.getUrl();
+        String keycloakRealm = credentials.getRealm();
+        String url = keycloakUrl + KEYCLOAK_TOKEN_SERVICE.replace("__REALM__", keycloakRealm);
+        Request request = client.newRequest(url);
+        request.content(new StringContentProvider(payload), KEYCLOAK_CONTENT_TYPE);
+        request.method(HttpMethod.POST);
+
+        try {
+            ContentResponse response = request.send();
+            if (response.getStatus() == HttpStatus.OK_200) {
+
+                String content = response.getContentAsString();
+
+                KeycloakAccessToken keycloakAccessToken = gson.fromJson(content, KeycloakAccessToken.class);
+                keycloakAccessToken.setAcquireTime(System.nanoTime());
+
+                return keycloakAccessToken;
+            }
+        } catch (Exception e) {
+        }
+        return null;
+    }
+
+    private String getKeycloakAccessPayload(KeycloakUserCredentials credentials) {
+        return "grant_type=password&client_id=" + credentials.getClient() +
+                "&username=" + credentials.getUsername() +
+                "&password=" + credentials.getPassword();
+    }
+
+    private String getKeycloakRefreshPayload(KeycloakUserCredentials credentials, KeycloakAccessToken keycloakAccessToken) {
+        return "grant_type=refresh_token&client_id=" + credentials.getClient() +
+                "&refresh_token=" + keycloakAccessToken.getRefreshToken();
+    }
+}
--- a/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/MongodTestUtil.java	Wed Sep 13 18:45:37 2017 +0200
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/MongodTestUtil.java	Thu Sep 14 10:23:32 2017 -0400
@@ -54,11 +54,12 @@
 
     private static final int WAIT_FOR_MAX_ITERATIONS = 100;
     private static final long WAIT_FOR_SLEEP_DURATION = 100L;
+    private static final int DEFAULT_PORT = 27519;
 
     private final String databaseName = "thermostat";
     private final String host = "127.0.0.1";
-    private final int port = 27519;
-    public final String listenAddress = host + ":" + port;
+    private final int port;
+    public final String listenAddress;
 
     private MongoClient mongoClient;
     private Path tempDbDir;
@@ -66,6 +67,15 @@
     public Process process;
     private boolean connectedToDatabase;
 
+    public MongodTestUtil() {
+        this(DEFAULT_PORT);
+    }
+
+    public MongodTestUtil(int port) {
+        this.port = port;
+        this.listenAddress = host + ":" + port;
+    }
+
     public void startMongod() throws IOException, InterruptedException {
         tempDbDir = Files.createTempDirectory("tms-mongo");
         tempDbDir.toFile().deleteOnExit();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/DefaultKeycloakUsers.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.utils.keycloak;
+
+public enum DefaultKeycloakUsers {
+
+    USER_A("tms-a"),
+    USER_B("tms-b"),
+    USER_C("tms-c"),
+    USER_D("tms-d"),
+    USER_E("tms-e"),
+    USER_F("tms-f"),
+    USER_G("tms-g"),
+
+    ;
+
+    private final String username;
+
+    DefaultKeycloakUsers(String username) {
+        this.username = username;
+    }
+
+    public KeycloakUserCredentials getCredentials() {
+        String defaultUrl = "http://127.0.0.1:31000";
+        String defaultRealm = "thermostat";
+        String defaultClient = "thermostat-web-client";
+        String defaultPassword = "tms-pass";
+        return new KeycloakUserCredentials(defaultUrl, defaultRealm, defaultClient, username, defaultPassword);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/KeycloakAccessToken.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.utils.keycloak;
+
+import com.google.gson.annotations.SerializedName;
+
+public class KeycloakAccessToken {
+    @SerializedName("access_token")
+    private String accessToken;
+
+    // In seconds
+    @SerializedName("expires_in")
+    private long expiresIn;
+
+    // In seconds
+    @SerializedName("refresh_expires_in")
+    private long refreshExpiresIn;
+
+    @SerializedName("refresh_token")
+    private String refreshToken;
+
+    // In nanoseconds
+    private transient long acquireTime;
+
+
+    public String getAccessToken() {
+        return accessToken;
+    }
+
+    public Long getExpiresIn() {
+        return expiresIn;
+    }
+
+    public Long getRefreshExpiresIn() {
+        return refreshExpiresIn;
+    }
+
+    public String getRefreshToken() {
+        return refreshToken;
+    }
+
+    public long getAcquireTime() {
+        return acquireTime;
+    }
+
+    public void setAcquireTime(long acquireTime) {
+        this.acquireTime = acquireTime;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/KeycloakServerCredentials.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.utils.keycloak;
+
+public class KeycloakServerCredentials {
+    public static final String KEYCLOAK_JSON = "{\n" +
+            "  \"realm\" : \"thermostat\",\n" +
+            "  \"bearer-only\" : true,\n" +
+            "  \"auth-server-url\" : \"http://127.0.0.1:31000/auth\",\n" +
+            "  \"ssl-required\" : \"external\",\n" +
+            "  \"resource\" : \"thermostat-bearer\"\n" +
+            "}\n";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/KeycloakTestConfigurationFactory.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.utils.keycloak;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.redhat.thermostat.gateway.common.core.config.Configuration;
+import com.redhat.thermostat.gateway.common.core.config.ConfigurationFactory;
+import com.redhat.thermostat.gateway.common.core.config.GlobalConfiguration;
+import com.redhat.thermostat.gateway.common.core.config.ServiceConfiguration;
+import com.redhat.thermostat.gateway.common.mongodb.configuration.MongoConfiguration;
+
+public class KeycloakTestConfigurationFactory extends ConfigurationFactory {
+
+    public static final int TEST_PORT = 40000;
+    public static final int MONGOD_TEST_PORT = 42000;
+
+    public KeycloakTestConfigurationFactory() {
+        super();
+    }
+
+    @Override
+    public Configuration createServiceConfiguration(String serviceName) {
+        Map<String, Object> configMap = new HashMap<>(super.createServiceConfiguration(serviceName).asMap());
+        configMap.put(ServiceConfiguration.ConfigurationKey.SECURITY_KEYCLOAK.name(), "true");
+        configMap.put(ServiceConfiguration.ConfigurationKey.KEYCLOAK_CONFIG.name(), KeycloakServerCredentials.KEYCLOAK_JSON);
+        configMap.put(MongoConfiguration.MONGO_URL.name(), "mongodb://127.0.0.1:" + MONGOD_TEST_PORT);
+        return new KeycloakTestConfiguration(configMap);
+    }
+
+    @Override
+    public Configuration createGlobalConfiguration() {
+        final Map<String, Object> configMap = new HashMap<>(super.createGlobalConfiguration().asMap());
+        configMap.put(GlobalConfiguration.ConfigurationKey.PORT.name(), Integer.toString(TEST_PORT));
+        return new Configuration() {
+            @Override
+            public Map<String, Object> asMap() {
+                return configMap;
+            }
+        };
+    }
+
+    @Override
+    public Configuration createGlobalServicesConfig() {
+        return super.createGlobalServicesConfig();
+    }
+
+    private class KeycloakTestConfiguration implements Configuration {
+        private final Map<String, Object> configMap;
+
+        KeycloakTestConfiguration(Map<String, Object> configMap) {
+            this.configMap = configMap;
+        }
+
+        @Override
+        public Map<String, Object> asMap() {
+            return configMap;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-utils/src/main/java/com/redhat/thermostat/gateway/tests/utils/keycloak/KeycloakUserCredentials.java	Thu Sep 14 10:23:32 2017 -0400
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2012-2017 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.gateway.tests.utils.keycloak;
+
+import java.util.Objects;
+
+public class KeycloakUserCredentials {
+    private final String url;
+    private final String realm;
+
+    private final String client;
+    private final String username;
+    private final String password;
+
+    public KeycloakUserCredentials(String url, String realm, String client, String username, String password) {
+        this.url = url;
+        this.realm = realm;
+        this.client = client;
+        this.username = username;
+        this.password = password;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public String getRealm() {
+        return realm;
+    }
+
+    public String getClient() {
+        return client;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        KeycloakUserCredentials that = (KeycloakUserCredentials) o;
+
+        if (!url.equals(that.url)) {
+            return false;
+        }
+        if (!realm.equals(that.realm)) {
+            return false;
+        }
+        if (!client.equals(that.client)) {
+            return false;
+        }
+        if (!username.equals(that.username)) {
+            return false;
+        }
+        return password.equals(that.password);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(url, realm, client, username, password);
+    }
+}