Mercurial > hg > thermostat-ng > agent
changeset 2625:703a2e1f90be
Remove server-side web storage
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-March/022522.html
author | Elliott Baron <ebaron@redhat.com> |
---|---|
date | Tue, 21 Mar 2017 18:47:16 -0400 |
parents | 56eebd386be2 |
children | 40903f2b0759 |
files | distribution/pom.xml web/endpoint-plugin/distribution/pom.xml web/endpoint-plugin/distribution/thermostat-plugin.xml web/endpoint-plugin/pom.xml web/endpoint-plugin/web-service/pom.xml web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/Activator.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/DelegatingClassLoader.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/DoNothingLifecycleListener.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfiguration.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncher.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/LocaleResources.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/StorageStartedListener.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/WebStorageLauncherCommand.java web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/WebappLauncherCommand.java web/endpoint-plugin/web-service/src/main/resources/com/redhat/thermostat/web/endpoint/internal/strings.properties web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/ActivatorTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/DelegatingClassLoaderTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfigurationTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncherTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/LocaleResourcesTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/StorageStartedListenerTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/WebStorageLauncherCommandTest.java web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/WebappLauncherCommandTest.java web/pom.xml web/server/pom.xml web/server/src/main/java/com/redhat/thermostat/web/server/CategoryManager.java web/server/src/main/java/com/redhat/thermostat/web/server/ConfigurationFinder.java web/server/src/main/java/com/redhat/thermostat/web/server/CursorManager.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownCategoryRegistry.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownCategoryRegistryFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementHolder.java web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementManager.java web/server/src/main/java/com/redhat/thermostat/web/server/PropertySettingServletContextListener.java web/server/src/main/java/com/redhat/thermostat/web/server/StoppableTimer.java web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactoryImpl.java web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactoryProvider.java web/server/src/main/java/com/redhat/thermostat/web/server/TimerRegistry.java web/server/src/main/java/com/redhat/thermostat/web/server/TokenManager.java web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/AbstractFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/AgentIdFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/BasicRole.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/DefaultPrincipalCallback.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/FilterResult.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/HostnameFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/JettyPrincipalCallback.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/PrincipalCallback.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/PrincipalCallbackFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/RolePrincipal.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/StatementFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/UserPrincipal.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmIdFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmUsernameFilter.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/WebStoragePathHandler.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/WrappedRolePrincipal.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/AbstractLoginModule.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/DelegateLoginModule.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUsernameRolesLoginModule.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/UserValidationException.java web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/UserValidator.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/AbstractContainerInfo.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/ContainerName.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/ContainerVersion.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/JettyContainerInfo.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/ServletContainerInfo.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/ServletContainerInfoFactory.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/TomcatContainerInfo.java web/server/src/main/java/com/redhat/thermostat/web/server/containers/WildflyContainerInfo.java web/server/src/main/webapp/WEB-INF/web.xml web/server/src/test/java/com/redhat/thermostat/web/server/CategoryManagerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/ConfigurationFinderTest.java web/server/src/test/java/com/redhat/thermostat/web/server/CursorManagerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/KnownCategoryRegistryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/PreparedStatementManagerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/PropertySettingServletContextListenerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/TimerRegistryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/TokenManagerTest.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndPointUnitTest.java web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java web/server/src/test/java/com/redhat/thermostat/web/server/WebstorageEndpointTestUtils.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/AgentIdFilterTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/DefaultPrincipalCallbackTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/HostnameFilterTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/JettyPrincipalCallbackTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/PrincipalCallbackFactoryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/RolePrincipalTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/UserPrincipalTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmIdFilterTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmUsernameFilterTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/WrappedRolePrincipalTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/AbstractLoginModuleTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/DelegateLoginModuleTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidatorTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUsernameRolesLoginModuleTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/RolesAmenderTest.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/SimpleCallBackHandler.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/StubFailureDelegateLoginModule.java web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/StubSuccessDelegateLoginModule.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/ContainerVersionTest.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/JettyContainerInfoTest.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/ServletContainerInfoFactoryTest.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/TomcatContainerInfoTest.java web/server/src/test/java/com/redhat/thermostat/web/server/containers/WildflyContainerInfoTest.java web/server/src/test/resources/broken_test_roles.properties web/server/src/test/resources/broken_test_roles2.properties web/server/src/test/resources/properties_module_test_roles.properties web/server/src/test/resources/properties_module_test_users.properties web/server/src/test/resources/test_roles.properties web/server/src/test/resources/test_users.properties web/war/pom.xml web/war/src/main/resources/logging.properties web/war/src/main/webapp-tomcat7/META-INF/context.xml web/war/src/main/webapp-tomcat8/META-INF/context.xml web/war/src/main/webapp/WEB-INF/jetty-web.xml web/war/src/main/webapp/WEB-INF/web.xml |
diffstat | 122 files changed, 0 insertions(+), 17498 deletions(-) [+] |
line wrap: on
line diff
--- a/distribution/pom.xml Tue Mar 21 18:40:40 2017 -0400 +++ b/distribution/pom.xml Tue Mar 21 18:47:16 2017 -0400 @@ -485,15 +485,6 @@ <artifactId>thermostat-web-client</artifactId> <version>${project.version}</version> </dependency> - <!-- depend on the web archive to be built in order - to be able to copy the exploded war into the - image directory --> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-war</artifactId> - <version>${project.version}</version> - <type>war</type> - </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-system-backend</artifactId> @@ -610,12 +601,6 @@ </dependency> <dependency> <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-endpoint-distribution</artifactId> - <version>${project.version}</version> - <type>zip</type> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> <artifactId>thermostat-killvm-distribution</artifactId> <version>${project.version}</version> <type>zip</type>
--- a/web/endpoint-plugin/distribution/pom.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -<?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-endpoint</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-web-endpoint-distribution</artifactId> - <packaging>pom</packaging> - - <name>Thermostat Web Embedded Servlet Container Endpoint Distribution</name> - - <properties> - <thermostat.plugin>embedded-web-endpoint</thermostat.plugin> - </properties> - - <build> - <plugins> - <plugin> - <artifactId>maven-assembly-plugin</artifactId> - <dependencies> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-assembly</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - <configuration> - <descriptorRefs> - <descriptorRef>plugin-assembly</descriptorRef> - </descriptorRefs> - <appendAssemblyId>false</appendAssemblyId> - </configuration> - <executions> - <execution> - <id>assemble-plugin</id> - <phase>package</phase> - <goals> - <goal>single</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - - <!-- Explicitly list all plug-in artifacts, transitive dependencies - are not included in assembly. --> - <dependencies> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-endpoint-plugin</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-servlet</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-xml</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-jaas</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.toolchain</groupId> - <artifactId>jetty-schemas</artifactId> - <version>${jetty-schemas.version}</version> - </dependency> - <!-- This will likely have to match what jetty-project's pom uses --> - <dependency> - <groupId>javax.servlet</groupId> - <artifactId>javax.servlet-api</artifactId> - <version>${jetty.javax.servlet.osgi.version}</version> - </dependency> - </dependencies> - -</project> -
--- a/web/endpoint-plugin/distribution/thermostat-plugin.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -<?xml version="1.0"?> -<!-- - - 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. - ---> -<plugin xmlns="http://icedtea.classpath.org/thermostat/plugins/v1.0" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://icedtea.classpath.org/thermostat/plugins/v1.0 thermostat-plugin.xsd"> - <commands> - <command> - <name>web-storage-service</name> - <summary>start mongodb storage, an embedded servlet container and an agent</summary> - <description> - Start mongodb storage, an embedded servlet container with the web - archive deployed and then connect an agent to this web endpoint. Do all - this as a foreground process. On exit, shut them all down. - </description> - <command-groups> - <command-group>thermostat-core</command-group> - </command-groups> - <environments> - <environment>cli</environment> - </environments> - <bundles> - <!-- Dependencies of the jetty-based web endpoint plugin --> - <bundle><symbolic-name>com.redhat.thermostat.web.endpoint</symbolic-name><version>${project.version}</version></bundle> - <!-- Required for running agent on top of http. - It should be the equivalent of $THERMOSTAT_HOME/etc/commands/agent.properties --> - <bundle><symbolic-name>com.redhat.thermostat.web.common</symbolic-name><version>${project.version}</version></bundle> - <bundle><symbolic-name>com.redhat.thermostat.web.client</symbolic-name><version>${project.version}</version></bundle> - <bundle><symbolic-name>com.redhat.thermostat.storage.mongodb</symbolic-name><version>${project.version}</version></bundle> - </bundles> - </command> - <command> - <name>web-storage</name> - <summary>start backing storage and deploy the web endpoint in a servlet container</summary> - <description> - Start mongodb storage, an embedded servlet container with the web - archive deployed as a foreground process. On exit, shut them down. - </description> - <command-groups> - <command-group>thermostat-core</command-group> - </command-groups> - <environments> - <environment>cli</environment> - </environments> - <bundles> - <bundle><symbolic-name>com.redhat.thermostat.web.endpoint</symbolic-name><version>${project.version}</version></bundle> - </bundles> - </command> - </commands> -</plugin> -
--- a/web/endpoint-plugin/pom.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -<?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</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-web-endpoint</artifactId> - <packaging>pom</packaging> - - <name>Thermostat Web Embedded Servlet Container Endpoint</name> - - <modules> - <module>distribution</module> - <module>web-service</module> - </modules> - -</project> -
--- a/web/endpoint-plugin/web-service/pom.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -<?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-endpoint</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-web-endpoint-plugin</artifactId> - - <packaging>bundle</packaging> - - <name>Thermostat Web Embedded Servlet Container Endpoint Core</name> - - <dependencies> - <!-- Plain OSGi --> - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.core</artifactId> - <scope>provided</scope> - </dependency> - - <!-- The war which we are going to deploy in embedded jetty --> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-war</artifactId> - <version>${project.version}</version> - <!-- thermostat-web-war has the attachClasses config set to true. - This allows us to use it here. In addition to the war a - file thermostat-web-war-<VERSION>-classes.jar is created - that way. --> - <classifier>classes</classifier> - </dependency> - - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-launcher</artifactId> - <version>${project.version}</version> - </dependency> - - <!-- The embedded servlet container we use --> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-jaas</artifactId> - <version>${jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - <version>${jetty.version}</version> - </dependency> - <!-- declarative services --> - <dependency> - <groupId>org.apache.felix</groupId> - <artifactId>org.apache.felix.scr.annotations</artifactId> - <scope>provided</scope> - </dependency> - - <!-- test scoped deps --> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-test</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-SymbolicName>com.redhat.thermostat.web.endpoint</Bundle-SymbolicName> - <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <!-- Do not autogenerate uses clauses in Manifests --> - <Bundle-Activator>com.redhat.thermostat.web.endpoint.internal.Activator</Bundle-Activator> - <!-- need to declare bundles explicitly since the automatisms fail if an embedded jetty - --> - <Import-Package> - javax.servlet, - javax.servlet.http, - org.eclipse.jetty.server, - org.eclipse.jetty.http, - org.eclipse.jetty.xml, - org.eclipse.jetty.util, - org.eclipse.jetty.io, - org.eclipse.jetty.webapp, - org.eclipse.jetty.security, - org.eclipse.jetty.servlet, - org.eclipse.jetty.servlet.listener, - org.eclipse.jetty.jaas, - *, - </Import-Package> - <Private-Package> - com.redhat.thermostat.web.endpoint.internal - </Private-Package> - <_nouses>true</_nouses> - </instructions> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-scr-plugin</artifactId> - <executions> - <execution> - <id>generate-scr-scrdescriptor</id> - <goals> - <goal>scr</goal> - </goals> - </execution> - </executions> - </plugin> - </plugins> - </build> - -</project> -
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/Activator.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -import com.redhat.thermostat.common.cli.CommandRegistry; -import com.redhat.thermostat.common.cli.CommandRegistryImpl; - -public class Activator implements BundleActivator { - - private CommandRegistry reg; - - @Override - public void start(final BundleContext context) throws Exception { - reg = new CommandRegistryImpl(context); - reg.registerCommand("web-storage-service", new WebappLauncherCommand(context)); - } - - @Override - public void stop(BundleContext context) throws Exception { - reg.unregisterCommands(); - } -} -
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/DelegatingClassLoader.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * 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.web.endpoint.internal; - -/** - * Asks a delegating classloader to load classes, and if not found defer to the - * system class loader. - */ -class DelegatingClassLoader extends ClassLoader { - - private final ClassLoader delegate; - - DelegatingClassLoader(ClassLoader delegate) { - this.delegate = delegate; - } - - public Class<?> loadClass(String className) throws ClassNotFoundException { - try { - return delegate.loadClass(className); - } catch (ClassNotFoundException e) { - return getSystemClassLoader().loadClass(className); - } - } -}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/DoNothingLifecycleListener.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import org.eclipse.jetty.util.component.LifeCycle; -import org.eclipse.jetty.util.component.LifeCycle.Listener; - -public class DoNothingLifecycleListener implements Listener { - - @Override - public void lifeCycleStopping(LifeCycle arg0) { - // nothing - } - - @Override - public void lifeCycleStopped(LifeCycle arg0) { - // nothing - } - - @Override - public void lifeCycleStarting(LifeCycle arg0) { - // nothing - } - - @Override - public void lifeCycleStarted(LifeCycle arg0) { - // nothing - } - - @Override - public void lifeCycleFailure(LifeCycle arg0, Throwable arg1) { - // nothing - } - -}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfiguration.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,247 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.List; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.HostPortPair; -import com.redhat.thermostat.common.utils.HostPortsParser; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.shared.locale.Translate; - -class EmbeddedServletContainerConfiguration { - - private static final Logger logger = LoggingUtils.getLogger(EmbeddedServletContainerConfiguration.class); - private static final Translate<LocaleResources> t = LocaleResources.createLocalizer(); - private final Properties systemConfiguration; - private final Properties userConfiguration; - private final CommonPaths paths; - - // Main constructor - EmbeddedServletContainerConfiguration(CommonPaths paths, Properties systemConfiguration, Properties userConfiguration) { - this.systemConfiguration = systemConfiguration; - this.userConfiguration = userConfiguration; - this.paths = paths; - } - - EmbeddedServletContainerConfiguration(CommonPaths paths, File sysConfig, File userConfig) { - this(paths, new Properties(), new Properties()); - // init from system config if existing - initConfig(sysConfig, this.systemConfiguration); - // init from user config if existing - initConfig(userConfig, this.userConfiguration); - } - - // For testing only - EmbeddedServletContainerConfiguration(File systemConfiguration, File userConfiguration) throws InvalidConfigurationException { - this(null, systemConfiguration, userConfiguration); - } - - // For testing only - EmbeddedServletContainerConfiguration(Properties systemConfiguration, Properties userConfiguration) { - this(null, systemConfiguration, userConfiguration); - } - - /** - * Main Constructor - * - * @param paths - * @throws InvalidConfigurationException - */ - EmbeddedServletContainerConfiguration(CommonPaths paths) throws InvalidConfigurationException { - this(paths, getSystemWebStorageServiceConfigFile(paths), getUserWebStorageServiceConfigFile(paths)); - } - - private static File getUserWebStorageServiceConfigFile(CommonPaths paths) throws InvalidConfigurationException { - return new File(paths.getUserConfigurationDirectory(), "web-storage-service.properties"); - } - - private static File getSystemWebStorageServiceConfigFile(CommonPaths paths) throws InvalidConfigurationException { - return new File(paths.getSystemConfigurationDirectory(), "web-storage-service.properties"); - } - - private static void initConfig(File configFile, - Properties configProps) { - try (FileInputStream configFis = new FileInputStream(configFile)) { - configProps.load(configFis); - } catch (FileNotFoundException e) { - // ignore, allow files to not exist on initialization - } catch (IOException e) { - throw new InvalidConfigurationException(e); - } - } - - HostPortPair getHostsPortsConfig() throws InvalidConfigurationException { - String hostsPortsString = systemConfiguration.getProperty(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name()); - // user config overrides system config - String userPortsString = userConfiguration.getProperty(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name()); - if (userPortsString != null) { - hostsPortsString = userPortsString; - } - // config must not be empty in both, system AND user config - if (hostsPortsString == null) { - throw new InvalidConfigurationException(t.localize(LocaleResources.BIND_ADDRESS_NULL)); - } - HostPortsParser parser = new HostPortsParser(hostsPortsString); - parser.parse(); - List<HostPortPair> hostsPorts = parser.getHostsPorts(); - if (hostsPorts.size() != 1) { - throw new InvalidConfigurationException("Cannot parse configuration (lists not allowed!)"); - } - return hostsPorts.get(0); - } - - /* The path to the context where the web archive gets bound to */ - String getContextPath() { - return "/thermostat/storage"; - } - - File getAbsolutePathToExplodedWebArchive() { - File thermostatHome = paths.getSystemThermostatHome(); - // The thermostat build produces an exploded war in $THERMOSTAT_HOME/webapp - File webArchiveDir = new File(thermostatHome, "webapp"); - return webArchiveDir; - } - - boolean isBackingStorageStart() { - String storageProp = systemConfiguration.getProperty(ConfigKeys.START_BACKING_STORAGE.name()); - // user config overrides system config - String userProp = userConfiguration.getProperty(ConfigKeys.START_BACKING_STORAGE.name()); - if (userProp != null) { - storageProp = userProp; - } - if (storageProp == null) { - // default to true if neither system nor user config is present - return true; - } - return Boolean.parseBoolean(storageProp); - } - - boolean isEnableTLS() { - String sslProp = systemConfiguration.getProperty(ConfigKeys.USE_SSL.name()); - // user config overrides system config - String userProp = userConfiguration.getProperty(ConfigKeys.USE_SSL.name()); - if (userProp != null) { - sslProp = userProp; - } - // default to false if neither system nor user config present - boolean propVal = Boolean.parseBoolean(sslProp); - return propVal; - } - - String getConnectionUrl() throws InvalidConfigurationException { - String httpPrefix = "http"; - if (isEnableTLS()) { - httpPrefix = httpPrefix + "s"; - } - HostPortPair hostPort = getHostsPortsConfig(); - String host = hostPort.getHost(); - if (host.indexOf(':') >= 0) { - // host is an IPv6 literal, enclose with '[' and ']' in order to - // be rfc3986 conformant - host = "[" + host + "]"; - } - String connectUrl = String.format("%s://%s:%s%s", httpPrefix, host, hostPort.getPort(), getContextPath()); - logger.log(Level.FINE, "Using agent connection URL '" + connectUrl + "'"); - return connectUrl; - } - - String getAbsolutePathToJaasConfig() throws InvalidConfigurationException { - File etcPath = paths.getSystemConfigurationDirectory(); - File thermostatJaasConf = new File(etcPath, "thermostat_jaas.conf"); - try { - return thermostatJaasConf.getCanonicalPath(); - } catch (IOException e) { - throw new InvalidConfigurationException(e); - } - } - - boolean hasRequestLogConfig() { - return getLogFileFromProperties() != null; - } - - String getAbsolutePathToRequestLog() throws InvalidConfigurationException { - String logFileName = getLogFileFromProperties(); - if (logFileName == null) { - // no config - return null; - } - File userLogsPath = paths.getUserLogDirectory(); - File requestLog = new File(userLogsPath, logFileName); - return requestLog.getAbsolutePath(); - } - - private String getLogFileFromProperties() { - String logFileName = systemConfiguration.getProperty(ConfigKeys.REQUEST_LOG_FILENAME.name()); - String userPotentialFileName = userConfiguration.getProperty(ConfigKeys.REQUEST_LOG_FILENAME.name()); - if (userPotentialFileName != null) { - logFileName = userPotentialFileName; - } - if (logFileName == null) { - // Not set - return null; - } - return logFileName; - } - - static enum ConfigKeys { - /* String: The bind address. host:port format */ - SERVLET_CONTAINER_BIND_ADDRESS, - /* Boolean: If set to "true" makes the embedded servlet container - * boot up with SSL support. It uses config in ssl.properties for - * keystore et al. - */ - USE_SSL, - /* Filename of the request log. It's relative to thermostat's - * logs directory. - */ - REQUEST_LOG_FILENAME, - /* - * Determine whether backing storage should get started too - */ - START_BACKING_STORAGE - } -}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncher.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,307 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Calendar; -import java.util.TimeZone; -import java.util.concurrent.CountDownLatch; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.net.ssl.SSLContext; - -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.HttpConfiguration; -import org.eclipse.jetty.server.HttpConnectionFactory; -import org.eclipse.jetty.server.NCSARequestLog; -import org.eclipse.jetty.server.SecureRequestCustomizer; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.SslConnectionFactory; -import org.eclipse.jetty.server.handler.ContextHandlerCollection; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.server.handler.RequestLogHandler; -import org.eclipse.jetty.util.component.LifeCycle; -import org.eclipse.jetty.util.ssl.SslContextFactory; -import org.eclipse.jetty.webapp.WebAppContext; -import org.osgi.framework.Bundle; -import org.osgi.framework.FrameworkUtil; - -import com.redhat.thermostat.common.ssl.SSLContextFactory; -import com.redhat.thermostat.common.ssl.SslInitException; -import com.redhat.thermostat.common.utils.HostPortPair; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -class JettyContainerLauncher { - - private static final Logger logger = LoggingUtils.getLogger(JettyContainerLauncher.class); - static final String JAAS_CONFIG_PROP = "java.security.auth.login.config"; - - private final EmbeddedServletContainerConfiguration config; - private final SSLConfiguration sslConfig; - private Server server; - private Thread serverThread; - private boolean isStartupSuccessFul = true; - - JettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) { - this.config = config; - this.sslConfig = sslConfig; - } - - - void startContainer(final CountDownLatch contextStartedLatch) { - serverThread = new Thread(new Runnable() { - - @Override - public void run() { - // Make the class loader aware of the osgi env. By default webapps use - // the set TCCL as parent. Note that a plain WebAppClassLoader is not sufficient. Mainly because of classes - // jetty itself is using (from the servlet API, other bundles etc). - // - // It's a simple delegating class loader. If the OSGi loader (the loader of this - // class) doesn't find the class, we delegate to the system class loader. - // - // Note that this also assumes proper wiring of the endpoint bundle. That should be - // the case by using explicit instructions for the maven-bundle-plugin - // and starting all required jetty bundles on boot. - // - // See also this bug for some discussion: - // https://github.com/eclipse/jetty.project/issues/705 - ClassLoader osgiLoader = JettyContainerLauncher.class.getClassLoader(); - Thread.currentThread().setContextClassLoader(new DelegatingClassLoader(osgiLoader)); - try { - startContainerAndDeployWar(contextStartedLatch); - } finally { - Thread.currentThread().setContextClassLoader(null); - } - } - - }); - serverThread.start(); - } - - boolean isStartupSuccessFul() { - return isStartupSuccessFul; - } - - void stopContainer() { - try { - server.stop(); - server.join(); - serverThread.join(); - } catch (Exception e) { - logger.log(Level.INFO, e.getMessage(), e); - } - } - - private void startContainerAndDeployWar(final CountDownLatch contextStartedLatch) { - // Since we call this in a thread and we wait for a countDown() on the - // latch be sure to always call it in the exception case. Otherwise - // the thread won't exit. - try { - doStartContainerAndDeployWar(contextStartedLatch); - } catch (Exception e) { - isStartupSuccessFul = false; - logger.log(Level.WARNING, e.getMessage(), e); - contextStartedLatch.countDown(); - } - } - - private void doStartContainerAndDeployWar(final CountDownLatch contextStartedLatch) throws Exception { - HostPortPair ipPort = null; - try { - ipPort = config.getHostsPortsConfig(); - } catch (InvalidConfigurationException e) { - logger.log(Level.SEVERE, e.getMessage(), e); - isStartupSuccessFul = false; - contextStartedLatch.countDown(); - return; - } - server = new Server(); - // Set up the connector with SSL enabled if so configured - ServerConnector connector = getServerConnector(); - - // Set host and port - connector.setHost(ipPort.getHost()); - connector.setPort(ipPort.getPort()); - server.addConnector(connector); - - File webArchiveDir = config.getAbsolutePathToExplodedWebArchive(); - if (!webArchiveDir.exists()) { - String msg = String.format("Exploded web archive '%s' not found, exitting!", - webArchiveDir.getCanonicalFile().getAbsolutePath()); - logger.log(Level.SEVERE, msg); - isStartupSuccessFul = false; - contextStartedLatch.countDown(); - return; - } - WebAppContext ctx = new WebAppContext(webArchiveDir.getAbsolutePath(), config.getContextPath()); - // Jetty insists on a webdefault.xml file. If the file is not found, - // it fails to boot the embedded server. We work around this by writing - // a temp file and convincing it to use that. The file content comes - // from jetty itself, so it should always be there. - Bundle bundle = FrameworkUtil.getBundle(WebAppContext.class); - URL uri = bundle.getResource("/org/eclipse/jetty/webapp/webdefault.xml"); - logger.log(Level.INFO, - uri == null ? - "webdefault.xml file not found!" : - "found file in: " + uri.toExternalForm()); - File tempWebDefaults = File.createTempFile("jetty-webdefault", ".xml"); - tempWebDefaults.deleteOnExit(); - - writeWebDefaults(tempWebDefaults, uri); - - // Jetty/OpenJDK requires this string to be a forward-slash separated path, even on windows - ctx.setDefaultsDescriptor("file:///" + tempWebDefaults.getAbsolutePath().replace('\\', '/')); - - // Make server startup fail if context cannot be deployed. - // Please don't change this. - ctx.setThrowUnavailableOnStartupException(true); - - // Wait for the context to be up and running - ctx.addLifeCycleListener(new DoNothingLifecycleListener() { - @Override - public void lifeCycleStarted(LifeCycle arg0) { - contextStartedLatch.countDown(); - } - - @Override - public void lifeCycleFailure(LifeCycle arg0, Throwable arg1) { - isStartupSuccessFul = false; - contextStartedLatch.countDown(); - } - }); - configureJaas(); - // Configure the context handler with request logging if - // so desired. - configureRequestLog(ctx); - - server.start(); - } - - private void configureRequestLog(WebAppContext ctx) { - if (config.hasRequestLogConfig()) { - HandlerCollection handlers = new HandlerCollection(); - ContextHandlerCollection contexts = new ContextHandlerCollection(); - RequestLogHandler requestLogHandler = new RequestLogHandler(); - handlers.setHandlers(new Handler[] { contexts, ctx, - requestLogHandler }); - server.setHandler(handlers); - - String logPath = config.getAbsolutePathToRequestLog(); - NCSARequestLog requestLog = new NCSARequestLog(logPath); - requestLog.setRetainDays(90); - requestLog.setAppend(true); - requestLog.setExtended(false); - TimeZone tz = Calendar.getInstance().getTimeZone(); - requestLog.setLogTimeZone(tz.getID()); - requestLogHandler.setRequestLog(requestLog); - logger.log(Level.FINEST, "Using jetty request log: " + logPath); - } else { - // no request logging just use the context as handler - server.setHandler(ctx); - } - } - - private ServerConnector getServerConnector() - throws InvalidConfigurationException, SslInitException { - ServerConnector connector; - if (config.isEnableTLS()) { - logger.log(Level.FINEST, "Enabling TLS enabled web storage endpoint"); - - // HTTP Configuration - HttpConfiguration http_config = new HttpConfiguration(); - http_config.setSecureScheme("https"); - - // SSL HTTP Configuration - HttpConfiguration https_config = new HttpConfiguration(http_config); - https_config.addCustomizer(new SecureRequestCustomizer()); - - SslContextFactory sslContextFactory = new SslContextFactory(); - SSLContext serverContext = SSLContextFactory.getServerContext(sslConfig); - sslContextFactory.setSslContext(serverContext); - // SSL Connector - connector = new ServerConnector(server, - new SslConnectionFactory(sslContextFactory,"http/1.1"), - new HttpConnectionFactory(https_config)); - } else { - // non-SSL - connector = new ServerConnector(server); - } - return connector; - } - - - private void writeWebDefaults(File tempWebDefaults, URL uri) { - try (FileOutputStream fout = new FileOutputStream(tempWebDefaults); - InputStream in = uri.openStream(); - BufferedInputStream bin = new BufferedInputStream(in)) { - byte[] buf = new byte[256]; - int len = -1; - while ((len = bin.read(buf)) > 0) { - fout.write(buf, 0, len); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - - /* - * Equivalent of -Djava.security.auth.login.config=$THERMOSTAT_HOME/etc/thermostat_jaas.conf - * - * package-private for testing. - */ - void configureJaas() { - String propVal = System.getProperty(JAAS_CONFIG_PROP); - // Only set JAAS config property if not already set - if (propVal == null) { - propVal = config.getAbsolutePathToJaasConfig(); - System.setProperty(JAAS_CONFIG_PROP, propVal); - } - logger.log(Level.FINE, "Using JAAS config '" + propVal + "'"); - } - -}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/LocaleResources.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import com.redhat.thermostat.shared.locale.Translate; - -public enum LocaleResources { - - COMMON_PATHS_UNAVAILABLE, - LAUNCHER_UNAVAILABLE, - SSL_CONFIGURATION_UNAVAILABLE, - - STORAGE_WAIT_INTERRUPTED, - ERROR_STARTING_STORAGE, - ERROR_STARTING_JETTY, - - BIND_ADDRESS_NULL, - - STARTING_AGENT_FAILED, - ; - - public static final String RESOURCE_BUNDLE = - "com.redhat.thermostat.web.endpoint.internal.strings"; - - public static Translate<LocaleResources> createLocalizer() { - return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); - } -} -
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/StorageStartedListener.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import java.util.concurrent.CountDownLatch; - -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.tools.ApplicationState; - -public class StorageStartedListener implements ActionListener<ApplicationState> { - private final CountDownLatch storageStarted; - private boolean startupSuccessful; - - protected StorageStartedListener(CountDownLatch latch) { - storageStarted = latch; - // Assume startup has failed initially, until a - // START action event is received - startupSuccessful = false; - } - - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { - ApplicationState state = actionEvent.getActionId(); - switch(state) { - case START: - startupSuccessful = true; - // fall-through - default: - storageStarted.countDown(); - break; - } - } - } - - public boolean isStartupSuccessful() { - return startupSuccessful; - } -}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/WebStorageLauncherCommand.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,254 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.logging.Logger; - -import org.apache.felix.scr.annotations.Component; -import org.apache.felix.scr.annotations.Property; -import org.apache.felix.scr.annotations.Reference; -import org.apache.felix.scr.annotations.Service; - -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.ExitStatus; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.Command; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.shared.locale.Translate; -import sun.misc.Signal; -import sun.misc.SignalHandler; - -@Component -@Service(Command.class) -@Property(name=Command.NAME, value="web-storage") -public class WebStorageLauncherCommand extends AbstractStateNotifyingCommand { - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - private static final Logger logger = LoggingUtils.getLogger(WebappLauncherCommand.class); - - private final List<ActionListener<ApplicationState>> listeners = new ArrayList<>(); - private final CustomSignalHandler handler = new CustomSignalHandler(); - private final CountDownLatch shutdownLatch; - private JettyContainerLauncher jettyLauncher; - - @Reference - private CommonPaths commonPaths; - - @Reference - private Launcher launcher; - - @Reference - private SSLConfiguration sslConfig; - - @Reference - private ExitStatus exitStatus; - - //for declarative services instantiation - public WebStorageLauncherCommand() { - this(new CountDownLatch(1)); - } - - //package private for testing - WebStorageLauncherCommand(CountDownLatch shutdownLatch) { - this.shutdownLatch = shutdownLatch; - } - - @Override - public void run(CommandContext ctx) throws CommandException { - EmbeddedServletContainerConfiguration config = getConfiguration(commonPaths); - handler.setConfig(config); - - if (config.isBackingStorageStart()) { - startStorage(); - } - - jettyLauncher = getJettyContainerLauncher(config, sslConfig); - CountDownLatch webStartedLatch = new CountDownLatch(1); - // start web container with the web archive deployed - jettyLauncher.startContainer(webStartedLatch); - try { - webStartedLatch.await(); - } catch (InterruptedException e) { - // ignore - } - if (!jettyLauncher.isStartupSuccessFul()) { - if (config.isBackingStorageStart()) { - stopStorage(launcher); - } - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.ERROR_STARTING_JETTY)); - } - - Signal.handle(new Signal("INT"), handler); - Signal.handle(new Signal("TERM"), handler); - - //Wait for SIGINT/SIGTERM - try { - shutdownLatch.await(); - } catch (InterruptedException e) { - handler.handle(new Signal("INT")); - } - } - - private void startStorage() throws CommandException { - // start storage - final CountDownLatch storageLatch = new CountDownLatch(1); - StorageStartedListener storageListener = new StorageStartedListener(storageLatch); - listeners.add(storageListener); - String[] storageArgs = new String[] { - "storage", "--start" - }; - launcher.run(storageArgs, listeners, false); - listeners.clear(); - try { - storageLatch.await(); - } catch (InterruptedException e) { - getNotifier().fireAction(ApplicationState.FAIL, e); - throw new CommandException(translator.localize(LocaleResources.STORAGE_WAIT_INTERRUPTED)); - } - if (!storageListener.isStartupSuccessful()) { - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.ERROR_STARTING_STORAGE)); - } - } - - // testing hook - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return new EmbeddedServletContainerConfiguration(paths); - } - - // testing hook - JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) { - return new JettyContainerLauncher(config, sslConfig); - } - - // This fires up the web endpoint. No need to automatically firing up - // storage. - @Override - public boolean isStorageRequired() { - return false; - } - - private void stopStorage(Launcher launcher) { - String[] storageStopArgs = new String[] { - "storage", "--stop" - }; - launcher.run(storageStopArgs, false); - } - - private class CustomSignalHandler implements SignalHandler { - - private EmbeddedServletContainerConfiguration config; - - @Override - public void handle(Signal arg0) { - try { - jettyLauncher.stopContainer(); - if (config.isBackingStorageStart()) { - stopStorage(launcher); - } - } catch (Exception ex) { - // We don't want any exception to hold back the signal handler, otherwise - // there will be no way to actually stop Thermostat. - ex.printStackTrace(); - } - logger.fine("Web storage stopped."); - // Hook for integration tests. Print a well known message to stdout - // if verbose mode is turned on via the system property. - shutdown(ExitStatus.EXIT_SUCCESS); - } - - private void setConfig(EmbeddedServletContainerConfiguration config) { - this.config = config; - } - } - - private void shutdown(int shutDownStatus) { - // Exit application - if (shutdownLatch != null) { - shutdownLatch.countDown(); - } - - this.exitStatus.setExitStatus(shutDownStatus); - if (shutDownStatus == ExitStatus.EXIT_SUCCESS) { - getNotifier().fireAction(ApplicationState.STOP); - } else { - getNotifier().fireAction(ApplicationState.FAIL); - } - } - - public void bindCommonPaths(CommonPaths commonPaths) { - this.commonPaths = commonPaths; - } - - public void bindExitStatus(ExitStatus exitStatus) { - this.exitStatus = exitStatus; - } - - public void bindLauncher(Launcher launcher) { - this.launcher = launcher; - } - - public void bindSslConfig(SSLConfiguration sslConfig) { - this.sslConfig = sslConfig; - } - - public void unbindCommonPaths(CommonPaths commonPaths) { - this.commonPaths = null; - } - - public void unbindExitStatus(ExitStatus exitStatus) { - this.exitStatus = null; - } - - public void unbindLauncher(Launcher launcher) { - this.launcher = null; - } - - public void unbindSslConfig(SSLConfiguration sslConfig) { - this.sslConfig = null; - } -}
--- a/web/endpoint-plugin/web-service/src/main/java/com/redhat/thermostat/web/endpoint/internal/WebappLauncherCommand.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.cli.Console; -import com.redhat.thermostat.common.utils.LoggingUtils; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; - -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.shared.locale.Translate; - -class WebappLauncherCommand extends AbstractStateNotifyingCommand { - - private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); - private static final Logger logger = LoggingUtils.getLogger(WebappLauncherCommand.class); - private boolean agentStarted = false; - - // The time to wait after the agent finished and before the web endpoint - // goes down. This increases the chance of emptying the queue. - private static final long AGENT_SHUTDOWN_PAUSE = 200; - - private final BundleContext context; - private final List<ActionListener<ApplicationState>> listeners; - - WebappLauncherCommand(BundleContext context) { - this.context = context; - listeners = new ArrayList<>(); - } - - // PRE: 1. Storage set up with credentials and credentials appropriately - // updated in the web archive's web.xml - // 2. agent.auth file appropriately set up - // 3. agent/client users appropriately defined in thermostat-users/ - // thermostat-roles.properties files. - @Override - public void run(CommandContext ctx) throws CommandException { - ServiceReference commonPathsRef = context.getServiceReference(CommonPaths.class.getName()); - if (commonPathsRef == null) { - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.COMMON_PATHS_UNAVAILABLE)); - } - CommonPaths paths = (CommonPaths)context.getService(commonPathsRef); - ServiceReference launcherRef = context.getServiceReference(Launcher.class.getName()); - if (launcherRef == null) { - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.LAUNCHER_UNAVAILABLE)); - } - Launcher launcher = (Launcher) context.getService(launcherRef); - EmbeddedServletContainerConfiguration config = getConfiguration(paths); - - // start storage only if so desired - if (config.isBackingStorageStart()) { - startStorage(launcher); - } - - ServiceReference sslConfigRef = context.getServiceReference(SSLConfiguration.class.getName()); - if (sslConfigRef == null) { - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.SSL_CONFIGURATION_UNAVAILABLE)); - } - SSLConfiguration sslConfig = (SSLConfiguration) context.getService(sslConfigRef); - - JettyContainerLauncher jettyLauncher = getJettyContainerLauncher(config, sslConfig); - CountDownLatch webStartedLatch = new CountDownLatch(1); - // start web container with the web archive deployed - jettyLauncher.startContainer(webStartedLatch); - try { - webStartedLatch.await(); - } catch (InterruptedException e) { - // ignore - } - if (!jettyLauncher.isStartupSuccessFul()) { - if (config.isBackingStorageStart()) { - stopStorage(launcher); - } - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.ERROR_STARTING_JETTY)); - } - - // start agent - try { - listeners.add(new AgentStartedListener(ctx.getConsole())); - String[] agentArgs = new String[] { - "agent", "-d", config.getConnectionUrl() - }; - // This blocks - launcher.run(agentArgs, listeners, false); - - ctx.getConsole().getOutput().println("Waiting " + AGENT_SHUTDOWN_PAUSE + "MS before exiting in order to empty queues"); - // Give the agent some time to finish it's work. Requests are - // queued and it increases the chance of finishing requests before - // exiting for sure. - try { - Thread.sleep(AGENT_SHUTDOWN_PAUSE); - } catch (InterruptedException e) { } // ignore - } finally { - jettyLauncher.stopContainer(); - if (config.isBackingStorageStart()) { - stopStorage(launcher); - } - }; - - if (agentStarted) { - getNotifier().fireAction(ApplicationState.STOP); - } - } - - private void startStorage(Launcher launcher) throws CommandException { - final CountDownLatch storageLatch = new CountDownLatch(1); - StorageStartedListener storageListener = new StorageStartedListener(storageLatch); - listeners.add(storageListener); - String[] storageArgs = new String[] { - "storage", "--start" - }; - launcher.run(storageArgs, listeners, false); - listeners.clear(); - try { - storageLatch.await(); - } catch (InterruptedException e) { - getNotifier().fireAction(ApplicationState.FAIL, e); - throw new CommandException(translator.localize(LocaleResources.STORAGE_WAIT_INTERRUPTED)); - } - if (!storageListener.isStartupSuccessful()) { - getNotifier().fireAction(ApplicationState.FAIL); - throw new CommandException(translator.localize(LocaleResources.ERROR_STARTING_STORAGE)); - } - } - - // testing hook - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return new EmbeddedServletContainerConfiguration(paths); - } - - // testing hook - JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) { - return new JettyContainerLauncher(config, sslConfig); - } - - // This fires up the web endpoint. No need to automatically firing up - // storage. - @Override - public boolean isStorageRequired() { - return false; - } - - private void stopStorage(Launcher launcher) { - String[] storageStopArgs = new String[] { - "storage", "--stop" - }; - launcher.run(storageStopArgs, false); - } - - private class AgentStartedListener implements ActionListener<ApplicationState> { - - private final Console console; - - private AgentStartedListener(Console console) { - this.console = console; - } - - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - if (actionEvent.getSource() instanceof AbstractStateNotifyingCommand) { - AbstractStateNotifyingCommand agent = (AbstractStateNotifyingCommand) actionEvent.getSource(); - // Implementation detail: there is a single AgentCommand instance registered - // as an OSGi service. We remove ourselves as listener so that we don't get - // notified in the case that the command is invoked by some other means later. - agent.getNotifier().removeActionListener(this); - - ApplicationState state = actionEvent.getActionId(); - // propagate the Agent ActionEvent - switch(state) { - case START: - agentStarted = true; - logger.fine("Agent started via web-storage-service. Agent ID was: " + actionEvent.getPayload()); - getNotifier().fireAction(ApplicationState.START, actionEvent.getPayload()); - break; - case FAIL: - console.getError().println(translator.localize(LocaleResources.STARTING_AGENT_FAILED).getContents()); - getNotifier().fireAction(ApplicationState.FAIL, actionEvent.getPayload()); - break; - case STOP: - getNotifier().fireAction(ApplicationState.STOP); - break; - default: - throw new AssertionError("Unexpected state " + state); - } - } - } - } - -}
--- a/web/endpoint-plugin/web-service/src/main/resources/com/redhat/thermostat/web/endpoint/internal/strings.properties Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -COMMON_PATHS_UNAVAILABLE = CommonPaths unavailable. -LAUNCHER_UNAVAILABLE = Launcher Unavailable -SSL_CONFIGURATION_UNAVAILABLE = SSLConfiguration Unavailable -STORAGE_WAIT_INTERRUPTED = Interrupted waiting for storage -ERROR_STARTING_STORAGE = Starting mongodb storage failed -ERROR_STARTING_JETTY = Failed to start embedded jetty instance -BIND_ADDRESS_NULL = CONFIG_LISTEN_ADDRESS must be specified. -STARTING_AGENT_FAILED = Thermostat agent failed to start. See logs for details. -
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/ActivatorTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; - -import com.redhat.thermostat.common.cli.Command; -import com.redhat.thermostat.testutils.StubBundleContext; -import com.redhat.thermostat.web.endpoint.internal.Activator; -import com.redhat.thermostat.web.endpoint.internal.WebappLauncherCommand; - -public class ActivatorTest { - - @Test - public void verifyCommandIsRegistered() throws Exception { - StubBundleContext context = new StubBundleContext(); - Activator activator = new Activator(); - activator.start(context); - assertTrue(context.isServiceRegistered(Command.class.getName(), WebappLauncherCommand.class)); - activator.stop(context); - assertFalse(context.isServiceRegistered(Command.class.getName(), WebappLauncherCommand.class)); - } -}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/DelegatingClassLoaderTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import org.junit.Test; - -public class DelegatingClassLoaderTest { - - @Test - public void verifyClassloaderDelegationFailsForNotExistingClass() throws Exception { - ClassLoader mockLoader = mock(ClassLoader.class); - DelegatingClassLoader delegateLoader = new DelegatingClassLoader(mockLoader); - String notExistingClassName = "com.redhat.thermostat.not.existing.FooClass"; - doThrow(ClassNotFoundException.class).when(mockLoader).loadClass(eq(notExistingClassName)); - try { - delegateLoader.loadClass(notExistingClassName); - fail("should not have found class " + notExistingClassName); - } catch (ClassNotFoundException e) { - // pass - verify(mockLoader).loadClass(eq(notExistingClassName)); - } - } - - @Test - public void verifyClassloaderDelegationWorksForExistingClass() throws Exception { - ClassLoader mockLoader = mock(ClassLoader.class); - DelegatingClassLoader webappLoader = new DelegatingClassLoader(mockLoader); - // This class is not really there, but the fake class loader does not - // throw a CNFE - String className = "com.redhat.thermostat.not.existing.FooClass"; - try { - Class<?> clazz = webappLoader.loadClass(className); - assertNull(clazz); - } catch (ClassNotFoundException e) { - fail("should have been able to load class since mock classloader does not throw CNFE"); - } - verify(mockLoader).loadClass(eq(className)); - } - - @Test - public void verifySystemClassIsResolvable() throws Exception { - ClassLoader mockLoader = mock(ClassLoader.class); - DelegatingClassLoader delegateLoader = new DelegatingClassLoader(mockLoader); - String className = "javax.security.auth.login.LoginContext"; - doThrow(ClassNotFoundException.class).when(mockLoader).loadClass(eq(className)); - try { - Class<?> clazz = delegateLoader.loadClass(className); - assertNotNull(clazz); - } catch (ClassNotFoundException e) { - fail("should have been able to load system class " + className); - } - } - -}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/EmbeddedServletContainerConfigurationTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,390 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.util.Properties; - -import org.junit.Test; - -import com.redhat.thermostat.common.utils.HostPortPair; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.web.endpoint.internal.EmbeddedServletContainerConfiguration.ConfigKeys; - -public class EmbeddedServletContainerConfigurationTest { - - /* - * empty configs defaults to false - */ - @Test - public void canGetSSLConfigNothingSpecified() { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertFalse(config.isEnableTLS()); - } - - /* - * Verifies that user config overrides system config - */ - @Test - public void canGetUserSSLConfig() { - Properties systemConfig = new Properties(); - systemConfig.put(ConfigKeys.USE_SSL.name(), "false"); - Properties userConfig = new Properties(); - userConfig.put(ConfigKeys.USE_SSL.name(), "true"); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertTrue(config.isEnableTLS()); - } - - /* - * Empty configs defaults to true - */ - @Test - public void canGetIsBackingStorageStartNothingSpecified() { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertTrue(config.isBackingStorageStart()); - } - - /* - * System config should be taken into account. No override by user config. - */ - @Test - public void canGetIsBackingStorageStartSystemSpecified() { - Properties systemConfig = new Properties(); - systemConfig.put(ConfigKeys.START_BACKING_STORAGE.name(), "false"); - Properties userConfig = new Properties(); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertFalse(config.isBackingStorageStart()); - } - - /* - * User config overrides system. - */ - @Test - public void canGetIsBackingStorageStartUserOverridesSystem() { - Properties systemConfig = new Properties(); - systemConfig.put(ConfigKeys.START_BACKING_STORAGE.name(), "false"); - Properties userConfig = new Properties(); - userConfig.put(ConfigKeys.START_BACKING_STORAGE.name(), "true"); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertTrue(config.isBackingStorageStart()); - } - - /* - * No system config only user config. - */ - @Test - public void canGetIsBackingStorageStartUserOverridesNoSystemConfig() { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - userConfig.put(ConfigKeys.START_BACKING_STORAGE.name(), "false"); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertFalse(config.isBackingStorageStart()); - } - - /* - * Verifies that system config works - */ - @Test - public void canGetSystemSSLConfig() { - Properties systemConfig = new Properties(); - systemConfig.put(ConfigKeys.USE_SSL.name(), "true"); - Properties userConfig = new Properties(); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertTrue(config.isEnableTLS()); - } - - @Test - public void garbageSSLConfigValsDoNotFail() { - Properties systemConfig = new Properties(); - systemConfig.put(ConfigKeys.USE_SSL.name(), "foo"); - Properties userConfig = new Properties(); - userConfig.put(ConfigKeys.USE_SSL.name(), "bar"); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertFalse(config.isEnableTLS()); - } - - /* - * No user config specified (empty properties) but - * system config has ips/ports pair. - */ - @Test - public void canGetSystemConfigListenAddress() throws InvalidConfigurationException { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - String host = "127.0.0.1"; - int port = 8888; - String systemConfigPairs = host + ":" + port; - systemConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), systemConfigPairs); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - HostPortPair hostPort = config.getHostsPortsConfig(); - assertEquals(host, hostPort.getHost()); - assertEquals(port, hostPort.getPort()); - } - - /* - * If both system *and* user config are specified, user config wins. - */ - @Test - public void userConfigOverridesSystemConfigListenAddress() throws InvalidConfigurationException { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - String host = "127.0.0.1"; - int port = 8888; - String systemConfigPairs = host + ":" + port; - String userHost = "host.example.com"; - int userPort = 3334; - String userConfigPairs = userHost + ":" + userPort; - systemConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), systemConfigPairs); - userConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), userConfigPairs); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - HostPortPair hostPort = config.getHostsPortsConfig(); - assertEquals(userHost, hostPort.getHost()); - assertEquals(userPort, hostPort.getPort()); - } - - /* - * If neither system nor user config has the CONFIG_LISTEN_ADDRESS key - * config is invalid. - */ - @Test(expected = InvalidConfigurationException.class) - public void testInvalidConfigNullListenAddress() { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - // this should throw InvalidConfigException - config.getHostsPortsConfig(); - } - - /* - * Implementation detail. The host/port parser supports parsing lists. - * However, in this context only one listen address can be specified. This - * test ensures that an InvalidConfigurationException is thrown if config - * contains a list. - */ - @Test - public void testListenAddressInvalidConfigList() { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - String hostPortList = "127.0.0.1:8889,127.0.1.1:9999"; - systemConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), hostPortList); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - try { - config.getHostsPortsConfig(); - fail("expected InvalidConfigurationException due to host/port list size > 1 in system config"); - } catch (InvalidConfigurationException e) { - // pass - } - userConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), hostPortList); - systemConfig.clear(); - config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - try { - config.getHostsPortsConfig(); - fail("expected InvalidConfigurationException due to host/port list size > 1 in user config"); - } catch (InvalidConfigurationException e) { - // pass - } - } - - /* - * Config should not throw and exception on instantiation if user config - * file does not exist. - */ - @Test - public void canLoadConfigWithUserFileNotExisting() throws Exception { - File systemFile = File.createTempFile("thermostat-tests", EmbeddedServletContainerConfigurationTest.class.getName()); - systemFile.deleteOnExit(); - assertTrue(systemFile.exists()); - File userFile = new File("/thermostat/i-do-not-exists"); - assertFalse(userFile.exists()); - try { - new EmbeddedServletContainerConfiguration(systemFile, userFile); - // pass - } catch (InvalidConfigurationException e) { - fail("Instantiation should not throw ICE due to missing files: " + e.getMessage()); - } - } - - /* - * Config should not throw and exception on instantiation if system config - * file does not exist. - */ - @Test - public void canLoadConfigWithSystemFileNotExisting() throws Exception { - File userFile = File.createTempFile("thermostat-tests", EmbeddedServletContainerConfigurationTest.class.getName()); - userFile.deleteOnExit(); - assertTrue(userFile.exists()); - File sysFile = new File("/thermostat/i-do-not-exists"); - assertFalse(sysFile.exists()); - try { - new EmbeddedServletContainerConfiguration(sysFile, userFile); - // pass - } catch (InvalidConfigurationException e) { - fail("Instantiation should not throw ICE due to missing files: " + e.getMessage()); - } - } - - /* - * Config should not throw and exception on instantiation if user config - * and system config file does not exist. - */ - @Test - public void canLoadConfigWithSystemAndUserFileNotExisting() { - File sysFile = new File("/thermostat/i-do-not-exists-system"); - File userFile = new File("/thermostat/i-do-not-exists-user"); - assertFalse(sysFile.exists()); - assertFalse(userFile.exists()); - try { - new EmbeddedServletContainerConfiguration(sysFile, userFile); - // pass - } catch (InvalidConfigurationException e) { - fail("Instantiation should not throw ICE due to missing files: " + e.getMessage()); - } - } - - @Test - public void testGetWebArchivePath() { - CommonPaths paths = mock(CommonPaths.class); - File fooThermostatHome = new File("/foo/path"); - when(paths.getSystemThermostatHome()).thenReturn(fooThermostatHome); - - // Any non-null file will do for user/system config files - File irrelevantForTest = new File("irrelevant"); - - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(paths, irrelevantForTest, irrelevantForTest); - File expected = new File(fooThermostatHome, "webapp"); - File actual = config.getAbsolutePathToExplodedWebArchive(); - assertEquals(expected.getAbsolutePath(), actual.getAbsolutePath()); - } - - /* - * If a request log configuration is set, be sure config paths are available - */ - @Test - public void verifyRequestLogConfiguration() { - CommonPaths paths = mock(CommonPaths.class); - File testUserHomeLogs = new File("/test/userhome/logs"); - when(paths.getUserLogDirectory()).thenReturn(testUserHomeLogs); - - // system config only - Properties userConfig = new Properties(); - Properties systemConfig = new Properties(); - systemConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "logfile.log"); - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig); - assertTrue("Should have request log config", config.hasRequestLogConfig()); - assertEquals(new File("/test/userhome/logs/logfile.log").getAbsolutePath(), config.getAbsolutePathToRequestLog()); - - // user config only - userConfig = new Properties(); - systemConfig = new Properties(); - userConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "userlogFile.log"); - config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig); - assertTrue("Should have request log config", config.hasRequestLogConfig()); - assertEquals(new File("/test/userhome/logs/userlogFile.log").getAbsolutePath(), config.getAbsolutePathToRequestLog()); - - // user and system config - userConfig = new Properties(); - systemConfig = new Properties(); - userConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "userlogFile.log"); - systemConfig.setProperty(ConfigKeys.REQUEST_LOG_FILENAME.name(), "systemlogFile.log"); - config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig); - assertTrue("Should have request log config", config.hasRequestLogConfig()); - assertEquals("User config overrides system config", - new File("/test/userhome/logs/userlogFile.log").getAbsolutePath(), - config.getAbsolutePathToRequestLog()); - - // no config - userConfig = new Properties(); - systemConfig = new Properties(); - config = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig); - assertFalse("Should NOT have request log config", config.hasRequestLogConfig()); - assertNull("No config specified", - config.getAbsolutePathToRequestLog()); - } - - @Test - public void canGetConnectionURL() { - doConnectionUrlTest("http://[1fff:0:a88:85a3::ac1f]:8999/thermostat/storage", "[1fff:0:a88:85a3::ac1f]:8999", false); - doConnectionUrlTest("http://host1.example.com:8888/thermostat/storage", "host1.example.com:8888", false); - doConnectionUrlTest("https://host1.example.com:8998/thermostat/storage", "host1.example.com:8998", true); - } - - @Test - public void canGetContextPath() { - String expectedContextPath = "/thermostat/storage"; - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration((Properties)null /* unused */, (Properties)null /* unused */); - assertEquals(expectedContextPath, config.getContextPath()); - } - - private void doConnectionUrlTest(String expectedUrl, String hostPortToken, boolean enableSSL) { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - systemConfig.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), hostPortToken); - if (enableSSL) { - systemConfig.put(ConfigKeys.USE_SSL.name(), Boolean.TRUE.toString()); - } - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(systemConfig, userConfig); - assertEquals(expectedUrl, config.getConnectionUrl()); - } - - @Test - public void canGetPathToJaasConfig() throws InvalidConfigurationException { - CommonPaths paths = mock(CommonPaths.class); - String fooThHome = "/foo/path/etc"; - File fooThermostatHome = new File(fooThHome); - when(paths.getSystemConfigurationDirectory()).thenReturn(fooThermostatHome); - - // Any non-null file will do for user/system config files - File irrelevantForTest = new File("irrelevant"); - - EmbeddedServletContainerConfiguration config = new EmbeddedServletContainerConfiguration(paths, irrelevantForTest, irrelevantForTest); - String actual = config.getAbsolutePathToJaasConfig(); - assertEquals(new File(fooThHome + "/thermostat_jaas.conf").getAbsolutePath(), actual); - } -}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/JettyContainerLauncherTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import java.io.File; -import java.util.concurrent.CountDownLatch; - -import org.junit.Test; - -import com.redhat.thermostat.common.utils.HostPortPair; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.web.endpoint.internal.EmbeddedServletContainerConfiguration; -import com.redhat.thermostat.web.endpoint.internal.JettyContainerLauncher; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.times; - -public class JettyContainerLauncherTest { - - @Test - public void startFailsIfWebArchivePathDoesNotExist() throws InterruptedException { - EmbeddedServletContainerConfiguration config = mock(EmbeddedServletContainerConfiguration.class); - File notThere = new File("/path/not-here-go-away"); - when(config.getAbsolutePathToExplodedWebArchive()).thenReturn(notThere); - HostPortPair hostPort = new HostPortPair("foo", 1111); - when(config.getHostsPortsConfig()).thenReturn(hostPort); - assertFalse(notThere.exists()); - JettyContainerLauncher launcher = new JettyContainerLauncher(config, mock(SSLConfiguration.class)); - CountDownLatch latch = new CountDownLatch(1); - launcher.startContainer(latch); - latch.await(); - assertFalse(launcher.isStartupSuccessFul()); - } - - @Test - public void canConfigureJaasNoPropSet() { - try { - assertNull("Precondition failed!", System.getProperty(JettyContainerLauncher.JAAS_CONFIG_PROP)); - EmbeddedServletContainerConfiguration config = mock(EmbeddedServletContainerConfiguration.class); - when(config.getAbsolutePathToJaasConfig()).thenReturn("/foo/jaas.conf"); - JettyContainerLauncher launcher = new JettyContainerLauncher(config, mock(SSLConfiguration.class)); - launcher.configureJaas(); - assertEquals("/foo/jaas.conf", System.getProperty(JettyContainerLauncher.JAAS_CONFIG_PROP)); - } finally { - System.clearProperty(JettyContainerLauncher.JAAS_CONFIG_PROP); - } - } - - // A preconfigured jaas property should be left untouched. - @Test - public void canConfigureJaasWithPropSet() { - try { - EmbeddedServletContainerConfiguration config = mock(EmbeddedServletContainerConfiguration.class); - System.setProperty(JettyContainerLauncher.JAAS_CONFIG_PROP, "foo_jaas.conf"); - JettyContainerLauncher launcher = new JettyContainerLauncher(config, mock(SSLConfiguration.class)); - launcher.configureJaas(); - verify(config, times(0)).getAbsolutePathToJaasConfig(); - assertEquals("foo_jaas.conf", System.getProperty(JettyContainerLauncher.JAAS_CONFIG_PROP)); - } finally { - System.clearProperty(JettyContainerLauncher.JAAS_CONFIG_PROP); - } - } -}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/LocaleResourcesTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import com.redhat.thermostat.testutils.AbstractLocaleResourcesTest; - -public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> { - - @Override - protected Class<LocaleResources> getEnumClass() { - return LocaleResources.class; - } - - @Override - protected String getResourceBundle() { - return LocaleResources.RESOURCE_BUNDLE; - } - - -} -
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/StorageStartedListenerTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.concurrent.CountDownLatch; - -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.tools.ApplicationState; - -public class StorageStartedListenerTest { - private StorageStartedListener listener; - private CountDownLatch latch; - private ActionEvent<ApplicationState> event; - - @Before - public void setup() { - latch = new CountDownLatch(1); - listener = new StorageStartedListener(latch); - event = mock(ActionEvent.class); - when(event.getSource()).thenReturn(mock(AbstractStateNotifyingCommand.class)); - } - - @Test - public void testStartAction() { - when(event.getActionId()).thenReturn(ApplicationState.START); - - listener.actionPerformed(event); - - assertTrue(listener.isStartupSuccessful()); - assertEquals(0, latch.getCount()); - } - - @Test - public void testDefaultAction() { - when(event.getActionId()).thenReturn(ApplicationState.STOP); - listener.actionPerformed(event); - - assertFalse(listener.isStartupSuccessful()); - assertEquals(0, latch.getCount()); - } -}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/WebStorageLauncherCommandTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,284 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import static org.junit.Assert.assertFalse; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.util.Collection; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.ExitStatus; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.SSLConfiguration; - -public class WebStorageLauncherCommandTest { - - private static final String[] STORAGE_START_ARGS = { "storage", "--start" }; - private static final String[] STORAGE_STOP_ARGS = { "storage", "--stop" }; - - private CommandContext mockCommandContext; - private CommonPaths mockPaths; - private ExitStatus mockExitStatus; - private Launcher mockLauncher; - private SSLConfiguration mockSslConfig; - private JettyContainerLauncher mockJettyLauncher; - private CountDownLatch shutdownLatch; - - @Before - public void setup() { - mockCommandContext = mock(CommandContext.class); - mockExitStatus = mock(ExitStatus.class); - mockPaths = mock(CommonPaths.class); - mockLauncher = mock(Launcher.class); - mockSslConfig = mock(SSLConfiguration.class); - - shutdownLatch = new CountDownLatch(1); - - final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class); - - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocationOnMock) throws Throwable { - AbstractStateNotifyingCommand cmd = mock(AbstractStateNotifyingCommand.class); - for (Object l : captor.getValue()) { - ActionEvent<ApplicationState> fakeEvent = new ActionEvent<>(cmd, ApplicationState.START); - ((ActionListener<ApplicationState>)l).actionPerformed(fakeEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), captor.capture(), eq(false)); - - - mockJettyLauncher = mock(JettyContainerLauncher.class); - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - CountDownLatch webStartedLatch = (CountDownLatch) invocation.getArguments()[0]; - webStartedLatch.countDown(); - return null; - } - }).when(mockJettyLauncher).startContainer(isA(CountDownLatch.class)); - when(mockJettyLauncher.isStartupSuccessFul()).thenReturn(true); - doNothing().when(mockJettyLauncher).stopContainer(); - } - - private void bind(WebStorageLauncherCommand command) { - command.bindCommonPaths(mockPaths); - command.bindExitStatus(mockExitStatus); - command.bindLauncher(mockLauncher); - command.bindSslConfig(mockSslConfig); - } - - @Test - public void testIsStorageRequired() { - WebStorageLauncherCommand command = new WebStorageLauncherCommand(); - - assertFalse(command.isStorageRequired()); - } - - @Test(expected = CommandException.class) - public void testRunCommandWithNoConfigListenAddressSpecified() throws Exception { - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - final EmbeddedServletContainerConfiguration testConfig = new EmbeddedServletContainerConfiguration(mockPaths, systemConfig, userConfig); - - WebStorageLauncherCommand command = new WebStorageLauncherCommand() { - @Override - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return testConfig; - } - }; - - bind(command); - command.run(mockCommandContext); - } - - @Test(expected = CommandException.class) - public void testRunCommandWithWebArchiveNotExisting() throws Exception { - CommonPaths paths = mock(CommonPaths.class); - - File thermostatHomeNotExisting = mock(File.class); - when(paths.getSystemThermostatHome()).thenReturn(thermostatHomeNotExisting); - - Properties systemConfig = new Properties(); - Properties userConfig = new Properties(); - userConfig.put(EmbeddedServletContainerConfiguration.ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), "127.0.0.1:8888"); - final EmbeddedServletContainerConfiguration testConfig = new EmbeddedServletContainerConfiguration(mockPaths, systemConfig, userConfig); - - WebStorageLauncherCommand command = new WebStorageLauncherCommand() { - @Override - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return testConfig; - } - }; - bind(command); - command.run(mockCommandContext); - } - - @Test - public void testRunOnce() throws CommandException { - boolean startBackingStorage = true; - doTestRunOnce(startBackingStorage); - } - - @Test - public void testRunOnceNoBackingStorage() throws CommandException { - boolean startBackingStorage = false; - doTestRunOnce(startBackingStorage); - } - - @SuppressWarnings("unchecked") - private void doTestRunOnce(boolean startBackingStorage) throws CommandException { - final EmbeddedServletContainerConfiguration mockConfig = mock(EmbeddedServletContainerConfiguration.class); - when(mockConfig.isBackingStorageStart()).thenReturn(startBackingStorage); - when(mockConfig.getConnectionUrl()).thenReturn("Test String"); - - WebStorageLauncherCommand command = new WebStorageLauncherCommand(shutdownLatch) { - @Override - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return mockConfig; - } - - @Override - JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) { - return mockJettyLauncher; - } - }; - - bind(command); - - shutdownLatch.countDown(); - - command.run(mockCommandContext); - - int numberOfTimesBackingStorage = 0; - if (startBackingStorage) { - numberOfTimesBackingStorage++; - } - verify(mockLauncher, times(numberOfTimesBackingStorage)).run(eq(STORAGE_START_ARGS), isA(Collection.class), eq(false)); - } - - @Test(expected = CommandException.class) - public void testStorageFailStart() throws CommandException { - final EmbeddedServletContainerConfiguration mockConfig = mock(EmbeddedServletContainerConfiguration.class); - when(mockConfig.getConnectionUrl()).thenReturn("Test String"); - when(mockConfig.isBackingStorageStart()).thenReturn(true); - - WebStorageLauncherCommand command = new WebStorageLauncherCommand(shutdownLatch) { - @Override - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return mockConfig; - } - - @Override - JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) { - return mockJettyLauncher; - } - }; - - final ArgumentCaptor<Collection> captor = ArgumentCaptor.forClass(Collection.class); - - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocationOnMock) throws Throwable { - AbstractStateNotifyingCommand cmd = mock(AbstractStateNotifyingCommand.class); - for (Object l : captor.getValue()) { - ActionEvent<ApplicationState> fakeEvent = new ActionEvent<>(cmd, ApplicationState.FAIL); - ((ActionListener<ApplicationState>)l).actionPerformed(fakeEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), captor.capture(), eq(false)); - - bind(command); - - shutdownLatch.countDown(); - - command.run(mockCommandContext); - } - - - @Test(expected = CommandException.class) - public void testWebContainerFailStart() throws CommandException { - final EmbeddedServletContainerConfiguration mockConfig = mock(EmbeddedServletContainerConfiguration.class); - when(mockConfig.getConnectionUrl()).thenReturn("Test String"); - - WebStorageLauncherCommand command = new WebStorageLauncherCommand(shutdownLatch) { - @Override - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return mockConfig; - } - - @Override - JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) { - return mockJettyLauncher; - } - }; - bind(command); - - when(mockJettyLauncher.isStartupSuccessFul()).thenReturn(false); - shutdownLatch.countDown(); - - command.run(mockCommandContext); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), eq(false)); - verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), eq(false)); - } -}
--- a/web/endpoint-plugin/web-service/src/test/java/com/redhat/thermostat/web/endpoint/internal/WebappLauncherCommandTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,668 +0,0 @@ -/* - * 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.web.endpoint.internal; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.ActionNotifier; -import com.redhat.thermostat.common.cli.Console; -import com.redhat.thermostat.testutils.NotImplementedException; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.common.ActionEvent; -import com.redhat.thermostat.common.ActionListener; -import com.redhat.thermostat.common.cli.AbstractStateNotifyingCommand; -import com.redhat.thermostat.common.cli.Arguments; -import com.redhat.thermostat.common.cli.CommandContext; -import com.redhat.thermostat.common.cli.CommandContextFactory; -import com.redhat.thermostat.common.cli.CommandException; -import com.redhat.thermostat.common.tools.ApplicationState; -import com.redhat.thermostat.launcher.Launcher; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.testutils.StubBundleContext; -import com.redhat.thermostat.web.endpoint.internal.EmbeddedServletContainerConfiguration.ConfigKeys; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -public class WebappLauncherCommandTest { - - private TestLogHandler handler; - private Logger logger; - private Launcher mockLauncher; - private WebappLauncherCommand cmd; - private CommandContext mockCommandContext; - private ByteArrayOutputStream stdErrOut; - private JettyContainerLauncher mockJettyLauncher; - - private static ActionEvent<ApplicationState> mockActionEvent; - private static Collection<ActionListener<ApplicationState>> listeners; - - private static final String[] STORAGE_START_ARGS = { "storage", "--start" }; - private static final String[] STORAGE_STOP_ARGS = { "storage", "--stop" }; - private static final String[] AGENT_ARGS = {"agent", "-d", "Test String"}; - private static final String AGENT_ID = "Test ID"; - - @Before - public void setup() { - mockActionEvent = mock(ActionEvent.class); - when(mockActionEvent.getPayload()).thenReturn(new String("Test String")); - AbstractStateNotifyingCommand mockNotifyingCommand = mock(AbstractStateNotifyingCommand.class); - ActionNotifier<ApplicationState> mockNotifier = mock(ActionNotifier.class); - when(mockNotifyingCommand.getNotifier()).thenReturn(mockNotifier); - when(mockActionEvent.getSource()).thenReturn(mockNotifyingCommand); - - mockLauncher = mock(Launcher.class); - StubBundleContext context = new StubBundleContext(); - context.registerService(CommonPaths.class, mock(CommonPaths.class), null); - context.registerService(Launcher.class, mockLauncher, null); - context.registerService(SSLConfiguration.class, mock(SSLConfiguration.class), null); - final EmbeddedServletContainerConfiguration mockConfig = mock(EmbeddedServletContainerConfiguration.class); - when(mockConfig.isBackingStorageStart()).thenReturn(true); - when(mockConfig.getConnectionUrl()).thenReturn("Test String"); - mockJettyLauncher = mock(JettyContainerLauncher.class); - doAnswer(new Answer<Void>() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - CountDownLatch webStartedLatch = (CountDownLatch) invocation.getArguments()[0]; - webStartedLatch.countDown(); - return null; - } - }).when(mockJettyLauncher).startContainer(isA(CountDownLatch.class)); - when(mockJettyLauncher.isStartupSuccessFul()).thenReturn(true); - doNothing().when(mockJettyLauncher).stopContainer(); - cmd = new WebappLauncherCommand(context) { - @Override - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return mockConfig; - } - - @Override - JettyContainerLauncher getJettyContainerLauncher(EmbeddedServletContainerConfiguration config, SSLConfiguration sslConfig) { - return mockJettyLauncher; - } - }; - - mockCommandContext = mock(CommandContext.class); - Console console = mock(Console.class); - stdErrOut = new ByteArrayOutputStream(); - PrintStream errOut = new PrintStream(stdErrOut); - when(console.getError()).thenReturn(errOut); - when(console.getOutput()).thenReturn(errOut); - when(mockCommandContext.getConsole()).thenReturn(console); - } - - @After - public void tearDown() { - if (handler != null && logger != null) { - logger.removeHandler(handler); - handler = null; - } - } - - @Test - public void testIsStorageRequired() { - WebappLauncherCommand cmd = new WebappLauncherCommand(null /* not used */); - assertFalse(cmd.isStorageRequired()); - } - - @Test - public void testRunCommandWithNoConfigListenAddressSpecified() { - CommonPaths paths = mock(CommonPaths.class); - - File thermostatHomeNotExisting = new File("/thermostat-home/not-existing"); - when(paths.getSystemThermostatHome()).thenReturn(thermostatHomeNotExisting); - // config needs non-null paths for configuration files. It does not - // matter if that file actually exists. Using the fake THERMOSTAT_HOME - // variable will do. - File nonNullConfigFile = new File("doesn't matter"); - - String matchString = "CONFIG_LISTEN_ADDRESS"; - runTestWithPathsAndConfigFiles(paths, nonNullConfigFile, nonNullConfigFile, matchString); - } - - @Test - public void testRunCommandWithWebArchiveNotExisting() throws Exception { - CommonPaths paths = mock(CommonPaths.class); - - File thermostatHomeNotExisting = new File("/thermostat-home/not-existing"); - when(paths.getSystemThermostatHome()).thenReturn(thermostatHomeNotExisting); - File nonNullSysConfig = new File("no matter"); - - Properties userProperties = new Properties(); - userProperties.put(ConfigKeys.SERVLET_CONTAINER_BIND_ADDRESS.name(), "127.0.0.1:8888"); - File userPropsTempFile = File.createTempFile("thermostat", WebappLauncherCommandTest.class.getName()); - userPropsTempFile.deleteOnExit(); - try (FileOutputStream fout = new FileOutputStream(userPropsTempFile)) { - userProperties.store(fout, "test props"); - } catch (IOException e) { - // ignore - } - assertTrue(userPropsTempFile.exists()); - - String matchString = "Exploded web archive"; - runTestWithPathsAndConfigFiles(paths, userPropsTempFile, nonNullSysConfig, matchString); - } - - private void runTestWithPathsAndConfigFiles(final CommonPaths paths, final File userConfig, - final File systemConfig, final String matchString) { - StubBundleContext context = new StubBundleContext(); - context.registerService(CommonPaths.class, paths, null); - Launcher launcher = new TestLauncher(); - context.registerService(Launcher.class, launcher, null); - context.registerService(SSLConfiguration.class, mock(SSLConfiguration.class), null); - final EmbeddedServletContainerConfiguration testConfig = new EmbeddedServletContainerConfiguration(paths, systemConfig, userConfig); - WebappLauncherCommand cmd = new WebappLauncherCommand(context) { - @Override - EmbeddedServletContainerConfiguration getConfiguration(CommonPaths paths) { - return testConfig; - } - }; - CommandContextFactory factory = new CommandContextFactory(context); - CommandContext ctxt = factory.createContext(new Arguments() { - - @Override - public List<String> getNonOptionArguments() { - return Collections.emptyList(); - } - - @Override - public boolean hasArgument(String name) { - return false; - } - - @Override - public String getArgument(String name) { - return null; - } - - @Override - public String getSubcommand() { - throw new NotImplementedException(); - } - }); - setupLogger(matchString); - assertFalse(handler.gotLogMessage); - try { - cmd.run(ctxt); - fail("Should have failed to run command"); - } catch (CommandException e) { - // pass - assertTrue("Did not match. message was: '" + e.getMessage() + "'", handler.gotLogMessage); - } - } - - @Test - public void testRunCommandCommonPathsNotRegistered() { - StubBundleContext context = new StubBundleContext(); - cmd = new WebappLauncherCommand(context); - final boolean[] result = new boolean[1]; - cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[1] = false; - break; - } - } - }); - try { - cmd.run(mockCommandContext); - fail("Command should have thrown an exception"); - } catch (CommandException e) { - Assert.assertTrue(e.getMessage().contains("CommonPaths unavailable.")); - } - - Assert.assertTrue("WebappLauncherCommand expected to fire FAIL event", result[0]); - } - - @Test - public void testRunCommandLauncherNotRegistered() { - StubBundleContext context = new StubBundleContext(); - context.registerService(CommonPaths.class, mock(CommonPaths.class), null); - cmd = new WebappLauncherCommand(context); - final boolean[] result = new boolean[1]; - cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[1] = false; - break; - } - } - }); - try { - cmd.run(mockCommandContext); - fail("Command should have thrown an exception"); - } catch (CommandException e) { - Assert.assertTrue(e.getMessage().contains("Launcher Unavailable")); - } - - Assert.assertTrue("WebappLauncherCommand expected to fire FAIL event", result[0]); - } - - @Test - public void testRunCommandSSLConfigurationNotRegistered() { - StubBundleContext context = new StubBundleContext(); - context.registerService(CommonPaths.class, mock(CommonPaths.class), null); - context.registerService(Launcher.class, mockLauncher, null); - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - - cmd = new WebappLauncherCommand(context); - final boolean[] result = new boolean[1]; - cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[1] = false; - break; - } - } - }); - try { - cmd.run(mockCommandContext); - fail("Command should have thrown an exception"); - } catch (CommandException e) { - Assert.assertTrue(e.getMessage().contains("SSLConfiguration Unavailable")); - } - - Assert.assertTrue("WebappLauncherCommand expected to fire FAIL event", result[0]); - } - - @SuppressWarnings("unchecked") - @Test(timeout=1000) - public void testRunOnce() throws CommandException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - when(mockActionEvent.getPayload()).thenReturn(AGENT_ID); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[2]; - final String[] agentIdFound = new String[1]; - cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = false; - break; - case START: - result[0] = true; - agentIdFound[0] = (String) actionEvent.getPayload(); - break; - case STOP: - result[1] = true; - break; - } - } - }); - - boolean exTriggered = false; - try { - cmd.run(mockCommandContext); - } catch (CommandException e) { - exTriggered = true; - } - Assert.assertFalse(exTriggered); - Assert.assertTrue("Agent expected to fire START event", result[0]); - Assert.assertTrue("Agent expected to fire STOP event", result[1]); - Assert.assertEquals("Payload does not contain AgentId matching the agent started", agentIdFound[0], AGENT_ID); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(2)).getActionId(); - } - - @SuppressWarnings("unchecked") - @Test(timeout=1000) - public void testStorageFailStart() throws CommandException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[1]; - cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[0] = false; - break; - } - } - }); - - try { - cmd.run(mockCommandContext); - fail("Command should have thrown an exception"); - } catch (CommandException e) { - Assert.assertTrue(e.getMessage().contains("Starting mongodb storage failed")); - } - - Assert.assertTrue("Agent expected to fire FAIL event", result[0]); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, never()).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(1)).getActionId(); - } - - @SuppressWarnings("unchecked") - @Test(timeout=1000) - public void testWebContainerFailStart() throws CommandException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[1]; - cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[0] = false; - break; - } - } - }); - - when(mockJettyLauncher.isStartupSuccessFul()).thenReturn(false); - - try { - cmd.run(mockCommandContext); - fail("Command should have thrown an exception"); - } catch (CommandException e) { - Assert.assertTrue(e.getMessage().contains("Failed to start embedded jetty instance")); - } - - Assert.assertTrue("Agent expected to fire FAIL event", result[0]); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, never()).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(1)).getActionId(); - } - - @SuppressWarnings("unchecked") - @Test(timeout=1000) - public void testAgentStartFail() throws CommandException { - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.START); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - doAnswer(new Answer<Void>() { - public Void answer(InvocationOnMock invocation) throws Throwable { - Object[] args = invocation.getArguments(); - listeners = (Collection<ActionListener<ApplicationState>>)args[1]; - - when(mockActionEvent.getActionId()).thenReturn(ApplicationState.FAIL); - - for(ActionListener<ApplicationState> listener : listeners) { - listener.actionPerformed(mockActionEvent); - } - return null; - } - }).when(mockLauncher).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - - final boolean[] result = new boolean[1]; - cmd.getNotifier().addActionListener(new ActionListener<ApplicationState>() { - @SuppressWarnings("incomplete-switch") - @Override - public void actionPerformed(ActionEvent<ApplicationState> actionEvent) { - switch (actionEvent.getActionId()) { - case FAIL: - result[0] = true; - break; - case START: - result[0] = false; - break; - case STOP: - result[0] = false; - break; - } - } - }); - - boolean exTriggered = false; - try { - cmd.run(mockCommandContext); - } catch (CommandException e) { - exTriggered = true; - } - Assert.assertFalse(exTriggered); - Assert.assertTrue(stdErrOut.toString().contains("Thermostat agent failed to start. See logs for details.")); - - verify(mockLauncher, times(1)).run(eq(STORAGE_START_ARGS), isA(Collection.class), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(STORAGE_STOP_ARGS), anyBoolean()); - verify(mockLauncher, times(1)).run(eq(AGENT_ARGS), isA(Collection.class), anyBoolean()); - verify(mockActionEvent, times(2)).getActionId(); - } - - private void setupLogger(String matchString) { - logger = Logger.getLogger("com.redhat.thermostat"); - handler = new TestLogHandler(matchString); - logger.addHandler(handler); - } - - private static class TestLauncher implements Launcher { - - @Override - public void run(String[] args, boolean inShell) { - // no-op - } - - @Override - public void run(String[] args, - Collection<ActionListener<ApplicationState>> listeners, - boolean inShell) { - if (args[0].equals("storage") && args[1].equals("--start")) { - // start storage - AbstractStateNotifyingCommand cmd = mock(AbstractStateNotifyingCommand.class); - for (ActionListener<ApplicationState> l: listeners) { - ActionEvent<ApplicationState> fakeEvent = new ActionEvent<>(cmd, ApplicationState.START); - l.actionPerformed(fakeEvent); - } - } - } - - } - - private static class TestLogHandler extends Handler { - - private final String matchString; - private boolean gotLogMessage = false; - - private TestLogHandler(String matchString) { - this.matchString = matchString; - } - - @Override - public void publish(LogRecord record) { - String logMessage = record.getMessage(); - if (record.getLevel().intValue() >= Level.WARNING.intValue() && - logMessage.contains(matchString)) { - gotLogMessage = true; - }; - } - - @Override - public void flush() { - // no-op - } - - @Override - public void close() throws SecurityException { - // no-op - } - } - -}
--- a/web/pom.xml Tue Mar 21 18:40:40 2017 -0400 +++ b/web/pom.xml Tue Mar 21 18:47:16 2017 -0400 @@ -52,10 +52,7 @@ <modules> <module>common</module> - <module>server</module> <module>client</module> - <module>endpoint-plugin</module> - <module>war</module> </modules> </project>
--- a/web/server/pom.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -<?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</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-web-server</artifactId> - <packaging>bundle</packaging> - - <name>Thermostat Web Server</name> - - <dependencies> - - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - <version>${jetty.version}</version> - <scope>test</scope> - </dependency> - <!-- Required for JAASLoginService used in WebStorageEndpointTest --> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-jaas</artifactId> - <version>${jetty.version}</version> - <scope>test</scope> - </dependency> - <!-- Used in jetty8 compatibility test --> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-plus</artifactId> - <version>${jetty8-tests.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - <version>${jetty.version}</version> - <scope>test</scope> - </dependency> - - - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-common-core</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-storage-mongodb</artifactId> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>javax.servlet</groupId> - <artifactId>servlet-api</artifactId> - <version>${javax.servlet.version}</version> - <scope>provided</scope> - </dependency> - - <dependency> - <groupId>com.google.code.gson</groupId> - <artifactId>gson</artifactId> - </dependency> - - <dependency> - <groupId>commons-fileupload</groupId> - <artifactId>commons-fileupload</artifactId> - <version>${commons-fileupload.version}</version> - </dependency> - <dependency> - <groupId>commons-io</groupId> - <artifactId>commons-io</artifactId> - <version>${commons-io.version}</version> - </dependency> - <dependency> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - <version>${commons-codec.version}</version> - </dependency> - - <dependency> - <groupId>org.osgi</groupId> - <artifactId>org.osgi.core</artifactId> - <scope>provided</scope> - </dependency> - - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-common</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-SymbolicName>com.redhat.thermostat.web.server</Bundle-SymbolicName> - <Bundle-Vendor>Red Hat, Inc.</Bundle-Vendor> - <Export-Package> - com.redhat.thermostat.web.server, - com.redhat.thermostat.web.server.auth, - com.redhat.thermostat.web.server.auth.spi, - com.redhat.thermostat.web.server.containers, - </Export-Package> - <!-- Do not autogenerate uses clauses in Manifests --> - <_nouses>true</_nouses> - </instructions> - </configuration> - </plugin> - </plugins> - </build> -</project> -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/CategoryManager.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* - * 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.web.server; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.SharedStateId; - -class CategoryManager { - - private final Map<CategoryIdentifier, SharedStateId> categoryIds; - private final Map<SharedStateId, Category<?>> categories; - private int categoryIdCounter = 0; - - CategoryManager() { - categories = new HashMap<>(); - categoryIds = new HashMap<>(); - } - - // Testing only - CategoryManager(int initialValue) { - this(); - categoryIdCounter = initialValue; - } - - synchronized <T extends Pojo> SharedStateId putCategory(UUID serverNonce, Category<T> category, CategoryIdentifier catId) { - if (categoryIds.containsKey(Objects.requireNonNull(catId))) { - return categoryIds.get(catId); - } else { - // add new category - Objects.requireNonNull(category); - Objects.requireNonNull(serverNonce); - SharedStateId newId = new SharedStateId(categoryIdCounter, serverNonce); - categoryIdCounter++; - // This really should not happen, but if it does fail early. - if (categoryIdCounter == Integer.MAX_VALUE) { - throw new IllegalStateException("Too many categories!"); - } - categoryIds.put(catId, newId); - categories.put(newId, category); - return newId; - } - } - - synchronized SharedStateId getCategoryId(CategoryIdentifier key) { - return categoryIds.get(Objects.requireNonNull(key)); - } - - @SuppressWarnings("unchecked") - synchronized <T extends Pojo> Category<T> getCategory(SharedStateId id) { - return (Category<T>)categories.get(Objects.requireNonNull(id)); - } - - static class CategoryIdentifier { - - private final String categoryName; - private final String dataClassName; - - CategoryIdentifier(String categoryName, String dataClassName) { - this.categoryName = categoryName; - this.dataClassName = dataClassName; - } - - @Override - public boolean equals(Object other) { - if (other == null || CategoryIdentifier.class != other.getClass()) { - return false; - } - CategoryIdentifier o = (CategoryIdentifier)other; - return Objects.equals(categoryName, o.categoryName) && - Objects.equals(dataClassName, o.dataClassName); - } - - @Override - public int hashCode() { - return Objects.hash(categoryName, dataClassName); - } - } -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/ConfigurationFinder.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * 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.web.server; - -import java.io.File; - -import com.redhat.thermostat.shared.config.CommonPaths; - -public class ConfigurationFinder { - - private final CommonPaths paths; - - public ConfigurationFinder(CommonPaths paths) { - this.paths = paths; - } - - /** Finds the best configuration file, accessible to the process */ - public File getConfiguration(String name) { - File systemFile = getConfigurationFile(paths.getSystemConfigurationDirectory(), name); - if (isUsable(systemFile)) { - return systemFile; - } - File userFile = getConfigurationFile(paths.getUserConfigurationDirectory(), name); - if (isUsable(userFile)) { - return userFile; - } - return null; - } - - /** package-private for testing only */ - File getConfigurationFile(File directory, String name) { - return new File(directory, name); - } - - private boolean isUsable(File file) { - return file.isFile() && file.canRead(); - } -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/CursorManager.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,233 +0,0 @@ -/* - * 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.web.server; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Timer; -import java.util.TimerTask; - -import com.redhat.thermostat.storage.core.Cursor; - -/** - * Manages (query) cursors for a single user. - * - */ -final class CursorManager { - - public static final int CURSOR_NOT_STORED = -1; - private final Map<Integer, CursorHolder> cursors; - private final TimerRegistry registry; - private int cursorIdCounter; - - // test-only - CursorManager(TimerRegistry registry, Map<Integer, CursorHolder> cursors) { - this.registry = registry; - this.cursors = cursors; - } - - CursorManager(TimerRegistry registry) { - this.cursors = new HashMap<>(); - this.registry = registry; - } - - // test-only - CursorManager(int cursorIdCounter) { - this(null); - this.cursorIdCounter = cursorIdCounter; - } - - /** - * Add a cursor to the map we know of if it has more results. - * - * @param cursor The potential candidate to add to the state we keep track - * of. - * @return The cursor ID or {@link CursorManager#CURSOR_NOT_STORED} if the - * passed in cursor has no more elements. - */ - synchronized int put(final Cursor<?> cursor) { - int cursorId = CURSOR_NOT_STORED; - if (cursor.hasNext()) { - // Be sure we don't overflow. For a long running web storage we - // could potentially run out of id's for a single user. However, - // the time between 0 and Integer.MAX_VALUE should be sufficiently - // large so that any given cursor expires before the id will get - // reused. - if (cursorIdCounter == Integer.MAX_VALUE) { - cursorIdCounter = 0; // start again from 0 - } - cursorId = cursorIdCounter; - cursors.put(cursorId, new CursorHolder(cursor, System.currentTimeMillis())); - cursorIdCounter++; - } - return cursorId; - } - - synchronized Cursor<?> get(int cursorId) { - CursorHolder holder = cursors.get(cursorId); - if (holder == null) { - return null; - } - return holder.getCursor(); - } - - synchronized void updateCursorTimeStamp(int cursorId) { - CursorHolder holder = cursors.get(cursorId); - if (holder == null) { - return; - } - holder.updateTimestamp(); - } - - synchronized void removeCursor(int cursorId) { - cursors.remove(cursorId); - } - - synchronized void expireCursors() { - final long currentTime = System.currentTimeMillis(); - List<Integer> expiredCursors = new ArrayList<>(); - for (Entry<Integer, CursorHolder> entry: cursors.entrySet()) { - CursorHolder holder = entry.getValue(); - if (holder.isCursorExpired(currentTime)) { - expiredCursors.add(entry.getKey()); - } - } - for (Integer expiredKey: expiredCursors) { - cursors.remove(expiredKey); - } - } - - void startSweeperTimer() { - CursorTimer sweeperTimer = new CursorTimer(new CursorSweeper(this)); - sweeperTimer.scheduleTask(); - registry.registerTimer(sweeperTimer); - } - - /** - * - * A container in order save and track cursors. This holder enables - * expiring cursors, as well as extending the liveness of a cursor. - * - */ - static class CursorHolder { - - private static final int MINUTES = 1000 * 60; - // The time out in minutes - static final int TIMEOUT = 3 * MINUTES; - - private final Cursor<?> cursor; - private long lastUpdated; - - CursorHolder(Cursor<?> cursor, long lastUpdated) { - this.cursor = cursor; - this.lastUpdated = lastUpdated; - } - - void updateTimestamp() { - this.lastUpdated = System.currentTimeMillis(); - } - - boolean isCursorExpired(long currentTime) { - return checkIsCursorExpired(currentTime, TIMEOUT); - } - - Cursor<?> getCursor() { - return cursor; - } - - // here in order to facilitate testing - boolean checkIsCursorExpired(long currentTime, final int timeoutInMillis) { - return lastUpdated < (currentTime - timeoutInMillis); - } - - // test-only - long getLastUpdated() { - return lastUpdated; - } - } - - /** - * {@link TimerTask} which times out cursors. - */ - static class CursorSweeper extends TimerTask { - - private final CursorManager manager; - - CursorSweeper(CursorManager manager) { - this.manager = manager; - } - - @Override - public void run() { - manager.expireCursors(); - } - - } - - static class CursorTimer implements StoppableTimer { - - private static final String NAME = NAME_PREFIX + "cursor-manager"; - private final Timer timer; - private final TimerTask task; - boolean taskScheduled = false; - - CursorTimer(TimerTask task) { - this(task, new Timer(NAME)); - } - - // for testing - CursorTimer(TimerTask task, Timer timer) { - this.timer = timer; - this.task = task; - } - - void scheduleTask() { - timer.scheduleAtFixedRate(task, 0, CursorHolder.TIMEOUT); - taskScheduled = true; - } - - @Override - public void stop() { - timer.cancel(); - } - - } - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownCategoryRegistry.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * 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.web.server; - -import java.util.Collections; -import java.util.HashSet; -import java.util.ServiceLoader; -import java.util.Set; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.auth.CategoryRegistration; - -/** - * Registers trusted category names. - * - * @see CategoryRegistration - * @see Category - */ -final class KnownCategoryRegistry { - - private static final ServiceLoader<CategoryRegistration> TRUSTED_CATEGORIES = ServiceLoader - .load(CategoryRegistration.class); - private final Set<String> trustedCategories; - - KnownCategoryRegistry() { - this(TRUSTED_CATEGORIES); - } - - KnownCategoryRegistry(Iterable<CategoryRegistration> registrations) { - trustedCategories = new HashSet<>(); - for (CategoryRegistration reg: registrations) { - Set<String> currentRegs = reg.getCategoryNames(); - // Some Set implementations throw NPEs when contains() is called on - // a null value. Be sure we catch NPE since those impls can't contain - // null values anyway. - try { - if (currentRegs.contains(null)) { - String msg = "null name not allowed!"; - throw new IllegalStateException(msg); - } - // Pass: Not containing null values. - } catch (NullPointerException npe) { - // Pass: Set impl does not support contains checks on null - // values. - } - trustedCategories.addAll(currentRegs); - } - } - - Set<String> getRegisteredCategoryNames() { - // return a read-only view of registered category names. - return Collections.unmodifiableSet(trustedCategories); - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownCategoryRegistryFactory.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * 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.web.server; - -/* - * Testing aid in order to be able to inject a KnownCategoryRegistry. - * - */ -class KnownCategoryRegistryFactory { - - private static KnownCategoryRegistry knownRegistry; - - static KnownCategoryRegistry getInstance() { - if (knownRegistry == null) { - return new KnownCategoryRegistry(); - } else { - return knownRegistry; - } - } - - static void setInstance(KnownCategoryRegistry reg) { - knownRegistry = reg; - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * 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.web.server; - -import java.util.Collections; -import java.util.HashSet; -import java.util.ServiceLoader; -import java.util.Set; - -import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; - -/** - * Registers trusted statement descriptors. - * - */ -final class KnownDescriptorRegistry { - - private static final ServiceLoader<StatementDescriptorRegistration> TRUSTED_DESCS = ServiceLoader - .load(StatementDescriptorRegistration.class); - private final Set<String> trustedSet; - - KnownDescriptorRegistry() { - this(TRUSTED_DESCS); - } - - KnownDescriptorRegistry(Iterable<StatementDescriptorRegistration> trustedDescs) { - trustedSet = new HashSet<>(); - for (StatementDescriptorRegistration reg: trustedDescs) { - Set<String> newCandidates = reg.getStatementDescriptors(); - // Some Set implementations throw NPEs when contains() is called on - // a null value. Be sure we catch NPE since those impls can't contain - // null values anyway. - try { - if (newCandidates.contains(null)) { - throw new IllegalStateException("null statement descriptor not acceptable!"); - } - // Pass: Not containing null values. - } catch (NullPointerException npe) { - // Pass: Set impl does not support contains checks on null - // values. - } - trustedSet.addAll(newCandidates); - } - } - - final Set<String> getRegisteredDescriptors() { - // return a read-only set of all descriptors - return Collections.unmodifiableSet(trustedSet); - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryFactory.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * 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.web.server; - -final class KnownDescriptorRegistryFactory { - - private static KnownDescriptorRegistry reg; - - static KnownDescriptorRegistry getInstance() { - if (reg == null) { - return new KnownDescriptorRegistry(); - } else { - return reg; - } - } - - static void setKnownDescriptorRegistry(KnownDescriptorRegistry reg) { - KnownDescriptorRegistryFactory.reg = reg; - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementHolder.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * 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.web.server; - -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.SharedStateId; - -class PreparedStatementHolder<T extends Pojo> { - - private final SharedStateId stmtId; - private final PreparedStatement<T> stmt; - private final Class<T> dataClass; - private final StatementDescriptor<T> desc; - - PreparedStatementHolder(SharedStateId stmtId, PreparedStatement<T> stmt, Class<T> dataClass, StatementDescriptor<T> desc) { - this.stmtId = stmtId; - this.stmt = stmt; - this.dataClass = dataClass; - this.desc = desc; - } - - SharedStateId getId() { - return stmtId; - } - - PreparedStatement<T> getStmt() { - return stmt; - } - - Class<T> getDataClass() { - return dataClass; - } - - StatementDescriptor<T> getStatementDescriptor() { - return desc; - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementManager.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * 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.web.server; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; - -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.SharedStateId; - -/** - * Manager for {@link PreparedStatement}s which get prepared/executed via - * {@link WebStorage}. - * - */ -class PreparedStatementManager { - - // We have one map per server token. - private final Map<SharedStateId, PreparedStatementHolder<?>> preparedStatementIds; - private final Map<StatementDescriptor<?>, PreparedStatementHolder<?>> preparedStmts; - private int currentPreparedStmtId = 0; - - PreparedStatementManager() { - preparedStatementIds = new HashMap<>(); - preparedStmts = new HashMap<>(); - } - - // Test only constructor - PreparedStatementManager(int initialValue) { - this(); - currentPreparedStmtId = initialValue; - } - - @SuppressWarnings("unchecked") // we are the only ones adding them - synchronized <T extends Pojo> PreparedStatementHolder<T> getStatementHolder(SharedStateId id) { - return (PreparedStatementHolder<T>)preparedStatementIds.get(Objects.requireNonNull(id)); - } - - @SuppressWarnings("unchecked") // we are the only ones adding them - synchronized <T extends Pojo> PreparedStatementHolder<T> getStatementHolder(StatementDescriptor<T> desc) { - return (PreparedStatementHolder<T>)preparedStmts.get(Objects.requireNonNull(desc)); - } - - /** - * Adds a new {@link PreparedStatementHolder} into this - * {@link PreparedStatementManager}. Adding an equal {@code targetDesc} - * statement twice will yield the same returned id. - * - * @param serverToken - * A server token used for creating a new {@link SharedStateId} - * if the target statement is not already tracked. - * @param targetStmt - * The target statement to keep track of. - * @param dataClass - * The data class of the target statement. - * @param targetDesc - * The {@link StatementDescriptor} which was used for creating - * the target statement {@code targetStmt} - * @return A unique ID identifying this statement. It's suitable to be - * shared between server and client. - */ - synchronized <T extends Pojo> SharedStateId createAndPutHolder( - UUID serverToken, - PreparedStatement<T> targetStmt, - Class<T> dataClass, - StatementDescriptor<T> targetDesc) { - // check if we have this descriptor already added - @SuppressWarnings("unchecked") - PreparedStatementHolder<T> holder = (PreparedStatementHolder<T>)preparedStmts.get(Objects.requireNonNull(targetDesc)); - if (holder != null) { - // nothing to do - assert( preparedStatementIds.get(holder.getId()) != null ); - return holder.getId(); - } - // OK, must be a new statement we don't yet track - SharedStateId id = new SharedStateId(currentPreparedStmtId, Objects.requireNonNull(serverToken)); - currentPreparedStmtId++; - // There is nothing we can do other than using a long rather than an int - // for the ID. That being said, having more than 2 billion *different* queries - // seems more than unlikely. It may very well be a bug. Either way it - // seems like a good idea to fail hard in order to be in the know about - // this situation. - if (currentPreparedStmtId == Integer.MAX_VALUE) { - throw new IllegalStateException("Too many different statements!"); - } - holder = new PreparedStatementHolder<>(id, - Objects.requireNonNull(targetStmt), - Objects.requireNonNull(dataClass), - targetDesc); - preparedStmts.put(targetDesc, holder); - preparedStatementIds.put(id, holder); - return id; - } -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/PropertySettingServletContextListener.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * 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.web.server; - -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import com.redhat.thermostat.common.Constants; - -/** - * Sets the THERMOSTAT_HOME system property as - * configured via said context-param in web.xml. - * <p> - * Does not set THERMOSTAT_HOME if the system property is already defined. - */ -public class PropertySettingServletContextListener implements - ServletContextListener { - - private static final String PROPERTY_NAME = "THERMOSTAT_HOME"; - - @Override - public void contextInitialized(ServletContextEvent sce) { - String thermostatHome = sce.getServletContext().getInitParameter(PROPERTY_NAME); - if (System.getProperty(PROPERTY_NAME) == null) { - System.setProperty(PROPERTY_NAME, thermostatHome); - } - System.setProperty(Constants.IS_PROXIED_STORAGE, Boolean.TRUE.toString()); - } - - @Override - public void contextDestroyed(ServletContextEvent sce) { - System.clearProperty(PROPERTY_NAME); - System.clearProperty(Constants.IS_PROXIED_STORAGE); - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StoppableTimer.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * 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.web.server; - -/** - * Interface for stoppable timers the {@link WebStorageEndPoint} uses. That is - * all timers it uses <strong>must</strong> implement this interface and be - * sure to register the timer via {@link TimerRegistry}. - * - */ -interface StoppableTimer { - - String NAME_PREFIX = "thermostat-timer-"; - - /** - * Stops this timer and the associated thread. - */ - void stop(); - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactory.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - * 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.web.server; - -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; - -interface StorageFactory { - - Storage getStorage(String storageClass, String storageEndpoint, CommonPaths paths, StorageCredentials creds); - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactoryImpl.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * 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.web.server; - -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.SSLConfiguration; -import com.redhat.thermostat.shared.config.internal.SSLConfigurationImpl; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.storage.core.StorageProvider; -import com.redhat.thermostat.storage.mongodb.MongoStorageProvider; - -class StorageFactoryImpl { - - private static Storage storage; - - // Web server is not OSGi, this factory method is workaround. - static Storage getStorage(String storageClass, final String storageEndpoint, final CommonPaths paths, - final StorageCredentials creds) { - if (storage != null) { - return storage; - } - SSLConfiguration sslConf = new SSLConfigurationImpl(paths); - try { - StorageProvider provider = (StorageProvider) Class.forName(storageClass).newInstance(); - provider.setConfig(storageEndpoint, creds, sslConf); - storage = provider.createStorage(); - storage.getConnection().connect(); - return storage; - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - // This fallback should infact not be used. But it gives us an automatic - // Import-Package in the OSGi descriptor, which actually *prevents* this same - // exception from happening (a recursive self-defeating catch-block) :-) - System.err.println("could not instantiate provider: " + storageClass + ", falling back to MongoStorage"); - e.printStackTrace(); - StorageProvider provider = new MongoStorageProvider(); - provider.setConfig(storageEndpoint, creds, sslConf); - storage = provider.createStorage(); - return storage; - } - } - - // Testing hook used in WebStorageEndpointTest - static void setStorage(Storage storage) { - StorageFactoryImpl.storage = storage; - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/StorageFactoryProvider.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * 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.web.server; - -interface StorageFactoryProvider { - - StorageFactory createStorageFactory(); - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/TimerRegistry.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * 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.web.server; - -import java.util.ArrayList; -import java.util.List; - -/** - * Registers {@link StoppableTimer}s and shuts them down when no longer - * needed. - * - */ -class TimerRegistry { - - private final List<StoppableTimer> registeredTimers; - - TimerRegistry() { - this(new ArrayList<StoppableTimer>()); - } - - // for testing - TimerRegistry(List<StoppableTimer> timers) { - this.registeredTimers = timers; - } - - void registerTimer(StoppableTimer timer) { - registeredTimers.add(timer); - } - - void shutDown() { - for (StoppableTimer timer: registeredTimers) { - timer.stop(); - } - } -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/TokenManager.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,179 +0,0 @@ -/* - * 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.web.server; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Timer; -import java.util.TimerTask; - -class TokenManager { - - private static final int TOKEN_LENGTH = 256; - - private final SecureRandom random = new SecureRandom(); - - private final Map<String,byte[]> tokens = Collections.synchronizedMap(new HashMap<String,byte[]>()); - - private final TokenManagerTimer timer; - - private int timeout = 30 * 1000; - - TokenManager(TimerRegistry registry) { - this(registry, new TokenManagerTimer()); - } - - // for testing - TokenManager(TimerRegistry registry, TokenManagerTimer timer) { - this.timer = timer; - registry.registerTimer(timer); - } - - void setTimeout(int timeout) { - this.timeout = timeout; - } - - byte[] generateToken(byte[] clientToken, String actionName) { - byte[] token = new byte[TOKEN_LENGTH]; - random.nextBytes(token); - final String clientKey = getKey(clientToken, - Objects.requireNonNull(actionName)); - tokens.put(clientKey, token); - scheduleRemoval(clientKey); - return token; - } - - private void scheduleRemoval(final String clientKey) { - TimerTask task = new TimerTask() { - - @Override - public void run() { - tokens.remove(clientKey); - } - }; - timer.schedule(task, timeout); - } - - private String getKey(byte[] clientToken, String actionName) { - try { - return getSha256HexString(clientToken, actionName.getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - // If this happens, this is clearly a bug. - throw new RuntimeException(e); - } - } - - boolean verifyToken(byte[] clientToken, byte[] candidateToken, String actionName) { - final String clientKey = getKey(clientToken, Objects.requireNonNull(actionName)); - if (tokens.containsKey(clientKey)) { - byte[] storedToken = tokens.get(clientKey); - boolean verified = Arrays.equals(candidateToken, storedToken); - if (verified) { - tokens.remove(clientKey); - } - return verified; - } - return false; - } - - private String getSha256HexString(byte[] clientToken, byte[] actionName) { - MessageDigest digest; - try { - digest = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - digest.update(clientToken); - digest.update(actionName); - byte[] result = digest.digest(); - return convertBytesToHexString(result); - } - - // package private for testing - String convertBytesToHexString(byte[] shaBytes) { - StringBuilder hexString = new StringBuilder(); - - for (byte shaByte : shaBytes) { - String hex = Integer.toHexString(0xff & shaByte); - if (hex.length() == 1) { - hexString.append('0'); - } - hexString.append(hex); - } - - return hexString.toString(); - } - - // Used for testing only - byte[] getStoredToken(String sha256) { - return tokens.get(sha256); - } - - static class TokenManagerTimer implements StoppableTimer { - - private static final String NAME = NAME_PREFIX + "token-manager"; - private final Timer timer; - - // for testing - TokenManagerTimer(Timer timer) { - this.timer = timer; - } - - TokenManagerTimer() { - this(new Timer(NAME)); - } - - @Override - public void stop() { - timer.cancel(); - } - - void schedule(TimerTask task, int timeout) { - timer.schedule(task, timeout); - } - - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1110 +0,0 @@ -/* - * 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.web.server; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.lang.reflect.Array; -import java.net.URLDecoder; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileItemFactory; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.shared.config.internal.CommonPathsImpl; -import com.redhat.thermostat.storage.config.FileStorageCredentials; -import com.redhat.thermostat.storage.core.BasicBatchCursor; -import com.redhat.thermostat.storage.core.Categories; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.CategoryAdapter; -import com.redhat.thermostat.storage.core.CloseOnSave; -import com.redhat.thermostat.storage.core.Connection; -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.DataModifyingStatement; -import com.redhat.thermostat.storage.core.DescriptorParsingException; -import com.redhat.thermostat.storage.core.IllegalPatchException; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.ParsedStatement; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.storage.core.PreparedParameters; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.Query; -import com.redhat.thermostat.storage.core.Statement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.Storage; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.storage.model.AggregateResult; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.BinaryLogicalExpression; -import com.redhat.thermostat.storage.query.BinaryLogicalOperator; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; -import com.redhat.thermostat.web.common.WebQueryResponse; -import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParametersTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.SharedStateIdTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementResponseTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebQueryResponseTypeAdapterFactory; -import com.redhat.thermostat.web.server.CategoryManager.CategoryIdentifier; -import com.redhat.thermostat.web.server.auth.FilterResult; -import com.redhat.thermostat.web.server.auth.PrincipalCallback; -import com.redhat.thermostat.web.server.auth.PrincipalCallbackFactory; -import com.redhat.thermostat.web.server.auth.Roles; -import com.redhat.thermostat.web.server.auth.UserPrincipal; -import com.redhat.thermostat.web.server.auth.WebStoragePathHandler; -import com.redhat.thermostat.web.server.containers.ServletContainerInfo; -import com.redhat.thermostat.web.server.containers.ServletContainerInfoFactory; - -@SuppressWarnings("serial") -public class WebStorageEndPoint extends HttpServlet { - - // This is an ugly hack in order to allow for testing of batched querying. - static int DEFAULT_QUERY_BATCH_SIZE = Cursor.DEFAULT_BATCH_SIZE; - - static final String CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX = "thermostat-cmdc-grant-"; - static final String FILES_READ_GRANT_ROLE_PREFIX = "thermostat-files-grant-read-filename-"; - static final String FILES_WRITE_GRANT_ROLE_PREFIX = "thermostat-files-grant-write-filename-"; - private static final String TOKEN_MANAGER_TIMEOUT_PARAM = "token-manager-timeout"; - private static final String TOKEN_MANAGER_KEY = "token-manager"; - private static final String CURSOR_MANAGER_KEY = "cursor-manager"; - static final String CATEGORY_MANAGER_KEY = "category-manager"; - static final String PREPARED_STMT_MANAGER_KEY = "prepared-stmt-manager"; - static final String SERVER_TOKEN_KEY = "server-token"; - - // our strings can contain non-ASCII characters. Use UTF-8 - // see also PR 1344 - private static final String RESPONSE_JSON_CONTENT_TYPE = "application/json; charset=UTF-8"; - private static final String CREDENTIALS_FILE = "web.auth"; - - private static final Logger logger = LoggingUtils.getLogger(WebStorageEndPoint.class); - - private final Object storageLock = new Object(); - private StorageFactoryProvider storageFactoryProvider; - private Storage storage; - private Gson gson; - private CommonPaths paths; - private ConfigurationFinder finder; - - public static final String STORAGE_ENDPOINT = "storage.endpoint"; - public static final String STORAGE_CLASS = "storage.class"; - - // read-only set of all known statement descriptors we trust and allow - private Set<String> knownStatementDescriptors; - // read-only set of all known categories which we allow to get registered. - private Set<String> knownCategoryNames; - // the principal callback used for retrieving the JAAS user principal - private PrincipalCallback principalCallback; - // a registry for timers which starts/stops registered timers on init() - // destroy() - private TimerRegistry timerRegistry; - - public WebStorageEndPoint() { - // this ugliness allows for both unit tests to inject mocks and "integration" tests to inject fake values - this.storageFactoryProvider = new StorageFactoryProvider() { - @Override - public StorageFactory createStorageFactory() { - return new StorageFactory() { - @Override - public Storage getStorage(String storageClass, String storageEndpoint, CommonPaths paths, StorageCredentials creds) { - return StorageFactoryImpl.getStorage(storageClass, storageEndpoint, paths, creds); - } - }; - } - }; - } - - // Package private for testing - WebStorageEndPoint(TimerRegistry timerRegistry, CommonPaths paths, ConfigurationFinder finder, - StorageFactoryProvider storageFactoryProvider) { - this.timerRegistry = timerRegistry; - this.paths = paths; - this.finder = finder; - this.storageFactoryProvider = storageFactoryProvider; - } - - @Override - public void init(ServletConfig config) throws ServletException { - super.init(config); - logger.log(Level.INFO, "Initializing web service"); - - // check if thermostat home is set and readable - // Side effect: sets this.paths - sanityCheckNecessaryFiles(); - - gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - - // Set the set of statement descriptors which we trust - KnownDescriptorRegistry descRegistry = KnownDescriptorRegistryFactory.getInstance(); - knownStatementDescriptors = descRegistry.getRegisteredDescriptors(); - // Set the set of category names which we allow to get registered - KnownCategoryRegistry categoryRegistry = KnownCategoryRegistryFactory.getInstance(); - knownCategoryNames = categoryRegistry.getRegisteredCategoryNames(); - - ServletContext servletContext = getServletContext(); - - String serverInfo = servletContext.getServerInfo(); - ServletContainerInfoFactory factory = new ServletContainerInfoFactory(serverInfo); - ServletContainerInfo info = factory.getInfo(); - PrincipalCallbackFactory cbFactory = new PrincipalCallbackFactory(info); - principalCallback = Objects.requireNonNull(cbFactory.getCallback()); - - timerRegistry = new TimerRegistry(); - TokenManager tokenManager = new TokenManager(timerRegistry); - String timeoutParam = getInitParameter(TOKEN_MANAGER_TIMEOUT_PARAM); - if (timeoutParam != null) { - tokenManager.setTimeout(Integer.parseInt(timeoutParam)); - } - // The following get set as servlet context attributes in order - // to support clustered deployments. - synchronized(servletContext) { - servletContext.setAttribute(TOKEN_MANAGER_KEY, tokenManager); - servletContext.setAttribute(CATEGORY_MANAGER_KEY, new CategoryManager()); - servletContext.setAttribute(PREPARED_STMT_MANAGER_KEY, new PreparedStatementManager()); - servletContext.setAttribute(SERVER_TOKEN_KEY, UUID.randomUUID()); - } - - synchronized (storageLock) { - if (storage == null) { - StorageCredentials creds; - try { - creds = getStorageCredentials(); - } catch (IOException e) { - String errorMsg = "Unable to retrieve backing storage credentials from file " + CREDENTIALS_FILE; - throw new InvalidConfigurationException(errorMsg); - } - // if creds are null there is no point to continue, fail prominently. - if (creds == null) { - String errorMsg = "No backing storage credentials file (" + CREDENTIALS_FILE + ") available"; - throw new InvalidConfigurationException(errorMsg); - } - String storageClass = getServletConfig().getInitParameter(STORAGE_CLASS); - String storageEndpoint = getServletConfig().getInitParameter(STORAGE_ENDPOINT); - storage = storageFactoryProvider.createStorageFactory().getStorage(storageClass, storageEndpoint, paths, creds); - } - } - } - - @Override - public void destroy() { - timerRegistry.shutDown(); - synchronized (storageLock) { - logger.log(Level.INFO, "Going to shut down web service"); - if (storage != null) { - // See IcedTea BZ#1315. Shut down storage in order - // to avoid further memory leaks. - Connection connection = storage.getConnection(); - try { - // Tests have null connections - if (connection != null) { - connection.disconnect(); - } - } finally { - storage.shutdown(); - } - } - logger.log(Level.INFO, "Web service shut down finished"); - } - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { - String uri = req.getRequestURI(); - int lastPartIdx = uri.lastIndexOf("/"); - String cmd = uri.substring(lastPartIdx + 1); - if (cmd.equals("prepare-statement")) { - prepareStatement(req, resp); - } else if (cmd.equals("query-execute")) { - queryExecute(req, resp); - } else if (cmd.equals("write-execute")) { - writeExecute(req, resp); - } else if (cmd.equals("register-category")) { - registerCategory(req, resp); - } else if (cmd.equals("save-file")) { - saveFile(req, resp); - } else if (cmd.equals("load-file")) { - loadFile(req, resp); - } else if (cmd.equals("purge")) { - purge(req, resp); - } else if (cmd.equals("ping")) { - ping(req, resp); - } else if (cmd.equals("generate-token")) { - generateToken(req, resp); - } else if (cmd.equals("verify-token")) { - verifyToken(req, resp); - } else if (cmd.equals("get-more")) { - getMore(req, resp); - } - } - - // package private for testing - StorageCredentials getStorageCredentials() throws IOException { - File credentialsFile = finder.getConfiguration(CREDENTIALS_FILE); - if (credentialsFile != null) { - logger.log(Level.CONFIG, "Loading authentication data from " + credentialsFile); - return createStorageCredentials(credentialsFile); - } else { - logger.warning("Unable to read database credentials."); - return null; - } - } - - // package private for testing - StorageCredentials createStorageCredentials(File underlyingFile) { - return new FileStorageCredentials(underlyingFile); - } - - // Side effect: sets this.paths - private void sanityCheckNecessaryFiles() { - if (paths == null) { // for unit tests, we inject this instance - try { - // Throws config exception if basic sanity checks for - // THERMOSTAT_HOME don't pass. - paths = new CommonPathsImpl(); - } catch (InvalidConfigurationException e) { - logger.log(Level.SEVERE, e.getMessage()); - throw new RuntimeException(e); - } - } - - if (finder == null) { // for unit tests, we inject this instance - finder = new ConfigurationFinder(paths); - } - - File thermostatHomeFile = getThermostatHome(); - - String notReadableMsg = " is not readable or does not exist!"; - // we need to be able to read ssl config for backing storage - // paths got set in isThermostatHomeSet() - File sslProperties = new File(paths.getSystemConfigurationDirectory(), "ssl.properties"); - if (!sslProperties.canRead()) { - String msg = "File " + sslProperties.getAbsolutePath() + - notReadableMsg; - logger.log(Level.SEVERE, msg); - throw new RuntimeException(msg); - } - // Thermostat home looks OK and seems usable - logger.log(Level.FINEST, "THERMOSTAT_HOME == " - + thermostatHomeFile.getAbsolutePath()); - } - - private File getThermostatHome() { - try { - return paths.getSystemThermostatHome(); - } catch (InvalidConfigurationException e) { - // we should have just checked if this throws any exception - logger.log(Level.SEVERE, "Illegal configuration!", e); - return null; - } - } - - @SuppressWarnings("unchecked") - @WebStoragePathHandler( path = "prepare-statement" ) - private <T extends Pojo> void prepareStatement(HttpServletRequest req, - HttpServletResponse resp) throws IOException { - if (! isAuthorized(req, resp, Roles.PREPARE_STATEMENT)) { - return; - } - String queryDescrParam = req.getParameter("query-descriptor"); - String categoryIdParam = req.getParameter("category-id"); - SharedStateId catId = gson.fromJson(URLDecoder.decode(categoryIdParam, "UTF-8"), SharedStateId.class); - // Check if server token of the given category id is still valid. If it is - // different it means that the server has been reloaded/redeployed - // while the client remained up. Of course, it does not rule out a - // malicious client which sends a bad token on purpose. In either case - // it should be OK to solely send back a distinct error code indicating - // this situation. - final UUID serverToken = getServerToken(); - if (!serverToken.equals(catId.getServerToken())) { - logger.log(Level.INFO, "Server token: '" + serverToken + - "' and client token '" + catId.getServerToken() + - "' out of sync."); - WebPreparedStatementResponse response = new WebPreparedStatementResponse(); - SharedStateId id = new SharedStateId(WebPreparedStatementResponse.CATEGORY_OUT_OF_SYNC, serverToken); - response.setStatementId(id); - writeResponse(resp, response, WebPreparedStatementResponse.class); - return; - } else { - CategoryManager catManager = getCategoryManager(); - Category<T> cat = (Category<T>)catManager.getCategory(catId); - WebPreparedStatementResponse response = new WebPreparedStatementResponse(); - if (cat == null) { - // bad category? we refuse to accept this - logger.log(Level.WARNING, "Attepted to prepare a statement with an illegal category id: '" + - catId + "'. server token was: '" + serverToken + "'"); - SharedStateId id = new SharedStateId(WebPreparedStatementResponse.ILLEGAL_STATEMENT, serverToken); - response.setStatementId(id); - writeResponse(resp, response, WebPreparedStatementResponse.class); - return; - } - StatementDescriptor<T> desc = new StatementDescriptor<>(cat, queryDescrParam); - // Check if descriptor is trusted (i.e. known) - if (!knownStatementDescriptors.contains(desc.getDescriptor())) { - String msg = "Attempted to prepare a statement descriptor which we " + - "don't trust! Descriptor was: ->" + desc.getDescriptor() + "<-"; - logger.log(Level.WARNING, msg); - SharedStateId id = new SharedStateId(WebPreparedStatementResponse.ILLEGAL_STATEMENT, serverToken); - response.setStatementId(id); - writeResponse(resp, response, WebPreparedStatementResponse.class); - return; - } - - PreparedStatementManager prepStmtManager = getPreparedStmtManager(); - // see if we've prepared this query already - PreparedStatementHolder<T> holder = prepStmtManager.getStatementHolder(desc); - if (holder != null) { - ParsedStatement<T> parsed = holder.getStmt().getParsedStatement(); - int freeVars = parsed.getNumParams(); - response.setNumFreeVariables(freeVars); - SharedStateId id = new SharedStateId(holder.getId().getId(), serverToken); - response.setStatementId(id); - writeResponse(resp, response, WebPreparedStatementResponse.class); - return; - } else { - // Prepare the target statement and track it via - // PreparedStatementManager - PreparedStatement<T> targetPreparedStatement; - try { - synchronized (storageLock) { - targetPreparedStatement = storage.prepareStatement(desc); - } - } catch (DescriptorParsingException e) { - logger.log(Level.WARNING, "Descriptor parse error!", e); - SharedStateId id = new SharedStateId(WebPreparedStatementResponse.DESCRIPTOR_PARSE_FAILED, serverToken); - response.setStatementId(id); - writeResponse(resp, response, - WebPreparedStatementResponse.class); - return; - } - SharedStateId stmtId = prepStmtManager.createAndPutHolder( - serverToken, targetPreparedStatement, cat.getDataClass(), - desc); - ParsedStatement<?> parsed = targetPreparedStatement - .getParsedStatement(); - response.setNumFreeVariables(parsed.getNumParams()); - response.setStatementId(stmtId); - logger.log(Level.INFO, "Server: prepare-statement: stmt: " + desc + " got assigned id: " + stmtId.getId()); - writeResponse(resp, response, WebPreparedStatementResponse.class); - } - } - } - - @WebStoragePathHandler( path = "ping" ) - private void ping(HttpServletRequest req, HttpServletResponse resp) { - if (! isAuthorized(req, resp, Roles.LOGIN)) { - return; - } - - resp.setStatus(HttpServletResponse.SC_OK); - } - - @WebStoragePathHandler( path = "purge" ) - private void purge(HttpServletRequest req, HttpServletResponse resp) { - if (! isAuthorized(req, resp, Roles.PURGE)) { - return; - } - - String agentId = req.getParameter("agentId"); - synchronized (storageLock) { - storage.purge(agentId); - } - resp.setStatus(HttpServletResponse.SC_OK); - } - - @WebStoragePathHandler( path = "load-file" ) - private void loadFile(HttpServletRequest req, HttpServletResponse resp) throws IOException { - if (! isAuthorized(req, resp, Roles.LOAD_FILE)) { - return; - } - - String name = req.getParameter("file"); - if (! isAllowedToLoadFile(req, resp, name)) { - return; - } - synchronized (storageLock) { - try (InputStream data = storage.loadFile(name)) { - if (data == null) { - resp.setStatus(HttpServletResponse.SC_NO_CONTENT); - return; - } - OutputStream out = resp.getOutputStream(); - byte[] buffer = new byte[512]; - int read = 0; - while (read >= 0) { - read = data.read(buffer); - if (read > 0) { - out.write(buffer, 0, read); - } - } - resp.setStatus(HttpServletResponse.SC_OK); - } - } - } - - @WebStoragePathHandler( path = "save-file" ) - private void saveFile(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - if (! isAuthorized(req, resp, Roles.SAVE_FILE)) { - return; - } - - boolean isMultipart = ServletFileUpload.isMultipartContent(req); - if (! isMultipart) { - throw new ServletException("expected multipart message"); - } - FileItemFactory factory = new DiskFileItemFactory(); - ServletFileUpload upload = new ServletFileUpload(factory); - try { - @SuppressWarnings("unchecked") - List<FileItem> items = upload.parseRequest(req); - for (FileItem item : items) { - String fieldName = item.getFieldName(); - if (fieldName.equals("file")) { - String name = item.getName(); - if (! isAllowedToSaveFile(req, resp, name)) { - return; - } - InputStream in = item.getInputStream(); - synchronized (storageLock) { - storage.saveFile(name, in, new CloseOnSave(in)); - } - } - } - } catch (FileUploadException ex) { - throw new ServletException(ex); - } - - } - - private boolean isAllowedToLoadFile(HttpServletRequest req, - HttpServletResponse resp, String filename) { - String fileRole = FILES_READ_GRANT_ROLE_PREFIX + filename; - return isAllowed(req, resp, filename, Roles.GRANT_FILES_READ_ALL, fileRole); - - } - - private boolean isAllowedToSaveFile(HttpServletRequest req, - HttpServletResponse resp, String filename) { - String fileRole = FILES_WRITE_GRANT_ROLE_PREFIX + filename; - return isAllowed(req, resp, filename, Roles.GRANT_FILES_WRITE_ALL, fileRole); - } - - private boolean isAllowed(HttpServletRequest req, HttpServletResponse resp, - String filename, String grantAllRole, String specificFileRole) { - if (req.isUserInRole(grantAllRole) || req.isUserInRole(specificFileRole)) { - return true; - } else { - String detailMsg = "User '" + req.getRemoteUser() + - "' does not belong to any of the following roles: [ " + - grantAllRole + ", " + - specificFileRole + " ]"; - logger.log(Level.INFO, "Permission denied for file '" + - filename + "'. " + detailMsg); - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - return false; - } - } - - @SuppressWarnings("unchecked") // we adapt categories in an unchecked fashion - @WebStoragePathHandler( path = "register-category" ) - private synchronized void registerCategory(HttpServletRequest req, HttpServletResponse resp) throws IOException { - if (! isAuthorized(req, resp, Roles.REGISTER_CATEGORY)) { - return; - } - String categoryName = req.getParameter("name"); - String dataClassName = req.getParameter("data-class"); - String categoryParam = req.getParameter("category"); - CategoryIdentifier catIdentifier = new CategoryIdentifier(categoryName, dataClassName); - CategoryManager catManager = getCategoryManager(); - SharedStateId id = catManager.getCategoryId(catIdentifier); - if (id == null) { - Class<?> dataClass = getDataClassFromName(dataClassName); - Category<?> category = null; - boolean isAggregateCat = false; - if ((AggregateResult.class.isAssignableFrom(dataClass))) { - // Aggregate category case - Category<?> original = Categories.getByName(categoryName); - if (original == null) { - // DAOs register categories when they are constructed. If we - // end up triggering this we are in deep water. An aggregate - // query was attempted before the underlying category is - // registered at all? Not good! - throw new IllegalStateException("Original category of aggregate not registered!"); - } - // Adapt the original category to the one we want - @SuppressWarnings({ "rawtypes" }) - CategoryAdapter adapter = new CategoryAdapter(original); - category = adapter.getAdapted(dataClass); - isAggregateCat = true; - } else { - // Regular, non-aggregate category. Those categories we actually - // need to register with backing storage. - // - // Make sure we only register known categories - if (! knownCategoryNames.contains(categoryName)) { - logger.log(Level.WARNING, - "Attempt to register category which we don't know of! Name was '" - + categoryName + "'"); - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - return; - } - // The following has the side effect of registering the newly - // deserialized Category in the Categories class. - category = gson.fromJson(categoryParam, Category.class); - synchronized (storageLock) { - storage.registerCategory(category); - } - } - id = catManager.putCategory(getServerToken(), category, catIdentifier); - if (isAggregateCat) { - logger.log(Level.FINEST, "(id: " + id.getId() + ") did not register aggregate category " + category ); - } else { - logger.log(Level.FINEST, "(id: " + id.getId() + ") registered non-aggreate category: " + category); - } - } - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType(RESPONSE_JSON_CONTENT_TYPE); - writeResponse(resp, id, SharedStateId.class); - } - - private Class<?> getDataClassFromName(String dataClassName) { - try { - Class<?> clazz = Class.forName(dataClassName); - return clazz; - } catch (ClassNotFoundException e) { - throw new IllegalStateException("Unknown data class: '" + dataClassName + "'"); - } - } - - /** - * Handler for query executions (except for getting more results). See - * {@link #getMore(HttpServletRequest, HttpServletResponse)}. - * - * @param req - * @param resp - * @throws IOException - */ - @WebStoragePathHandler( path = "query-execute" ) - private <T extends Pojo> void queryExecute(HttpServletRequest req, HttpServletResponse resp) throws IOException { - if (! isAuthorized(req, resp, Roles.READ)) { - return; - } - String queryParam = req.getParameter("prepared-stmt"); - @SuppressWarnings("unchecked") - WebPreparedStatement<T> stmt = gson.fromJson(queryParam, WebPreparedStatement.class); - - // Check if the server token the client knows about still matches. - // Bail out early otherwise. - SharedStateId stmtId = stmt.getStatementId(); - final UUID serverToken = getServerToken(); - if (!serverToken.equals(stmtId.getServerToken())) { - logger.log(Level.INFO, "Server token: '" + serverToken + - "' and client token '" + stmtId.getServerToken() + - "' out of sync."); - WebQueryResponse<T> response = new WebQueryResponse<>(); - response.setResponseCode(PreparedStatementResponseCode.PREP_STMT_BAD_STOKEN); - writeResponse(resp, response, WebQueryResponse.class); - return; - } - PreparedParameters p = stmt.getParams(); - PreparedParameter[] params = p.getParams(); - PreparedStatementManager prepStmtManager = getPreparedStmtManager(); - PreparedStatementHolder<T> targetStmtHolder = prepStmtManager.getStatementHolder(stmtId); - PreparedStatement<T> targetStmt = targetStmtHolder.getStmt(); - ParsedStatement<T> parsed = targetStmt.getParsedStatement(); - Query<T> targetQuery = null; - WebQueryResponse<T> response = new WebQueryResponse<>(); - try { - targetQuery = (Query<T>)parsed.patchStatement(params); - response.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - } catch (IllegalPatchException e) { - logger.log(Level.INFO, "Failed to execute query", e); - response.setResponseCode(PreparedStatementResponseCode.ILLEGAL_PATCH); - writeResponse(resp, response, WebQueryResponse.class); - return; - } - - StatementDescriptor<T> desc = targetStmtHolder.getStatementDescriptor(); - - UserPrincipal userPrincipal = getUserPrincipal(req); - targetQuery = getQueryForPrincipal(userPrincipal, targetQuery, desc); - Cursor<T> cursor = targetQuery.execute(); - List<T> resultsList = null; - resultsList = getBatchFromCursor(cursor, DEFAULT_QUERY_BATCH_SIZE); - assert(resultsList.size() <= DEFAULT_QUERY_BATCH_SIZE); - CursorManager cursorManager = null; - HttpSession userSession = req.getSession(); - synchronized(userSession) { - cursorManager = (CursorManager)userSession.getAttribute(CURSOR_MANAGER_KEY); - if (cursorManager == null) { - // Not yet set for this user, create a new cursor manager - // and start the sweeper timer so as to prevent memory - // leaks due to cursors kept as a reference in cursor manager - cursorManager = new CursorManager(timerRegistry); - cursorManager.startSweeperTimer(); - userSession.setAttribute(CURSOR_MANAGER_KEY, cursorManager); - } - } - // Only record cursor if there are more results to return than the - // first batch size. - int cursorId = cursorManager.put(cursor); - response.setCursorId(cursorId); - response.setHasMoreBatches(cursor.hasNext()); - writeQueryResponse(resp, response, resultsList, targetStmtHolder); - } - - // package-private for testing - @SuppressWarnings("unchecked") - <T> T getServletContextAttribute(final String attributeName) { - ServletContext servletContext = getServletContext(); - T attributeVal = null; - synchronized(servletContext) { - attributeVal = (T)servletContext.getAttribute(attributeName); - } - // If this throws a NPE this is certainly a bug. - return Objects.requireNonNull(attributeVal); - } - - private UUID getServerToken() { - return getServletContextAttribute(SERVER_TOKEN_KEY); - } - - private CategoryManager getCategoryManager() { - return getServletContextAttribute(CATEGORY_MANAGER_KEY); - } - - private PreparedStatementManager getPreparedStmtManager() { - return getServletContextAttribute(PREPARED_STMT_MANAGER_KEY); - } - - private <T extends Pojo> void writeQueryResponse(HttpServletResponse resp, WebQueryResponse<T> response, List<T> resultsList, PreparedStatementHolder<T> targetStmtHolder) throws IOException { - @SuppressWarnings("unchecked") - T[] results = (T[])Array.newInstance(targetStmtHolder.getDataClass(), resultsList.size()); - for (int i = 0; i < resultsList.size(); i++) { - results[i] = resultsList.get(i); - } - response.setResultList(results); - writeResponse(resp, response, WebQueryResponse.class); - } - - /** - * Handler for getting more results for a query. Queries return results - * in batches. The first batch is returned via {@link #queryExecute(HttpServletRequest, HttpServletResponse)}. Subsequent results will get returned using - * this path. - * - * @param req - * @param resp - * @throws IOException - */ - @WebStoragePathHandler( path = "get-more" ) - private <T extends Pojo> void getMore(HttpServletRequest req, HttpServletResponse resp) throws IOException { - if (! isAuthorized(req, resp, Roles.READ)) { - return; - } - String stmtIdParam = req.getParameter("prepared-stmt-id"); - String cursorIdParam = req.getParameter("cursor-id"); - String batchSizeParam = req.getParameter("batch-size"); - - // Statement Id is JSON encoded. - SharedStateId id = gson.fromJson(URLDecoder.decode(stmtIdParam, "UTF-8"), SharedStateId.class); - int cursorId = Integer.parseInt(cursorIdParam); - int batchSize = Integer.parseInt(batchSizeParam); - - HttpSession userSession = req.getSession(); - CursorManager cursorManager = null; - synchronized(userSession) { - cursorManager = (CursorManager)userSession.getAttribute(CURSOR_MANAGER_KEY); - } - if (cursorManager == null) { - // Trying to get a cursorManager for a user which does not - // have it in the session as an attribute? Perhaps a cluster - // deployment problem? - throw new IllegalStateException("[get-more] No cursor manager available in session for " + req.getRemoteUser()); - } - @SuppressWarnings("unchecked") - Cursor<T> batchCursor = (Cursor<T>)cursorManager.get(cursorId); - - PreparedStatementManager prepStmtManager = getPreparedStmtManager(); - PreparedStatementHolder<T> targetStmtHolder = prepStmtManager.getStatementHolder(id); - if (batchCursor == null) { - // This either means: - // 1. The underlying (backing-storage) cursor didn't have - // more results, thus WebQueryResponse.hasMoreBatches() == false, - // when queryExecute() returned its WebQueryResponse. Still, - // the client requested more elements anyway and ended up here. - // That's really a bug in the client which performed this request. - // 2. The cursor expired via the sweeper timer in CursorManager, - // before the client actually managed to request more results. In - // that case the client is advised to re-issue the query in order - // to get a new cursor, since the underlying data in the DB might - // have changed anyway and results returned would be surprising. - // See http://docs.mongodb.org/manual/core/cursors/ - // (section "Cursor Isolation") - String msg = "No cursor found for user " + - req.getRemoteUser() + " and cursor id: " + cursorId + - ". Query was: " + targetStmtHolder.getStatementDescriptor(); - logger.log(Level.WARNING, msg); - WebQueryResponse<T> response = new WebQueryResponse<>(); - response.setResponseCode(PreparedStatementResponseCode.GET_MORE_NULL_CURSOR); - response.setHasMoreBatches(false); - response.setCursorId(cursorId); - List<T> empty = Collections.emptyList(); - writeQueryResponse(resp, response, empty, targetStmtHolder); - return; - } - // Update backing storage cursor with (possibly) changed params. - // This will validate batchSize input - batchCursor.setBatchSize(batchSize); - - List<T> nextBatch = getBatchFromCursor(batchCursor, batchCursor.getBatchSize()); - boolean stillMoreResults = batchCursor.hasNext(); - if (stillMoreResults) { - // Refresh timestamp of a live cursor so that it won't expire. - cursorManager.updateCursorTimeStamp(cursorId); - } else { - // no more results, remove cursor - cursorManager.removeCursor(cursorId); - } - logger.log(Level.FINEST, "Fetched more results (" + nextBatch.size() + ") for user '" + req.getRemoteUser() + "' cursorId " + cursorId + - ". Statement: " + targetStmtHolder.getStatementDescriptor()); - WebQueryResponse<T> response = new WebQueryResponse<>(); - response.setResponseCode(PreparedStatementResponseCode.QUERY_SUCCESS); - response.setHasMoreBatches(stillMoreResults); - response.setCursorId(cursorId); - writeQueryResponse(resp, response, nextBatch, targetStmtHolder); - } - - // Fetches the first batch of results. Number of results are determined - // by the default batch size in AdvancedCursor - private <T extends Pojo> List<T> getBatchFromCursor(final Cursor<T> cursor, final int batchSize) { - ArrayList<T> resultList = new ArrayList<>(batchSize); - for (int i = 0; i < batchSize && cursor.hasNext(); i++) { - resultList.add(cursor.next()); - } - return resultList; - } - - @SuppressWarnings("unchecked") - @WebStoragePathHandler( path = "write-execute" ) - private <T extends Pojo> void writeExecute(HttpServletRequest req, HttpServletResponse resp) throws IOException { - if (! isAuthorized(req, resp, Roles.WRITE)) { - return; - } - String queryParam = req.getParameter("prepared-stmt"); - WebPreparedStatement<T> stmt = gson.fromJson(queryParam, WebPreparedStatement.class); - - // Check if the server token the client knows about still matches. - // Bail out early otherwise. - SharedStateId stmtId = stmt.getStatementId(); - final UUID serverToken = getServerToken(); - if (!serverToken.equals(stmtId.getServerToken())) { - logger.log(Level.INFO, "Server token: '" + serverToken + - "' and client token '" + stmtId.getServerToken() + - "' out of sync."); - writeResponse(resp, PreparedStatementResponseCode.PREP_STMT_BAD_STOKEN, int.class); - return; - } - PreparedParameters p = stmt.getParams(); - PreparedParameter[] params = p.getParams(); - PreparedStatementManager prepStmtManager = getPreparedStmtManager(); - PreparedStatementHolder<T> targetStmtHolder = prepStmtManager.getStatementHolder(stmt.getStatementId()); - PreparedStatement<T> targetStmt = targetStmtHolder.getStmt(); - ParsedStatement<T> parsed = targetStmt.getParsedStatement(); - - DataModifyingStatement<T> targetStatement = null; - try { - // perform the patching of the target statement. - targetStatement = (DataModifyingStatement<T>)parsed.patchStatement(params); - } catch (IllegalPatchException e) { - logger.log(Level.INFO, "Failed to execute write. Stmt id was: " + stmtId, e); - writeResponse(resp, PreparedStatementResponseCode.ILLEGAL_PATCH, int.class); - return; - } - - // executes statement - int response = targetStatement.apply(); - writeResponse(resp, response, int.class); - } - - private UserPrincipal getUserPrincipal(HttpServletRequest req) { - Principal principal = req.getUserPrincipal(); - return principalCallback.getUserPrincipal(principal); - } - - /* - * Performs the heavy lifting of query filtering. It adds a where expression - * and uses conjunction to the original, unfilterered, query. - */ - private <T extends Pojo> Query<T> getQueryForPrincipal( - UserPrincipal userPrincipal, Query<T> patchedQuery, - StatementDescriptor<T> desc) { - Expression whereExpression = patchedQuery.getWhereExpression(); - FilterResult result = userPrincipal.getReadFilter(desc); - Expression authorizationExpression = null; - switch (result.getType()) { - case ALL: // fall-through. same as next case. - case QUERY_EXPRESSION: - authorizationExpression = result.getFilterExpression(); - break; - case EMPTY: - return getEmptyQuery(); - default: - throw new IllegalStateException("Unknown type!"); - } - // Handled empty already - if (whereExpression == null) { - // no where, use auth expression only - if (authorizationExpression != null) { - patchedQuery.where(authorizationExpression); - return patchedQuery; - } - } else { - if (authorizationExpression != null) { - Expression andExpression = new BinaryLogicalExpression<Expression, Expression>( - authorizationExpression, BinaryLogicalOperator.AND, - whereExpression); - patchedQuery.where(andExpression); - return patchedQuery; - } - } - assert(authorizationExpression == null); - // nothing to tag on - return patchedQuery; - } - - private void writeResponse(HttpServletResponse resp, - Object responseObj, Class<?> typeOfResponseObj) throws IOException { - String json = null; - try { - json = gson.toJson(responseObj, typeOfResponseObj); - } catch (Exception e) { - logger.log(Level.WARNING, "JSON serialization failed for " + typeOfResponseObj, e); - resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - return; - } - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType(RESPONSE_JSON_CONTENT_TYPE); - try (PrintWriter pw = resp.getWriter()) { - pw.write(json); - } - resp.flushBuffer(); - } - - @WebStoragePathHandler( path = "generate-token" ) - private void generateToken(HttpServletRequest req, HttpServletResponse resp) throws IOException { - if (! isAuthorized(req, resp, Roles.CMD_CHANNEL_GENERATE) ) { - return; - } - TokenManager tokenManager = (TokenManager) getServletContext().getAttribute(TOKEN_MANAGER_KEY); - assert tokenManager != null; - String clientTokenParam = req.getParameter("client-token"); - byte[] clientToken = Base64.decodeBase64(clientTokenParam); - String actionName = req.getParameter("action-name"); - // Perform pre-authorization: Since it's the client user which issues - // generate-token we have the correct user for which we can check role - // membership - and, thus, determine if this action is allowed to be - // performed. If the action is not allowed to be performed for this user - // a 403 will get returned and further verify-token would also fail, - // since no token gets added into the map. Trustworthiness of the - // action name will be implicitly checked by verify-token. - // - // We authorize based on role membership of this user. I.e. in order - // for a ping request (action-name == "ping") to properly authorize - // the user needs to be a member of role - // "thermostat-cmdc-grant-ping". More generally, membership of role - // "thermostat-cmdc-grant-<actionName>" grants the authenticated - // user the <actionName> command channel action. - String requiredRole = CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName; - if (! isAuthorized(req, resp, requiredRole)) { - return; - } - // authorization succeeded at this point - byte[] token = tokenManager.generateToken(clientToken, actionName); - resp.setContentType("application/octet-stream"); - resp.setContentLength(token.length); - resp.getOutputStream().write(token); - } - - @WebStoragePathHandler( path = "verify-token" ) - private void verifyToken(HttpServletRequest req, HttpServletResponse resp) { - if (! isAuthorized(req, resp, Roles.CMD_CHANNEL_VERIFY) ) { - return; - } - TokenManager tokenManager = (TokenManager) getServletContext().getAttribute(TOKEN_MANAGER_KEY); - assert tokenManager != null; - String clientTokenParam = req.getParameter("client-token"); - byte[] clientToken = Base64.decodeBase64(clientTokenParam); - String actionName = req.getParameter("action-name"); - byte[] token = Base64.decodeBase64(req.getParameter("token")); - // Perform authentication of the request. We can't do authorization for - // the originating client request here, since the only user info we have - // in verify-token is the identity of the agent which the client asked - // to perform the action for. Hence looking up role membership is not - // what we want here in order to limit privileges of the client. - // - // Note that we achieve this by performing authorization checks during - // generate-token. This is something the client user initiates and hence - // there we have the required user information. The entire command - // channel interaction can only succeed if and only if generate-token - // AND verify-token succeeded for the same token. Thus it's OK to only - // verify the token here - which in would only verify successfully if - // generate-token worked properly as a first step. - boolean verified = tokenManager.verifyToken(clientToken, token, actionName); - if (! verified) { - logger.log(Level.INFO, "Command channel action " + actionName + " from remote host " + - req.getRemoteAddr() + " FAILED to authenticate!"); - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - } else { - logger.log(Level.FINEST, "Command channel action " + actionName + " from remote host " + - req.getRemoteAddr() + " PASSED authentication."); - resp.setStatus(HttpServletResponse.SC_OK); - } - } - - private boolean isAuthorized(HttpServletRequest req, HttpServletResponse resp, String role) { - if (req.isUserInRole(role)) { - return true; - } else { - logger.log(Level.INFO, "Not permitting access to " + req.getPathInfo() + ". User '" + req.getRemoteUser() + "' not in role " + role); - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - return false; - } - } - - private <T extends Pojo> Query<T> getEmptyQuery() { - final Query<T> empty = new Query<T>() { - - @Override - public void where(Expression expr) { - // must not be called. - throw new IllegalStateException(); - } - - @Override - public void sort(Key<?> key, - com.redhat.thermostat.storage.core.Query.SortDirection direction) { - // must not be called. - throw new IllegalStateException(); - } - - @Override - public void limit(int n) { - // must not be called. - throw new IllegalStateException(); - } - - @Override - public Cursor<T> execute() { - return getEmptyCursor(); - } - - @Override - public Expression getWhereExpression() { - // must not be called. - throw new IllegalStateException(); - } - - @Override - public Statement<T> getRawDuplicate() { - // must not be called. - throw new IllegalStateException(); - } - - }; - return empty; - } - - private <T extends Pojo> Cursor<T> getEmptyCursor() { - final Cursor<T> empty = new BasicBatchCursor<T>() { - - @Override - public boolean hasNext() { - return false; - } - - @Override - public T next() { - // must not be called. - throw new IllegalStateException(); - } - - }; - return empty; - } - - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/AbstractFilter.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * 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.web.server.auth; - -import java.util.HashSet; -import java.util.Set; - -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -abstract class AbstractFilter<T extends Pojo> implements StatementFilter<T> { - - private static final String ALL_ROLE_NAME = "ALL"; - protected final Set<BasicRole> userRoles; - - protected AbstractFilter(Set<BasicRole> userRoles) { - this.userRoles = userRoles; - } - - protected Set<String> getGranted(String prefix) { - Set<String> allowedObjectsFromRoles = new HashSet<>(); - for (BasicRole r : userRoles) { - if (r.getName().startsWith(prefix)) { - String allowedVm = r.getName().substring( - prefix.length()); - if (!allowedVm.equals(ALL_ROLE_NAME)) { - allowedObjectsFromRoles.add(allowedVm); - } - } - } - return allowedObjectsFromRoles; - } - - protected FilterResult allWithExpression(Expression parentExpression) { - if (parentExpression != null) { - FilterResult result = new FilterResult( - ResultType.QUERY_EXPRESSION); - result.setFilterExpression(parentExpression); - return result; - } else { - return new FilterResult(ResultType.ALL); - } - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/AgentIdFilter.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * 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.web.server.auth; - -import java.util.Set; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -/** - * Filters queries based on granted agent IDs. - * - * @see Roles#GRANT_AGENTS_READ_ALL - */ -class AgentIdFilter<T extends Pojo> extends AbstractFilter<T> { - - static final RolePrincipal GRANT_AGENTS_READ_ALL = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL); - static final String AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX = "thermostat-agents-grant-read-agentId-"; - - AgentIdFilter(Set<BasicRole> userRoles) { - super(userRoles); - } - - @Override - public FilterResult applyFilter(StatementDescriptor<T> desc, - Expression parentExpression) { - if (userRoles.contains(GRANT_AGENTS_READ_ALL)) { - return allWithExpression(parentExpression); - } - Category<T> category = desc.getCategory(); - // user cannot read all agents - if (category.getKey(Key.AGENT_ID.getName()) != null) { - // tag on in clause for agentId - ExpressionFactory factory = new ExpressionFactory(); - Set<String> agentIds = getGrantedAgentsByAgentId(); - Expression filterExpression = factory.in(Key.AGENT_ID, agentIds, String.class); - FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION); - if (parentExpression != null) { - filterExpression = factory.and(parentExpression, filterExpression); - } - result.setFilterExpression(filterExpression); - return result; - } else { - // can't do anything here, let it through for next stage. - return allWithExpression(parentExpression); - } - } - - private Set<String> getGrantedAgentsByAgentId() { - return getGranted(AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX); - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/BasicRole.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * 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.web.server.auth; - -import java.io.Serializable; -import java.security.Principal; -import java.security.acl.Group; -import java.util.Objects; - -/** - * Base class for all thermostat roles. - * - * To be precise, every {@link Principal} which does NOT have the same name - * as the currently logged in user, are BasicRole principals. The name of a - * Principal is defined by {@link Principal#getName()}. - * - */ -public abstract class BasicRole implements Group, Serializable { - - private static final long serialVersionUID = -4572772782292794645L; - protected String name; - - public BasicRole(String name) { - this.name = name; - } - - /** - * Compares two BasicRoles. - * - * @return true if and only if other is a BasicRole and its name is the same - * as this role. - */ - @Override - public boolean equals(Object other) { - if (!(other instanceof BasicRole)) { - return false; - } - String otherName = ((Principal) other).getName(); - return Objects.equals(name, otherName); - } - - @Override - public int hashCode() { - return (name == null ? 0 : name.hashCode()); - } - - @Override - public String getName() { - return name; - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/DefaultPrincipalCallback.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * 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.web.server.auth; - -import java.security.Principal; - -/** - * Default callback which simply casts the given principal. - * - */ -final class DefaultPrincipalCallback implements PrincipalCallback { - - @Override - public UserPrincipal getUserPrincipal(Principal principal) { - // Since we use our own JAAS based auth module this cast is safe for - // Tomcat and JBoss AS 7/wildfly since they allow for configuration of - // user principal classes. - return (UserPrincipal)principal; - } - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/FilterResult.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * 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.web.server.auth; - -import com.redhat.thermostat.storage.query.Expression; - -public class FilterResult { - - public enum ResultType { - /** Statement would return an empty result */ - EMPTY, - /** Statement can go through unfiltered */ - ALL, - /** Statement needs to be filtered with the given expression */ - QUERY_EXPRESSION - } - - private final ResultType type; - private Expression filterExpression; - - FilterResult(ResultType type) { - this.type = type; - } - - public Expression getFilterExpression() { - return filterExpression; - } - - void setFilterExpression(Expression filterExpression) { - if (type != ResultType.QUERY_EXPRESSION) { - throw new IllegalStateException("Only query expression return type can have filter expression set"); - } - this.filterExpression = filterExpression; - } - - public ResultType getType() { - return type; - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/HostnameFilter.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * 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.web.server.auth; - -import java.util.Set; - -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.dao.HostInfoDAO; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -/** - * - * Filters based on granted host names. - * - * @see Roles#GRANT_HOSTS_READ_ALL - */ -class HostnameFilter<T extends Pojo> extends AbstractFilter<T> { - - static final RolePrincipal GRANT_HOSTS_READ_ALL = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL); - static final String HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX = "thermostat-hosts-grant-read-hostname-"; - - HostnameFilter(Set<BasicRole> userRoles) { - super(userRoles); - } - - @Override - public FilterResult applyFilter(StatementDescriptor<T> desc, - Expression parentExpression) { - if (userRoles.contains(GRANT_HOSTS_READ_ALL)) { - return allWithExpression(parentExpression); - } - // not all hosts are allowed - if (desc.getCategory().equals(HostInfoDAO.hostInfoCategory)) { - // add a hostname query expression - ExpressionFactory factory = new ExpressionFactory(); - Set<String> hostnames = getGrantedHostsByHostname(); - Expression filterExpression = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class); - FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION); - if (parentExpression != null) { - filterExpression = factory.and(parentExpression, filterExpression); - } - result.setFilterExpression(filterExpression); - return result; - } else { - // can't do anything - return allWithExpression(parentExpression); - } - } - - private Set<String> getGrantedHostsByHostname() { - return getGranted(HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX); - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/JettyPrincipalCallback.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * 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.web.server.auth; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.Principal; -import java.util.Objects; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.security.auth.Subject; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.web.server.containers.ContainerVersion; -import com.redhat.thermostat.web.server.containers.ServletContainerInfo; - -/** - * Principal callback for the jetty container. - * - */ -class JettyPrincipalCallback implements PrincipalCallback { - - private static final String JETTY8_JAAS_USER_PRINCIPAL_CLASS_NAME = "org.eclipse.jetty.plus.jaas.JAASUserPrincipal"; - private static final String JETTY9_JAAS_USER_PRINCIPAL_CLASS_NAME = "org.eclipse.jetty.jaas.JAASUserPrincipal"; - - private static final Logger logger = LoggingUtils.getLogger(JettyPrincipalCallback.class); - private final ServletContainerInfo info; - - JettyPrincipalCallback(ServletContainerInfo info) { - this.info = Objects.requireNonNull(info); - } - - @Override - public UserPrincipal getUserPrincipal(Principal principal) { - Subject subject = getJettySubject(principal); - Set<UserPrincipal> userPrincipals = subject.getPrincipals(UserPrincipal.class); - if (userPrincipals.size() != 1) { - throw new IllegalStateException("Number of thermostat user principals must be exactly 1!"); - } - return userPrincipals.iterator().next(); - } - - private Subject getJettySubject(Principal principal) { - ContainerVersion version = info.getContainerVersion(); - // Jetty has our principal on the accessible subject. - // The package of the JAASUserPrincipal class changed between - // Jetty 8 and Jetty 9. - if (version.getMajor() <= 8) { - return getSubjectFromClass(principal, JETTY8_JAAS_USER_PRINCIPAL_CLASS_NAME); - } else { - // >= 9 and go with jetty 9's name - return getSubjectFromClass(principal, JETTY9_JAAS_USER_PRINCIPAL_CLASS_NAME); - } - } - - private Subject getSubjectFromClass(Principal principal, String clazzName) { - Subject subject = null; - try { - // Do this via reflection in order to avoid a hard dependency - // on jetty-plus. - Class<?> jassUserPrincipal = Class.forName(clazzName); - Method method = jassUserPrincipal.getDeclaredMethod("getSubject"); - subject = (Subject)method.invoke(principal); - } catch (ClassNotFoundException | NoSuchMethodException - | SecurityException | IllegalAccessException - | IllegalArgumentException | InvocationTargetException e) { - // log and continue - logger.log(Level.WARNING, e.getMessage(), e); - } - if (subject == null) { - throw new IllegalStateException( - "Could not retrieve subject from principal of type " - + principal.getClass().getName()); - } - return subject; - } - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/PrincipalCallback.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * 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.web.server.auth; - -import java.security.Principal; - -import javax.servlet.http.HttpServletRequest; - -/** - * - * Callback for retrieving the {@link UserPrincipal} from the generic - * {@link Principal} returned by {@link HttpServletRequest#getUserPrincipal()}. - * - * In general, there should be one implementation per supported servlet - * container. - * - */ -public interface PrincipalCallback { - - /** - * - * @param principal The principal as returned by {@link HttpServletRequest#getUserPrincipal()}. - * @return Thermostat's matching {@link UserPrincipal}. - */ - UserPrincipal getUserPrincipal(Principal principal); -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/PrincipalCallbackFactory.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * 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.web.server.auth; - -import com.redhat.thermostat.web.server.containers.ContainerName; -import com.redhat.thermostat.web.server.containers.ServletContainerInfo; - -/** - * Factory producing a {@link PrincipalCallback}. - * - */ -public class PrincipalCallbackFactory { - - private final ServletContainerInfo info; - - public PrincipalCallbackFactory(ServletContainerInfo info) { - this.info = info; - } - - public PrincipalCallback getCallback() { - // info may be null. in this case return the default callback - if (info == null) { - return new DefaultPrincipalCallback(); - } - ContainerName name = info.getName(); - switch(name) { - case JETTY: - return new JettyPrincipalCallback(info); - default: - // includes tomcat and wildfly/JBoss AS - return new DefaultPrincipalCallback(); - } - } -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/RolePrincipal.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * 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.web.server.auth; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Objects; -import java.util.Vector; - -import static com.redhat.thermostat.common.utils.IteratorUtils.asList; - -/** - * Class representing a simple thermostat role. Roles can be nested. - * - * @see Group - */ -public class RolePrincipal extends BasicRole { - - private static final long serialVersionUID = -7366668253791828610L; - // the set of nested roles if any - private final HashSet<Group> roles = new HashSet<>(); - - /** - * Creates a role principal with the specified role name containing no roles - * within it. - * - * @param roleName - * @throws NullPointerException if roleName was null. - */ - public RolePrincipal(String roleName) { - super(Objects.requireNonNull(roleName)); - } - - /** - * Adds a role this role principal. - * - * @return true if and only if the role has been successfully added. - * @throws IllegalArgumentException - * if the principal to be added is not a {@link Group} - * NullPointerException If the role was null. - */ - @Override - public boolean addMember(Principal role) { - if (!(Objects.requireNonNull(role) instanceof Group)) { - throw new IllegalArgumentException("principal not a group"); - } - return roles.add((Group) role); - } - - /** - * Removes a role from this role principal. - * - * @return true if the principal was successfully removed. - */ - @Override - public boolean removeMember(Principal role) { - // will return false if role not a member, omit check for Group - return roles.remove(role); - } - - @Override - public boolean isMember(Principal member) { - if (roles.contains(member)) { - return true; - } - // recursive case - boolean isMember = false; - for (Group group : roles) { - isMember = isMember || group.isMember(member); - if (!isMember) { - break; - } - } - return isMember; - } - - @Override - public Enumeration<? extends Principal> members() { - Vector<Principal> vector = new Vector<>(); - for (Group group : roles) { - vector.add(group); - } - return vector.elements(); - } - -} \ No newline at end of file
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - * 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.web.server.auth; - -/** - * Roles thermostat knows about. - * - */ -public interface Roles { - - /** - * Allows for a user to read records tied to any host. - */ - final String GRANT_HOSTS_READ_ALL = "thermostat-hosts-grant-read-hostname-ALL"; - /** - * Allows for a user to read records tied to any JVM id. - */ - final String GRANT_VMS_READ_BY_VM_ID_ALL = "thermostat-vms-grant-read-vmId-ALL"; - /** - * Allows for a user to read records tied to any username the JVM is running as. - */ - final String GRANT_VMS_READ_BY_USERNAME_ALL = "thermostat-vms-grant-read-username-ALL"; - /** - * Allows for a user to read any file from storage. - */ - final String GRANT_FILES_READ_ALL = "thermostat-files-grant-read-filename-ALL"; - /** - * Allows for a user to write any file to storage. - */ - final String GRANT_FILES_WRITE_ALL = "thermostat-files-grant-write-filename-ALL"; - /** - * Allows for a user to see records tied to any agent. - */ - final String GRANT_AGENTS_READ_ALL = "thermostat-agents-grant-read-agentId-ALL"; - /** - * Allows for a user to read all records. No restrictions are - * performed on as to what this user can see. - */ - final String GRANT_READ_ALL = "thermostat-grant-read-ALL"; - - /* - * TODO: Not sure if we still want to use the following 4 stop-gap roles. - */ - final String APPEND = "thermostat-add"; - final String REPLACE = "thermostat-replace"; - final String UPDATE = "thermostat-update"; - final String DELETE = "thermostat-remove"; - - final String PREPARE_STATEMENT = "thermostat-prepare-statement"; - final String READ = "thermostat-query"; - final String WRITE = "thermostat-write"; - final String LOAD_FILE = "thermostat-load-file"; - final String SAVE_FILE = "thermostat-save-file"; - final String PURGE = "thermostat-purge"; - final String REGISTER_CATEGORY = "thermostat-register-category"; - final String CMD_CHANNEL_VERIFY = "thermostat-cmdc-verify"; - final String CMD_CHANNEL_GENERATE = "thermostat-cmdc-generate"; - final String LOGIN = "thermostat-login"; - final String ACCESS_REALM = "thermostat-realm"; - - final String[] ALL_ROLES = { APPEND, REPLACE, UPDATE, DELETE, READ, - LOAD_FILE, SAVE_FILE, PURGE, REGISTER_CATEGORY, - CMD_CHANNEL_GENERATE, CMD_CHANNEL_VERIFY, LOGIN, ACCESS_REALM, - PREPARE_STATEMENT, GRANT_AGENTS_READ_ALL, GRANT_HOSTS_READ_ALL, - GRANT_VMS_READ_BY_USERNAME_ALL, GRANT_VMS_READ_BY_VM_ID_ALL, - GRANT_READ_ALL }; - - final String[] AGENT_ROLES = { - APPEND, REPLACE, UPDATE, DELETE, SAVE_FILE, PURGE, - REGISTER_CATEGORY, CMD_CHANNEL_VERIFY, - LOGIN, ACCESS_REALM - }; - - final String[] CLIENT_ROLES = { - ACCESS_REALM, LOGIN, CMD_CHANNEL_GENERATE, LOAD_FILE, - READ, REGISTER_CATEGORY, PREPARE_STATEMENT - }; - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/StatementFilter.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * 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.web.server.auth; - -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; - -/** - * A filter suitable to get applied to {@link PreparedStatement}s before they - * are executed. - * - */ -interface StatementFilter<T extends Pojo> { - - /** - * Applies this filter. Note that filters may be chained. - * - * @param desc - * The statement descriptor to apply the filter to. - * @param parentExpression - * The Expression as constructed by the previous Filter. May be - * null. - * @return A filtered result with the Expression set to use for filtering if - * result type was QUERY_EXPRESSION. - */ - FilterResult applyFilter(StatementDescriptor<T> desc, - Expression parentExpression); - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/UserPrincipal.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * 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.web.server.auth; - -import java.io.Serializable; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -/** - * Class representing thermostat users - * - */ -public class UserPrincipal implements Serializable, Principal { - - private static final RolePrincipal GRANT_READ_ALL = new RolePrincipal(Roles.GRANT_READ_ALL); - - private static final long serialVersionUID = 2646753284881445421L; - // The set of roles this user is a member of (they may be nested) - private final Set<BasicRole> roles = new HashSet<>(); - // The name of this principal - private String name; - - /** - * Creates a new user principal with the given name - * - * @param name The user name. - * @throws NullPointerException if name is null. - */ - public UserPrincipal(String name) { - this.name = Objects.requireNonNull(name); - } - - /** - * - * @return The set of roles this principal is a member of. An empty set - * if this user has no role memberships. - */ - public final Set<BasicRole> getRoles() { - return new HashSet<>(roles); - } - - /** - * Sets the set of roles which this principal is a member of. - * - * @param roles the set of roles - * @throws NullPointerException If the given role set was null. - */ - public void setRoles(Set<BasicRole> roles) { - this.roles.addAll(Objects.requireNonNull(roles)); - } - - /** - * Prepare a read filter for this user which can be applied prior executing - * trusted prepared queries. - * - * @param desc the descriptor for which to get the filter. - * - * @return An {@link FilterResult} which can be used to make a decision on - * which records to return. - */ - public <T extends Pojo> FilterResult getReadFilter(StatementDescriptor<T> desc) { - if (getRoles().contains(GRANT_READ_ALL)) { - // user can see everything, no filtering is happening at all. - return new FilterResult(ResultType.ALL); - } - List<StatementFilter<T>> filters = buildFilters(); - - // perform filtering using our list of filters - Expression parentExpression = null; - FilterResult overallResult = null; - for (StatementFilter<T> filter: filters) { - overallResult = filter.applyFilter(desc, parentExpression); - switch (overallResult.getType()) { - case ALL: // fall-through, expression == null - case QUERY_EXPRESSION: - // continue filtering - parentExpression = overallResult.getFilterExpression(); - break; - case EMPTY: - // no point continuing, already nothing - return overallResult; - default: - throw new IllegalStateException("Unknown result type!"); - } - } - // done filtering - return overallResult; - } - - /* - * Filters are applied in order. Passing through one which didn't return - * empty continues the filter chain. Currently, we filter by: - * agent IDs -> hostnames -> vm IDs -> vm usernames - */ - private <T extends Pojo> List<StatementFilter<T>> buildFilters() { - List<StatementFilter<T>> filters = new ArrayList<>(); - Set<BasicRole> roles = getRoles(); - AgentIdFilter<T> agentIdFilter = new AgentIdFilter<>(roles); - HostnameFilter<T> hostnameFilter = new HostnameFilter<>(roles); - VmIdFilter<T> vmIdFilter = new VmIdFilter<>(roles); - VmUsernameFilter<T> vmUsernameFilter = new VmUsernameFilter<>(roles); - filters.add(agentIdFilter); - filters.add(hostnameFilter); - filters.add(vmIdFilter); - filters.add(vmUsernameFilter); - return filters; - } - - @Override - public String getName() { - return name; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof Principal)) { - return false; - } - String otherName = ((Principal) other).getName(); - return Objects.equals(name, otherName); - } - - @Override - public int hashCode() { - return (name == null ? 0 : name.hashCode()); - } - - @Override - public String toString() { - return this.getClass().getName() + ": " + name; - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmIdFilter.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * 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.web.server.auth; - -import java.util.Set; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -/** - * Filters based on granted VM IDs. - * - * @see Roles#GRANT_VMS_READ_BY_VM_ID_ALL - */ -class VmIdFilter<T extends Pojo> extends AbstractFilter<T> { - - static final RolePrincipal GRANT_VMS_BY_ID_READ_ALL = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL); - static final String VMS_BY_VM_ID_GRANT_ROLE_PREFIX = "thermostat-vms-grant-read-vmId-"; - - VmIdFilter(Set<BasicRole> userRoles) { - super(userRoles); - } - - @Override - public FilterResult applyFilter(StatementDescriptor<T> desc, - Expression parentExpression) { - if (userRoles.contains(GRANT_VMS_BY_ID_READ_ALL)) { - return allWithExpression(parentExpression); - } - // perform filtering on vmId - Category<T> category = desc.getCategory(); - if (category.getKey(Key.VM_ID.getName()) != null) { - // add vmId IN clause - ExpressionFactory factory = new ExpressionFactory(); - Set<String> vmIds = getGrantedVmsByVmId(); - Expression filterExpression = factory.in(Key.VM_ID, vmIds, String.class); - if (parentExpression != null) { - filterExpression = factory.and(parentExpression, filterExpression); - } - FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION); - result.setFilterExpression(filterExpression); - return result; - } else { - // can't do much - return allWithExpression(parentExpression); - } - } - - private Set<String> getGrantedVmsByVmId() { - return getGranted(VMS_BY_VM_ID_GRANT_ROLE_PREFIX); - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmUsernameFilter.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * 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.web.server.auth; - -import java.util.Set; - -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -/** - * Filters based on the granted VM usernames. I.e. the Unix username the - * individual VM runs as. - * - * @see Roles#GRANT_VMS_READ_BY_USERNAME_ALL - */ -class VmUsernameFilter<T extends Pojo> extends AbstractFilter<T> { - - static final RolePrincipal GRANT_VMS_USERNAME_READ_ALL = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL); - static final String VMS_BY_USERNAME_GRANT_ROLE_PREFIX = "thermostat-vms-grant-read-username-"; - - VmUsernameFilter(Set<BasicRole> userRoles) { - super(userRoles); - } - - @Override - public FilterResult applyFilter(StatementDescriptor<T> desc, - Expression parentExpression) { - if (userRoles.contains(GRANT_VMS_USERNAME_READ_ALL)) { - return allWithExpression(parentExpression); - } - // perform filtering on the username of the vm - if (desc.getCategory().equals(VmInfoDAO.vmInfoCategory)) { - ExpressionFactory factory = new ExpressionFactory(); - Set<String> vmUsernames = getGrantedVmsByUsername(); - Expression filterExpression = factory.in(VmInfoDAO.usernameKey, vmUsernames, String.class); - if (parentExpression != null) { - filterExpression = factory.and(parentExpression, filterExpression); - } - FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION); - result.setFilterExpression(filterExpression); - return result; - } else { - // can't do much - return allWithExpression(parentExpression); - } - } - - private Set<String> getGrantedVmsByUsername() { - return getGranted(VMS_BY_USERNAME_GRANT_ROLE_PREFIX); - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/WebStoragePathHandler.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * 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.web.server.auth; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Marker annotation for web storage handler methods. This is used in order - * to ensure proper authorization coverage. - * - */ -@Target( ElementType.METHOD ) -@Retention( RetentionPolicy.RUNTIME ) -public @interface WebStoragePathHandler { - - String path(); - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/WrappedRolePrincipal.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * 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.web.server.auth; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.Enumeration; - -/** - * Class representing a thermostat role. It simply wraps an existing {@link Group}. - * - * @see Group - */ -public class WrappedRolePrincipal extends BasicRole { - - private static final long serialVersionUID = -3852507889428067737L; - // the underlying group - private final Group group; - - /** - * Creates a role which delegates to the given group. - * - * @param group - */ - public WrappedRolePrincipal(Group group) { - super(group.getName()); - this.group = group; - } - - @Override - public boolean addMember(Principal user) { - return this.group.addMember(user); - } - - @Override - public boolean removeMember(Principal user) { - return this.group.removeMember(user); - } - - @Override - public boolean isMember(Principal member) { - return this.group.isMember(member); - } - - @Override - public Enumeration<? extends Principal> members() { - return this.group.members(); - } - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/AbstractLoginModule.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.io.IOException; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -import com.redhat.thermostat.common.utils.LoggingUtils; - -/** - * Base class for Thermostat JAAS login modules. - * - */ -public abstract class AbstractLoginModule implements LoginModule { - - private static final Logger logger = LoggingUtils.getLogger(AbstractLoginModule.class); - protected CallbackHandler callBackHandler; - protected Subject subject; - protected boolean debug = false; - - @Override - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map<String, ?> sharedState, Map<String, ?> options) { - this.subject = subject; - this.callBackHandler = callbackHandler; - this.debug = "true".equalsIgnoreCase((String)options.get("debug")); - } - - /** - * Get username and password from the callback. - * - * @return An array of length two where the first element is the username as - * String and the second element is the password as char[]. - * @throws LoginException - * if the retrieval fails (e.g. no callback is available). - */ - protected Object[] getUsernamePasswordFromCallBack() throws LoginException { - if (callBackHandler == null) { - throw new LoginException("No callback handler"); - } - Object[] creds = new Object[2]; - NameCallback nc = new NameCallback("Username: "); - PasswordCallback pc = new PasswordCallback("Password: ", false); - Callback[] callbacks = new Callback[] { nc, pc }; - try { - callBackHandler.handle(callbacks); - creds[0] = nc.getName(); - creds[1] = pc.getPassword(); - pc.clearPassword(); - return creds; - } catch (IOException | UnsupportedCallbackException e) { - logger.log(Level.FINEST, "Can't get username", e); - throw new LoginException(e.getMessage()); - } - } - - /** - * Get the user's name from the callback. - * - * @return The user's name. - * @throws LoginException - * if the retrieval fails (e.g. no callback is available). - */ - protected String getUsernameFromCallBack() throws LoginException { - if (callBackHandler == null) { - throw new LoginException("No callback handler"); - } - NameCallback nc = new NameCallback("Username: "); - PasswordCallback pc = new PasswordCallback("Password: ", false); - Callback[] callbacks = new Callback[] { nc, pc }; - try { - callBackHandler.handle(callbacks); - return nc.getName(); - } catch (IOException | UnsupportedCallbackException e) { - logger.log(Level.FINEST, "Can't get username", e); - throw new LoginException(e.getMessage()); - } - } - - protected final void debugLog(Level level, String message) { - if (debug) { - logger.log(level, message); - } - } - - protected final void debugLog(Level level, String message, Exception ex) { - if (debug) { - logger.log(level, message, ex); - } - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/DelegateLoginModule.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,214 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; -import javax.servlet.http.HttpServletRequest; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.web.server.auth.BasicRole; -import com.redhat.thermostat.web.server.auth.RolePrincipal; -import com.redhat.thermostat.web.server.auth.UserPrincipal; -import com.redhat.thermostat.web.server.auth.WrappedRolePrincipal; - -/** - * LoginModule which delegates to the configured implementing - * {@link LoginModule}. This is useful in order to be able to provide a - * guarrantee that a {@link UserPrincipal} is always returned for - * {@link HttpServletRequest#getUserPrincipal()} if any. - * - */ -public final class DelegateLoginModule extends AbstractLoginModule { - - private static final Logger logger = LoggingUtils.getLogger(DelegateLoginModule.class); - private static final String JAAS_DELEGATE_CONFIG_NAME = "ThermostatJAASDelegate"; - // the delegate - private LoginContext delegateContext; - private String username; - /** - * The config name to use. Defaults to {@linkplain DelegateLoginModule#JAAS_DELEGATE_CONFIG_NAME} - */ - private String configName; - - /** - * Default, no-arg constructor. - */ - public DelegateLoginModule() { - this.configName = JAAS_DELEGATE_CONFIG_NAME; - } - - // used for testing - DelegateLoginModule(String configName) { - this.configName = configName; - } - - - @Override - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map<String, ?> sharedState, Map<String, ?> options) { - super.initialize(subject, callbackHandler, sharedState, options); - /* - * Create and initialize the delegate - */ - try { - this.delegateContext = new LoginContext(configName, subject, callbackHandler); - debugLog(Level.FINEST, "successfully created delegate login context"); - } catch (LoginException e) { - // This only happens if there is no "ThermostatJAASDelegate" config - // and also no configuration with the name "other", which is likely - // always there for real application servers. - String message = "Fatal: Could not initialize delegate. " + - "'ThermostatJAASDelegate' " + - "and 'other' login modules are both not configured!"; - logger.log(Level.SEVERE, message, e); - throw new RuntimeException(message); - } - } - - @Override - public boolean login() throws LoginException { - try { - username = super.getUsernameFromCallBack(); - delegateContext.login(); - debugLog(Level.FINEST, "Login succeeded for " + username + " using the delegate."); - } catch (LoginException e) { - // This only shows up if debug is turned on - // since it's just a plain login failure. - debugLog(Level.FINEST, "Login failed", e); - throw e; - } - return true; - } - - @Override - public boolean commit() throws LoginException { - /* - * Make sure to retrieve principals from the authenticated subject, - * wrap them in UserPrincipal/BasicRole principals and inform the - * UserPrincipal about the roles it is a member of. - */ - Set<Principal> principals = subject.getPrincipals(); - int size = principals.size(); - Set<Principal> wrappedPrincipals = new HashSet<>(size); - // the user principal is not in the roles set - Set<BasicRole> roles = new HashSet<>(size -1); - UserPrincipal userPrincipal = null; - for (Principal p : principals) { - if (p.getName().equals(username)) { - // add our user principal - if (userPrincipal != null) { - logger.log(Level.SEVERE, "Fatal: > 1 user principals!"); - throw new IllegalStateException("> 1 user principals!"); - } - userPrincipal = new UserPrincipal(username); - wrappedPrincipals.add(userPrincipal); - } else { - // group (a.k.a role). It may be a simple principal or a - // Group. If it is a group, we simply wrap it. If it isn't - // we use our simple RolePrincipal instead. - BasicRole role; - if (p instanceof Group) { - role = new WrappedRolePrincipal((Group)p); - wrappedPrincipals.add(role); - roles.add(role); - } else { - role = new RolePrincipal(p.getName()); - wrappedPrincipals.add(role); - roles.add(role); - } - } - } - // Remove old principals and push the newly wrapped ones - principals.clear(); - principals.addAll(wrappedPrincipals); - // Finally, inform the user principal about the roles it is a member of. - // We need this in order to be able to do something (filtering/authorization) - // with these roles from the web storage servlet. - if (userPrincipal != null) { - userPrincipal.setRoles(roles); - } - - debugLog(Level.FINEST, "Committed changes for '" + username + "'"); - return true; - } - - @Override - public boolean abort() throws LoginException { - if (subject != null) { - // remove any principals - Set<Principal> principals = subject.getPrincipals(); - principals.clear(); - } - debugLog(Level.FINEST, "Login aborted!"); - return true; - } - - @Override - public boolean logout() throws LoginException { - try { - delegateContext.logout(); - Set<Principal> principals = subject.getPrincipals(); - principals.clear(); - debugLog(Level.FINEST, "Logged out successfully!"); - return true; - } catch (LoginException e) { - debugLog(Level.FINEST, "Logout failed!" + e.getMessage()); - return false; - } - } - - /* - * Package private method in order to get at the subject - */ - final Subject getSubject() { - return this.subject; - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidator.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Collections; -import java.util.Properties; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.shared.config.internal.CommonPathsImpl; -import com.redhat.thermostat.web.server.ConfigurationFinder; - -/** - * - * Validates users against an internal, properties based, user database. - * - */ -class PropertiesUserValidator implements UserValidator { - - private static final Logger logger = LoggingUtils.getLogger(PropertiesUserValidator.class); - private static final String DEFAULT_USERS_FILE = "thermostat-users.properties"; - private Properties users; - - PropertiesUserValidator() { - // this is the default configuration. it should be overriden through different means - // see javadoc of PropertiesUsernameRolesLoginModule - this(new ConfigurationFinder(new CommonPathsImpl()).getConfiguration(DEFAULT_USERS_FILE)); - } - - PropertiesUserValidator(String usersFile) { - this(new File(usersFile)); - } - - PropertiesUserValidator(File file) { - loadUsers(file); - } - - @Override - public synchronized void authenticate(String username, char[] password) - throws UserValidationException { - if (users == null) { - throw new UserValidationException("No user database"); - } - String tmp = users.getProperty(username); - if (tmp == null) { - throw new UserValidationException("User '" + username + "' not found"); - } - // We have an entry in our user db for the requested username. - char refPassWd[] = tmp.toCharArray(); - try { - validate(password, refPassWd); - } finally { - // clear our password - for (int i = 0; i < refPassWd.length; i++) { - refPassWd[i] = '\0'; - } - } - } - - private void validate(char[] theirPwd, char[] ourPwd) throws UserValidationException { - String failureMessage = "Login failed!"; - if (theirPwd.length != ourPwd.length) { - throw new UserValidationException(failureMessage); - } - for (int i = 0; i < theirPwd.length; i++) { - if (theirPwd[i] != ourPwd[i]) { - throw new UserValidationException(failureMessage); - } - } - } - - private void loadUsers(File userDB) { - if (users == null) { - Properties users = new Properties(); - try (FileInputStream stream = new FileInputStream(userDB)) { - users.load(stream); - this.users = users; - } catch (IOException e) { - String msg = "Unable to load user database"; - logger.log(Level.WARNING, msg, e); - throw new InvalidConfigurationException(msg); - } - } - } - - @Override - public Set<Object> getAllKnownUsers() throws IllegalStateException { - if (users == null) { - throw new IllegalStateException("No user database"); - } - return Collections.unmodifiableSet(users.keySet()); - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUsernameRolesLoginModule.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,210 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.web.server.auth.BasicRole; -import com.redhat.thermostat.web.server.auth.RolePrincipal; -import com.redhat.thermostat.web.server.auth.UserPrincipal; - -/** - * <p> - * A login module which uses properties files for validating users and for - * amending authenticated users with appropriate roles. - * </p> - * <p> - * The properties file which will be used for user credential validation can be - * specified via the <code>users.properties</code> option and defaults to - * <code>$THERMOSTAT_HOME/thermostat-users.properties</code> if no such option - * has been specified. Mappings for users to roles come from a file as specified - * by the <code>roles.properties</code> option and defaults to - * <code>$THERMOSTAT_HOME/thermostat-roles.properties</code> if no such option - * has been provided. - * </p> - */ -public class PropertiesUsernameRolesLoginModule extends AbstractLoginModule { - - private static final Logger logger = LoggingUtils.getLogger(PropertiesUsernameRolesLoginModule.class); - - // The validator to use for authentication - private UserValidator validator; - private RolesAmender amender; - private String username; - private boolean loginOK = false; - - - @Override - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map<String, ?> sharedState, Map<String, ?> options) { - super.initialize(subject, callbackHandler, sharedState, options); - this.validator = getValidator((String) options.get("users.properties")); - this.amender = getRolesAmender((String) options.get("roles.properties"), - validator.getAllKnownUsers()); - } - - @Override - public boolean login() throws LoginException { - debugLog(Level.FINEST, "Logging in ..."); - loginOK = false; - char[] password = null; - try { - Object[] creds = super.getUsernamePasswordFromCallBack(); - username = (String)creds[0]; - password = (char[])creds[1]; - validator.authenticate(username, password); - loginOK = true; - debugLog(Level.FINEST, "Logged in successfully: user == '" + username + "'"); - } catch (UserValidationException e) { - debugLog(Level.INFO, "Authentication failed for user '" + username + "'"); - throw new LoginException(e.getMessage()); - } finally { - clearPassword(password); - } - return loginOK; - } - - @Override - public boolean commit() throws LoginException { - if (!loginOK) { - return false; - } - debugLog(Level.FINEST, "Committing principals for user '" + username + "'"); - Set<Principal> principals = subject.getPrincipals(); - // Tomcat uses classes as specified by the LoginModule config - // in order to distinguish between user principals and role principals - // JBoss on the other hand uses string based name matching for the - // user principal - principals.add(new UserPrincipal(username)); - Set<BasicRole> roles; - try { - roles = amender.getRoles(username); - } catch (IllegalStateException e) { - debugLog(Level.INFO, "Failed to commit" + e.getMessage()); - throw new LoginException(); - } - principals.addAll(roles); - // JBoss uses the Group "Roles" as the principal - // for role matching - Group rolesRole = new RolePrincipal("Roles"); - for (BasicRole r : roles) { - rolesRole.addMember(r); - } - principals.add(rolesRole); - return true; - } - - @Override - public boolean abort() throws LoginException { - clearPrincipals(); - debugLog(Level.FINEST, "Login aborted!"); - return true; - } - - @Override - public boolean logout() throws LoginException { - clearPrincipals(); - debugLog(Level.FINEST, "Logged out!"); - return true; - } - - private void clearPassword(char[] password) { - if (password == null) { - return; - } - for (int i= 0; i < password.length; i++) { - password[i] = '\0'; - } - } - - private void clearPrincipals() { - Set<Principal> principals = subject.getPrincipals(); - principals.clear(); - } - - private UserValidator getValidator(final String usersProperties) { - UserValidator validator; - try { - if (usersProperties == null) { - debugLog(Level.FINEST, "Using default user database"); - validator = new PropertiesUserValidator(); - } else { - debugLog(Level.FINEST, "Using user database as defined in file '" + usersProperties + "'"); - validator = new PropertiesUserValidator(usersProperties); - } - } catch (Throwable e) { - // Can't continue at this point, since we need this for - // authentication. - String msg = "Fatal: Failed to initialize user database"; - logger.log(Level.SEVERE, msg, e); - throw new RuntimeException(msg); - } - return validator; - } - - private RolesAmender getRolesAmender(final String rolesProperties, final Set<Object> users) { - RolesAmender roleAmender; - try { - if (rolesProperties == null) { - debugLog(Level.FINEST, "Using default roles database"); - roleAmender = new RolesAmender(users); - } else { - debugLog(Level.FINEST, "Using roles database as defined in file '" + rolesProperties + "'"); - roleAmender = new RolesAmender(rolesProperties, users); - } - } catch (Throwable e) { - // Can't continue at this point, since we need this for - // authentication. - String msg = "Fatal: Failed to initialize role/user mapping database"; - logger.log(Level.SEVERE, msg, e); - throw new RuntimeException(msg, e); - } - return roleAmender; - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/RolesAmender.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,239 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.shared.config.internal.CommonPathsImpl; -import com.redhat.thermostat.web.server.ConfigurationFinder; -import com.redhat.thermostat.web.server.auth.BasicRole; -import com.redhat.thermostat.web.server.auth.RolePrincipal; - -/** - * Class responsible for parsing roles from a properties file. - * - */ -class RolesAmender { - - private static final Logger logger = LoggingUtils.getLogger(RolesAmender.class); - private static final String DEFAULT_ROLES_FILE = "thermostat-roles.properties"; - private static final String ROLE_SEPARATOR = ","; - // A username => roles mapping - private Map<String, Set<BasicRole>> rolesMap; - // The set of all users we know about - private final Set<Object> users; - - RolesAmender(Set<Object> users) { - // this is the default configuration supplied with thermostat - // it should not be overriden by editing this configuraton file - // see javadocs of PropertiesUsernameRolesLoginModule - this(new ConfigurationFinder(new CommonPathsImpl()).getConfiguration(DEFAULT_ROLES_FILE), users); - } - - RolesAmender(String rolesFile, Set<Object> users) { - this(new File(rolesFile), users); - } - - RolesAmender(File rolesFile, Set<Object> users) { - this.users = Objects.requireNonNull(users); - loadRoles(rolesFile); - } - - /** - * Gets the set of roles for a specific username. - * - * @param username the username whose roles to get - * @return The role-set for the given user or an empty set if this user is - * not a member of any role. - * @throws IllegalStateException If the roles database was null. - */ - Set<BasicRole> getRoles(String username) throws IllegalStateException { - if (rolesMap == null) { - throw new IllegalStateException("Roles database missing"); - } - Set<BasicRole> roles = rolesMap.get(username); - if (roles == null) { - // username not in list of roles, default to empty set for her - return new HashSet<>(); - } - return roles; - } - - private void loadRoles(File file) { - if (rolesMap == null) { - Properties rawRoles = new Properties(); - try (FileInputStream stream = new FileInputStream(file)) { - rawRoles.load(stream); - } catch (IOException e) { - String msg = "Failed to load roles from properties"; - logger.log(Level.SEVERE, msg, e); - throw new InvalidConfigurationException(msg); - } - try { - prepareRolesMap(rawRoles); - } catch (Throwable e) { - String msg = "Failed to parse roles"; - logger.log(Level.SEVERE, msg, e); - throw new IllegalStateException(msg); - } - } - } - - private void prepareRolesMap(Properties rawRoles) { - rolesMap = new HashMap<>(); - Map<String, RolesInfo> rolesSoFar = new HashMap<>(); - for (Object user : users) { - // users came from props, this should be a safe cast to string - String username = (String) user; - String rolesRaw = rawRoles.getProperty(username); - if (rolesRaw == null) { - // Since the list of usernames is not necessarily a subset of - // lines listed in roles for the case where there are just users - // defined, but don't appear in the roles file (i.e. have no - // role memberships). In this case, we simply skip this entry. - continue; - } - rolesRaw = rolesRaw.trim(); - String[] roles = rolesRaw.split(ROLE_SEPARATOR); - Set<BasicRole> uRoles = new HashSet<>(); - for (String tmp : roles) { - String role = tmp.trim(); - if (role.equals("")) { - // skip empty role names - continue; - } - RolesInfo info = rolesSoFar.get(role); - if (info == null) { - // new role, define it and create role-info - BasicRole r = new RolePrincipal(role); - info = new RolesInfo(r); - info.getMemberUsers().add(username); - rolesSoFar.put(role, info); - } - info.getMemberUsers().add(username); - uRoles.add(info.getRole()); - } - // finished one username, add it to roles map, to the intermediate - // set cache, and remove entry from raw roles list. - rolesMap.put(username, uRoles); - rawRoles.remove(username); - } - // what's left now are recursive role definitions. - Set<Object> recursiveRoles = rawRoles.keySet(); - for (Object r: recursiveRoles) { - RolesInfo recRole = rolesSoFar.get((String)r); - if (recRole == null) { - // This is bad news, new role defined but no username we know - // of is member of that role - throw new IllegalStateException("Recursive role '" + r + "' defined, but no user is a member"); - } - String memberRoles = rawRoles.getProperty((String)r).trim(); - for (String tmp: memberRoles.split(ROLE_SEPARATOR)) { - String member = tmp.trim(); - if (member.equals("")) { - // skip empty role name - continue; - } - if (users.contains(member)) { - throw new IllegalStateException("User '" + member + "' part of recursive role definition!"); - } - RolesInfo role = rolesSoFar.get(member); - if (role == null) { - // new role, define it and add it as member to recursive - // role - BasicRole ro = new RolePrincipal(member); - role = new RolesInfo(ro); - rolesSoFar.put(member, role); - } - recRole.getRole().addMember(role.getRole()); - } - expandRoles(recRole); - } - } - - /* - * Add roles to users which are member of a recursive role - */ - private void expandRoles(RolesInfo recRole) { - for (String s : recRole.getMemberUsers()) { - @SuppressWarnings("unchecked") // we've added them so safe - Enumeration<BasicRole> members = (Enumeration<BasicRole>) recRole.getRole().members(); - Set<BasicRole> userRoles = rolesMap.get(s); - while (members.hasMoreElements()) { - BasicRole r = members.nextElement(); - userRoles.add(r); - } - } - } - - /* - * Container data structure which is used for (role => member users) lookup. - */ - static class RolesInfo { - - private final Set<String> memberUsers; - private final BasicRole role; - - RolesInfo(BasicRole role) { - this.role = role; - memberUsers = new HashSet<>(); - } - - Set<String> getMemberUsers() { - return memberUsers; - } - - BasicRole getRole() { - return role; - } - } - -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/UserValidationException.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/* - * 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.web.server.auth.spi; - -/** - * Exception thrown if user credential validation failed. - * - * @see UserValidator - */ -public class UserValidationException extends Exception { - - private static final long serialVersionUID = -4552159492521496288L; - - public UserValidationException(String reason) { - super(reason); - } -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/spi/UserValidator.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.util.Set; - -/** - * Validates user's password credentials against an internal user database. - * - */ -public interface UserValidator { - - /** - * Validates the given username/password combination. If no - * {@link UserValidationException} is thrown validation was successful. - * - * @param username The user to validate against the internal database. - * @param password The password of <code>username</code> - * @throws UserValidationException If the user could not be validated. Reasons - * as to why this exception may be thrown include: - * <ul> - * <li>The user does not exist in the database</li> - * <li>Invalid credentials were provided</li> - * </ul> - */ - void authenticate(String username, char[] password) throws UserValidationException; - - /** - * Get a read-only set of all users the system knows about. All members of - * the set are Strings. - * - * @return All known users. - * @throws IllegalStateException If no user database is available. - */ - Set<Object> getAllKnownUsers() throws IllegalStateException; -} -
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/AbstractContainerInfo.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * 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.web.server.containers; - -import java.util.Objects; - -/** - * Super class for container infos. - * - */ -abstract class AbstractContainerInfo { - - protected void check(String serverInfo) { - Objects.requireNonNull(serverInfo); - if (serverInfo.length() == 0) { - throw new IllegalArgumentException("Illegal server info: '" + serverInfo + "'"); - } - } - - protected abstract ContainerVersion parseVersion(String serverInfo); -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/ContainerName.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * 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.web.server.containers; - -/** - * Enum for known-to-be-working servlet containers. - * - * @see ServletContainerInfo - */ -public enum ContainerName { - /** - * Apache Tomcat. - * - * @see http://tomcat.apache.org/ - */ - TOMCAT, - /** - * Eclipse Jetty - * - * @see http://eclipse.org/jetty/ - */ - JETTY, - /** - * Wildfly Application Server, formerly known as JBoss AS. - * - * @see http://www.wildfly.org/ - * @see http://www.jboss.org/jbossas/ - */ - WILDFLY, - /** - * Any unknown container. - */ - UNKNOWN -} \ No newline at end of file
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/ContainerVersion.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * 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.web.server.containers; - -/** - * - * Version information of a servlet container. - * - */ -public class ContainerVersion { - - public static final String UNKNOWN_SUFFIX = "UNKNOWN"; - - private final int major; - private final int minor; - private final int micro; - private final String suffix; - - /** - * Constructor - * - * @param major - * The major version number of the servlet container. - * @param minor - * The minor version number of the servlet container. - * @param micro - * The micro version number of the servlet container. - * @param suffix - * Optional suffix of the servlet container version. May be - * {@code null}. - */ - ContainerVersion(int major, int minor, int micro, String suffix) { - this.major = major; - this.minor = minor; - this.micro = micro; - this.suffix = suffix; - } - - public int getMajor() { - return major; - } - - public int getMinor() { - return minor; - } - - public int getMicro() { - return micro; - } - - /** - * - * @return Any other version suffix, such as qualifiers. Never, {@code null} - * . Returns {@link ContainerVersion#UNKNOWN_SUFFIX} if suffix was - * unknown or not set. - * - */ - public String getSuffix() { - if (suffix == null) { - return UNKNOWN_SUFFIX; - } - return suffix; - } - - @Override - public String toString() { - return major + "." + minor + "." + micro + "." + getSuffix(); - } - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/JettyContainerInfo.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * 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.web.server.containers; - - -class JettyContainerInfo extends AbstractContainerInfo implements ServletContainerInfo { - - private final ContainerVersion version; - - JettyContainerInfo(String infoString) { - this.version = parseVersion(infoString); - } - - @Override - public ContainerName getName() { - return ContainerName.JETTY; - } - - @Override - public ContainerVersion getContainerVersion() { - return version; - } - - @Override - protected ContainerVersion parseVersion(String serverInfo) { - super.check(serverInfo); - // jetty server info is of the form: jetty/x.y.z.suffix - String v = serverInfo.substring(serverInfo.indexOf("/") + 1); - String[] versions = v.split("\\."); - int major = Integer.parseInt(versions[0]); - int minor = Integer.parseInt(versions[1]); - int micro = Integer.parseInt(versions[2]); - String suffix = versions[3]; - return new ContainerVersion(major, minor, micro, suffix); - } - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/ServletContainerInfo.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * 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.web.server.containers; - -/** - * Interface providing information about the hosting servlet container. - * - */ -public interface ServletContainerInfo { - - /** - * - * @return The name of the servlet container. - */ - ContainerName getName(); - - /** - * - * @return The version of the servlet container. - */ - ContainerVersion getContainerVersion(); -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/ServletContainerInfoFactory.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * 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.web.server.containers; - -import javax.servlet.ServletContext; - -/** - * Factory producing {@link ServletContainerInfo} from strings as returned from - * {@link ServletContext#getServerInfo()}. - * - */ -public class ServletContainerInfoFactory { - - private static final String JETTY_PREFIX = "jetty"; - private static final String TOMCAT_PREFIX = "Apache Tomcat"; - private static final String WILDFLY_PREFIX = "Undertow"; - private static final String JBOSS_AS_PREFIX = "JBoss Web"; - - private final String containerInfo; - - public ServletContainerInfoFactory(String containerInfo) { - this.containerInfo = containerInfo; - } - - /** - * - * @return Information about the hosting container or {@code null} if the - * servlet container is not recognized. - */ - public ServletContainerInfo getInfo() { - if (containerInfo.startsWith(JETTY_PREFIX)) { - return new JettyContainerInfo(containerInfo); - } - if (containerInfo.startsWith(TOMCAT_PREFIX)) { - return new TomcatContainerInfo(containerInfo); - } - if (containerInfo.startsWith(WILDFLY_PREFIX) - || containerInfo.startsWith(JBOSS_AS_PREFIX)) { - return new WildflyContainerInfo(containerInfo); - } - // unknown, return null - return null; - } - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/TomcatContainerInfo.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/* - * 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.web.server.containers; - -class TomcatContainerInfo extends AbstractContainerInfo implements ServletContainerInfo { - - private final ContainerVersion version; - - TomcatContainerInfo(String serverInfo) { - this.version = parseVersion(serverInfo); - } - - @Override - public ContainerName getName() { - return ContainerName.TOMCAT; - } - - @Override - public ContainerVersion getContainerVersion() { - return version; - } - - @Override - protected ContainerVersion parseVersion(String serverInfo) { - super.check(serverInfo); - // tomcat server info is of the form: Apache Tomcat/x.y.z - String v = serverInfo.substring(serverInfo.indexOf("/") + 1); - String[] versions = v.split("\\."); - int major = Integer.parseInt(versions[0]); - int minor = Integer.parseInt(versions[1]); - int micro = Integer.parseInt(versions[2]); - return new ContainerVersion(major, minor, micro, null); - } - -}
--- a/web/server/src/main/java/com/redhat/thermostat/web/server/containers/WildflyContainerInfo.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * 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.web.server.containers; - -class WildflyContainerInfo extends AbstractContainerInfo implements ServletContainerInfo { - - private static final String JBOSS_WEB_PREFIX = "JBoss Web"; - private static final String UNDERTOW_PREFIX = "Undertow"; - private final ContainerVersion version; - - WildflyContainerInfo(String serverInfo) { - this.version = parseVersion(serverInfo); - } - - @Override - public ContainerName getName() { - return ContainerName.WILDFLY; - } - - @Override - public ContainerVersion getContainerVersion() { - return version; - } - - @Override - protected ContainerVersion parseVersion(String serverInfo) { - super.check(serverInfo); - if (serverInfo.startsWith(JBOSS_WEB_PREFIX)) { - return parseJBossWeb(serverInfo); - } else if (serverInfo.startsWith(UNDERTOW_PREFIX)) { - return parseUndertow(serverInfo); - } else { - // Don't know how to parse - return null; - } - } - - private ContainerVersion parseUndertow(String serverInfo) { - // Wildfly 8 uses undertow and looks like: Undertow - x.y.z.suffix - String version = serverInfo.substring(serverInfo.indexOf("-") + 2); - return parseVersionCommon(version); - } - - private ContainerVersion parseJBossWeb(String serverInfo) { - // JBOSS AS 7 server info is of the form: JBoss Web/x.y.z.suffix - String version = serverInfo.substring(serverInfo.indexOf("/") + 1); - return parseVersionCommon(version); - } - - private ContainerVersion parseVersionCommon(String version) { - String[] versionTokens = version.split("\\."); - int major = Integer.parseInt(versionTokens[0]); - int minor = Integer.parseInt(versionTokens[1]); - int micro = Integer.parseInt(versionTokens[2]); - String suffix = versionTokens[3]; - return new ContainerVersion(major, minor, micro, suffix); - } - -}
--- a/web/server/src/main/webapp/WEB-INF/web.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -<!-- - - 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. - ---> -<!DOCTYPE web-app PUBLIC - "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" - "http://java.sun.com/dtd/web-app_2_3.dtd" > - -<web-app> - <display-name>Archetype Created Web Application</display-name> - - <servlet> - <servlet-name>reststorage-servlet</servlet-name> - <servlet-class>com.redhat.thermostat.web.server.WebStorageEndPoint</servlet-class> - <!-- The timeout of the token manager in ms. We use 500ms for testing. --> - <init-param> - <param-name>token-manager-timeout</param-name> - <param-value>500</param-value> - </init-param> - </servlet> - - <servlet-mapping> - <servlet-name>reststorage-servlet</servlet-name> - <url-pattern>/storage/*</url-pattern> - </servlet-mapping> - - <security-constraint> - <web-resource-collection> - <web-resource-name>Entire Application</web-resource-name> - <url-pattern>/*</url-pattern> - </web-resource-collection> - <auth-constraint> - <role-name>thermostat-realm</role-name> - </auth-constraint> - </security-constraint> - - <login-config> - <auth-method>BASIC</auth-method> - <realm-name>Thermostat Realm</realm-name> - </login-config> - - <security-role> - <role-name>thermostat-realm</role-name> - </security-role> - - <!-- THERMOSTAT_HOME is set via the listener below --> - <context-param> - <param-name>THERMOSTAT_HOME</param-name> - <param-value>/tmp/test-thermostat-home</param-value> - </context-param> - - <listener> - <listener-class>com.redhat.thermostat.web.server.PropertySettingServletContextListener</listener-class> - </listener> - -</web-app>
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/CategoryManagerTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ -/* - * 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.web.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import java.util.UUID; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.server.CategoryManager.CategoryIdentifier; - -public class CategoryManagerTest { - - // CategoryIdentifier tests - - @Test - public void testCategoryIdentifierEquals() { - String catName = "foo-collection"; - String dataClassName = "com.redhat.thermostat.storage.core.model.Foo"; - CategoryIdentifier id = new CategoryIdentifier(catName, dataClassName); - assertTrue(id.equals(id)); - assertFalse(id.equals(null)); - String dataClass2 = "com.redhat.thermostat.storage.core.model.Bar"; - CategoryIdentifier id2 = new CategoryIdentifier(catName, dataClass2); - assertFalse("different data classes", id.equals(id2)); - String otherCatName = "bar-collection"; - CategoryIdentifier id3 = new CategoryIdentifier(otherCatName, dataClassName); - assertFalse("different category names", id.equals(id3)); - CategoryIdentifier id4 = new CategoryIdentifier(catName, dataClassName); - assertNotSame(id, id4); - assertTrue("category name and data class name match up", id.equals(id4)); - } - - @Test - public void testCategoryIdentifierHashCode() { - String catName = "foo-collection"; - String dataClassName = "com.redhat.thermostat.storage.core.model.Foo"; - CategoryIdentifier id = new CategoryIdentifier(catName, dataClassName); - assertTrue(id.hashCode() == id.hashCode()); - String dataClass2 = "com.redhat.thermostat.storage.core.model.Bar"; - CategoryIdentifier id2 = new CategoryIdentifier(catName, dataClass2); - assertTrue("different data classes", id.hashCode() != id2.hashCode()); - String otherCatName = "bar-collection"; - CategoryIdentifier id3 = new CategoryIdentifier(otherCatName, dataClassName); - assertTrue("different category names", id.hashCode() != id3.hashCode()); - CategoryIdentifier id4 = new CategoryIdentifier(catName, dataClassName); - assertNotSame(id, id4); - assertTrue("category name and data class name match up", id.hashCode() == id4.hashCode()); - } - - // CategoryManager tests - - /** - * Verifies that only categories can be added to a manager correctly. It - * should add a category which has been added already (same cat-identifier) - * only once. - */ - @Test - public void testPutCategory() { - UUID serverToken = UUID.randomUUID(); - String catName = "foo-collection"; - String dataClassName = "com.redhat.thermostat.storage.core.model.Foo"; - CategoryIdentifier identifier = new CategoryIdentifier(catName, dataClassName); - Category<?> mockCategory = mock(Category.class); - CategoryManager manager = new CategoryManager(); - SharedStateId id = manager.putCategory(serverToken, mockCategory, identifier); - assertNotNull(id); - assertEquals(serverToken, id.getServerToken()); - assertEquals(0, id.getId()); - CategoryIdentifier identifier2 = new CategoryIdentifier("bar", dataClassName); - Category<?> otherCat = mock(Category.class); - SharedStateId otherId = manager.putCategory(serverToken, otherCat, identifier2); - assertNotNull(otherId); - assertNotSame(id, otherId); - assertFalse(otherId.equals(id)); - - // This should give back the same id since it's the very same identifier - SharedStateId thirdId = manager.putCategory(serverToken, mockCategory, identifier); - assertSame(id, thirdId); - } - - /** - * Verifies that NPEs get thrown when essential params are null. - */ - @Test - public void testPutCategoryNullParams() { - UUID serverToken = UUID.randomUUID(); - String catName = "foo-collection"; - String dataClassName = "com.redhat.thermostat.storage.core.model.Foo"; - CategoryIdentifier identifier = new CategoryIdentifier(catName, dataClassName); - Category<?> mockCategory = mock(Category.class); - CategoryManager manager = new CategoryManager(); - try { - manager.putCategory(null, mockCategory, identifier); - fail("Expected NPE due to null server token"); - } catch (NullPointerException e) { - // pass - } - try { - manager.putCategory(serverToken, null, identifier); - fail("Expected NPE due to null category"); - } catch (NullPointerException e) { - // pass - } - try { - manager.putCategory(serverToken, mockCategory, null); - fail("Expected NPE due to null category identifier"); - } catch (NullPointerException e) { - // pass - } - } - - @Test - public void testGetCategoryIdNullParams() { - CategoryManager manager = new CategoryManager(); - try { - manager.getCategoryId(null); - fail("Expected NPE due to null identifier"); - } catch (NullPointerException e) { - // pass - } - } - - @Test - public void canGetCategoryId() { - UUID serverNonce = UUID.randomUUID(); - CategoryManager manager = new CategoryManager(); - CategoryIdentifier catIdentifier = mock(CategoryIdentifier.class); - Category<?> mockCat = mock(Category.class); - SharedStateId id = manager.putCategory(serverNonce, mockCat, catIdentifier); - SharedStateId getId = manager.getCategoryId(catIdentifier); - assertEquals(id, getId); - assertSame(id, getId); - - // unknown cat identifier should return null - CategoryIdentifier otherIdentifier = mock(CategoryIdentifier.class); - assertNull(manager.getCategoryId(otherIdentifier)); - } - - @Test - public void testGetCategoryNullParams() { - CategoryManager manager = new CategoryManager(); - try { - manager.getCategory(null); - fail("Expected NPE due to null shared state id"); - } catch (NullPointerException e) { - // pass - } - } - - /** - * Check CategoryManager.getCategory() and CategoryManager.getCategoryId() - * in tandem. - */ - @Test - public void canGetCategoryCategoryId() { - UUID serverNonce = UUID.randomUUID(); - CategoryManager manager = new CategoryManager(); - assertNull(manager.getCategory(mock(SharedStateId.class))); - assertNull(manager.getCategoryId(mock(CategoryIdentifier.class))); - - // add an element - Category<?> category = mock(Category.class); - CategoryIdentifier catId = new CategoryIdentifier("foo", "bar"); - SharedStateId id = manager.putCategory(serverNonce, category, catId); - - // getting it should never be null now - Category<?> cat = manager.getCategory(id); - assertNotNull(cat); - SharedStateId otherId = manager.getCategoryId(catId); - assertNotNull(otherId); - - assertSame(id, otherId); - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/ConfigurationFinderTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/* - * 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.web.server; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.shared.config.CommonPaths; - -public class ConfigurationFinderTest { - - private File systemConfigDir = mock(File.class); - private File userConfigDir = mock(File.class); - - private File realFile1; - private File realFile2; - - private CommonPaths paths; - - @Before - public void setUp() throws IOException { - realFile1 = Files.createTempFile("configfinder-unit-test", null).toFile(); - realFile1.createNewFile(); - - realFile2 = Files.createTempFile("configfinder-unit-test", null).toFile(); - realFile2.createNewFile(); - - paths = mock(CommonPaths.class); - when(paths.getSystemConfigurationDirectory()).thenReturn(systemConfigDir); - when(paths.getUserConfigurationDirectory()).thenReturn(userConfigDir); - } - - @After - public void tearDown() { - realFile1.delete(); - realFile2.delete(); - } - - @Test - public void verifyFileFromUserHomeIsUsedIfSystemHomeIsNotUsable() throws Exception { - ConfigurationFinder finder = new ConfigurationFinder(paths) { - @Override - File getConfigurationFile(File directory, String name) { - if (directory == systemConfigDir) { - return new File("/does-not-exist/really-it-doesn't"); - } else if (directory == userConfigDir) { - return realFile1; - } - throw new AssertionError("Unknown test case"); - }; - }; - - File config = finder.getConfiguration("web.auth"); - assertEquals(realFile1, config); - } - - @Test - public void verifyFileFromSystemHomeIsUsedIfBothAreUsable() throws IOException { - final File systemFile = realFile1; - final File userFile = realFile2; - - ConfigurationFinder finder = new ConfigurationFinder(paths) { - @Override - File getConfigurationFile(File directory, String name) { - if (directory == systemConfigDir) { - return systemFile; - } else if (directory == userConfigDir) { - return userFile; - } - throw new AssertionError("Unknown test case"); - }; - }; - - File config = finder.getConfiguration("web.auth"); - assertEquals(systemFile, config); - } - - @Test - public void verifyFileFromSystemHomeIsUsedIfUserHomeNotUsable() throws IOException { - ConfigurationFinder finder = new ConfigurationFinder(paths) { - @Override - File getConfigurationFile(File directory, String name) { - if (directory == systemConfigDir) { - return realFile1; - } else if (directory == userConfigDir) { - return new File("/does-not-exist/really-it-doesn't"); - } - throw new AssertionError("Unknown test case"); - }; - }; - - File config = finder.getConfiguration("web.auth"); - assertEquals(realFile1, config); - } - -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/CursorManagerTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,275 +0,0 @@ -/* - * 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.web.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.HashMap; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; - -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.web.server.CursorManager.CursorHolder; -import com.redhat.thermostat.web.server.CursorManager.CursorSweeper; -import com.redhat.thermostat.web.server.CursorManager.CursorTimer; - -public class CursorManagerTest { - - /** - * Test putting cursors which return true on hasNext() - * those cursors need to get tracked. - */ - @Test - public void testPutBasicCursorHasMore() { - CursorManager manager = new CursorManager(mock(TimerRegistry.class)); - int id = manager.put(getHasMoreBatchCursor()); - assertTrue(id >= 0); - assertEquals(0, id); - id = manager.put(getHasMoreBatchCursor()); - assertTrue(id != 0); - assertEquals(1, id); - } - - /** - * Verifies that cursor IDs won't overflow. - */ - @Test - public void testPutCursorOverflow() { - int startValue = Integer.MAX_VALUE - 5; - // construct a cursor manager with high enough counter to simulate - // overflow. - CursorManager manager = new CursorManager(startValue); - int numIterations = 10; - boolean rollOver = false; - for (int i = 0, id; i < numIterations; i++) { - id = manager.put(getHasMoreBatchCursor()); - assertTrue(id >= 0); - assertFalse(id == Integer.MAX_VALUE); - if (id == 0) { - rollOver = true; - } - } - assertTrue("Expected id to start again from 0", rollOver); - } - - /** - * Test putting a cursor which returns false on hasNext(). - * CursorManager should not add such cursors and should - * return CURSOR_NOT_STORED. - */ - @Test - public void testPutNoHasMoreCursor() { - CursorManager manager = new CursorManager(mock(TimerRegistry.class)); - int id = manager.put(mock(Cursor.class)); - assertEquals(CursorManager.CURSOR_NOT_STORED, id); - } - - private Cursor<?> getHasMoreBatchCursor() { - Cursor<?> c = mock(Cursor.class); - when(c.hasNext()).thenReturn(true); - return c; - } - - @Test - public void testGetInvalidId() { - CursorManager manager = new CursorManager(mock(TimerRegistry.class)); - Cursor<?> c = manager.get(CursorManager.CURSOR_NOT_STORED); - assertNull(c); - } - - /** - * Basic test for CursorManager.get(). Add some cursors, - * then add one we track the id for and verify that we - * can get the BatchCursor reference. - */ - @Test - public void testGetHasMore() { - CursorManager manager = new CursorManager(mock(TimerRegistry.class)); - int num = (int)(Math.random() * 300); - addCursors(num, manager); - Cursor<?> cursor = getHasMoreBatchCursor(); - int interestingId = manager.put(cursor); - num = (int)(Math.random() * 40); - addCursors(num, manager); - Cursor<?> actual = manager.get(interestingId); - assertSame(actual, cursor); - } - - @Test - public void testExpireCursors() { - Map<Integer, CursorHolder> cursors = new HashMap<>(); - long expiredTime = System.currentTimeMillis() - ( 5 * 60 * 1000); - long notExpiredTime = System.currentTimeMillis(); - cursors.put(3, new CursorHolder(mock(Cursor.class), expiredTime)); - cursors.put(4, new CursorHolder(mock(Cursor.class), expiredTime)); - cursors.put(5, new CursorHolder(mock(Cursor.class), notExpiredTime)); - cursors.put(7, new CursorHolder(mock(Cursor.class), expiredTime)); - CursorManager manager = new CursorManager(mock(TimerRegistry.class), cursors); - manager.expireCursors(); // should remove old cursors - assertEquals(1, cursors.keySet().size()); - assertNotNull(cursors.get(5)); - } - - @Test - public void testRemoveCursor() { - Map<Integer, CursorHolder> cursors = new HashMap<>(); - cursors.put(3, new CursorHolder(mock(Cursor.class), 3)); - cursors.put(4, new CursorHolder(mock(Cursor.class), 4)); - cursors.put(5, new CursorHolder(mock(Cursor.class), 5)); - CursorManager manager = new CursorManager(mock(TimerRegistry.class), cursors); - manager.removeCursor(3); - assertEquals(2, cursors.keySet().size()); - assertNotNull(cursors.get(4)); - assertNotNull(cursors.get(5)); - assertNull(cursors.get(3)); - } - - @Test - public void testUpdateCursorTimeStamp() { - Map<Integer, CursorHolder> cursors = new HashMap<>(); - long expiredTime = System.currentTimeMillis() - ( 5 * 60 * 1000); - long notExpiredTime = System.currentTimeMillis(); - cursors.put(4, new CursorHolder(mock(Cursor.class), expiredTime)); - cursors.put(5, new CursorHolder(mock(Cursor.class), notExpiredTime)); - cursors.put(7, new CursorHolder(mock(Cursor.class), expiredTime)); - CursorManager manager = new CursorManager(mock(TimerRegistry.class), cursors); - // refresh 4's timestamp so that it's now no longer expired - manager.updateCursorTimeStamp(4); - manager.expireCursors(); - assertEquals(2, cursors.keySet().size()); - assertNotNull("4 has been updated and is thus still alive", cursors.get(4)); - assertNotNull("5 was expired from the outset", cursors.get(5)); - } - - @Test - public void canStartSweeperTimerViaManager() { - TimerRegistry registry = mock(TimerRegistry.class); - CursorManager manager = new CursorManager(registry); - manager.startSweeperTimer(); - ArgumentCaptor<CursorTimer> timerCaptor = ArgumentCaptor.forClass(CursorTimer.class); - verify(registry).registerTimer(timerCaptor.capture()); - CursorTimer timer = timerCaptor.getValue(); - assertNotNull("expected non-null timer => timer thread started", timer); - assertTrue("startSweeperTimer() expected to schedule task", timer.taskScheduled); - } - - private void addCursors(int num, CursorManager manager) { - for (int i = 0; i < num; i++) { - manager.put(getHasMoreBatchCursor()); - } - } - - // CursorTimer tests - - @Test - public void testCursorTimerScheduleTask() { - TimerTask timerTask = mock(TimerTask.class); - Timer timer = mock(Timer.class); - CursorTimer cursorTimer = new CursorTimer(timerTask, timer); - long threeMinutes = 3 * 60 * 1000; - cursorTimer.scheduleTask(); - verify(timer).scheduleAtFixedRate(timerTask, 0, threeMinutes); - } - - @Test - public void testCursorTimerStop() { - TimerTask timerTask = mock(TimerTask.class); - Timer timer = mock(Timer.class); - CursorTimer cursorTimer = new CursorTimer(timerTask, timer); - cursorTimer.stop(); - verify(timer).cancel(); - } - - // CursorHolder tests - - @Test - public void testUpdateTimeStamp() { - long now = System.currentTimeMillis(); - CursorHolder holder = new CursorHolder(mock(Cursor.class), now); - sleep(10); - holder.updateTimestamp(); - assertTrue(now != holder.getLastUpdated()); - } - - @Test - public void testCheckIsCursorExpired() { - long now = 0; - CursorHolder holder = new CursorHolder(mock(Cursor.class), now); - long laterTime = 10; - assertFalse("cursor still valid. timeout == 20ms, but only 10ms old.", - holder.checkIsCursorExpired(laterTime, 20)); - assertTrue("cursor older than 5 milliseconds", holder.checkIsCursorExpired(laterTime, 5)); - } - - @Test - public void testGetCursor() { - long now = System.currentTimeMillis(); - Cursor<?> cursor = mock(Cursor.class); - CursorHolder holder = new CursorHolder(cursor, now); - assertSame(cursor, holder.getCursor()); - } - - private void sleep(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException e) { - // ignore - } - } - - // CursorSweeper tests - - public void testCursorSweeper() { - CursorManager manager = mock(CursorManager.class); - CursorSweeper sweeper = new CursorSweeper(manager); - sweeper.run(); - verify(manager).expireCursors(); - } - -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/KnownCategoryRegistryTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/* - * 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.web.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.HashSet; -import java.util.Set; -import java.util.TreeSet; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.auth.CategoryRegistration; - -public class KnownCategoryRegistryTest { - - private static final String DUPLICATE_CAT_NAME = "some-category"; - - @Test - public void canAddCategories() { - Set<String> categoryNames = new HashSet<>(); - categoryNames.add(DUPLICATE_CAT_NAME); // duplicate - categoryNames.add("some-other-category"); - Iterable<CategoryRegistration> regs = getRegs(categoryNames); - KnownCategoryRegistry reg = null; - try { - reg = new KnownCategoryRegistry(regs); - } catch (IllegalStateException e) { - // should not fail - fail(e.getMessage()); - } - Set<String> actualRegs = reg.getRegisteredCategoryNames(); - assertFalse(actualRegs.contains(null)); - assertEquals(2, actualRegs.size()); - for (String item: categoryNames) { - assertTrue(actualRegs.contains(item)); - } - } - - private Iterable<CategoryRegistration> getRegs(Set<String> categoryNames) { - Set<CategoryRegistration> regs = new HashSet<>(); - regs.add(new TestCategoryRegistration(categoryNames)); - Set<String> myDup = new HashSet<>(); - myDup.add(DUPLICATE_CAT_NAME); - regs.add(new TestCategoryRegistration(myDup)); - return regs; - } - - @Test - public void refuseToAddNullCategoryName() { - Set<String> categoryNames = new HashSet<>(); - categoryNames.add(null); - categoryNames.add("some-other-category"); - Iterable<CategoryRegistration> regs = getRegs(categoryNames); - try { - new KnownCategoryRegistry(regs); - fail("Should not reach here, null name added!"); - } catch (IllegalStateException e) { - // pass - } - } - - /** - * Tests that {@code set.contains(null)} does not throw exceptions since - * plug-ins may supply any {@link Set} implementation. {@link TreeSet} for - * example throws a NPE if such a check is attempted. - * - * See: http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2077 - */ - @Test - public void testNullCheckWithTreeSet() { - String categoryName = "foo-category"; - Set<String> descs = new TreeSet<>(); - descs.add(categoryName); - try { - descs.add(null); - fail("Expected NPE when adding null to TreeSet"); - } catch (NullPointerException e) { - // pre-condition passes - } - Iterable<CategoryRegistration> regs = getRegs(descs); - KnownCategoryRegistry registry = null; - try { - registry = new KnownCategoryRegistry(regs); - // pass - } catch (NullPointerException npe) { - npe.printStackTrace(); - fail("Should not have thrown NPE"); - } - assertTrue("category should be known", registry.getRegisteredCategoryNames().contains(categoryName)); - } - - @Test - public void canLoadRegistrationsInClasspath() { - KnownCategoryRegistry reg = new KnownCategoryRegistry(); - Set<String> actualRegs = reg.getRegisteredCategoryNames(); - assertNotNull(actualRegs); - // storage-core registers them. no-other modules in classpath. - assertEquals(6, actualRegs.size()); - } - - private static class TestCategoryRegistration implements CategoryRegistration { - - private final Set<String> catNames; - - private TestCategoryRegistration(Set<String> catNames) { - this.catNames = catNames; - } - - @Override - public Set<String> getCategoryNames() { - return catNames; - } - - } - -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,151 +0,0 @@ -/* - * 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.web.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.TreeSet; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; - -public class KnownDescriptorRegistryTest { - - @Test - public void canAddDescriptors() { - Set<String> descs = new HashSet<>(); - descs.add("QUERY test WHERE 'a' = ?s"); - descs.add("QUERY agent-config"); - Iterable<StatementDescriptorRegistration> regs = getRegs(descs); - KnownDescriptorRegistry reg = new KnownDescriptorRegistry(regs); - Set<String> registeredDescs = null; - try { - registeredDescs = reg.getRegisteredDescriptors(); - } catch (IllegalStateException e) { - fail(e.getMessage()); - } - assertNotNull(registeredDescs); - for (String d: registeredDescs) { - assertTrue(descs.contains(d)); - } - } - - @Test - public void testServiceLoadersInClassPath() { - KnownDescriptorRegistry reg = new KnownDescriptorRegistry(); - Set<String> trustedDescs = reg.getRegisteredDescriptors(); - assertNotNull(trustedDescs); - // storage-core registers 25 descriptors; this module has - // only storage-core as maven dep which registers queries. - // see DAOImplStatementDescriptorRegistration - assertEquals(25, trustedDescs.size()); - } - - /** - * Tests that {@code set.contains(null)} does not throw exceptions since - * plug-ins may supply any {@link Set} implementation. {@link TreeSet} for - * example throws a NPE if such a check is attempted. - * - * See: http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2077 - */ - @Test - public void testNullCheckWithTreeSet() { - String desc = "QUERY test WHERE 'a' = ?s"; - Set<String> descs = new TreeSet<>(); - descs.add(desc); - try { - descs.add(null); - fail("Expected NPE when adding null to TreeSet"); - } catch (NullPointerException e) { - // pre-condition passes - } - Iterable<StatementDescriptorRegistration> regs = getRegs(descs); - KnownDescriptorRegistry registry = null; - try { - registry = new KnownDescriptorRegistry(regs); - // pass - } catch (NullPointerException npe) { - npe.printStackTrace(); - fail("Should not have thrown NPE"); - } - assertTrue("descriptor should be known", registry.getRegisteredDescriptors().contains(desc)); - } - - @Test - public void cannotAddNullDescriptors() { - Set<String> descs = new HashSet<>(); - descs.add("QUERY test WHERE 'a' = ?s"); - descs.add(null); - Iterable<StatementDescriptorRegistration> regs = getRegs(descs); - try { - new KnownDescriptorRegistry(regs); - fail("Should not have accepted null descriptor"); - } catch (IllegalStateException e) { - assertEquals("null statement descriptor not acceptable!", e.getMessage()); - } - } - - private Iterable<StatementDescriptorRegistration> getRegs(Set<String> descs) { - StatementDescriptorRegistration reg = new TestStatementDescriptorRegistration( - descs); - StatementDescriptorRegistration[] regs = new StatementDescriptorRegistration[] { reg }; - return Arrays.asList(regs); - } - - private static class TestStatementDescriptorRegistration implements StatementDescriptorRegistration { - - private final Set<String> descs; - - private TestStatementDescriptorRegistration(Set<String> descs) { - this.descs = descs; - } - - @Override - public Set<String> getStatementDescriptors() { - return descs; - } - - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/PreparedStatementManagerTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,221 +0,0 @@ -/* - * 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.web.server; - -import java.util.UUID; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.web.common.SharedStateId; - -public class PreparedStatementManagerTest { - - /** - * Verify that every call to put creates a new ID entry only if - * statements (id'ed by descriptor) are different. - */ - @Test - public void canCreateAndPutStmt() { - PreparedStatementManager manager = new PreparedStatementManager(); - UUID serverToken = UUID.randomUUID(); - @SuppressWarnings("unchecked") - PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class); - @SuppressWarnings({ "unchecked" }) - StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(mock(Category.class), "unused"); - Class<TestPojo> testClass = TestPojo.class; - SharedStateId id = manager.createAndPutHolder(serverToken, targetStmt, testClass, testDesc); - assertNotNull(id); - assertEquals(serverToken, id.getServerToken()); - assertEquals("counter starts with 0", 0, id.getId()); - // do it again with a different statement - @SuppressWarnings("unchecked") - PreparedStatement<TestPojo> otherTargetStmt = mock(PreparedStatement.class); - @SuppressWarnings({ "unchecked" }) - StatementDescriptor<TestPojo> otherTestDesc = new StatementDescriptor<>(mock(Category.class), "other"); - SharedStateId otherId = manager.createAndPutHolder(serverToken, otherTargetStmt, testClass, otherTestDesc); - assertNotNull(otherId); - assertFalse(id.equals(otherId)); - assertEquals(1, otherId.getId()); - assertEquals(serverToken, otherId.getServerToken()); - // do it once more with same token, which should yield the same id than - // we used to get for the first createAndPutHolder() call. - SharedStateId thirdId = manager.createAndPutHolder(serverToken, targetStmt, testClass, testDesc); - assertEquals(id, thirdId); - assertSame(id, thirdId); - } - - /** - * Verify that adding a new value when the int ID would overflow throws an - * exception. - */ - @Test - public void intIdOverflowThrowsException() { - PreparedStatementManager manager = new PreparedStatementManager(Integer.MAX_VALUE - 1); - UUID serverNonce = UUID.randomUUID(); - @SuppressWarnings("unchecked") - PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class); - @SuppressWarnings({ "unchecked" }) - StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(mock(Category.class), "unused"); - Class<TestPojo> testClass = TestPojo.class; - try { - manager.createAndPutHolder(serverNonce, targetStmt, testClass, testDesc); - fail("Should have thrown ISE due to int id overflow"); - } catch (IllegalStateException e) { - assertEquals("Too many different statements!", e.getMessage()); - } - } - - /** - * Basic parameters must not be null. - */ - @Test - public void rejectsNullValuesAsParameters() { - PreparedStatementManager manager = new PreparedStatementManager(); - @SuppressWarnings("unchecked") - PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class); - @SuppressWarnings({ "unchecked" }) - StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(mock(Category.class), "unused"); - Class<TestPojo> testClass = TestPojo.class; - try { - manager.createAndPutHolder(null, targetStmt, testClass, testDesc); - fail("Expected NPE due to null server token"); - } catch (NullPointerException e) { - // pass - } - UUID serverNonce = UUID.randomUUID(); - try { - manager.createAndPutHolder(serverNonce, null, testClass, testDesc); - fail("Expected NPE due to null target stmt"); - } catch (NullPointerException e) { - // pass - } - try { - manager.createAndPutHolder(serverNonce, targetStmt, null, testDesc); - fail("Expected NPE due to null data class"); - } catch (NullPointerException e) { - // pass - } - try { - manager.createAndPutHolder(serverNonce, targetStmt, testClass, null); - fail("Expected NPE due to null stmt descriptor"); - } catch (NullPointerException e) { - // pass - } - } - - @Test - public void canGetAddedHolderItemViaID() { - PreparedStatementManager manager = new PreparedStatementManager(); - UUID serverNonce = UUID.randomUUID(); - @SuppressWarnings("unchecked") - PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class); - @SuppressWarnings({ "unchecked" }) - StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(mock(Category.class), "unused"); - Class<TestPojo> testClass = TestPojo.class; - SharedStateId id = manager.createAndPutHolder(serverNonce, targetStmt, testClass, testDesc); - PreparedStatementHolder<TestPojo> holder = manager.getStatementHolder(id); - assertNotNull(holder); - assertSame(serverNonce, holder.getId().getServerToken()); - assertSame(id, holder.getId()); - assertSame(targetStmt, holder.getStmt()); - assertSame(testClass, holder.getDataClass()); - assertSame(testDesc, holder.getStatementDescriptor()); - // do it again with an equal ID - SharedStateId retrievalId = new SharedStateId(0, serverNonce); - assertTrue(retrievalId.equals(id)); - holder = manager.getStatementHolder(retrievalId); - assertEquals(id, holder.getId()); - assertNotSame(retrievalId, holder.getId()); - assertSame(id, holder.getId()); - assertSame(targetStmt, holder.getStmt()); - assertSame(testClass, holder.getDataClass()); - assertSame(testDesc, holder.getStatementDescriptor()); - - // unknown server token should return null - assertNull(manager.getStatementHolder(new SharedStateId(0, UUID.randomUUID()))); - } - - @Test - public void canGetAddedHolderItemViaDescriptor() { - PreparedStatementManager manager = new PreparedStatementManager(); - UUID serverNonce = UUID.randomUUID(); - @SuppressWarnings("unchecked") - PreparedStatement<TestPojo> targetStmt = mock(PreparedStatement.class); - @SuppressWarnings({ "unchecked" }) - Category<TestPojo> cat = mock(Category.class); - StatementDescriptor<TestPojo> testDesc = new StatementDescriptor<>(cat, "no-matter"); - Class<TestPojo> testClass = TestPojo.class; - SharedStateId id = manager.createAndPutHolder(serverNonce, targetStmt, testClass, testDesc); - PreparedStatementHolder<TestPojo> holder = manager.getStatementHolder(testDesc); - assertNotNull(holder); - assertSame(serverNonce, holder.getId().getServerToken()); - assertSame(id, holder.getId()); - assertSame(targetStmt, holder.getStmt()); - assertSame(testClass, holder.getDataClass()); - assertSame(testDesc, holder.getStatementDescriptor()); - - // do it again with an equal descriptor - StatementDescriptor<TestPojo> equalDesc = new StatementDescriptor<>(cat, "no-matter"); - assertNotSame(testDesc, equalDesc); - assertEquals(testDesc, equalDesc); - holder = manager.getStatementHolder(equalDesc); - assertNotNull(holder); - assertSame(serverNonce, holder.getId().getServerToken()); - assertSame(id, holder.getId()); - assertSame(targetStmt, holder.getStmt()); - assertSame(testClass, holder.getDataClass()); - assertSame(testDesc, holder.getStatementDescriptor()); - } - - private static class TestPojo implements Pojo { - // nothing - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/PropertySettingServletContextListenerTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * 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.web.server; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; - -import org.junit.After; -import org.junit.Assume; -import org.junit.Test; - -import com.redhat.thermostat.common.Constants; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.mockito.Matchers.any; - -public class PropertySettingServletContextListenerTest { - - @After - public void tearDown() { - System.clearProperty("THERMOSTAT_HOME"); - System.clearProperty(Constants.IS_PROXIED_STORAGE); - } - - @Test - public void verifySetsProperty() { - Assume.assumeTrue(System.getenv("THERMOSTAT_HOME") == null); - PropertySettingServletContextListener listener = new PropertySettingServletContextListener(); - ServletContextEvent event = mock(ServletContextEvent.class); - ServletContext mockContext = mock(ServletContext.class); - when(event.getServletContext()).thenReturn(mockContext); - String fakeHome = "testing"; - when(mockContext.getInitParameter(any(String.class))).thenReturn(fakeHome); - listener.contextInitialized(event); - assertEquals(fakeHome, System.getProperty("THERMOSTAT_HOME")); - boolean isProxyStorage = Boolean.getBoolean(Constants.IS_PROXIED_STORAGE); - assertTrue("Expected to set proxied storage property", isProxyStorage); - } - - @Test - public void verifyClearsProperty() { - System.setProperty("THERMOSTAT_HOME", "somevalue"); - PropertySettingServletContextListener listener = new PropertySettingServletContextListener(); - listener.contextDestroyed(null); - assertNull(System.getProperty("THERMOSTAT_HOME")); - boolean isProxyStorage = Boolean.getBoolean(Constants.IS_PROXIED_STORAGE); - assertFalse("Expected context listener to clear proxied storage property", isProxyStorage); - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/TimerRegistryTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * 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.web.server; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import java.util.List; - -import org.junit.Test; - -public class TimerRegistryTest { - - @Test - public void canRegisterTimers() { - @SuppressWarnings("unchecked") - List<StoppableTimer> timers = mock(List.class); - TimerRegistry reg = new TimerRegistry(timers); - StoppableTimer mockTimer = mock(StoppableTimer.class); - reg.registerTimer(mockTimer); - verify(timers).add(mockTimer); - verifyNoMoreInteractions(timers); - } - - @Test - public void shutdownStopsTimers() { - TimerRegistry registry = new TimerRegistry(); - StoppableTimer mockTimer = mock(StoppableTimer.class); - StoppableTimer timer2 = mock(StoppableTimer.class); - registry.registerTimer(timer2); - registry.registerTimer(mockTimer); - registry.shutDown(); - verify(timer2).stop(); - verify(mockTimer).stop(); - verifyNoMoreInteractions(mockTimer); - verifyNoMoreInteractions(timer2); - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/TokenManagerTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ -/* - * 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.web.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Matchers.isA; - -import java.io.UnsupportedEncodingException; -import java.util.Arrays; -import java.util.Timer; -import java.util.TimerTask; - -import org.junit.Test; - -import com.redhat.thermostat.web.server.TokenManager.TokenManagerTimer; - -public class TokenManagerTest { - - /** - * Since we want to make sure that the action-name parameter for - * CMD channel interactions are trustworthy, we SHA256 hash the client - * token + the action name parameter, convert the resulting bytes into - * a hex string and finally put it into the tokens map. This way - * verification of the token should never pass if either the client token - * or the action-name was wrong. - * - * This test verifies that we have SHA256 hex-strings as keys. SHA256 hex - * strings are generated using the the client token first and then the - * action name for the digest. - */ - @Test - public void generateTokenTest() { - TokenManager tokenManager = new TokenManager(mock(TimerRegistry.class)); - String clientToken = "something"; - String action = "myAction"; - byte[] token = tokenManager.generateToken(clientToken.getBytes(), action); - String expectedKey = "8d51bc31b39f54a1a12f2f94f09371ad5afe2263c1fdb7a3785aaacea6a386ef"; - byte[] actualToken = tokenManager.getStoredToken(expectedKey); - assertNotNull(actualToken); - assertTrue(Arrays.equals(token, actualToken)); - } - - @Test - public void canConvertBytesToHexString() throws UnsupportedEncodingException { - byte[] expected = new byte[] { - (byte)0xff, 0x6f, 0x6d, 0x65, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x65, 0x48, 0x61, 0x73, 0x68 - }; - TokenManager tokenManager = new TokenManager(mock(TimerRegistry.class)); - String actual = tokenManager.convertBytesToHexString(expected); - assertEquals(expected.length * 2, actual.length()); - assertEquals("ff6f6d65537472696e67576548617368", actual); - } - - @Test - public void generateTokenCanNotBeReusedTest() { - TokenManager tokenManager = new TokenManager(mock(TimerRegistry.class)); - String clientToken = "something"; - String action = "myAction"; - byte[] token = tokenManager.generateToken(clientToken.getBytes(), action); - assertTrue(tokenManager.verifyToken(clientToken.getBytes(), token, action)); - // try again with same action name, which should not verify - assertFalse(tokenManager.verifyToken(clientToken.getBytes(), token, action)); - } - - @Test - public void generateAndVerifyTokenTest() { - TokenManager tokenManager = new TokenManager(mock(TimerRegistry.class)); - String clientToken = "something"; - String action = "myAction"; - byte[] token = tokenManager.generateToken(clientToken.getBytes(), action); - assertTrue(tokenManager.verifyToken(clientToken.getBytes(), token, action)); - // try again with different action name, which should not verify - String wrongAction = "someAction"; - assertFalse(tokenManager.verifyToken(clientToken.getBytes(), token, wrongAction)); - } - - @Test - public void instantiationRegistersTimer() { - TimerRegistry registry = mock(TimerRegistry.class); - new TokenManager(registry); - verify(registry).registerTimer(isA(TokenManagerTimer.class)); - registry = mock(TimerRegistry.class); - TokenManagerTimer timer = mock(TokenManagerTimer.class); - new TokenManager(registry, timer); - verify(registry).registerTimer(timer); - } - - // TokenManagerTimer tests - - @Test - public void tokenManagerTimerCanScheduleTasks() { - Timer mockTimer = mock(Timer.class); - TokenManagerTimer timer = new TokenManagerTimer(mockTimer); - TimerTask task = mock(TimerTask.class); - int timeout = -100; - timer.schedule(task, timeout); - verify(mockTimer).schedule(task, -100); - } - - @Test - public void tokenManagerTimerCanStopTimer() { - Timer mockTimer = mock(Timer.class); - TokenManagerTimer timer = new TokenManagerTimer(mockTimer); - timer.stop(); - verify(mockTimer).cancel(); - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndPointUnitTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ -/* - * 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.web.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; -import static org.mockito.Mockito.verify; -import static org.mockito.Matchers.eq; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.FileAttribute; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import com.redhat.thermostat.common.internal.test.Bug; -import com.redhat.thermostat.shared.config.OS; -import com.redhat.thermostat.storage.core.Storage; -import org.junit.After; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.shared.config.CommonPaths; -import com.redhat.thermostat.storage.core.StorageCredentials; -import com.redhat.thermostat.web.server.auth.WebStoragePathHandler; - -/** - * A test class for {@link WebStorageEndPoint}. It should contain tests for - * which we don't need the servlet deployed in a container. I.e. which are - * more of the unit-test nature (rather than of the functional test nature). - * - */ -public class WebStorageEndPointUnitTest { - - private static final String TH_HOME_PROP_NAME = "THERMOSTAT_HOME"; - - private StorageFactoryProvider storageFactoryProvider; - private StorageFactory storageFactory; - private Storage storage; - - @Before - public void setup() { - storage = mock(Storage.class); - storageFactory = mock(StorageFactory.class); - storageFactoryProvider = mock(StorageFactoryProvider.class); - - when(storageFactoryProvider.createStorageFactory()).thenReturn(storageFactory); - when(storageFactory.getStorage(anyString(), anyString(), any(CommonPaths.class), any(StorageCredentials.class))) - .thenReturn(storage); - } - - @After - public void tearDown() { - System.clearProperty(TH_HOME_PROP_NAME); - } - - /** - * Makes sure that all paths we dispatch to, dispatch to - * {@link WebStoragePathHandler} annotated methods. - * - * @throws Exception - */ - @Test - public void ensureAuthorizationCovered() throws Exception { - // manually maintained list of path handlers which should include - // authorization checks - final String[] authPaths = new String[] { - "prepare-statement", "query-execute", "write-execute", "register-category", - "save-file", "load-file", "purge", "ping", "generate-token", "verify-token", - "get-more" - }; - Map<String, Boolean> checkedAutPaths = new HashMap<>(); - for (String path: authPaths) { - checkedAutPaths.put(path, false); - } - int methodsReqAuthorization = 0; - for (Method method: WebStorageEndPoint.class.getDeclaredMethods()) { - if (method.isAnnotationPresent(WebStoragePathHandler.class)) { - methodsReqAuthorization++; - WebStoragePathHandler annot = method.getAnnotation(WebStoragePathHandler.class); - try { - // this may NPE if there is something funny going on in - // WebStorageEndPoint (e.g. one method annotated but this - // reference list has not been updated). - if (!checkedAutPaths.get(annot.path())) { - // mark path as covered - checkedAutPaths.put(annot.path(), true); - } else { - throw new AssertionError( - "method " - + method - + " annotated as web storage path handler (path '" - + annot.path() - + "'), but not in reference list we know about!"); - } - } catch (NullPointerException e) { - throw new AssertionError("Don't know about path '" - + annot.path() + "'"); - } - } - } - // at this point we should have all dispatched paths covered - for (String path: authPaths) { - assertTrue( - "Is " + path - + " marked with @WebStoragePathHandler and have proper authorization checks been included?", - checkedAutPaths.get(path)); - } - assertEquals(authPaths.length, methodsReqAuthorization); - } - - @Test - public void initThrowsRuntimeExceptionIfThermostatHomeNotSet() { - Assume.assumeTrue(System.getenv("THERMOSTAT_HOME") == null); - WebStorageEndPoint endpoint = new WebStorageEndPoint(); - ServletConfig config = mock(ServletConfig.class); - try { - endpoint.init(config); - fail("Thermostat home was not set in config, should not get here!"); - } catch (RuntimeException e) { - // pass - assertTrue(e.getMessage().contains(TH_HOME_PROP_NAME)); - } catch (ServletException e) { - fail(e.getMessage()); - } - // set config with non-existing dir - when(config.getInitParameter(TH_HOME_PROP_NAME)).thenReturn("not-existing"); - try { - endpoint.init(config); - fail("Thermostat home was set in config but file does not exist, should have died!"); - } catch (RuntimeException e) { - // pass - assertTrue(e.getMessage().contains(TH_HOME_PROP_NAME)); - } catch (ServletException e) { - fail(e.getMessage()); - } - } - - @Test - public void initThrowsRuntimeExceptionIfSSLPropertiesNotReadable() throws Exception { - Assume.assumeTrue(!OS.IS_WINDOWS); // Windows can't set directories non-readable - ThCreatorResult result = null; - try { - result = creatWorkingThermostatHome(); - // explicitly remove read perms from etc directory - result.etcDir.setExecutable(false); - assertFalse(result.sslProperties.canRead()); - - WebStorageEndPoint endpoint = new WebStorageEndPoint(); - System.setProperty(TH_HOME_PROP_NAME, result.thermostatHome.toFile().getAbsolutePath()); - try { - endpoint.init(mock(ServletConfig.class)); - fail("should have failed to initialize! can't read ssl.properties"); - } catch (RuntimeException e) { - assertTrue(e.getMessage().contains("ssl.properties")); - } - } finally { - result.etcDir.setExecutable(true); - if (result.thermostatHome != null) { - WebstorageEndpointTestUtils.deleteDirectoryRecursive(result.thermostatHome); - } - } - } - - @Test - public void initThrowsRuntimeExceptionIfSSLPropertiesDoesnotExist() throws Exception { - Path testThermostatHome = null; - try { - testThermostatHome = Files.createTempDirectory( - "bar-thermostat-home-", new FileAttribute[] {}); - File thFile = testThermostatHome.toFile(); - WebStorageEndPoint endpoint = new WebStorageEndPoint(); - System.setProperty(TH_HOME_PROP_NAME, thFile.getAbsolutePath()); - try { - endpoint.init(mock(ServletConfig.class)); - fail("should have failed to initialize, ssl.properties not existing!"); - } catch (RuntimeException e) { - assertTrue(e.getMessage().contains("ssl.properties")); - } - } finally { - if (testThermostatHome != null) { - WebstorageEndpointTestUtils.deleteDirectoryRecursive(testThermostatHome); - } - } - } - - /** - * Verifies that Servlet.init() sets servlet context attributes correctly. - * @throws ServletException - * @throws IOException - */ - @Test - public void testSetServletAttribute() throws ServletException, IOException { - final ServletContext mockContext = mock(ServletContext.class); - when(mockContext.getServerInfo()).thenReturn("jetty/9.1.0.v20131115"); - ConfigurationFinder finder = mock(ConfigurationFinder.class); - when(finder.getConfiguration(anyString())).thenReturn(mock(File.class)); - @SuppressWarnings("serial") - WebStorageEndPoint endpoint = new WebStorageEndPoint(null, null, finder, storageFactoryProvider) { - @Override - public ServletContext getServletContext() { - return mockContext; - } - }; - ServletConfig config = mock(ServletConfig.class); - when(config.getInitParameter(WebStorageEndPoint.STORAGE_CLASS)).thenReturn("fooKlazz"); // let it fail through - when(config.getInitParameter(WebStorageEndPoint.STORAGE_ENDPOINT)).thenReturn("fooEndPoint"); - ThCreatorResult result = creatWorkingThermostatHome(); - System.setProperty(TH_HOME_PROP_NAME, result.thermostatHome.toFile().getAbsolutePath()); - endpoint.init(config); - ArgumentCaptor<CategoryManager> categoryManagerCaptor = ArgumentCaptor.forClass(CategoryManager.class); - ArgumentCaptor<PreparedStatementManager> prepStmtManagerCaptor = ArgumentCaptor.forClass(PreparedStatementManager.class); - ArgumentCaptor<TokenManager> tokenManagerCaptor = ArgumentCaptor.forClass(TokenManager.class); - ArgumentCaptor<UUID> serverTokenCaptor = ArgumentCaptor.forClass(UUID.class); - verify(mockContext).setAttribute(eq("category-manager"), categoryManagerCaptor.capture()); - verify(mockContext).setAttribute(eq("prepared-stmt-manager"), prepStmtManagerCaptor.capture()); - verify(mockContext).setAttribute(eq("token-manager"), tokenManagerCaptor.capture()); - verify(mockContext).setAttribute(eq("server-token"), serverTokenCaptor.capture()); - assertNotNull(categoryManagerCaptor.getValue()); - assertNotNull(prepStmtManagerCaptor.getValue()); - assertNotNull(tokenManagerCaptor.getValue()); - assertNotNull(serverTokenCaptor.getValue()); - } - - @Test - public void testShutDownCancelsTimers() { - TimerRegistry registry = mock(TimerRegistry.class); - WebStorageEndPoint endpoint = new WebStorageEndPoint(registry, null, null, storageFactoryProvider); - endpoint.destroy(); - verify(registry).shutDown(); - } - - /** - * If storage credentials are not found then null is expected to get returned. - */ - @Test - public void storageCredentialsNull() throws IOException { - CommonPaths paths = mock(CommonPaths.class); - TimerRegistry registry = mock(TimerRegistry.class); - ConfigurationFinder finder = mock(ConfigurationFinder.class); - when(finder.getConfiguration("web.auth")).thenReturn(null); - - WebStorageEndPoint endpoint = new WebStorageEndPoint(registry, paths, finder, storageFactoryProvider); - StorageCredentials creds = endpoint.getStorageCredentials(); - - assertNull(creds); - } - - @Test - @Bug(id = "PR2941", - url = "http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2941", - summary = "Concurrent webstorage connections may cause storage exceptions") - public void testStorageIsCreatedOnceOnInit() throws Exception { - final ServletContext mockContext = mock(ServletContext.class); - when(mockContext.getServerInfo()).thenReturn("jetty/9.1.0.v20131115"); - ConfigurationFinder finder = mock(ConfigurationFinder.class); - when(finder.getConfiguration(anyString())).thenReturn(mock(File.class)); - @SuppressWarnings("serial") - WebStorageEndPoint endpoint = new WebStorageEndPoint(null, null, finder, storageFactoryProvider) { - @Override - public ServletContext getServletContext() { - return mockContext; - } - }; - ServletConfig config = mock(ServletConfig.class); - when(config.getInitParameter(WebStorageEndPoint.STORAGE_CLASS)).thenReturn("fooKlazz"); // let it fail through - when(config.getInitParameter(WebStorageEndPoint.STORAGE_ENDPOINT)).thenReturn("fooEndPoint"); - ThCreatorResult result = creatWorkingThermostatHome(); - System.setProperty(TH_HOME_PROP_NAME, result.thermostatHome.toFile().getAbsolutePath()); - - // not created yet - verifyZeroInteractions(storageFactoryProvider); - verifyZeroInteractions(storageFactory); - - endpoint.init(mock(ServletConfig.class)); - - // created once - verify(storageFactoryProvider).createStorageFactory(); - verify(storageFactory).getStorage(anyString(), anyString(), any(CommonPaths.class), any(StorageCredentials.class)); - - endpoint.init(mock(ServletConfig.class)); - - // still only once - verify(storageFactoryProvider).createStorageFactory(); - verify(storageFactory).getStorage(anyString(), anyString(), any(CommonPaths.class), any(StorageCredentials.class)); - } - - private ThCreatorResult creatWorkingThermostatHome() throws IOException { - Path testThermostatHome = Files.createTempDirectory( - "foo-thermostat-home-", new FileAttribute[] {}); - File thFile = testThermostatHome.toFile(); - File etcDir = new File(thFile, "etc"); - etcDir.mkdir(); - assertTrue(etcDir.exists()); - assertTrue(etcDir.canWrite()); - File sslProperties = new File(etcDir, "ssl.properties"); - sslProperties.createNewFile(); - assertTrue(sslProperties.canRead()); - return new ThCreatorResult(testThermostatHome, etcDir, sslProperties); - } - - private static class ThCreatorResult { - private final Path thermostatHome; - private final File etcDir; - private final File sslProperties; - - ThCreatorResult(Path thermostatHome, File etcFile, File sslProperties) { - this.thermostatHome = thermostatHome; - this.etcDir = etcFile; - this.sslProperties = sslProperties; - } - } - -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1836 +0,0 @@ -/* - * 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.web.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Type; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.ProtocolException; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.file.Path; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; -import javax.security.auth.login.Configuration; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.codec.binary.Base64; -import org.eclipse.jetty.jaas.JAASLoginService; -import org.eclipse.jetty.security.DefaultUserIdentity; -import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.MappedLoginService; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.UserIdentity; -import org.eclipse.jetty.util.component.LifeCycle; -import org.eclipse.jetty.util.component.LifeCycle.Listener; -import org.eclipse.jetty.util.security.Password; -import org.eclipse.jetty.webapp.WebAppContext; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.reflect.TypeToken; -import com.redhat.thermostat.common.internal.test.FreePortFinder; -import com.redhat.thermostat.common.internal.test.FreePortFinder.TryPort; -import com.redhat.thermostat.storage.core.Add; -import com.redhat.thermostat.storage.core.AggregateQuery; -import com.redhat.thermostat.storage.core.AggregateQuery.AggregateFunction; -import com.redhat.thermostat.storage.core.BackingStorage; -import com.redhat.thermostat.storage.core.Categories; -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.CategoryAdapter; -import com.redhat.thermostat.storage.core.CloseOnSave; -import com.redhat.thermostat.storage.core.Cursor; -import com.redhat.thermostat.storage.core.Entity; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.ParsedStatement; -import com.redhat.thermostat.storage.core.Persist; -import com.redhat.thermostat.storage.core.PreparedParameter; -import com.redhat.thermostat.storage.core.PreparedStatement; -import com.redhat.thermostat.storage.core.Query; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.auth.CategoryRegistration; -import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; -import com.redhat.thermostat.storage.dao.HostInfoDAO; -import com.redhat.thermostat.storage.model.AggregateCount; -import com.redhat.thermostat.storage.model.BasePojo; -import com.redhat.thermostat.storage.model.HostInfo; -import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.common.PreparedStatementResponseCode; -import com.redhat.thermostat.web.common.SharedStateId; -import com.redhat.thermostat.web.common.WebPreparedStatement; -import com.redhat.thermostat.web.common.WebPreparedStatementResponse; -import com.redhat.thermostat.web.common.WebQueryResponse; -import com.redhat.thermostat.web.common.typeadapters.PojoTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParameterTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.PreparedParametersTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.SharedStateIdTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementResponseTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebPreparedStatementTypeAdapterFactory; -import com.redhat.thermostat.web.common.typeadapters.WebQueryResponseTypeAdapterFactory; -import com.redhat.thermostat.web.server.auth.BasicRole; -import com.redhat.thermostat.web.server.auth.RolePrincipal; -import com.redhat.thermostat.web.server.auth.Roles; -import com.redhat.thermostat.web.server.auth.UserPrincipal; - -public class WebStorageEndpointTest { - - @Entity - public static class TestClass extends BasePojo { - - public TestClass() { - super(null); - } - - private String key1; - private int key2; - @Persist - public String getKey1() { - return key1; - } - @Persist - public void setKey1(String key1) { - this.key1 = key1; - } - @Persist - public int getKey2() { - return key2; - } - @Persist - public void setKey2(int key2) { - this.key2 = key2; - } - public boolean equals(Object o) { - if (! (o instanceof TestClass)) { - return false; - } - TestClass other = (TestClass) o; - return key1.equals(other.key1) && key2 == other.key2; - } - } - - private Server server; - private int port; - private BackingStorage mockStorage; - - private static Key<String> key1; - private static Key<Integer> key2; - private static Category<TestClass> category; - private static String categoryName = "test"; - private static File testThermostatHome; - - @BeforeClass - public static void setupCategory() { - key1 = new Key<>("key1"); - key2 = new Key<>("key2"); - category = new Category<>(categoryName, TestClass.class, key1, key2); - } - - @AfterClass - public static void cleanupCategory() { - Categories.remove(category); - category = null; - key2 = null; - key1 = null; - - if (testThermostatHome != null) { - Path testTh = testThermostatHome.toPath(); - try { - WebstorageEndpointTestUtils.deleteDirectoryRecursive(testTh); - } catch (IOException e) { - e.printStackTrace(System.err); - } - } - } - - @Before - public void setUp() throws Exception { - - mockStorage = mock(BackingStorage.class); - StorageFactoryImpl.setStorage(mockStorage); - } - - private void startServer(int port, LoginService loginService) throws Exception { - server = new Server(port); - // This makes the test use the web.xml in src/main/webapp. That's - // also where the test's thermostat home is set up via - // the context listener. THERMOSTAT_HOME == /tmp/test-thermostat-home - // See src/main/webapp/WEB-INF/web.xml - final WebAppContext ctx = new WebAppContext("src/main/webapp", "/"); - ctx.getSecurityHandler().setLoginService(loginService); - // We get access to the THERMOSTAT_HOME value once the context has - // been started. - ctx.addLifeCycleListener(new Listener() { - - @Override - public void lifeCycleFailure(LifeCycle arg0, Throwable arg1) { - // nothing - } - - @Override - public void lifeCycleStarted(LifeCycle arg0) { - // In Servlet.init() we check if ssl.properties exists. We need - // to create that file in order for the tests to get past this - // check. - File thermostatHome = new File(ctx.getInitParameter("THERMOSTAT_HOME")); - if (testThermostatHome == null) { - testThermostatHome = thermostatHome; - } - if (!thermostatHome.exists()) { - thermostatHome.mkdir(); - } - File configDirectory = new File(thermostatHome, "etc"); - if (!configDirectory.exists()) { - configDirectory.mkdir(); - } - File sslProperties = new File(configDirectory, "ssl.properties"); - // only creates file if it doesn't exist yet - try { - sslProperties.createNewFile(); - } catch (IOException e) { - throw new RuntimeException(e); - } - File webAuthFile = new File(configDirectory, "web.auth"); - // only creates file if it doesn't exist yet - try { - webAuthFile.createNewFile(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public void lifeCycleStarting(LifeCycle arg0) { - // nothing - } - - @Override - public void lifeCycleStopped(LifeCycle arg0) { - // nothing - } - - @Override - public void lifeCycleStopping(LifeCycle arg0) { - // nothing - } - - }); - server.setHandler(ctx); - server.start(); - } - - @After - public void tearDown() throws Exception { - - // some tests don't use server - if (server != null) { - server.stop(); - server.join(); - } - KnownCategoryRegistryFactory.setInstance(null); - KnownDescriptorRegistryFactory.setKnownDescriptorRegistry(null); - } - - @Test - public void authorizedPrepareQueryWithUnTrustedDescriptor() throws Exception { - String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42"; - // setup a statement descriptor set so as to mimic a not trusted desc - String wrongDescriptor = "QUERY something-other WHERE 'a' = true"; - setupTrustedStatementRegistry(wrongDescriptor); - - String[] roleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.PREPARE_STATEMENT, - Roles.ACCESS_REALM, - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - SharedStateId catId = registerCategoryAndGetId(category, testuser, password); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/prepare-statement"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setDoInput(true); - conn.setDoOutput(true); - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .create(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId); - out.write(body + "\n"); - out.flush(); - - Reader in = new InputStreamReader(conn.getInputStream()); - WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class); - assertEquals("descriptor not trusted, so expected number should be negative!", -1, response.getNumFreeVariables()); - assertEquals(WebPreparedStatementResponse.ILLEGAL_STATEMENT, response.getStatementId().getId()); - assertEquals("application/json; charset=UTF-8", conn.getContentType()); - } - - /** - * Tests a successful query execution, starting from preparing the query, - * then executing the query and finally getting more results for the query. - * - * @throws Exception - * - * @see {@link #authorizedPrepareQueryWithTrustedDescriptorGetMoreFail()} - */ - @SuppressWarnings({ "rawtypes" }) - @Test - public void authorizedPrepareQueryWithTrustedDescriptorSuccessfulGetMore() throws Exception { - // Get the trusted descriptor - String strDescriptor = setupPreparedQueryWithTrustedDescriptor(); - SharedStateId catId = registerCategoryAndGetId(category, "ignored1", "ignored2"); - - // Prepare the query - boolean moreBatches = true; - TrustedPreparedQueryTestResult prepareQueryResult = prepareQuery(catId, strDescriptor, moreBatches); - - Type typeToken = new TypeToken<WebQueryResponse<TestClass>>(){}.getType(); - - WebPreparedStatement<TestClass> stmt = new WebPreparedStatement<>(1, prepareQueryResult.stmtId); - stmt.setString(0, "fluff"); - - // Execute the query, preserver the cookie - String cookieValue = executeQuery(prepareQueryResult.gson, prepareQueryResult.mockMongoQuery, typeToken, stmt, moreBatches); - - // Simulate getting more elements - int cursorId = 0; - int batchSize = 3; - // stub the underlying cursor so that it can fill up a single batch (3) - // and leaves one element more => 3 + 1. - when(prepareQueryResult.cursor.hasNext()).thenReturn(true) // 1 - .thenReturn(true) // 2 - .thenReturn(true) // 3 - .thenReturn(true) // 4 - .thenReturn(false); - - - when(prepareQueryResult.cursor.next()) - .thenReturn(new TestClass()) // 1 - .thenReturn(new TestClass()) // 2 - .thenReturn(new TestClass()) // 3 - .thenReturn(new TestClass()) // 4 - .thenReturn(null); - when(prepareQueryResult.cursor.getBatchSize()).thenReturn(batchSize); - URL url = new URL(getEndpoint() + "/get-more"); - HttpURLConnection getMoreConn = (HttpURLConnection) url.openConnection(); - getMoreConn.setRequestMethod("POST"); - setCookie(getMoreConn, cookieValue); - sendAuthentication(getMoreConn, "ignored1", "ignored2"); - getMoreConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - getMoreConn.setDoInput(true); - getMoreConn.setDoOutput(true); - - OutputStreamWriter out = new OutputStreamWriter(getMoreConn.getOutputStream()); - String body = "prepared-stmt-id=" + URLEncoder.encode(prepareQueryResult.gson.toJson(stmt.getStatementId()), "UTF-8") + "&"; - body += "cursor-id=" + cursorId + "&"; - body += "batch-size=" + batchSize; - out.write(body); - out.flush(); - - InputStreamReader in = new InputStreamReader(getMoreConn.getInputStream()); - WebQueryResponse result = prepareQueryResult.gson.fromJson(in, typeToken); - assertEquals(3, result.getResultList().length); - assertEquals(cursorId, result.getCursorId()); - assertTrue("There was one more result than the batch size", result.hasMoreBatches()); - assertEquals("application/json; charset=UTF-8", getMoreConn.getContentType()); - // expected setBatchSize to be called via get-more request - verify(prepareQueryResult.cursor).setBatchSize(batchSize); - } - - /** - * Tests authorized prepared query which attempts to do a get-more but does - * not have a cursor in the user's cursor manager. - * - * @throws Exception - * - * @see {@link #authorizedPrepareQueryWithTrustedDescriptorSuccessfulGetMore} - */ - @SuppressWarnings({ "rawtypes" }) - @Test - public void authorizedPrepareQueryWithTrustedDescriptorGetMoreFail() throws Exception { - // Get the trusted descriptor - String strDescriptor = setupPreparedQueryWithTrustedDescriptor(); - SharedStateId catId = registerCategoryAndGetId(category, "ignored1", "ignored2"); - - // Prepare the query - boolean moreBatches = false; - TrustedPreparedQueryTestResult prepareQueryResult = prepareQuery(catId, strDescriptor, moreBatches); - - Type typeToken = new TypeToken<WebQueryResponse<TestClass>>(){}.getType(); - - WebPreparedStatement<TestClass> stmt = new WebPreparedStatement<>(1, prepareQueryResult.stmtId); - stmt.setString(0, "fluff"); - - // Execute the query, preserver the cookie - String cookieValue = executeQuery(prepareQueryResult.gson, prepareQueryResult.mockMongoQuery, typeToken, stmt, moreBatches); - - // Simulate getting more elements - int cursorId = 0; - int batchSize = 3; - // stub the underlying cursor so that it can fill up a single batch (3) - // and leaves one element more => 3 + 1. - when(prepareQueryResult.cursor.hasNext()).thenReturn(true) // 1 - .thenReturn(true) // 2 - .thenReturn(true) // 3 - .thenReturn(false) // 4 - .thenReturn(false); - - - when(prepareQueryResult.cursor.next()) - .thenReturn(new TestClass()) // 1 - .thenReturn(new TestClass()) // 2 - .thenReturn(new TestClass()) // 3 - .thenReturn(null) // 4 - .thenReturn(null); - when(prepareQueryResult.cursor.getBatchSize()).thenReturn(batchSize); - URL url = new URL(getEndpoint() + "/get-more"); - HttpURLConnection getMoreConn = (HttpURLConnection) url.openConnection(); - getMoreConn.setRequestMethod("POST"); - setCookie(getMoreConn, cookieValue); - sendAuthentication(getMoreConn, "ignored1", "ignored2"); - getMoreConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - getMoreConn.setDoInput(true); - getMoreConn.setDoOutput(true); - - OutputStreamWriter out = new OutputStreamWriter(getMoreConn.getOutputStream()); - String body = "prepared-stmt-id=" + URLEncoder.encode(prepareQueryResult.gson.toJson(stmt.getStatementId()), "UTF-8") + "&"; - body += "cursor-id=" + cursorId + "&"; - body += "batch-size=" + batchSize; - out.write(body); - out.flush(); - - InputStreamReader in = new InputStreamReader(getMoreConn.getInputStream()); - WebQueryResponse result = prepareQueryResult.gson.fromJson(in, typeToken); - assertEquals(PreparedStatementResponseCode.GET_MORE_NULL_CURSOR, result.getResponseCode()); - assertNotNull(result.getResultList()); - assertEquals(0, result.getResultList().length); - assertEquals(cursorId, result.getCursorId()); - assertFalse("This is a failure response, no more batches", result.hasMoreBatches()); - assertEquals("application/json; charset=UTF-8", getMoreConn.getContentType()); - } - - private String executeQuery(Gson gson, Query<TestClass> mockMongoQuery, - Type typeToken, WebPreparedStatement<TestClass> stmt, boolean moreBatches) - throws MalformedURLException, IOException, ProtocolException { - URL url = new URL(getEndpoint() + "/query-execute"); - HttpURLConnection queryExecuteConn = (HttpURLConnection) url.openConnection(); - queryExecuteConn.setRequestMethod("POST"); - sendAuthentication(queryExecuteConn, "ignored1", "ignored2"); - queryExecuteConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - queryExecuteConn.setDoInput(true); - queryExecuteConn.setDoOutput(true); - - OutputStreamWriter out = new OutputStreamWriter(queryExecuteConn.getOutputStream()); - String body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class); - out.write(body + "\n"); - out.flush(); - - String cookieValue = queryExecuteConn.getHeaderField("Set-Cookie"); - InputStreamReader in = new InputStreamReader(queryExecuteConn.getInputStream()); - WebQueryResponse<TestClass> result = gson.fromJson(in, typeToken); - assertEquals("Expected more batches", moreBatches, result.hasMoreBatches()); - TestClass[] results = result.getResultList(); - assertEquals(2, results.length); - assertEquals("fluff1", results[0].getKey1()); - assertEquals(42, results[0].getKey2()); - assertEquals("fluff2", results[1].getKey1()); - assertEquals(43, results[1].getKey2()); - - assertEquals("application/json; charset=UTF-8", queryExecuteConn.getContentType()); - verify(mockMongoQuery).execute(); - verify(mockMongoQuery).getWhereExpression(); - verifyNoMoreInteractions(mockMongoQuery); - return cookieValue; - } - - private static class TrustedPreparedQueryTestResult { - - private final Gson gson; - private final Query<TestClass> mockMongoQuery; - private final Cursor<TestClass> cursor; - private final SharedStateId stmtId; - - private TrustedPreparedQueryTestResult(Gson gson, Query<TestClass> mockMongoQuery, Cursor<TestClass> cursor, SharedStateId stmtId) { - this.cursor = cursor; - this.gson = gson; - this.mockMongoQuery = mockMongoQuery; - this.stmtId = stmtId; - } - } - - @SuppressWarnings("unchecked") - private TrustedPreparedQueryTestResult prepareQuery(SharedStateId catId, String strDescriptor, boolean moreBatches) throws Exception { - TestClass expected1 = new TestClass(); - expected1.setKey1("fluff1"); - expected1.setKey2(42); - TestClass expected2 = new TestClass(); - expected2.setKey1("fluff2"); - expected2.setKey2(43); - // prepare-statement does this under the hood - Query<TestClass> mockMongoQuery = mock(Query.class); - when(mockStorage.createQuery(eq(category))).thenReturn(mockMongoQuery); - - Cursor<TestClass> cursor = mock(Cursor.class); - WebStorageEndPoint.DEFAULT_QUERY_BATCH_SIZE = 2; - // Assuming: moreBatches == true then we have - // WebStorageEndpoint.getBatchFromCursor() method calls hasNext() twice, - // CursorManager.put() calls it once and WebStorageEndpoint.queryExecute() - // calls it once. Thus, 2 + 1 + 1 = 4 x true, then return false; - when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(moreBatches).thenReturn(moreBatches).thenReturn(false); - when(cursor.next()).thenReturn(expected1).thenReturn(expected2); - - PreparedStatement<TestClass> mockPreparedQuery = mock(PreparedStatement.class); - when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery); - - ParsedStatement<TestClass> mockParsedStatement = mock(ParsedStatement.class); - when(mockParsedStatement.getNumParams()).thenReturn(1); - when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoQuery); - when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement); - - // The web layer - when(mockPreparedQuery.executeQuery()).thenReturn(cursor); - // And the mongo layer - when(mockMongoQuery.execute()).thenReturn(cursor); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/prepare-statement"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, "ignored1", "ignored2"); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setDoInput(true); - conn.setDoOutput(true); - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId); - out.write(body + "\n"); - out.flush(); - - Reader in = new InputStreamReader(conn.getInputStream()); - WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class); - assertEquals(1, response.getNumFreeVariables()); - assertEquals(0, response.getStatementId().getId()); - assertEquals("application/json; charset=UTF-8", conn.getContentType()); - - return new TrustedPreparedQueryTestResult(gson, mockMongoQuery, cursor, response.getStatementId()); - } - - private String setupPreparedQueryWithTrustedDescriptor() throws Exception { - String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42"; - // metadata which basically does no filtering. There's another test which - // asserts only allowed data (via ACL) gets returned. - setupTrustedStatementRegistry(strDescriptor); - - Set<BasicRole> roles = new HashSet<>(); - roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY)); - roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT)); - roles.add(new RolePrincipal(Roles.READ)); - roles.add(new RolePrincipal(Roles.ACCESS_REALM)); - UserPrincipal testUser = new UserPrincipal("ignored1"); - testUser.setRoles(roles); - - final JAASLoginService loginService = getConfiguredLoginService(testUser, roles); - - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - return strDescriptor; - } - - /* - * - * This test simulates a case where the mongo query would return more than - * a user can see. In this case only records matching agentIds which are - * allowed via roles should get returned. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Test - public void authorizedFilteredQuery() throws Exception { - Category oldCategory = category; - String categoryName = "test-authorizedFilteredQuery"; - // redefine category to include the agentId key in the category. - // undone via a the try-finally block. - category = new Category(categoryName, TestClass.class, key1, key2, Key.AGENT_ID); - try { - String strDescriptor = "QUERY " + category.getName() + " WHERE '" + - key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42"; - setupTrustedStatementRegistry(strDescriptor); - - Set<BasicRole> roles = new HashSet<>(); - roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY)); - roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT)); - roles.add(new RolePrincipal(Roles.READ)); - roles.add(new RolePrincipal(Roles.ACCESS_REALM)); - String fakeAgentId = "someAgentId"; - roles.add(new RolePrincipal("thermostat-agents-grant-read-agentId-" + fakeAgentId)); - UserPrincipal testUser = new UserPrincipal("ignored1"); - testUser.setRoles(roles); - - final JAASLoginService loginService = getConfiguredLoginService(testUser, roles); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - SharedStateId catId = registerCategoryAndGetId(category, "ignored1", "ignored2"); - - TestClass expected1 = new TestClass(); - expected1.setKey1("fluff1"); - expected1.setKey2(42); - TestClass expected2 = new TestClass(); - expected2.setKey1("fluff2"); - expected2.setKey2(43); - // prepare-statement does this under the hood - Query<TestClass> mockMongoQuery = mock(Query.class); - - when(mockStorage.createQuery(eq(category))).thenReturn(mockMongoQuery); - - Cursor<TestClass> cursor = mock(Cursor.class); - when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false); - when(cursor.next()).thenReturn(expected1).thenReturn(expected2); - - PreparedStatement mockPreparedQuery = mock(PreparedStatement.class); - when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery); - - ParsedStatement mockParsedStatement = mock(ParsedStatement.class); - when(mockParsedStatement.getNumParams()).thenReturn(1); - when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoQuery); - when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement); - - // The web layer - when(mockPreparedQuery.executeQuery()).thenReturn(cursor); - // And the mongo layer - when(mockMongoQuery.execute()).thenReturn(cursor); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/prepare-statement"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, "ignored1", "ignored2"); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setDoInput(true); - conn.setDoOutput(true); - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId); - out.write(body + "\n"); - out.flush(); - - Reader in = new InputStreamReader(conn.getInputStream()); - WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class); - assertEquals(1, response.getNumFreeVariables()); - assertEquals(0, response.getStatementId().getId()); - assertEquals("application/json; charset=UTF-8", conn.getContentType()); - - - - // now execute the query we've just prepared - WebPreparedStatement<TestClass> stmt = new WebPreparedStatement<>(1, response.getStatementId()); - stmt.setString(0, "fluff"); - - url = new URL(endpoint + "/query-execute"); - HttpURLConnection conn2 = (HttpURLConnection) url.openConnection(); - conn2.setRequestMethod("POST"); - sendAuthentication(conn2, "ignored1", "ignored2"); - conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn2.setDoInput(true); - conn2.setDoOutput(true); - - out = new OutputStreamWriter(conn2.getOutputStream()); - body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class); - out.write(body + "\n"); - out.flush(); - - in = new InputStreamReader(conn2.getInputStream()); - Type typeToken = new TypeToken<WebQueryResponse<TestClass>>(){}.getType(); - WebQueryResponse<TestClass> result = gson.fromJson(in, typeToken); - TestClass[] results = result.getResultList(); - assertEquals(2, results.length); - assertEquals("fluff1", results[0].getKey1()); - assertEquals(42, results[0].getKey2()); - assertEquals("fluff2", results[1].getKey1()); - assertEquals(43, results[1].getKey2()); - - assertEquals("application/json; charset=UTF-8", conn2.getContentType()); - verify(mockMongoQuery).execute(); - verify(mockMongoQuery).getWhereExpression(); - ArgumentCaptor<Expression> expressionCaptor = ArgumentCaptor.forClass(Expression.class); - verify(mockMongoQuery).where(expressionCaptor.capture()); - verifyNoMoreInteractions(mockMongoQuery); - - Expression capturedExpression = expressionCaptor.getValue(); - assertTrue(capturedExpression instanceof BinarySetMembershipExpression); - Set<String> agentIds = new HashSet<>(); - agentIds.add(fakeAgentId); - Expression expectedExpression = new ExpressionFactory().in(Key.AGENT_ID, agentIds, String.class); - assertEquals(expectedExpression, capturedExpression); - } finally { - category = oldCategory; - } - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Test - public void authorizedPreparedAggregateQuery() throws Exception { - String strDescriptor = "QUERY-COUNT " + category.getName(); - setupTrustedStatementRegistry(strDescriptor); - - Set<BasicRole> roles = new HashSet<>(); - roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY)); - roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT)); - roles.add(new RolePrincipal(Roles.READ)); - roles.add(new RolePrincipal(Roles.ACCESS_REALM)); - UserPrincipal testUser = new UserPrincipal("ignored1"); - testUser.setRoles(roles); - - final JAASLoginService loginService = getConfiguredLoginService(testUser, roles); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - - AggregateCount count = new AggregateCount(); - count.setCount(500); - // prepare-statement does this under the hood - AggregateQuery<AggregateCount> mockMongoQuery = mock(AggregateQuery.class); - Category<AggregateCount> adapted = new CategoryAdapter(category).getAdapted(AggregateCount.class); - SharedStateId catId = registerCategoryAndGetId(adapted, "no-matter", "no-matter"); - when(mockStorage.createAggregateQuery(eq(AggregateFunction.COUNT), eq(adapted))).thenReturn(mockMongoQuery); - - Cursor<AggregateCount> cursor = mock(Cursor.class); - when(cursor.hasNext()).thenReturn(true).thenReturn(false); - when(cursor.next()).thenReturn(count); - - PreparedStatement mockPreparedQuery = mock(PreparedStatement.class); - when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery); - - ParsedStatement mockParsedStatement = mock(ParsedStatement.class); - when(mockParsedStatement.getNumParams()).thenReturn(0); - when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoQuery); - when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement); - - // The web layer - when(mockPreparedQuery.executeQuery()).thenReturn(cursor); - // And the mongo layer - when(mockMongoQuery.execute()).thenReturn(cursor); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/prepare-statement"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, "no-matter", "no-matter"); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setDoInput(true); - conn.setDoOutput(true); - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebQueryResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId); - out.write(body + "\n"); - out.flush(); - - Reader in = new InputStreamReader(conn.getInputStream()); - WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class); - assertEquals(0, response.getNumFreeVariables()); - assertEquals(0, response.getStatementId().getId()); - assertEquals("application/json; charset=UTF-8", conn.getContentType()); - - - - // now execute the query we've just prepared - WebPreparedStatement<AggregateCount> stmt = new WebPreparedStatement<>(0, response.getStatementId()); - - url = new URL(endpoint + "/query-execute"); - HttpURLConnection conn2 = (HttpURLConnection) url.openConnection(); - conn2.setRequestMethod("POST"); - sendAuthentication(conn2, "no-matter", "no-matter"); - conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn2.setDoInput(true); - conn2.setDoOutput(true); - - out = new OutputStreamWriter(conn2.getOutputStream()); - body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class); - out.write(body + "\n"); - out.flush(); - - in = new InputStreamReader(conn2.getInputStream()); - Type typeToken = new TypeToken<WebQueryResponse<AggregateCount>>(){}.getType(); - WebQueryResponse<AggregateCount> result = gson.fromJson(in, typeToken); - AggregateCount[] results = result.getResultList(); - assertEquals(1, results.length); - assertEquals(500, results[0].getCount()); - - assertEquals("application/json; charset=UTF-8", conn2.getContentType()); - verify(mockMongoQuery).execute(); - verify(mockMongoQuery).getWhereExpression(); - verifyNoMoreInteractions(mockMongoQuery); - } - - private void setupTrustedCategory(String categoryName) { - Set<String> descs = new HashSet<>(); - descs.add(categoryName); - CategoryRegistration reg = mock(CategoryRegistration.class); - when(reg.getCategoryNames()).thenReturn(descs); - List<CategoryRegistration> regs = new ArrayList<>(1); - regs.add(reg); - KnownCategoryRegistry registry = new KnownCategoryRegistry(regs); - KnownCategoryRegistryFactory.setInstance(registry); - } - - private void setupTrustedStatementRegistry(String strDescriptor) { - Set<String> descs = new HashSet<>(); - descs.add(strDescriptor); - StatementDescriptorRegistration reg = new TestStatementDescriptorRegistration(descs); - List<StatementDescriptorRegistration> regs = new ArrayList<>(1); - regs.add(reg); - KnownDescriptorRegistry registry = new KnownDescriptorRegistry(regs); - KnownDescriptorRegistryFactory.setKnownDescriptorRegistry(registry); - } - - @SuppressWarnings("unchecked") - @Test - public void authorizedPreparedWrite() throws Exception { - Category<TestClass> oldCategory = category; - String categoryName = "test-authorizedPreparedWrite"; - // redefine category to include the agentId key in the category. - // undone via a the try-finally block. - category = new Category<>(categoryName, TestClass.class, key1, key2, Key.AGENT_ID); - try { - String strDescriptor = "ADD " + category.getName() + " SET '" + - key1.getName() + "' = ?s , '" + key2.getName() + "' = ?s"; - setupTrustedStatementRegistry(strDescriptor); - - Set<BasicRole> roles = new HashSet<>(); - roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY)); - roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT)); - roles.add(new RolePrincipal(Roles.WRITE)); - roles.add(new RolePrincipal(Roles.ACCESS_REALM)); - UserPrincipal testUser = new UserPrincipal("ignored1"); - testUser.setRoles(roles); - - final JAASLoginService loginService = getConfiguredLoginService(testUser, roles); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - SharedStateId catId = registerCategoryAndGetId(category, "ignored1", "ignored2"); - - // prepare-statement does this under the hood - Add<TestClass> mockMongoAdd = mock(Add.class); - - when(mockStorage.createAdd(eq(category))).thenReturn(mockMongoAdd); - - PreparedStatement<TestClass> mockPreparedQuery = mock(PreparedStatement.class); - when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery); - - ParsedStatement<TestClass> mockParsedStatement = mock(ParsedStatement.class); - when(mockParsedStatement.getNumParams()).thenReturn(2); - when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoAdd); - when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement); - - // The web layer - when(mockPreparedQuery.execute()).thenReturn(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE); - // And the mongo layer - when(mockMongoAdd.apply()).thenReturn(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/prepare-statement"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, "ignored1", "ignored2"); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn.setDoInput(true); - conn.setDoOutput(true); - Gson gson = new GsonBuilder() - .registerTypeAdapterFactory(new PojoTypeAdapterFactory()) - .registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParameterTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementTypeAdapterFactory()) - .registerTypeAdapterFactory(new WebPreparedStatementResponseTypeAdapterFactory()) - .registerTypeAdapterFactory(new PreparedParametersTypeAdapterFactory()) - .create(); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + getURLEncodedCategoryIdJson(gson, catId); - out.write(body + "\n"); - out.flush(); - - Reader in = new InputStreamReader(conn.getInputStream()); - WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class); - assertEquals(2, response.getNumFreeVariables()); - assertEquals(0, response.getStatementId().getId()); - assertEquals("application/json; charset=UTF-8", conn.getContentType()); - - - - // now execute the ADD we've just prepared - WebPreparedStatement<TestClass> stmt = new WebPreparedStatement<>(2, response.getStatementId()); - stmt.setString(0, "fluff"); - stmt.setString(1, "test2"); - - url = new URL(endpoint + "/write-execute"); - HttpURLConnection conn2 = (HttpURLConnection) url.openConnection(); - conn2.setRequestMethod("POST"); - sendAuthentication(conn2, "ignored1", "ignored2"); - conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - conn2.setDoInput(true); - conn2.setDoOutput(true); - - out = new OutputStreamWriter(conn2.getOutputStream()); - body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class); - out.write(body + "\n"); - out.flush(); - - in = new InputStreamReader(conn2.getInputStream()); - int result = gson.fromJson(in, int.class); - assertEquals(PreparedStatementResponseCode.WRITE_GENERIC_FAILURE, result); - } finally { - category = oldCategory; - } - } - - private String getURLEncodedCategoryIdJson(Gson gson, SharedStateId catId) throws UnsupportedEncodingException { - return URLEncoder.encode(gson.toJson(catId), "UTF-8"); - } - - @Test - public void cannotRegisterCategoryWithoutRegistrationOnInit() throws Exception { - // need this in order to pass basic permissions. - String[] roleNames = new String[] { - Roles.REGISTER_CATEGORY - }; - String username = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(username, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - try { - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/register-category"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - String enc = "UTF-8"; - conn.setRequestProperty("Content-Encoding", enc); - conn.setDoOutput(true); - conn.setDoInput(true); - conn.setRequestMethod("POST"); - sendAuthentication(conn, username, password); - OutputStream out = conn.getOutputStream(); - Gson gson = new Gson(); - OutputStreamWriter writer = new OutputStreamWriter(out); - writer.write("name="); - writer.write(URLEncoder.encode(category.getName(), enc)); - writer.write("&category="); - writer.write(URLEncoder.encode(gson.toJson(category), enc)); - writer.flush(); - - // "test" category name not registered, expecting forbidden. - assertEquals(HttpServletResponse.SC_FORBIDDEN, conn.getResponseCode()); - } catch (IOException e) { - fail("Should not throw exception! " + e.getMessage()); - } - } - - @Test - public void unauthorizedPrepareStmt() throws Exception { - String failMsg = "thermostat-prepare-statement role missing, expected Forbidden!"; - doUnauthorizedTest("prepare-statement", failMsg); - } - - @Test - public void unauthorizedExecutePreparedQuery() throws Exception { - String failMsg = "thermostat-read role missing, expected Forbidden!"; - doUnauthorizedTest("query-execute", failMsg); - } - - private void doUnauthorizedTest(String pathForEndPoint, String failMessage) throws Exception { - String[] insufficientRoleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.ACCESS_REALM - }; - doUnauthorizedTest(pathForEndPoint, failMessage, insufficientRoleNames, true); - } - - private void doUnauthorizedTest(String pathForEndPoint, String failMessage, - String[] insufficientRoles, boolean doRegisterCategory) throws Exception, - MalformedURLException, IOException, ProtocolException { - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, insufficientRoles); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - if (doRegisterCategory) { - // This makes register category work for the "test" category. - // Undone via @After - setupTrustedCategory(categoryName); - registerCategoryAndGetId(category, testuser, password); - } - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/" + pathForEndPoint); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - - assertEquals(failMessage, HttpServletResponse.SC_FORBIDDEN, conn.getResponseCode()); - } - - @Test - public void authorizedRegisterCategoryTest() throws Exception { - Set<BasicRole> roles = new HashSet<>(); - roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY)); - roles.add(new RolePrincipal(Roles.ACCESS_REALM)); - UserPrincipal testUser = new UserPrincipal("ignored1"); - testUser.setRoles(roles); - - final JAASLoginService loginService = getConfiguredLoginService(testUser, roles); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - Category<HostInfo> wantedCategory = HostInfoDAO.hostInfoCategory; - Category<AggregateCount> aggregate = new CategoryAdapter<HostInfo, AggregateCount>(wantedCategory).getAdapted(AggregateCount.class); - - // First the originating category has to be registered, then the adapted - // one. - SharedStateId realId = registerCategoryAndGetId(wantedCategory, "no-matter", "no-matter"); - SharedStateId aggregateId = registerCategoryAndGetId(aggregate, "no-matter", "no-matter"); - - assertTrue("Aggregate categories need their own ID", realId.getId() != aggregateId.getId()); - - verify(mockStorage).registerCategory(eq(wantedCategory)); - verifyNoMoreInteractions(mockStorage); - } - - private SharedStateId registerCategoryAndGetId(Category<?> cat, String username, String password) throws Exception { - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/register-category"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, username, password); - - conn.setDoOutput(true); - conn.setDoInput(true); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - Gson gson = new GsonBuilder().registerTypeAdapterFactory(new SharedStateIdTypeAdapterFactory()).create(); - out.write("name=" + cat.getName() + "&data-class=" + cat.getDataClass().getName() + "&category=" + gson.toJson(cat)); - out.flush(); - assertEquals(200, conn.getResponseCode()); - Reader reader = new InputStreamReader(conn.getInputStream()); - SharedStateId id = gson.fromJson(reader, SharedStateId.class); - return id; - } - - private void setCookie(HttpURLConnection conn, String cookieVal) { - conn.setRequestProperty("Cookie", cookieVal); - } - - private void sendAuthentication(HttpURLConnection conn, String username, String passwd) { - String userpassword = username + ":" + passwd; - String encodedAuthorization = Base64.encodeBase64String(userpassword.getBytes()); - conn.setRequestProperty("Authorization", "Basic "+ encodedAuthorization); - } - - @Test - public void authorizedSaveFile() throws Exception { - String filename = "fluff"; - String[] roleNames = new String[] { - Roles.SAVE_FILE, - Roles.ACCESS_REALM, - // User also needs permission for specific file to be saved. - WebStorageEndPoint.FILES_WRITE_GRANT_ROLE_PREFIX + filename - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - String endpoint = getEndpoint(); - - URL url = new URL(endpoint + "/save-file"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=fluff"); - conn.setRequestProperty("Transfer-Encoding", "chunked"); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("--fluff\r\n"); - out.write("Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"\r\n"); - out.write("Content-Type: application/octet-stream\r\n"); - out.write("Content-Transfer-Encoding: binary\r\n"); - out.write("\r\n"); - out.write("Hello World\r\n"); - out.write("--fluff--\r\n"); - out.flush(); - // needed in order to trigger inCaptor interaction with mock - int respCode = conn.getResponseCode(); - assertEquals(HttpServletResponse.SC_OK, respCode); - ArgumentCaptor<InputStream> inCaptor = ArgumentCaptor.forClass(InputStream.class); - verify(mockStorage).saveFile(eq(filename), inCaptor.capture(), isA(CloseOnSave.class)); - InputStream in = inCaptor.getValue(); - byte[] data = new byte[11]; - int totalRead = 0; - while (totalRead < 11) { - int read = in.read(data, totalRead, 11 - totalRead); - if (read < 0) { - fail(); - } - totalRead += read; - } - assertEquals("Hello World", new String(data)); - } - - @Test - public void unauthorizedSaveFile() throws Exception { - String failMsg = "thermostat-save-file role missing, expected Forbidden!"; - String[] insufficientRoles = new String[] { - Roles.ACCESS_REALM - }; - doUnauthorizedTest("save-file", failMsg, insufficientRoles, false); - } - - @Test - public void unauthorizedSaveFileMissingSpecificRole() throws Exception { - String filename = "foo.txt"; - String[] insufficientRoles = new String[] { - Roles.SAVE_FILE, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, insufficientRoles); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - String endpoint = getEndpoint(); - - URL url = new URL(endpoint + "/save-file"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=fluff"); - conn.setRequestProperty("Transfer-Encoding", "chunked"); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("--fluff\r\n"); - out.write("Content-Disposition: form-data; name=\"file\"; filename=\"" + filename + "\"\r\n"); - out.write("Content-Type: application/octet-stream\r\n"); - out.write("Content-Transfer-Encoding: binary\r\n"); - out.write("\r\n"); - out.write("Hello World\r\n"); - out.write("--fluff--\r\n"); - out.flush(); - int respCode = conn.getResponseCode(); - assertEquals(HttpServletResponse.SC_FORBIDDEN, respCode); - verifyNoMoreInteractions(mockStorage); - } - - @Test - public void authorizedLoadFile() throws Exception { - String filename = "fluff"; - String[] roleNames = new String[] { - Roles.LOAD_FILE, - Roles.ACCESS_REALM, - // Grant the specific read file permission - WebStorageEndPoint.FILES_READ_GRANT_ROLE_PREFIX + filename - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - - byte[] data = "Hello World".getBytes(); - InputStream in = new ByteArrayInputStream(data); - when(mockStorage.loadFile(filename)).thenReturn(in); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/load-file"); - - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setDoInput(true); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("file=" + filename); - out.flush(); - int respCode = conn.getResponseCode(); - assertEquals(HttpServletResponse.SC_OK, respCode); - in = conn.getInputStream(); - data = new byte[11]; - int totalRead = 0; - while (totalRead < 11) { - int read = in.read(data, totalRead, 11 - totalRead); - if (read < 0) { - fail(); - } - totalRead += read; - } - assertEquals("Hello World", new String(data)); - verify(mockStorage).loadFile(filename); - } - - @Test - public void unauthorizedLoadFile() throws Exception { - String failMsg = "thermostat-load-file role missing, expected Forbidden!"; - String[] insufficientRoles = new String[] { - Roles.ACCESS_REALM - }; - doUnauthorizedTest("load-file", failMsg, insufficientRoles, false); - } - - @Test - public void unauthorizedLoadFileMissingSpecificRole() throws Exception { - String filename = "foo.txt"; - String[] insufficientRoles = new String[] { - Roles.LOAD_FILE, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, insufficientRoles); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - - byte[] data = "Hello World".getBytes(); - InputStream in = new ByteArrayInputStream(data); - when(mockStorage.loadFile(filename)).thenReturn(in); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/load-file"); - - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setDoInput(true); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("file=" + filename); - out.flush(); - int respCode = conn.getResponseCode(); - assertEquals(HttpServletResponse.SC_FORBIDDEN, respCode); - verifyNoMoreInteractions(mockStorage); - } - - @Test - public void authorizedPurge() throws Exception { - String[] roleNames = new String[] { - Roles.PURGE, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/purge"); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setDoOutput(true); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.getOutputStream().write("agentId=fluff".getBytes()); - int status = conn.getResponseCode(); - assertEquals(HttpServletResponse.SC_OK, status); - verify(mockStorage).purge("fluff"); - } - - @Test - public void unauthorizedAccessRealm() throws Exception { - String failMsg = Roles.ACCESS_REALM + " role missing, expected Forbidden!"; - String[] insufficientRoles = new String[0]; - // entry point for this test doesn't matter. Use '/'. - doUnauthorizedTest("", failMsg, insufficientRoles, false); - } - - @Test - public void authorizedAccessRealm() throws Exception { - String[] roles = new String[] { - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roles); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/"); // Testing the realm, nothing else. - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); - conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - - assertEquals(HttpServletResponse.SC_OK, conn.getResponseCode()); - } - - @Test - public void unauthorizedPurge() throws Exception { - String failMsg = "thermostat-purge role missing, expected Forbidden!"; - String[] insufficientRoles = new String[] { - Roles.ACCESS_REALM - }; - doUnauthorizedTest("purge", failMsg, insufficientRoles, false); - } - - private String getEndpoint() { - return "http://localhost:" + port + "/storage"; - } - - @Test - public void authorizedGenerateToken() throws Exception { - String actionName = "testing"; - String[] roleNames = new String[] { - Roles.CMD_CHANNEL_GENERATE, - Roles.ACCESS_REALM, - // grant the "testing" action - WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - verifyAuthorizedGenerateToken(testuser, password, actionName); - } - - @Test - public void unauthorizedGenerateToken() throws Exception { - String failMsg = "thermostat-cmdc-generate role missing, expected Forbidden!"; - String[] insufficientRoles = new String[] { - Roles.ACCESS_REALM - }; - doUnauthorizedTest("generate-token", failMsg, insufficientRoles, false); - } - - @Test - public void authorizedGenerateVerifyToken() throws Exception { - String actionName = "someAction"; - String[] roleNames = new String[] { - Roles.CMD_CHANNEL_GENERATE, - Roles.CMD_CHANNEL_VERIFY, - Roles.ACCESS_REALM, - // grant "someAction" to be performed - WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName, - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - byte[] token = verifyAuthorizedGenerateToken(testuser, password, actionName); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/verify-token"); - - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setDoInput(true); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("client-token=fluff&action-name=" + actionName + "&token=" + - URLEncoder.encode(Base64.encodeBase64String(token), "UTF-8")); - out.flush(); - assertEquals(200, conn.getResponseCode()); - } - - @Test - public void unAuthorizedGenerateVerifyToken() throws Exception { - String testuser = "testuser"; - String password = "testpassword"; - String actionName = "someAction"; - String[] roleNames = new String[] { - Roles.CMD_CHANNEL_GENERATE, - Roles.CMD_CHANNEL_VERIFY, - Roles.ACCESS_REALM, - // missing the thermostat-cmdc-grant-someAction role - }; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - - byte[] result = verifyAuthorizedGenerateToken(testuser, password, actionName, 403); - assertNull(result); - } - - @Test - public void authenticatedGenerateVerifyTokenWithActionNameMismatch() throws Exception { - String actionName = "someAction"; - String[] roleNames = new String[] { - Roles.CMD_CHANNEL_GENERATE, - WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName, - Roles.CMD_CHANNEL_VERIFY, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - byte[] token = verifyAuthorizedGenerateToken(testuser, password, actionName); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/verify-token"); - - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setDoInput(true); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - // expected action-name parameter is "someAction". This should not - // verify => 403. - out.write("client-token=fluff&action-name=wrongAction&token=" + URLEncoder.encode(Base64.encodeBase64String(token), "UTF-8")); - out.flush(); - assertEquals(403, conn.getResponseCode()); - } - - - @Test - public void authenticatedTokenTimeout() throws Exception { - String actionName = "someAction"; - String[] roleNames = new String[] { - Roles.CMD_CHANNEL_GENERATE, - Roles.CMD_CHANNEL_VERIFY, - Roles.ACCESS_REALM, - // Grant "someAction", this test tests the time-out - WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - byte[] token = verifyAuthorizedGenerateToken(testuser, password, actionName); - - Thread.sleep(700); // Timeout is set to 500ms for tests, 700ms should be enough for everybody. ;-) - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/verify-token"); - - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setDoInput(true); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("client-token=fluff&action-name=" + actionName + "&token=" + - URLEncoder.encode(Base64.encodeBase64String(token), "UTF-8")); - out.flush(); - assertEquals(403, conn.getResponseCode()); - } - - @Test - public void authenticatedVerifyNonExistentToken() throws Exception { - String[] roleNames = new String[] { - Roles.CMD_CHANNEL_VERIFY, - Roles.ACCESS_REALM - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); - port = FreePortFinder.findFreePort(new TryPort() { - - @Override - public void tryPort(int port) throws Exception { - startServer(port, loginService); - } - }); - - byte[] token = "fluff".getBytes(); - - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/verify-token"); - - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); - sendAuthentication(conn, testuser, password); - conn.setDoOutput(true); - conn.setDoInput(true); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("client-token=fluff&action-name=someAction&token=" + URLEncoder.encode(Base64.encodeBase64String(token), "UTF-8")); - out.flush(); - assertEquals(403, conn.getResponseCode()); - } - - @Test - public void unauthorizedVerifyToken() throws Exception { - String failMsg = "thermostat-cmdc-verify role missing, expected Forbidden!"; - String[] insufficientRoles = new String[] { - Roles.ACCESS_REALM - }; - doUnauthorizedTest("verify-token", failMsg, insufficientRoles, false); - } - - private byte[] verifyAuthorizedGenerateToken(String username, String password, String actionName) throws IOException { - return verifyAuthorizedGenerateToken(username, password, actionName, 200); - } - - private byte[] verifyAuthorizedGenerateToken(String username, String password, String actionName, int expectedResponseCode) throws IOException { - return verifyAuthorizedGenerateToken(username, password, expectedResponseCode, actionName); - } - - private JAASLoginService getConfiguredLoginService(UserPrincipal user, Set<BasicRole> roles) { - Configuration config = new TestConfiguration(user, roles); - Configuration.setConfiguration(config); - JAASLoginService loginService = new JAASLoginService("foo"); - loginService.setRoleClassNames(new String[] { RolePrincipal.class.getName() }); - return loginService; - } - - private byte[] verifyAuthorizedGenerateToken(String username, - String password, int expectedResponseCode, String actionName) - throws IOException { - String endpoint = getEndpoint(); - URL url = new URL(endpoint + "/generate-token"); - - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("POST"); - sendAuthentication(conn, username, password); - conn.setDoOutput(true); - conn.setDoInput(true); - OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); - out.write("client-token=fluff&action-name=" + actionName); - out.flush(); - int actualResponseCode = conn.getResponseCode(); - assertEquals(expectedResponseCode, actualResponseCode); - if (actualResponseCode == 200) { - InputStream in = conn.getInputStream(); - int length = conn.getContentLength(); - byte[] token = new byte[length]; - assertEquals(256, length); - int totalRead = 0; - while (totalRead < length) { - int read = in.read(token, totalRead, length - totalRead); - if (read < 0) { - fail(); - } - totalRead += read; - } - return token; - } else { - return null; - } - } - - private static class TestLoginService extends MappedLoginService { - - private final String[] roleNames; - private final String username; - private final String password; - - private TestLoginService(String username, String password, - String[] roleNames) { - this.username = username; - this.password = password; - this.roleNames = roleNames; - } - - @Override - protected void loadUsers() throws IOException { - putUser(username, new Password(password), - roleNames); - } - - @Override - protected UserIdentity loadUser(String username) { - return new DefaultUserIdentity(null, null, - roleNames); - } - } - - private static class TestStatementDescriptorRegistration implements StatementDescriptorRegistration { - - private final Set<String> descriptorSet; - private TestStatementDescriptorRegistration(Set<String> descriptorSet) { - assertEquals(1, descriptorSet.size()); - this.descriptorSet = descriptorSet; - } - - @Override - public Set<String> getStatementDescriptors() { - return descriptorSet; - } - - } - - private class TestConfiguration extends Configuration { - - private final UserPrincipal uPrincipal; - private final Set<BasicRole> roles; - - TestConfiguration(UserPrincipal uPrincipal, Set<BasicRole> roles) { - this.uPrincipal = uPrincipal; - this.roles = roles; - } - - @Override - public AppConfigurationEntry[] getAppConfigurationEntry(String name) { - Map<String, Object> state = new HashMap<>(); - // TestLoginModule uses those options - state.put("user", uPrincipal); - state.put("roles", roles); - AppConfigurationEntry entry = new AppConfigurationEntry(TestLoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, state); - return new AppConfigurationEntry[] { entry }; - } - - } - - public static class TestLoginModule implements LoginModule { - - private Subject subject; - private UserPrincipal user; - private Set<BasicRole> roles; - - @SuppressWarnings("unchecked") - @Override - public void initialize(Subject subject, - CallbackHandler callbackHandler, Map<String, ?> sharedState, - Map<String, ?> options) { - this.subject = subject; - this.user = (UserPrincipal)options.get("user"); - this.roles = (Set<BasicRole>)options.get("roles"); - } - - @Override - public boolean login() throws LoginException { - Set<Principal> principals = subject.getPrincipals(); - principals.add(user); - principals.addAll(roles); - return true; - } - - @Override - public boolean commit() throws LoginException { - return true; - } - - @Override - public boolean abort() throws LoginException { - return true; - } - - @Override - public boolean logout() throws LoginException { - return true; - } - - } - -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebstorageEndpointTestUtils.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/* - * 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.web.server; - -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; - -public class WebstorageEndpointTestUtils { - - static void deleteDirectoryRecursive(Path dir) throws IOException { - Files.walkFileTree(dir, new FileVisitor<Path>() { - - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attrs) throws IOException { - // nothing - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) - throws IOException { - exc.printStackTrace(); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) - throws IOException { - // All files have been visitated before that. - Files.delete(dir); - return FileVisitResult.CONTINUE; - } - - }); - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/AgentIdFilterTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,189 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.BinaryLogicalExpression; -import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -public class AgentIdFilterTest { - - private static class FooPojo implements Pojo { - // Dummy class for testing - } - - private static final Category<FooPojo> TEST_NON_NULL_CATEGORY = new Category<>("foo-agentid-filter-test", FooPojo.class, Key.AGENT_ID); - private static final Category<FooPojo> TEST_NULL_CATEGORY = new Category<>("foo-agentid-filter-test-null", FooPojo.class); - /** - * A query descriptor which will return a non-null Key for the "vmId" name. - */ - private static final StatementDescriptor<FooPojo> TEST_DESC_NON_NULL_AGENT_ID = new StatementDescriptor<>(TEST_NON_NULL_CATEGORY, "QUERY foo"); - /** - * A query descriptor which will return a null Key for the "vmId" name. - */ - private static final StatementDescriptor<FooPojo> TEST_DESC_NULL_AGENT_ID = new StatementDescriptor<>(TEST_NULL_CATEGORY, "QUERY foo-null"); - - @Test - public void testReadAll() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal agentReadAll = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL); - roles.add(agentReadAll); - - AgentIdFilter<?> filter = new AgentIdFilter<>(roles); - FilterResult result = filter.applyFilter(null, null); - assertEquals(ResultType.ALL, result.getType()); - assertEquals(null, result.getFilterExpression()); - } - - @Test - public void testReadAllAddToParent() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal agentReadAll = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL); - roles.add(agentReadAll); - - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - AgentIdFilter<?> filter = new AgentIdFilter<>(roles); - FilterResult result = filter.applyFilter(null, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertEquals(parentExpression, result.getFilterExpression()); - } - - @Test - public void addsAgentIdInQuery() { - String agentId = UUID.randomUUID().toString(); - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); - roles.add(agent1Role); - AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles); - // returning non-null agent id key will work - FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_AGENT_ID, null); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinarySetMembershipExpression); - Set<String> agentIdSet = new HashSet<>(); - agentIdSet.add(agentId); - Expression expected = new ExpressionFactory().in(Key.AGENT_ID, agentIdSet, String.class); - assertEquals(expected, actual); - } - - @Test - public void addsAgentIdInQueryToParentExpression() { - String agentId = UUID.randomUUID().toString(); - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); - roles.add(agent1Role); - AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles); - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_AGENT_ID, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinaryLogicalExpression); - Set<String> agentIdSet = new HashSet<>(); - agentIdSet.add(agentId); - Expression expectedIn = factory.in(Key.AGENT_ID, agentIdSet, String.class); - Expression expected = factory.and(parentExpression, expectedIn); - assertEquals(expected, actual); - } - - @Test - public void addsAgentIdInQuery2() { - String agentId = UUID.randomUUID().toString(); - String agentId2 = UUID.randomUUID().toString(); - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); - RolePrincipal agent2Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId2); - roles.add(agent1Role); - roles.add(agent2Role); - AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles); - FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_AGENT_ID, null); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinarySetMembershipExpression); - Set<String> agentIdSet = new HashSet<>(); - agentIdSet.add(agentId); - agentIdSet.add(agentId2); - Expression expected = new ExpressionFactory().in(Key.AGENT_ID, agentIdSet, String.class); - assertEquals(expected, actual); - } - - @Test - public void returnsAllForUnrelatedQuery() { - Set<BasicRole> roles = new HashSet<>(); - - // want for the agent id key to not be present in category - AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles); - FilterResult result = filter.applyFilter(TEST_DESC_NULL_AGENT_ID, null); - assertEquals(ResultType.ALL, result.getType()); - assertNull(result.getFilterExpression()); - } - - @Test - public void returnsParentExpressionForUnrelatedQuery() { - Set<BasicRole> roles = new HashSet<>(); - - Expression parentExpression = new ExpressionFactory().equalTo(Key.AGENT_ID, "testKey"); - AgentIdFilter<FooPojo> filter = new AgentIdFilter<>(roles); - // want for the agent id key to not be present in category - FilterResult result = filter.applyFilter(TEST_DESC_NULL_AGENT_ID, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - assertEquals(parentExpression, result.getFilterExpression()); - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/DefaultPrincipalCallbackTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; - -import java.security.Principal; - -import org.junit.Test; - -import static org.mockito.Mockito.mock; - -public class DefaultPrincipalCallbackTest { - - @Test - public void testCastSuccess() { - UserPrincipal principal = new UserPrincipal("foo"); - DefaultPrincipalCallback callback = new DefaultPrincipalCallback(); - UserPrincipal other = callback.getUserPrincipal(principal); - assertSame(principal, other); - } - - @Test - public void testCastFailure() { - Principal wrongPrincipal = mock(Principal.class); - DefaultPrincipalCallback callback = new DefaultPrincipalCallback(); - try { - callback.getUserPrincipal(wrongPrincipal); - fail("should fail to cast!"); - } catch (ClassCastException e) { - // pass - } - } - - -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/HostnameFilterTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashSet; -import java.util.Set; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.dao.HostInfoDAO; -import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.storage.model.HostInfo; -import com.redhat.thermostat.storage.query.BinaryLogicalExpression; -import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -public class HostnameFilterTest { - - @Test - public void testReadAll() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal hostnameReadAll = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL); - roles.add(hostnameReadAll); - - HostnameFilter<?> filter = new HostnameFilter<>(roles); - FilterResult result = filter.applyFilter(null, null); - assertEquals(ResultType.ALL, result.getType()); - assertEquals(null, result.getFilterExpression()); - } - - @Test - public void testReadAllAddsToParentExpression() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal hostnameReadAll = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL); - roles.add(hostnameReadAll); - - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - HostnameFilter<?> filter = new HostnameFilter<>(roles); - FilterResult result = filter.applyFilter(null, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertEquals(parentExpression, result.getFilterExpression()); - } - - @Test - public void addsHostnameInQueryForHostInfo() { - String testHostname = "testhost.example.com"; - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal hostnameRole = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + testHostname); - roles.add(hostnameRole); - - StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(HostInfoDAO.hostInfoCategory, "QUERY " + HostInfoDAO.hostInfoCategory.getName()); - - Set<String> hostnames = new HashSet<>(); - hostnames.add(testHostname); - Expression expected = new ExpressionFactory().in(HostInfoDAO.hostNameKey, hostnames, String.class); - HostnameFilter<HostInfo> filter = new HostnameFilter<>(roles); - FilterResult result = filter.applyFilter(desc, null); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinarySetMembershipExpression); - assertEquals(expected, actual); - } - - @Test - public void addsHostnameInQueryForHostInfoAndAddsParentExpression() { - String testHostname = "testhost.example.com"; - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal hostnameRole = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + testHostname); - roles.add(hostnameRole); - - StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(HostInfoDAO.hostInfoCategory, "QUERY " + HostInfoDAO.hostInfoCategory.getName()); - - Set<String> hostnames = new HashSet<>(); - hostnames.add(testHostname); - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - Expression expectedIn = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class); - Expression expected = factory.and(parentExpression, expectedIn); - HostnameFilter<HostInfo> filter = new HostnameFilter<>(roles); - FilterResult result = filter.applyFilter(desc, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinaryLogicalExpression); - assertEquals(expected, actual); - } - - @Test - public void byPassesFilterForUnrelatedQuery() { - Set<BasicRole> roles = new HashSet<>(); - - StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, "QUERY " + AgentInfoDAO.CATEGORY.getName()); - - HostnameFilter<AgentInformation> filter = new HostnameFilter<>(roles); - FilterResult result = filter.applyFilter(desc, null); - assertEquals(ResultType.ALL, result.getType()); - assertNull(result.getFilterExpression()); - } - - @Test - public void byPassesFilterForUnrelatedQueryAndParentExpression() { - Set<BasicRole> roles = new HashSet<>(); - - StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, "QUERY " + AgentInfoDAO.CATEGORY.getName()); - - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - HostnameFilter<AgentInformation> filter = new HostnameFilter<>(roles); - FilterResult result = filter.applyFilter(desc, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - assertEquals(parentExpression, result.getFilterExpression()); - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/JettyPrincipalCallbackTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.security.Principal; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.login.LoginContext; - -import org.eclipse.jetty.jaas.JAASUserPrincipal; -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.web.server.containers.ContainerVersion; -import com.redhat.thermostat.web.server.containers.ServletContainerInfo; - -public class JettyPrincipalCallbackTest { - - private ContainerVersion jetty9Version; - private ContainerVersion jetty8Version; - private ContainerVersion unknownVersion; - - @Before - public void setup() { - jetty9Version = mock(ContainerVersion.class); - when(jetty9Version.getMajor()).thenReturn(9); - jetty8Version = mock(ContainerVersion.class); - when(jetty8Version.getMajor()).thenReturn(8); - unknownVersion = mock(ContainerVersion.class); - when(unknownVersion.getMajor()).thenReturn(100); - } - - @Test - public void canGetUserPrincipalJetty9() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getContainerVersion()).thenReturn(jetty9Version); - Subject subject = new Subject(); - String principalName = "foo"; - UserPrincipal userPrincipal = new UserPrincipal(principalName); - Set<Principal> principals = subject.getPrincipals(); - principals.add(userPrincipal); - LoginContext loginContext = mock(LoginContext.class); - Principal principal = new JAASUserPrincipal(principalName, subject, loginContext); - - JettyPrincipalCallback callback = new JettyPrincipalCallback(info); - UserPrincipal other = callback.getUserPrincipal(principal); - assertSame(userPrincipal, other); - } - - @Test - public void canGetUserPrincipalJetty8() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getContainerVersion()).thenReturn(jetty8Version); - Subject subject = new Subject(); - String principalName = "foo"; - UserPrincipal userPrincipal = new UserPrincipal(principalName); - Set<Principal> principals = subject.getPrincipals(); - principals.add(userPrincipal); - LoginContext loginContext = mock(LoginContext.class); - // use the jetty 8 principal - Principal principal = new org.eclipse.jetty.plus.jaas.JAASUserPrincipal(principalName, subject, loginContext); - - JettyPrincipalCallback callback = new JettyPrincipalCallback(info); - UserPrincipal other = callback.getUserPrincipal(principal); - assertSame(userPrincipal, other); - } - - @Test - public void failsOnUnknownPrincipal() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getContainerVersion()).thenReturn(unknownVersion); - Principal principal = mock(Principal.class); - JettyPrincipalCallback callback = new JettyPrincipalCallback(info); - try { - callback.getUserPrincipal(principal); - fail("should have failed to retrieve user principal from non-jetty principal"); - } catch (IllegalStateException e) { - // pass - } - } - - @Test - public void testNoUserPrincipalInSetOfPrincipals() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getContainerVersion()).thenReturn(jetty9Version); - Subject subject = new Subject(); - String principalName = "foo"; - LoginContext loginContext = mock(LoginContext.class); - Principal principal = new JAASUserPrincipal(principalName, subject, loginContext); - - JettyPrincipalCallback callback = new JettyPrincipalCallback(info); - try { - callback.getUserPrincipal(principal); - fail("should have thrown ISE, since no thermostat UserPrincipal is in the principal set"); - } catch (IllegalStateException e) { - assertEquals("Number of thermostat user principals must be exactly 1!", e.getMessage()); - } - } - - @Test - public void testMoreThanOneUserPrincipalsInSetOfPrincipals() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getContainerVersion()).thenReturn(jetty9Version); - Subject subject = new Subject(); - String principalName = "foo"; - UserPrincipal userPrincipal = new UserPrincipal(principalName); - Set<Principal> principals = subject.getPrincipals(); - UserPrincipal userPrincipal2 = new UserPrincipal("other"); - principals.add(userPrincipal); - principals.add(userPrincipal2); - LoginContext loginContext = mock(LoginContext.class); - Principal principal = new JAASUserPrincipal(principalName, subject, loginContext); - - JettyPrincipalCallback callback = new JettyPrincipalCallback(info); - try { - callback.getUserPrincipal(principal); - fail("should have thrown ISE, since 2 thermostat UserPrincipals are in the principal set"); - } catch (IllegalStateException e) { - assertEquals("Number of thermostat user principals must be exactly 1!", e.getMessage()); - } - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/PrincipalCallbackFactoryTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * 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.web.server.auth; - -import org.junit.Test; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.redhat.thermostat.web.server.containers.ContainerName; -import com.redhat.thermostat.web.server.containers.ServletContainerInfo; - -public class PrincipalCallbackFactoryTest { - - @Test - public void unknownReturnsDefault() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getName()).thenReturn(ContainerName.UNKNOWN); - PrincipalCallbackFactory factory = new PrincipalCallbackFactory(info); - PrincipalCallback cb = factory.getCallback(); - assertNotNull(cb); - assertTrue(cb instanceof DefaultPrincipalCallback); - } - - @Test - public void tomcatReturnsDefault() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getName()).thenReturn(ContainerName.TOMCAT); - PrincipalCallbackFactory factory = new PrincipalCallbackFactory(info); - PrincipalCallback cb = factory.getCallback(); - assertNotNull(cb); - assertTrue(cb instanceof DefaultPrincipalCallback); - } - - @Test - public void jettyReturnsJettyCallBack() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getName()).thenReturn(ContainerName.JETTY); - PrincipalCallbackFactory factory = new PrincipalCallbackFactory(info); - PrincipalCallback cb = factory.getCallback(); - assertNotNull(cb); - assertTrue(cb instanceof JettyPrincipalCallback); - } - - @Test - public void wildflyReturnsDefault() { - ServletContainerInfo info = mock(ServletContainerInfo.class); - when(info.getName()).thenReturn(ContainerName.WILDFLY); - PrincipalCallbackFactory factory = new PrincipalCallbackFactory(info); - PrincipalCallback cb = factory.getCallback(); - assertNotNull(cb); - assertTrue(cb instanceof DefaultPrincipalCallback); - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/RolePrincipalTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.security.Principal; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; - -import org.junit.Test; - -public class RolePrincipalTest { - - @Test - public void testEmptyRoles() { - RolePrincipal principal = new RolePrincipal("RolesContainer"); - assertEquals(false, principal.members().hasMoreElements()); - assertEquals(false, principal.isMember(new RolePrincipal("not-there"))); - assertEquals(false, principal.isMember(new UserPrincipal("user also not there"))); - assertEquals("RolesContainer", principal.getName()); - } - - @Test - public void canRemoveMembers() { - RolePrincipal principal = new RolePrincipal("Testing"); - assertFalse(principal.removeMember(new RolePrincipal("other"))); - assertFalse(principal.removeMember(new UserPrincipal("testuser"))); - RolePrincipal firstRoleMember = new RolePrincipal("first"); - RolePrincipal secondRoleMember = new RolePrincipal("second"); - RolePrincipal thirdRoleMember = new RolePrincipal("third"); - principal.addMember(firstRoleMember); - assertTrue("first member of Testing", principal.removeMember(firstRoleMember)); - principal.addMember(secondRoleMember); - principal.addMember(thirdRoleMember); - assertTrue("third member of Testing", principal.removeMember(thirdRoleMember)); - List<String> members = new ArrayList<>(); - @SuppressWarnings("unchecked") - Enumeration<Principal> roles = (Enumeration<Principal>) principal.members(); - while (roles.hasMoreElements()) { - members.add(roles.nextElement().getName()); - } - assertEquals(1, members.size()); - assertEquals("second", members.get(0)); - } - - @Test - public void rolePrincipalDoesNotAllowNonGroupsToBeAdded() { - RolePrincipal role = new RolePrincipal("test"); - try { - role.addMember(new UserPrincipal("something")); - fail("UserPrincipal not a Group, should not come here!"); - } catch (IllegalArgumentException e) { - // pass - } - } - - @Test( expected = NullPointerException.class ) - public void nullName() { - new RolePrincipal(null); - } - - @Test - public void isMemberWorksForNestedGroups() { - RolePrincipal principal = new RolePrincipal("Roles"); - RolePrincipal otherRole = new RolePrincipal("Nested 1"); - RolePrincipal thirdRole = new RolePrincipal("find-me"); - RolePrincipal notExistingRole = new RolePrincipal("notthere"); - otherRole.addMember(thirdRole); - principal.addMember(otherRole); - assertEquals("find-me member of Nested 1 which is member of Roles", true, principal.isMember(thirdRole)); - assertEquals(false, principal.isMember(notExistingRole)); - assertTrue(otherRole.removeMember(thirdRole)); - assertEquals("find-me no longer member of Nested 1 (which is still a member of Roles)", false, principal.isMember(thirdRole)); - } - - @Test - public void testEquals() { - UserPrincipal user = new UserPrincipal("test"); - RolePrincipal role = new RolePrincipal("test"); - assertFalse("Roles and users must not be equal", role.equals(user)); - assertTrue(role.equals(role)); - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/UserPrincipalTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,342 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import java.security.Principal; -import java.util.HashSet; -import java.util.Set; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.dao.HostInfoDAO; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.model.HostInfo; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.model.VmInfo; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -public class UserPrincipalTest { - - private static class FooPojo implements Pojo { - // empty dummy pojo. - } - - @Test(expected = NullPointerException.class) - public void testConstructor() { - new UserPrincipal(null); - } - - @Test - public void getName() { - UserPrincipal p = new UserPrincipal("testing"); - assertEquals("testing", p.getName()); - } - - @Test - public void canSetRoles() { - UserPrincipal p = new UserPrincipal("superuser"); - try { - p.setRoles(null); - fail("null roles not allowed"); - } catch (NullPointerException e) { - // pass - } - Set<BasicRole> roles = new HashSet<>(); - BasicRole role = mock(BasicRole.class); - roles.add(role); - p.setRoles(roles); - assertEquals(1, p.getRoles().size()); - } - - @Test - public void setRolesDefensiveCopy() { - UserPrincipal p = new UserPrincipal("testuser"); - Set<BasicRole> roles = new HashSet<>(); - BasicRole fooRole = mock(BasicRole.class); - roles.add(fooRole); - p.setRoles(roles); - BasicRole barRole = mock(BasicRole.class); - roles.add(barRole); - assertFalse(p.getRoles().contains(barRole)); - } - - @Test - public void getRolesDoesntLeak() { - UserPrincipal p = new UserPrincipal("testuser"); - Set<BasicRole> roles = p.getRoles(); - BasicRole fooRole = mock(BasicRole.class); - roles.add(fooRole); - assertFalse(p.getRoles().contains(fooRole)); - } - - @Test - public void testEquals() { - UserPrincipal p = new UserPrincipal("testuser"); - assertTrue(p.equals(p)); - SimplePrincipal p2 = new SimplePrincipal("testuser"); - assertTrue(p2.equals(p)); - assertTrue(p.equals(p2)); - SimplePrincipal p3 = new SimplePrincipal("Tester"); - assertFalse(p2.equals(p3)); - assertFalse(p.equals(p3)); - Principal principal = new Principal() { - - @Override - public String getName() { - return "testuser"; - } - - }; - assertTrue(p.equals(principal)); - } - - @Test - public void readAllRoleBypassesReadFilters() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal readEverything = new RolePrincipal(Roles.GRANT_READ_ALL); - roles.add(readEverything); - SimplePrincipal testMe = new SimplePrincipal("test me"); - testMe.setRoles(roles); - FilterResult result = testMe.getReadFilter(null); - assertEquals(ResultType.ALL, result.getType()); - assertNull(result.getFilterExpression()); - } - - @Test - public void testEntireFilterChainNoSpecificAgentIdVmId() { - String agentId = "someAgentID"; - String vmId = "someVmID"; - String vmUsername = "someUser"; - RolePrincipal readAllHosts = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL); - RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); - RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); - RolePrincipal readVmUsername = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + vmUsername); - - Set<BasicRole> roles = new HashSet<>(); - roles.add(readAllHosts); - roles.add(readAgentId); - roles.add(readVmUsername); - roles.add(readVmId); - - assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL)); - assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL)); - assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL)); - assertFalse(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL)); - SimplePrincipal testMe = new SimplePrincipal("test me"); - testMe.setRoles(roles); - StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, "QUERY " + VmInfoDAO.vmInfoCategory.getName()); - - // should pass through agentId -> hostname -> vmId -> vmUsername filters - FilterResult result = testMe.getReadFilter(desc); - - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - ExpressionFactory factory = new ExpressionFactory(); - Set<String> agentIds = new HashSet<>(); - agentIds.add(agentId); - Set<String> vmIds = new HashSet<>(); - vmIds.add(vmId); - Expression agentInExpr = factory.in(Key.AGENT_ID, agentIds, String.class); - Expression vmIdInExpr = factory.in(Key.VM_ID, vmIds, String.class); - Set<String> vmUsernames = new HashSet<>(); - vmUsernames.add(vmUsername); - Expression vmIdUsernameInExpr = factory.in(VmInfoDAO.usernameKey, vmUsernames, String.class); - Expression expected = factory.and(factory.and(agentInExpr, vmIdInExpr), vmIdUsernameInExpr); - assertEquals(expected, actual); - } - - @Test - public void testEntireFilterChainSpecificAgentIdVmId() { - String agentId = "someAgentID"; - String vmId = "someVmID"; - RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); - RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); - - Set<BasicRole> roles = new HashSet<>(); - roles.add(HostnameFilter.GRANT_HOSTS_READ_ALL); - roles.add(readAgentId); - roles.add(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL); - roles.add(readVmId); - - assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL)); - assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL)); - assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL)); - assertTrue(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL)); - SimplePrincipal testMe = new SimplePrincipal("test me"); - testMe.setRoles(roles); - - // want for the agent/vm id key to be present in category - Key<?>[] keys = new Key[] { - Key.AGENT_ID, Key.VM_ID - }; - Category<FooPojo> agentAndVmIdCat = new Category<>("agentAndVmIdCat", FooPojo.class, keys); - StatementDescriptor<FooPojo> desc = new StatementDescriptor<>(agentAndVmIdCat, "QUERY agentAndVmIdCat"); - - // should pass through agentId -> hostname -> vmId -> vmUsername filters - FilterResult result = testMe.getReadFilter(desc); - - // should return all, since ACL allows specific agentId/vmIds - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - Expression expected = getExpectedAgentIdVmIdExpression(agentId, vmId); - assertEquals(expected, result.getFilterExpression()); - } - - private Expression getExpectedAgentIdVmIdExpression(String agentId, - String vmId) { - ExpressionFactory factory = new ExpressionFactory(); - Set<String> agentIdSet = new HashSet<>(); - agentIdSet.add(agentId); - Expression agentIdExp = factory.in(Key.AGENT_ID, agentIdSet, String.class); - Set<String> vmIdSet = new HashSet<>(); - vmIdSet.add(vmId); - Expression vmIdExp = factory.in(Key.VM_ID, vmIdSet, String.class); - return factory.and(agentIdExp, vmIdExp); - } - - @Test - public void testEntireFilterChainSpecificAgentIdVmIdPlusHostname() { - String agentId = "someAgentID"; - String vmId = "someVmID"; - String hostname = "somehost.example.com"; - RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); - RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); - RolePrincipal readHostname = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + hostname); - - Set<BasicRole> roles = new HashSet<>(); - roles.add(readHostname); - roles.add(readAgentId); - roles.add(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL); - roles.add(readVmId); - - assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL)); - assertFalse(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL)); - assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL)); - assertTrue(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL)); - SimplePrincipal testMe = new SimplePrincipal("test me"); - testMe.setRoles(roles); - StatementDescriptor<HostInfo> desc = new StatementDescriptor<>(HostInfoDAO.hostInfoCategory, "QUERY " + HostInfoDAO.hostInfoCategory.getName()); - - // should pass through agentId -> hostname -> vmId -> vmUsername filters - FilterResult result = testMe.getReadFilter(desc); - - // should return query expression in order to allow only specific - // hostname and specific agent id. Since the category does not - // include vmId, nothing is added by the vm id filter. - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - ExpressionFactory factory = new ExpressionFactory(); - Set<String> agentIdSet = new HashSet<>(); - agentIdSet.add(agentId); - Expression agentIdExp = factory.in(Key.AGENT_ID, agentIdSet, String.class); - Set<String> hostnames = new HashSet<>(); - hostnames.add(hostname); - Expression hostnameExp = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class); - Expression expected = factory.and(agentIdExp, hostnameExp); - assertEquals(expected, actual); - } - - @Test - public void testEntireFilterChainSpecificAgentIdVmIdPlusVmUsername() { - String agentId = "someAgentID"; - String vmId = "someVmID"; - String vmUserame = "someOwningUser"; - RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); - RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); - RolePrincipal readVmUsername = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + vmUserame); - - Set<BasicRole> roles = new HashSet<>(); - roles.add(readVmUsername); - roles.add(readAgentId); - roles.add(HostnameFilter.GRANT_HOSTS_READ_ALL); - roles.add(readVmId); - - assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL)); - assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL)); - assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL)); - assertFalse(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL)); - SimplePrincipal testMe = new SimplePrincipal("test me"); - testMe.setRoles(roles); - StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, "QUERY " + VmInfoDAO.vmInfoCategory.getName()); - - // should pass through agentId -> hostname -> vmId -> vmUsername filters - FilterResult result = testMe.getReadFilter(desc); - - // should return query expression in order to allow only specific - // owning vm username. - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - ExpressionFactory factory = new ExpressionFactory(); - Set<String> usernames = new HashSet<>(); - usernames.add(vmUserame); - Expression userNameExp = factory.in(VmInfoDAO.usernameKey, usernames, String.class); - Set<String> agentIdSet = new HashSet<>(); - agentIdSet.add(agentId); - Expression agentIdExp = factory.in(Key.AGENT_ID, agentIdSet, String.class); - Set<String> vmIdSet = new HashSet<>(); - vmIdSet.add(vmId); - Expression vmIdExp = factory.in(Key.VM_ID, vmIdSet, String.class); - Expression lhs = factory.and(agentIdExp, vmIdExp); - Expression expected = factory.and(lhs, userNameExp); - assertEquals(expected, actual); - } - - - @SuppressWarnings("serial") - private static class SimplePrincipal extends UserPrincipal { - - public SimplePrincipal(String name) { - super(name); - } - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmIdFilterTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.Category; -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.model.Pojo; -import com.redhat.thermostat.storage.query.BinaryLogicalExpression; -import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -public class VmIdFilterTest { - - private static class FooPojo implements Pojo { - // Dummy class for testing - } - - private static final Category<FooPojo> TEST_NON_NULL_CATEGORY = new Category<>("foo-vmid-filter-test", FooPojo.class, Key.VM_ID); - private static final Category<FooPojo> TEST_NULL_CATEGORY = new Category<>("foo-vmid-filter-test-null", FooPojo.class); - /** - * A query descriptor which will return a non-null Key for the "vmId" name. - */ - private static final StatementDescriptor<FooPojo> TEST_DESC_NON_NULL_VM_ID = new StatementDescriptor<>(TEST_NON_NULL_CATEGORY, "QUERY foo"); - /** - * A query descriptor which will return a null Key for the "vmId" name. - */ - private static final StatementDescriptor<FooPojo> TEST_DESC_NULL_VM_ID = new StatementDescriptor<>(TEST_NULL_CATEGORY, "QUERY foo-null"); - - @Test - public void testReadAll() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vmIdReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL); - roles.add(vmIdReadAll); - - VmIdFilter<?> filter = new VmIdFilter<>(roles); - FilterResult result = filter.applyFilter(null, null); - assertEquals(ResultType.ALL, result.getType()); - assertEquals(null, result.getFilterExpression()); - } - - @Test - public void testReadAllAndParentExpression() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vmIdReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL); - roles.add(vmIdReadAll); - - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - VmIdFilter<?> filter = new VmIdFilter<>(roles); - FilterResult result = filter.applyFilter(null, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertEquals(parentExpression, result.getFilterExpression()); - } - - @Test - public void addsVmIdInQuery() { - String vmId = UUID.randomUUID().toString(); - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vmIdRole = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); - roles.add(vmIdRole); - VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles); - FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_VM_ID, null); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinarySetMembershipExpression); - Set<String> vmIdSet = new HashSet<>(); - vmIdSet.add(vmId); - Expression expected = new ExpressionFactory().in(Key.VM_ID, vmIdSet, String.class); - assertEquals(expected, actual); - } - - @Test - public void addsVmIdInQueryAndParentExpression() { - String vmId = UUID.randomUUID().toString(); - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vmIdRole = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); - roles.add(vmIdRole); - VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles); - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_VM_ID, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinaryLogicalExpression); - Set<String> vmIdSet = new HashSet<>(); - vmIdSet.add(vmId); - - Expression expectedIn = factory.in(Key.VM_ID, vmIdSet, String.class); - Expression expected = factory.and(parentExpression, expectedIn); - assertEquals(expected, actual); - } - - @Test - public void addsVmIdInQuery2() { - String vmId = UUID.randomUUID().toString(); - String vmId2 = UUID.randomUUID().toString(); - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vm1Role = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); - RolePrincipal vm2Role = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId2); - roles.add(vm1Role); - roles.add(vm2Role); - VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles); - FilterResult result = filter.applyFilter(TEST_DESC_NON_NULL_VM_ID, null); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinarySetMembershipExpression); - Set<String> vmIdSet = new HashSet<>(); - vmIdSet.add(vmId); - vmIdSet.add(vmId2); - Expression expected = new ExpressionFactory().in(Key.VM_ID, vmIdSet, String.class); - assertEquals(expected, actual); - } - - @Test - public void returnsAllForUnrelatedQuery() { - Set<BasicRole> roles = new HashSet<>(); - - VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles); - // want to have a null retval of vmId - FilterResult result = filter.applyFilter(TEST_DESC_NULL_VM_ID, null); - assertEquals(ResultType.ALL, result.getType()); - assertNull(result.getFilterExpression()); - } - - @Test - public void returnsParentExpressionForUnrelatedQuery() { - Set<BasicRole> roles = new HashSet<>(); - - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - VmIdFilter<FooPojo> filter = new VmIdFilter<>(roles); - // want to have a null retval of vmId - FilterResult result = filter.applyFilter(TEST_DESC_NULL_VM_ID, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - assertEquals(parentExpression, result.getFilterExpression()); - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmUsernameFilterTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.util.HashSet; -import java.util.Set; - -import org.junit.Test; - -import com.redhat.thermostat.storage.core.Key; -import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.dao.AgentInfoDAO; -import com.redhat.thermostat.storage.dao.VmInfoDAO; -import com.redhat.thermostat.storage.model.AgentInformation; -import com.redhat.thermostat.storage.model.VmInfo; -import com.redhat.thermostat.storage.query.BinaryLogicalExpression; -import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; -import com.redhat.thermostat.storage.query.Expression; -import com.redhat.thermostat.storage.query.ExpressionFactory; -import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; - -public class VmUsernameFilterTest { - - @Test - public void testReadAll() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vmUsernameReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL); - roles.add(vmUsernameReadAll); - - VmUsernameFilter<?> filter = new VmUsernameFilter<>(roles); - FilterResult result = filter.applyFilter(null, null); - assertEquals(ResultType.ALL, result.getType()); - assertEquals(null, result.getFilterExpression()); - } - - @Test - public void testReadAllWithParentExpression() { - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vmUsernameReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL); - roles.add(vmUsernameReadAll); - - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - VmUsernameFilter<?> filter = new VmUsernameFilter<>(roles); - FilterResult result = filter.applyFilter(null, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertEquals(parentExpression, result.getFilterExpression()); - } - - @Test - public void addsVmUsernameInQueryForVmInfo() { - String testUsername = "fooBar"; - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vmUsernameRole = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + testUsername); - roles.add(vmUsernameRole); - - StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, "QUERY " + VmInfoDAO.vmInfoCategory.getName()); - - Set<String> usernames = new HashSet<>(); - usernames.add(testUsername); - Expression expected = new ExpressionFactory().in(VmInfoDAO.usernameKey, usernames, String.class); - VmUsernameFilter<VmInfo> filter = new VmUsernameFilter<>(roles); - FilterResult result = filter.applyFilter(desc, null); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinarySetMembershipExpression); - assertEquals(expected, actual); - } - - @Test - public void addsVmUsernameInQueryForVmInfoAndParentExpression() { - String testUsername = "fooBar"; - Set<BasicRole> roles = new HashSet<>(); - RolePrincipal vmUsernameRole = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + testUsername); - roles.add(vmUsernameRole); - - StatementDescriptor<VmInfo> desc = new StatementDescriptor<>(VmInfoDAO.vmInfoCategory, "QUERY " + VmInfoDAO.vmInfoCategory.getName()); - - Set<String> usernames = new HashSet<>(); - usernames.add(testUsername); - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - Expression expectedIn = factory.in(VmInfoDAO.usernameKey, usernames, String.class); - Expression expected = factory.and(parentExpression, expectedIn); - VmUsernameFilter<VmInfo> filter = new VmUsernameFilter<>(roles); - FilterResult result = filter.applyFilter(desc, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - Expression actual = result.getFilterExpression(); - assertTrue(actual instanceof BinaryLogicalExpression); - assertEquals(expected, actual); - } - - @Test - public void byPassesFilterForUnrelatedQuery() { - Set<BasicRole> roles = new HashSet<>(); - - StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, "QUERY " + AgentInfoDAO.CATEGORY.getName()); - - VmUsernameFilter<AgentInformation> filter = new VmUsernameFilter<>(roles); - FilterResult result = filter.applyFilter(desc, null); - assertEquals(ResultType.ALL, result.getType()); - assertNull(result.getFilterExpression()); - } - - @Test - public void byPassesFilterForUnrelatedQueryAndParentExpression() { - Set<BasicRole> roles = new HashSet<>(); - - StatementDescriptor<AgentInformation> desc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, "QUERY " + AgentInfoDAO.CATEGORY.getName()); - - ExpressionFactory factory = new ExpressionFactory(); - Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); - VmUsernameFilter<AgentInformation> filter = new VmUsernameFilter<>(roles); - FilterResult result = filter.applyFilter(desc, parentExpression); - assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); - assertNotNull(result.getFilterExpression()); - assertEquals(parentExpression, result.getFilterExpression()); - } - -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/WrappedRolePrincipalTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - * 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.web.server.auth; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.Enumeration; -import java.util.Vector; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class WrappedRolePrincipalTest { - - private Group group; - @SuppressWarnings("rawtypes") - private Enumeration members = new Vector().elements(); - - @SuppressWarnings("unchecked") - @Before - public void setup() { - group = mock(Group.class); - when(group.addMember(any(Principal.class))).thenReturn(true); - when(group.isMember(any(Principal.class))).thenReturn(true); - when(group.getName()).thenReturn("group-under-the-hood"); - when(group.members()).thenReturn(members); - when(group.removeMember(any(Principal.class))).thenReturn(false); - } - - @After - public void tearDown() { - group = null; - } - - @Test - public void testAllDelegates() { - WrappedRolePrincipal p = new WrappedRolePrincipal(group); - Principal mock = mock(Principal.class); - assertEquals(true, p.addMember(mock)); - assertEquals(true, p.isMember(mock)); - assertEquals("group-under-the-hood", p.getName()); - assertEquals(members, p.members()); - assertEquals(false, p.removeMember(mock)); - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/AbstractLoginModuleTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import static org.junit.Assert.assertEquals; - -import java.util.Map; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; - -import org.junit.Test; - -public class AbstractLoginModuleTest { - - @Test - public void canGetUserNameFromCallBack() throws LoginException { - SimpleCallBackHandler handler = new SimpleCallBackHandler("testuser"); - LoginModuleImpl loginModule = new LoginModuleImpl(); - loginModule.initialize(new Subject(), handler, null, null); - assertEquals("testuser", loginModule.getUsernameFromCallBack()); - } - - @Test - public void canGetUserPasswordFromCallBack() throws LoginException { - SimpleCallBackHandler handler = new SimpleCallBackHandler("testuser", "testpassword".toCharArray()); - LoginModuleImpl loginModule = new LoginModuleImpl(); - loginModule.initialize(new Subject(), handler, null, null); - Object[] creds = loginModule.getUsernamePasswordFromCallBack(); - String user = (String)creds[0]; - char[] pwd = (char[])creds[1]; - assertEquals("testuser", user); - assertEquals("testpassword", new String(pwd)); - } - - private static class LoginModuleImpl extends AbstractLoginModule { - - @Override - public void initialize(Subject subject, - CallbackHandler callbackHandler, Map<String, ?> sharedState, - Map<String, ?> options) { - this.callBackHandler = callbackHandler; - } - - @Override - public boolean login() throws LoginException { - // don't care - return false; - } - - @Override - public boolean commit() throws LoginException { - // don't care - return false; - } - - @Override - public boolean abort() throws LoginException { - // don't care - return false; - } - - @Override - public boolean logout() throws LoginException { - // don't care - return false; - } - - @Override - public String getUsernameFromCallBack() throws LoginException { - return super.getUsernameFromCallBack(); - } - - @Override - public Object[] getUsernamePasswordFromCallBack() throws LoginException { - return super.getUsernamePasswordFromCallBack(); - } - - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/DelegateLoginModuleTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,197 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.security.Principal; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag; -import javax.security.auth.login.Configuration; -import javax.security.auth.login.LoginException; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.web.server.auth.BasicRole; -import com.redhat.thermostat.web.server.auth.RolePrincipal; -import com.redhat.thermostat.web.server.auth.UserPrincipal; - -public class DelegateLoginModuleTest { - - private Subject subject; - private Map<String, Object> mockSharedState; - private Map<String, Object> mockOptions; - private CallbackHandler mockCallBack; - - @Before - public void setup() { - subject = new Subject(); - mockSharedState = new HashMap<>(); - mockOptions = new HashMap<>(); - // DelegateLoginModule uses the name callback - mockCallBack = new SimpleCallBackHandler("testUser", "doesn't matter".toCharArray()); - // sets jaas config so as to use Stub*DelegateLoginModule - Configuration config = new TestConfiguration(); - Configuration.setConfiguration(config); - } - - @After - public void teardown() { - subject = null; - mockSharedState = null; - mockOptions = null; - mockCallBack = null; - } - - @Test - public void testBasicsSuccess() throws Exception { - DelegateLoginModule delegateLogin = new DelegateLoginModule("Success"); - delegateLogin.initialize(subject, mockCallBack, mockSharedState, mockOptions); - assertTrue("Stub delegate in use is always successfull", delegateLogin.login()); - assertTrue("Stub delegate in use is always successfull", delegateLogin.commit()); - // SubSuccessDelegateLoginModule added one user principal - // 'testUser' and one role principal 'testRole'. - Subject subject = delegateLogin.getSubject(); - assertEquals(this.subject, subject); - Set<Principal> principals = subject.getPrincipals(); - assertEquals(2, principals.size()); - for (Principal p : principals) { - if (p.getName().equals("testUser")) { - // user principal - assertTrue(p instanceof UserPrincipal); - UserPrincipal uPrincipal = (UserPrincipal) p; - assertNotNull("Should now be a thermostat UserPrincipal containing roles", uPrincipal.getRoles()); - assertEquals(1, uPrincipal.getRoles().size()); - for (BasicRole role : uPrincipal.getRoles()) { - assertEquals("testRole", role.getName()); - } - } - if (p.getName().equals("testRole")) { - assertTrue("Should have been wrapped into a BasicRole", p instanceof BasicRole); - } - } - // Test the same another way for good measure. - assertTrue(principals.contains(new UserPrincipal("testUser"))); - assertTrue(principals.contains(new RolePrincipal("testRole"))); - - // now logout. we expect principals to be cleared - delegateLogin.logout(); - assertEquals(0, subject.getPrincipals().size()); - } - - @Test - public void testBasicsFailure() throws Exception { - DelegateLoginModule delegateLogin = new DelegateLoginModule("Failure"); - delegateLogin.initialize(subject, mockCallBack, mockSharedState, mockOptions); - // add some principal to the subject in order to make sure delegate - // clears principals on login failure. - Principal mock = new Principal() { - - @Override - public String getName() { - return "tester"; - } - - }; - subject.getPrincipals().add(mock); - assertEquals(1, subject.getPrincipals().size()); - try { - // this triggers abort() being called for the delegate. - delegateLogin.login(); - fail("StubFailureDelegateLoginModule should have thrown LE"); - } catch (LoginException e) { - // pass - } - assertEquals(0, subject.getPrincipals().size()); - } - - @Test - public void testAbort() throws LoginException { - // add some principal to the subject in order to make sure delegate - // clears principals on login failure. - Principal mock = new Principal() { - - @Override - public String getName() { - return "tester"; - } - - }; - subject.getPrincipals().add(mock); - assertEquals(1, subject.getPrincipals().size()); - DelegateLoginModule delegateLogin = new DelegateLoginModule("Failure"); - delegateLogin.initialize(subject, mockCallBack, mockSharedState, mockOptions); - // simulate abort which should clear any principals from the subject - delegateLogin.abort(); - assertEquals(0, subject.getPrincipals().size()); - } - - private class TestConfiguration extends Configuration { - - private final AppConfigurationEntry successEntry = - new AppConfigurationEntry(StubSuccessDelegateLoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, new HashMap<String, Object>()); - private final AppConfigurationEntry failureEntry = - new AppConfigurationEntry(StubFailureDelegateLoginModule.class.getName(), LoginModuleControlFlag.REQUIRED, new HashMap<String, Object>()); - - @Override - public AppConfigurationEntry[] getAppConfigurationEntry(String name) { - AppConfigurationEntry entry = null; - if (name.equals("Failure")) { - entry = failureEntry; - } else if (name.equals("Success")) { - entry = successEntry; - } else { - throw new RuntimeException("Don't know how to handle config name '" + name + "'"); - } - return new AppConfigurationEntry[] { entry }; - } - - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUserValidatorTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLDecoder; -import java.util.HashSet; -import java.util.Set; - -import org.junit.After; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.shared.config.InvalidConfigurationException; - -public class PropertiesUserValidatorTest { - - private PropertiesUserValidator validator; - - @Before - public void setup() { - String testFile = decodeFilePath(this.getClass().getResource("/test_users.properties")); - validator = new PropertiesUserValidator(testFile); - } - - @After - public void tearDown() { - validator = null; - } - - - @Test - public void authenticationFailsForNonExistingUser() { - try { - validator.authenticate("does not exist", null); - fail("user does not exist in file"); - } catch (UserValidationException e) { - // pass - assertEquals("User 'does not exist' not found", e.getMessage()); - } - } - - @Test - public void passwordMatch() { - try { - validator.authenticate("user1", "passwd1".toCharArray()); - validator.authenticate("strange\nuser", "testMe".toCharArray()); - validator.authenticate("c102892{0}", "test".toCharArray()); - // extra spaces are remved from properties system - validator.authenticate("multiuser", "blah\ntest test".toCharArray()); - // '\0' in test_users.properties become '0' - validator.authenticate("strange0user", "test0Me".toCharArray()); - // pass - } catch (UserValidationException e) { - e.printStackTrace(); - fail("should have been able to authenticate user"); - } - } - - @Test - public void passwordMismatch() { - try { - validator.authenticate("user1", "passwD1".toCharArray()); - fail("password does not match!"); - } catch (UserValidationException e) { - assertEquals("Login failed!", e.getMessage()); - } - try { - validator.authenticate("c102892{0}", "passwd1".toCharArray()); - } catch (UserValidationException e) { - assertEquals("Login failed!", e.getMessage()); - } - } - - @Test - public void testInit() { - Assume.assumeTrue(System.getenv("THERMOSTAT_HOME") == null); - try { - new PropertiesUserValidator(); - fail("THERMOSTAT_HOME not set, should have failed!"); - } catch (InvalidConfigurationException e) { - // pass - assertTrue(e.getMessage().contains("THERMOSTAT_HOME")); - } - } - - @Test - public void testInitWithMissingFile() { - try { - new PropertiesUserValidator("file/which/does/not/exist"); - } catch (InvalidConfigurationException e) { - // pass - assertEquals("Unable to load user database", e.getMessage()); - } - } - - @Test - public void canGetUserSet() { - Set<String> expectedSet = new HashSet<>(10); - expectedSet.add("user1"); - expectedSet.add("testing"); - expectedSet.add("multiuser"); - expectedSet.add("c102892{0}"); - expectedSet.add("strange\nuser"); - expectedSet.add("strange0user"); - Set<Object> actual = validator.getAllKnownUsers(); - assertTrue(expectedSet.equals(actual)); - expectedSet.remove("user1"); - assertFalse(expectedSet.equals(actual)); - } - - private static String decodeFilePath(URL url) { - try { - // Spaces are encoded as %20 in URLs. Use URLDecoder.decode() so - // as to handle cases like that. - return URLDecoder.decode(url.getFile(), "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new AssertionError("UTF-8 not supported, huh?"); - } - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/PropertiesUsernameRolesLoginModuleTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,331 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLDecoder; -import java.security.Principal; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.web.server.auth.RolePrincipal; -import com.redhat.thermostat.web.server.auth.UserPrincipal; - -public class PropertiesUsernameRolesLoginModuleTest { - - private Subject subject; - private Map<String, Object> mockSharedState; - private Map<String, Object> mockOptions; - private CallbackHandler mockCallBack; - - @Before - public void setup() { - subject = new Subject(); - mockSharedState = new HashMap<>(); - mockOptions = new HashMap<>(); - } - - @After - public void teardown() { - subject = null; - mockSharedState = null; - mockOptions = null; - mockCallBack = null; - } - - @Test - public void canInitialize() { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("testUser", "testpassword".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - try { - // this must not throw an exception - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - // pass - } catch (Exception e) { - fail("Did not expect any exception here!"); - } - } - - @Test - public void failsToLoginWithInvalidCredentials() { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - // testUser/testpassword not defined - mockCallBack = new SimpleCallBackHandler("testUser", "testpassword".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - try { - loginModule.login(); - fail("testUser not defined in properties_module_test_users.properties"); - } catch (LoginException e) { - // pass - assertEquals("User 'testUser' not found", e.getMessage()); - } - mockCallBack = new SimpleCallBackHandler("user1", "wrongpassword".toCharArray()); - loginModule = new PropertiesUsernameRolesLoginModule(); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - try { - loginModule.login(); - fail("user1 provided wrong password!"); - } catch (LoginException e) { - assertEquals("Login failed!", e.getMessage()); - } - } - - @Test - public void canLoginWithValidCredentials() { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - try { - boolean retval = loginModule.login(); - // pass - assertTrue("Login should have returned true", retval); - } catch (LoginException e) { - fail("'user1' should be able to login"); - } - mockCallBack = new SimpleCallBackHandler("user2", "password".toCharArray()); - loginModule = new PropertiesUsernameRolesLoginModule(); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - try { - boolean retval = loginModule.login(); - // pass - assertTrue("Login should have returned true", retval); - } catch (LoginException e) { - fail("'user2' should be able to login"); - } - } - - @Test - public void canCommitOnSuccessfulLogin() throws LoginException { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - assertTrue(loginModule.login()); - try { - boolean retval = loginModule.commit(); - // pass - assertTrue("Commit should have returned true", retval); - } catch (LoginException e) { - fail("'user1' should have been able to commit"); - } - // assert principals are added to subject - Set<Principal> principals = subject.getPrincipals(); - // my-role, my-role2, Roles, user1 - assertEquals(4, principals.size()); - assertTrue(principals.contains(new RolePrincipal("my-role"))); - assertTrue(principals.contains(new RolePrincipal("my-role2"))); - assertTrue(principals.contains(new RolePrincipal("Roles"))); - assertTrue(principals.contains(new UserPrincipal("user1"))); - } - - @Test - public void testRecursiveRoles() throws LoginException { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("user2", "password".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - assertTrue(loginModule.login()); - try { - boolean retval = loginModule.commit(); - // pass - assertTrue("Commit should have returned true", retval); - } catch (LoginException e) { - fail("'user2' should have been able to commit"); - } - // assert principals are added to subject - Set<Principal> principals = subject.getPrincipals(); - // new-role, role1, other-role, Roles, user2 - assertEquals(5, principals.size()); - assertTrue(principals.contains(new RolePrincipal("new-role"))); - assertTrue(principals.contains(new RolePrincipal("role1"))); - assertTrue(principals.contains(new RolePrincipal("Roles"))); - // via recursive role 'role1' - assertTrue(principals.contains(new RolePrincipal("other-role"))); - assertTrue(principals.contains(new UserPrincipal("user2"))); - } - - @Test - public void testRecursiveRolesMultiple() throws LoginException { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("user3", "password".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - assertTrue(loginModule.login()); - try { - boolean retval = loginModule.commit(); - // pass - assertTrue("Commit should have returned true", retval); - } catch (LoginException e) { - fail("'user3' should have been able to commit"); - } - // assert principals are added to subject - Set<Principal> principals = subject.getPrincipals(); - // other-role, role1, Roles, user3 - assertEquals(4, principals.size()); - assertTrue(principals.contains(new RolePrincipal("role1"))); - assertTrue(principals.contains(new RolePrincipal("Roles"))); - // via recursive role 'role1' - assertTrue(principals.contains(new RolePrincipal("other-role"))); - assertTrue(principals.contains(new UserPrincipal("user3"))); - loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("user2", "password".toCharArray()); - subject = new Subject(); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - assertTrue(loginModule.login()); - try { - boolean retval = loginModule.commit(); - // pass - assertTrue("Commit should have returned true", retval); - } catch (LoginException e) { - fail("'user2' should have been able to commit"); - } - // assert principals are added to subject - principals = subject.getPrincipals(); - // new-role, other-role, role1, Roles, user2 - assertEquals(5, principals.size()); - assertTrue(principals.contains(new RolePrincipal("role1"))); - assertTrue(principals.contains(new RolePrincipal("Roles"))); - // via recursive role 'role1' - assertTrue(principals.contains(new RolePrincipal("other-role"))); - assertTrue(principals.contains(new UserPrincipal("user2"))); - assertTrue(principals.contains(new RolePrincipal("new-role"))); - } - - @Test - public void cannotCommitWithoutLoggingIn() throws LoginException { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - assertFalse(loginModule.commit()); - - loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - assertFalse(loginModule.commit()); - assertEquals(0, subject.getPrincipals().size()); - } - - @Test - public void testLoginCommitAbort() throws LoginException { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - assertTrue(loginModule.login()); - assertTrue(loginModule.commit()); - // assert principals are added to subject after login - Set<Principal> principals = subject.getPrincipals(); - // my-role, my-role2, Roles, user1 - assertEquals(4, principals.size()); - assertTrue(loginModule.abort()); - // make sure principals are cleared - assertEquals(0, principals.size()); - } - - @Test - public void testLoginCommitLogout() throws LoginException { - LoginModule loginModule = new PropertiesUsernameRolesLoginModule(); - mockCallBack = new SimpleCallBackHandler("user1", "somepassword".toCharArray()); - String userFile = decodeFilePath(this.getClass().getResource("/properties_module_test_users.properties")); - String rolesFile = decodeFilePath(this.getClass().getResource("/properties_module_test_roles.properties")); - mockOptions.put("users.properties", userFile); - mockOptions.put("roles.properties", rolesFile); - loginModule.initialize(subject, mockCallBack, mockSharedState, mockOptions); - assertTrue(loginModule.login()); - assertTrue(loginModule.commit()); - // assert principals are added to subject after login - Set<Principal> principals = subject.getPrincipals(); - // my-role, my-role2, Roles, user1 - assertEquals(4, principals.size()); - assertTrue(loginModule.logout()); - // make sure principals are cleared - assertEquals(0, principals.size()); - } - - private static String decodeFilePath(URL url) { - try { - // Spaces are encoded as %20 in URLs. Use URLDecoder.decode() so - // as to handle cases like that. - return URLDecoder.decode(url.getFile(), "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new AssertionError("UTF-8 not supported, huh?"); - } - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/RolesAmenderTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,281 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLDecoder; -import java.security.Principal; -import java.util.Collections; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.junit.After; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; - -import com.redhat.thermostat.shared.config.InvalidConfigurationException; -import com.redhat.thermostat.web.server.auth.BasicRole; -import com.redhat.thermostat.web.server.auth.RolePrincipal; -import com.redhat.thermostat.web.server.auth.spi.RolesAmender.RolesInfo; - -public class RolesAmenderTest { - - private RolesAmender rolesAmender; - private String validFile; - private Set<Object> validUsers; - - @Before - public void setup() { - String testFile = decodeFilePath(this.getClass().getResource("/test_roles.properties")); - validFile = testFile; - Set<Object> users = new HashSet<>(); - users.add("user1"); - users.add("user2"); - users.add("someuser"); - users.add("someotheruser"); - validUsers = Collections.unmodifiableSet(users); - } - - @After - public void tearDown() { - rolesAmender = null; - validFile = null; - } - - @Test - public void testGetRolesDoesntLeak() { - rolesAmender = new RolesAmender(validFile, validUsers); - Set<BasicRole> roles = rolesAmender.getRoles("foo"); - assertEquals(roles, Collections.emptySet()); - BasicRole fooRole = mock(BasicRole.class); - roles.add(fooRole); - assertEquals(rolesAmender.getRoles("foo"), Collections.emptySet()); - } - - @Test - public void canParseRoles() { - rolesAmender = new RolesAmender(validFile, validUsers); - Set<BasicRole> roles = rolesAmender.getRoles("user1"); - assertEquals(2, roles.size()); - Map<String, Boolean> userRolesMap = new HashMap<>(); - for (BasicRole role : roles) { - // don't expect role nesting - assertTrue(role instanceof RolePrincipal); - assertFalse(role.members().hasMoreElements()); - userRolesMap.put(role.getName(), true); - } - assertTrue(userRolesMap.containsKey("my-role")); - assertTrue(userRolesMap.containsKey("my-role2")); - roles = rolesAmender.getRoles("user2"); - // new-role, role1, other-role - assertEquals(3, roles.size()); - for (BasicRole role : roles) { - assertTrue(role instanceof RolePrincipal); - if (role.getName().equals("role1")) { - // nested role - int count = 0; - @SuppressWarnings("rawtypes") - Enumeration members = role.members(); - while (members.hasMoreElements()) { - count++; - assertEquals("other-role", ((Principal) members.nextElement()).getName()); - } - assertEquals(1, count); - } - if (role.getName().equals("new-role")) { - // not nested - assertFalse(role.members().hasMoreElements()); - } - } - assertTrue(roles.contains(new RolePrincipal("other-role"))); - // role1 is not a user - roles = rolesAmender.getRoles("role1"); - // expect empty - assertEquals(0, roles.size()); - } - - @Test - public void canParseRecursiveRolesWithMultipleMemberships() { - rolesAmender = new RolesAmender(validFile, validUsers); - Set<BasicRole> roles = rolesAmender.getRoles("user2"); - // new-role, role1, other-role - assertEquals(3, roles.size()); - for (BasicRole role : roles) { - assertTrue(role instanceof RolePrincipal); - if (role.getName().equals("role1")) { - // nested role - int count = 0; - @SuppressWarnings("rawtypes") - Enumeration members = role.members(); - while (members.hasMoreElements()) { - count++; - assertEquals("other-role", ((Principal) members.nextElement()).getName()); - } - assertEquals(1, count); - } - if (role.getName().equals("new-role")) { - // not nested - assertFalse(role.members().hasMoreElements()); - } - } - assertTrue(roles.contains(new RolePrincipal("other-role"))); - // role1 is not a user - roles = rolesAmender.getRoles("role1"); - // expect empty - assertEquals(0, roles.size()); - // test another user which is member of the recursive role - roles = rolesAmender.getRoles("someuser"); - assertEquals( - "Expected someuser to be a member of 'testing', 'role1' and 'other-role'", - 3, roles.size()); - assertTrue(roles.contains(new RolePrincipal("other-role"))); - assertTrue(roles.contains(new RolePrincipal("testing"))); - assertTrue(roles.contains(new RolePrincipal("role1"))); - // and yet another user which is part of a recursive role - roles = rolesAmender.getRoles("someotheruser"); - assertEquals( - "Expected someotheruser to be a member of 'role1' and 'other-role'", - 2, roles.size()); - assertTrue(roles.contains(new RolePrincipal("other-role"))); - assertTrue(roles.contains(new RolePrincipal("role1"))); - } - - @Test - public void canParseRolesWithMoreUsersThanUsedInRoles() { - Set<Object> users = new HashSet<>(); - users.add("user1"); - users.add("user2"); - users.add("someuser"); - users.add("someotheruser"); - users.add("user-with-no-roles"); - validUsers = Collections.unmodifiableSet(users); - try { - rolesAmender = new RolesAmender(validFile, validUsers); - } catch (Exception e) { - fail("should be able to parse roles"); - } - Set<BasicRole> roles = rolesAmender.getRoles("user-with-no-roles"); - assertEquals(0, roles.size()); - } - - @Test - public void parseFailsIfUserInRecursiveRole() { - String brokenFile = decodeFilePath(this.getClass().getResource("/broken_test_roles.properties")); - try { - rolesAmender = new RolesAmender(brokenFile, validUsers); - fail("Should not parse"); - } catch (Exception e) { - assertTrue(e instanceof IllegalStateException); - assertEquals("Failed to parse roles", e.getMessage()); - } - } - - @Test - public void parseFailsIfNotAnyUserMemberOfRecursiveRole() { - String brokenFile = decodeFilePath(this.getClass().getResource("/broken_test_roles2.properties")); - try { - rolesAmender = new RolesAmender(brokenFile, validUsers); - fail("Should not parse"); - } catch (Exception e) { - assertTrue(e instanceof IllegalStateException); - assertEquals("Failed to parse roles", e.getMessage()); - } - } - - @Test - public void testInit() { - Assume.assumeTrue(System.getenv("THERMOSTAT_HOME") == null); - try { - new RolesAmender(null); - fail("THERMOSTAT_HOME not set, should have failed!"); - } catch (InvalidConfigurationException e) { - // pass - assertTrue(e.getMessage().contains("THERMOSTAT_HOME")); - } - } - - @Test - public void testInitWithMissingFile() { - try { - new RolesAmender("file/which/does/not/exist", validUsers); - } catch (InvalidConfigurationException e) { - // pass - assertEquals("Failed to load roles from properties", e.getMessage()); - } - } - - @Test(expected = NullPointerException.class) - public void testInitNull() { - new RolesAmender("not-important", null); - } - - @Test - public void rolesInfoTest() { - RolePrincipal p = new RolePrincipal("test-role"); - RolesInfo info = new RolesInfo(p); - assertEquals("test-role", info.getRole().getName()); - assertEquals(0, info.getMemberUsers().size()); - Set<String> roleMembers = info.getMemberUsers(); - roleMembers.add("testuser"); - assertEquals(1, info.getMemberUsers().size()); - assertEquals(true, info.getMemberUsers().contains("testuser")); - roleMembers.add("testuser"); - assertEquals(1, info.getMemberUsers().size()); - } - - private static String decodeFilePath(URL url) { - try { - // Spaces are encoded as %20 in URLs. Use URLDecoder.decode() so - // as to handle cases like that. - return URLDecoder.decode(url.getFile(), "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new AssertionError("UTF-8 not supported, huh?"); - } - } -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/SimpleCallBackHandler.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.io.IOException; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; - -class SimpleCallBackHandler implements CallbackHandler { - - private final String username; - private final char[] password; - - SimpleCallBackHandler(String username) { - this.username = username; - this.password = null; - } - - SimpleCallBackHandler(String username, char[] password) { - this.username = username; - this.password = password; - } - - @Override - public void handle(Callback[] callbacks) throws IOException, - UnsupportedCallbackException { - for (int i = 0; i < callbacks.length; i++) { - Callback cb = callbacks[i]; - if (cb instanceof NameCallback) { - ((NameCallback) cb).setName(username); - } - if (cb instanceof PasswordCallback) { - ((PasswordCallback) cb).setPassword(password); - } - } - - } - -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/StubFailureDelegateLoginModule.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.util.Map; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -public class StubFailureDelegateLoginModule implements LoginModule { - - private boolean initialized = false; - private boolean loginCalled = false; - private Subject subject; - - @Override - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map<String, ?> sharedState, Map<String, ?> options) { - this.subject = subject; - this.initialized = true; - } - - @Override - public boolean login() throws LoginException { - if (!initialized) { - throw new AssertionError("logging in when not initialized"); - } - loginCalled = true; - throw new LoginException("Failed to login"); - } - - @Override - public boolean commit() throws LoginException { - throw new AssertionError("should never be called"); - } - - @Override - public boolean abort() throws LoginException { - if (!loginCalled) { - throw new AssertionError("should have called login first"); - } - subject.getPrincipals().clear(); - return true; - } - - @Override - public boolean logout() throws LoginException { - // don't care - return true; - } - -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/spi/StubSuccessDelegateLoginModule.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/* - * 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.web.server.auth.spi; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.Enumeration; -import java.util.Map; -import java.util.Set; -import java.util.Vector; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -public class StubSuccessDelegateLoginModule implements LoginModule { - - private boolean initialized = false; - private boolean loggedIn = false; - private Subject subject; - - @Override - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map<String, ?> sharedState, Map<String, ?> options) { - this.subject = subject; - this.initialized = true; - } - - @Override - public boolean login() throws LoginException { - if (!initialized) { - throw new AssertionError("logging in when not initialized"); - } - this.loggedIn = true; - return true; - } - - @Override - public boolean commit() throws LoginException { - if (!loggedIn) { - throw new AssertionError("committing when not logged in"); - } - // fake adding two principals. One user and one role - // principal. - Set<Principal> principals = this.subject.getPrincipals(); - principals.add(new Principal() { - - @Override - public String getName() { - return "testUser"; - } - - }); - principals.add(new Group() { - - @Override - public String getName() { - return "testRole"; - } - - @Override - public boolean addMember(Principal user) { - // don't care - return false; - } - - @Override - public boolean removeMember(Principal user) { - // don't care - return false; - } - - @Override - public boolean isMember(Principal member) { - // don't care - return false; - } - - @Override - public Enumeration<? extends Principal> members() { - Vector<Principal> stub = new Vector<>(); - return stub.elements(); - } - - }); - return true; - } - - @Override - public boolean abort() throws LoginException { - throw new AssertionError("Should never be called"); - } - - @Override - public boolean logout() throws LoginException { - return true; - } - -} -
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/ContainerVersionTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * 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.web.server.containers; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -import com.redhat.thermostat.web.server.containers.ContainerVersion; - -public class ContainerVersionTest { - - - @Test - public void canGetVersion() { - ContainerVersion version = new ContainerVersion(0, 20, 10, null); - assertEquals(0, version.getMajor()); - assertEquals(20, version.getMinor()); - assertEquals(10, version.getMicro()); - } - - @Test - public void testSuffix() { - ContainerVersion version = new ContainerVersion(0, 20, 10, null); - assertEquals(ContainerVersion.UNKNOWN_SUFFIX, version.getSuffix()); - version = new ContainerVersion(0, 20, 10, "foo"); - assertEquals("foo", version.getSuffix()); - } - - @Test - public void testToString() { - ContainerVersion version = new ContainerVersion(0, 20, 10, null); - assertEquals("0.20.10." + ContainerVersion.UNKNOWN_SUFFIX, version.toString()); - version = new ContainerVersion(0, 20, 10, "foo"); - assertEquals("0.20.10.foo", version.toString()); - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/JettyContainerInfoTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * 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.web.server.containers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import org.junit.Test; - -public class JettyContainerInfoTest { - - static final String JETTY8_SERVER_INFO = "jetty/8.1.5.v20120716"; - static final String JETTY9_SERVER_INFO = "jetty/9.1.0.v20131115"; - - @Test - public void testParseJetty8ContainerVersion() { - JettyContainerInfo info = new JettyContainerInfo(JETTY8_SERVER_INFO); - assertEquals(ContainerName.JETTY, info.getName()); - ContainerVersion version = info.getContainerVersion(); - assertNotNull(version); - assertEquals(8, version.getMajor()); - assertEquals(1, version.getMinor()); - assertEquals(5, version.getMicro()); - assertEquals("v20120716", version.getSuffix()); - assertEquals("8.1.5.v20120716", version.toString()); - } - - @Test - public void testParseJetty9ContainerVersion() { - JettyContainerInfo info = new JettyContainerInfo(JETTY9_SERVER_INFO); - assertEquals(ContainerName.JETTY, info.getName()); - ContainerVersion version = info.getContainerVersion(); - assertNotNull(version); - assertEquals(9, version.getMajor()); - assertEquals(1, version.getMinor()); - assertEquals(0, version.getMicro()); - assertEquals("v20131115", version.getSuffix()); - assertEquals("9.1.0.v20131115", version.toString()); - } - - @Test - public void testParseEmpty() { - try { - new JettyContainerInfo(""); - fail("should have failed to instantiate"); - } catch (IllegalArgumentException e) { - assertEquals("Illegal server info: ''", e.getMessage()); - } - } - - @Test - public void testParseNull() { - try { - new JettyContainerInfo(null); - fail("should have failed to instantiate"); - } catch (NullPointerException e) { - // pass - } - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/ServletContainerInfoFactoryTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * 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.web.server.containers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; - -import org.junit.Test; - -public class ServletContainerInfoFactoryTest { - - @Test - public void canGetTomcat7ContainerInfo() { - ServletContainerInfoFactory factory = new ServletContainerInfoFactory(TomcatContainerInfoTest.TOMCAT7_SERVER_INFO); - ServletContainerInfo info = factory.getInfo(); - assertNotNull(info); - assertEquals(ContainerName.TOMCAT, info.getName()); - assertNotNull(info.getContainerVersion()); - } - - @Test - public void canGetTomcat6ContainerInfo() { - ServletContainerInfoFactory factory = new ServletContainerInfoFactory(TomcatContainerInfoTest.TOMCAT6_SERVER_INFO); - ServletContainerInfo info = factory.getInfo(); - assertNotNull(info); - assertEquals(ContainerName.TOMCAT, info.getName()); - assertNotNull(info.getContainerVersion()); - } - - @Test - public void canGetJBossAS7ContainerInfo() { - ServletContainerInfoFactory factory = new ServletContainerInfoFactory(WildflyContainerInfoTest.JBOSS_AS7_SERVER_INFO); - ServletContainerInfo info = factory.getInfo(); - assertNotNull(info); - assertEquals(ContainerName.WILDFLY, info.getName()); - assertNotNull(info.getContainerVersion()); - } - - @Test - public void canGetWildfly8ContainerInfo() { - ServletContainerInfoFactory factory = new ServletContainerInfoFactory(WildflyContainerInfoTest.WILDFLY8_SERVER_INFO); - ServletContainerInfo info = factory.getInfo(); - assertNotNull(info); - assertEquals(ContainerName.WILDFLY, info.getName()); - assertNotNull(info.getContainerVersion()); - } - - @Test - public void canGetJetty8ContainerInfo() { - ServletContainerInfoFactory factory = new ServletContainerInfoFactory(JettyContainerInfoTest.JETTY8_SERVER_INFO); - ServletContainerInfo info = factory.getInfo(); - assertNotNull(info); - assertEquals(ContainerName.JETTY, info.getName()); - assertNotNull(info.getContainerVersion()); - } - - @Test - public void canGetJetty9ContainerInfo() { - ServletContainerInfoFactory factory = new ServletContainerInfoFactory(JettyContainerInfoTest.JETTY9_SERVER_INFO); - ServletContainerInfo info = factory.getInfo(); - assertNotNull(info); - assertEquals(ContainerName.JETTY, info.getName()); - assertNotNull(info.getContainerVersion()); - } - - @Test - public void unknownReturnsNull() { - ServletContainerInfoFactory factory = new ServletContainerInfoFactory("dont-know"); - ServletContainerInfo info = factory.getInfo(); - assertNull(info); - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/TomcatContainerInfoTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * 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.web.server.containers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; - -import org.junit.Test; - -public class TomcatContainerInfoTest { - - static final String TOMCAT7_SERVER_INFO = "Apache Tomcat/7.0.35"; - static final String TOMCAT6_SERVER_INFO = "Apache Tomcat/6.0.37"; - - @Test - public void testTomcat7ContainerInfo() { - ServletContainerInfo info = new TomcatContainerInfo(TOMCAT7_SERVER_INFO); - assertNotNull(info); - assertEquals(ContainerName.TOMCAT, info.getName()); - ContainerVersion version = info.getContainerVersion(); - assertNotNull(version); - assertEquals(7, version.getMajor()); - assertEquals(0, version.getMinor()); - assertEquals(35, version.getMicro()); - assertEquals(ContainerVersion.UNKNOWN_SUFFIX, version.getSuffix()); - assertEquals("7.0.35." + ContainerVersion.UNKNOWN_SUFFIX, version.toString()); - } - - @Test - public void testTomcat6ContainerInfo() { - ServletContainerInfo info = new TomcatContainerInfo(TOMCAT6_SERVER_INFO); - assertNotNull(info); - assertEquals(ContainerName.TOMCAT, info.getName()); - ContainerVersion version = info.getContainerVersion(); - assertNotNull(version); - assertEquals(6, version.getMajor()); - assertEquals(0, version.getMinor()); - assertEquals(37, version.getMicro()); - assertEquals(ContainerVersion.UNKNOWN_SUFFIX, version.getSuffix()); - assertEquals("6.0.37." + ContainerVersion.UNKNOWN_SUFFIX, version.toString()); - } - - @Test - public void testNull() { - try { - new TomcatContainerInfo(null); - fail("should have failed to instantiate"); - } catch (NullPointerException e) { - // pass - } - } - - @Test - public void testEmpty() { - try { - new TomcatContainerInfo(""); - fail("should have failed to instantiate"); - } catch (IllegalArgumentException e) { - assertEquals("Illegal server info: ''", e.getMessage()); - } - } -}
--- a/web/server/src/test/java/com/redhat/thermostat/web/server/containers/WildflyContainerInfoTest.java Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * 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.web.server.containers; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - -import org.junit.Test; - -public class WildflyContainerInfoTest { - - // JBoss AS uses JBoss Web as servlet container - static final String JBOSS_AS7_SERVER_INFO = "JBoss Web/7.0.13.Final"; - // wildfly uses undertow as it's servlet container: see http://undertow.io/ - static final String WILDFLY8_SERVER_INFO = "Undertow - 1.0.0.Beta17"; - - @Test - public void testJBossAS7ContainerInfo() { - ServletContainerInfo info = new WildflyContainerInfo(JBOSS_AS7_SERVER_INFO); - assertNotNull(info); - assertEquals(ContainerName.WILDFLY, info.getName()); - ContainerVersion version = info.getContainerVersion(); - assertNotNull(version); - assertEquals(7, version.getMajor()); - assertEquals(0, version.getMinor()); - assertEquals(13, version.getMicro()); - assertEquals("Final", version.getSuffix()); - assertEquals("7.0.13.Final", version.toString()); - } - - @Test - public void testWildfly8ContainerInfo() { - ServletContainerInfo info = new WildflyContainerInfo(WILDFLY8_SERVER_INFO); - assertNotNull(info); - assertEquals(ContainerName.WILDFLY, info.getName()); - ContainerVersion version = info.getContainerVersion(); - assertNotNull(version); - assertEquals(1, version.getMajor()); - assertEquals(0, version.getMinor()); - assertEquals(0, version.getMicro()); - assertEquals("Beta17", version.getSuffix()); - assertEquals("1.0.0.Beta17", version.toString()); - } - - @Test - public void testUnknownWildflyServerInfo() { - ServletContainerInfo info = new WildflyContainerInfo("foo - 1.1.1.beta"); - assertNotNull(info); - assertEquals(ContainerName.WILDFLY, info.getName()); - ContainerVersion version = info.getContainerVersion(); - assertNull(version); - } - - @Test - public void testNull() { - try { - new WildflyContainerInfo(null); - fail("should have failed to instantiate"); - } catch (NullPointerException e) { - // pass - } - } - - @Test - public void testEmpty() { - try { - new WildflyContainerInfo(""); - fail("should have failed to instantiate"); - } catch (IllegalArgumentException e) { - assertEquals("Illegal server info: ''", e.getMessage()); - } - } -}
--- a/web/server/src/test/resources/broken_test_roles.properties Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -user1 = my-role, my-role2 -user2 = new-role, role1 -role1 = other-role, user1 \ No newline at end of file
--- a/web/server/src/test/resources/broken_test_roles2.properties Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -# Defines recursive role, but no user is a member of it. -# Therefore, should fail to parse -user1 = my-role, my-role2 -user2 = new-role -role1 = other-role, user1 \ No newline at end of file
--- a/web/server/src/test/resources/properties_module_test_roles.properties Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -user1 = my-role, my-role2 -user2 = new-role, role1 -user3 = role1 -role1 = other-role \ No newline at end of file
--- a/web/server/src/test/resources/properties_module_test_users.properties Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -user1 = somepassword -user2 = password -user3 = password \ No newline at end of file
--- a/web/server/src/test/resources/test_roles.properties Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -someuser = testing, role1 -user1 = my-role, my-role2 -# empty should get skipped (', ,') -user2 = new-role, role1, , -role1 = other-role -someotheruser = role1
--- a/web/server/src/test/resources/test_users.properties Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -user1=passwd1 -# comment -testing = password -multiuser = blah\ntest \ - test -c102892{0} = test -strange\nuser = testMe - -strange\0user = test\0Me
--- a/web/war/pom.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,322 +0,0 @@ -<?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</artifactId> - <version>1.99.12-SNAPSHOT</version> - </parent> - - <artifactId>thermostat-web-war</artifactId> - <packaging>war</packaging> - - <name>Thermostat Web WAR package</name> - - <!-- context.xml config syntax changed from Tomcat 7 to Tomcat 8. - See: https://tomcat.apache.org/migration-8.html#Web_application_resources - Work around this problem by choosing the correct context.xml file at build - time: - Default => tomcat 6, 7 compatible - -Dtomcat=8 => tomcat 8 compatible - --> - <profiles> - <profile> - <id>tomcat8</id> - <activation> - <property> - <name>tomcat</name> - <value>8</value> - </property> - </activation> - <properties> - <tomcat-context-xml-dir>src/main/webapp-tomcat8</tomcat-context-xml-dir> - </properties> - </profile> - <profile> - <id>tomcat-lower-8</id> - <activation> - <activeByDefault>true</activeByDefault> - </activation> - <properties> - <tomcat-context-xml-dir>src/main/webapp-tomcat7</tomcat-context-xml-dir> - </properties> - </profile> - </profiles> - - <!-- The set of dependencies of the web archive should be - as minimal as possible. --> - <dependencies> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-web-server</artifactId> - <version>${project.version}</version> - <!-- exclude conflicting jars. Those cause problems for servlet - containers and hence prevent the web archive to deploy - properly --> - <exclusions> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-servlet</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-util</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-continuation</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-http</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-io</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-security</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-xml</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-plus</artifactId> - </exclusion> - <exclusion> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-jndi</artifactId> - </exclusion> - </exclusions> - </dependency> - - <!-- Plug-in dependencies: - Required because of model classes and - registries. --> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-host-cpu-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-host-memory-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-numa-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-numa-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-thread-collector</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-classstat-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-compiler-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-byteman-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-cpu-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-gc-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-heap-analysis-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-io-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-jmx-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-memory-common</artifactId> - <version>${project.version}</version> - </dependency> - <dependency> - <groupId>com.redhat.thermostat</groupId> - <artifactId>thermostat-vm-profiler-common</artifactId> - <version>${project.version}</version> - </dependency> - </dependencies> - - <build> - <plugins> - <!-- skip coverage for war --> - <plugin> - <groupId>org.jacoco</groupId> - <artifactId>jacoco-maven-plugin</artifactId> - <configuration> - <skip>true</skip> - </configuration> - </plugin> - <!-- skip tests for war --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <skip>true</skip> - </configuration> - </plugin> - <plugin> - <artifactId>maven-resources-plugin</artifactId> - <executions> - <execution> - <id>move-web-resources</id> - <phase>generate-sources</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/webapp-resources</outputDirectory> - <resources> - <resource> - <directory>src/main/webapp</directory> - <!-- web.xml contains properties, which we'd like to have interpolated --> - <filtering>true</filtering> - </resource> - </resources> - </configuration> - </execution> - <execution> - <id>move-context-xml</id> - <phase>process-sources</phase> - <goals> - <goal>copy-resources</goal> - </goals> - <configuration> - <outputDirectory>${project.build.directory}/webapp-resources</outputDirectory> - <resources> - <resource> - <directory>${tomcat-context-xml-dir}</directory> - <includes> - <include>**/context.xml</include> - </includes> - </resource> - </resources> - </configuration> - </execution> - </executions> - </plugin> - - <!-- - Package the web archive (WAR) as an exploded WAR *and WAR. Downstream - distributions can build and deploy the war via a maven build call similar to - the following (from the top level dir): - $ mvn -Dthermostat.web.deploy.dir=<path-to-tomcat>/webapps/thermostat clean package - --> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-war-plugin</artifactId> - <executions> - <execution> - <id>exploded-war</id> - <phase>package</phase> - <goals> - <goal>exploded</goal> - </goals> - <configuration> - <warSourceDirectory>${project.build.directory}/webapp-resources</warSourceDirectory> - <webXml>${project.build.directory}/webapp-resources/WEB-INF/web.xml</webXml> - <webappDirectory>${thermostat.web.deploy.dir}</webappDirectory> - </configuration> - </execution> - <execution> - <id>war</id> - <phase>package</phase> - <goals> - <goal>war</goal> - </goals> - <configuration> - <warSourceDirectory>${project.build.directory}/webapp-resources</warSourceDirectory> - <webXml>${project.build.directory}/webapp-resources/WEB-INF/web.xml</webXml> - <!-- Required for the embedded servlet endpoint plugin. --> - <attachClasses>true</attachClasses> - </configuration> - </execution> - </executions> - </plugin> - </plugins> - </build> - -</project> -
--- a/web/war/src/main/resources/logging.properties Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -# Copyright 2012-2014 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. - -################################################################### -# Thermostat web service (war in tomcat) logging configuration -################################################################### - -handlers = org.apache.juli.FileHandler - -############################################################ -# Handler specific properties. -# Describes specific configuration info for Handlers. -############################################################ - -org.apache.juli.FileHandler.level = FINEST -org.apache.juli.FileHandler.directory = ${catalina.base}/logs -org.apache.juli.FileHandler.prefix = thermostat-web-storage. - -com.redhat.thermostat.handlers = org.apache.juli.FileHandler -com.redhat.thermostat.level = FINEST -
--- a/web/war/src/main/webapp-tomcat7/META-INF/context.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -<?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. - ---> -<!-- allow symlinks to /usr/share/java deps in WEB-INF/lib --> -<Context path="/thermostat" allowLinking="true"> - <!-- Configures JAAS for Tomcat --> - <Realm className="org.apache.catalina.realm.JAASRealm" - appName="ThermostatJAASLogin" - userClassNames="com.redhat.thermostat.web.server.auth.UserPrincipal" - roleClassNames="com.redhat.thermostat.web.server.auth.WrappedRolePrincipal, - com.redhat.thermostat.web.server.auth.RolePrincipal"/> -</Context>
--- a/web/war/src/main/webapp-tomcat8/META-INF/context.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -<?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. - ---> -<Context path="/thermostat"> - <!-- allow symlinks to /usr/share/java deps in WEB-INF/lib --> - <Resources allowLinking="true"/> - <!-- Configures JAAS for Tomcat --> - <Realm className="org.apache.catalina.realm.JAASRealm" - appName="ThermostatJAASLogin" - userClassNames="com.redhat.thermostat.web.server.auth.UserPrincipal" - roleClassNames="com.redhat.thermostat.web.server.auth.WrappedRolePrincipal, - com.redhat.thermostat.web.server.auth.RolePrincipal"/> -</Context>
--- a/web/war/src/main/webapp/WEB-INF/jetty-web.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -<?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. - ---> -<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure.dtd"> - -<!-- ================================================================== -Thermostat JAAS configuration for jetty. This tells jetty that -it should use JAAS for the "Thermostat Realm". It is imperative that -the realm name matches. It also tells jetty which classes map to -role principals and set the name of the JAAS config entry to use. - -This should work with Jetty 8. - -===================================================================== --> - -<Configure class="org.eclipse.jetty.webapp.WebAppContext"> - <Set name="contextPath">/thermostat</Set> - <Get name="securityHandler"> - <Set name="loginService"> - <New class="org.eclipse.jetty.jaas.JAASLoginService"> - <Set name="name">Thermostat Realm</Set> - <Set name="loginModuleName">ThermostatJAASLogin</Set> - <Set name="roleClassNames"> - <Array type="java.lang.String"> - <Item>com.redhat.thermostat.web.server.auth.RolePrincipal</Item> - <Item>com.redhat.thermostat.web.server.auth.WrappedRolePrincipal</Item> - </Array> - </Set> - </New> - </Set> - </Get> -</Configure>
--- a/web/war/src/main/webapp/WEB-INF/web.xml Tue Mar 21 18:40:40 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -<!-- - - 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. - ---> -<!DOCTYPE web-app PUBLIC - "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" - "http://java.sun.com/dtd/web-app_2_3.dtd" > - -<web-app> - - <display-name>Thermostat Web Service</display-name> - <description>Thermostat Web Service</description> - <servlet> - <init-param> - <param-name>storage.class</param-name> - <param-value>com.redhat.thermostat.storage.mongodb.MongoStorageProvider</param-value> - </init-param> - <init-param> - <param-name>storage.endpoint</param-name> - <param-value>mongodb://127.0.0.1:27518</param-value> - </init-param> - <!-- The timeout of the token manager in ms --> - <init-param> - <param-name>token-manager-timeout</param-name> - <param-value>3000</param-value> - </init-param> - <servlet-name>reststorage-servlet</servlet-name> - <servlet-class>com.redhat.thermostat.web.server.WebStorageEndPoint</servlet-class> - </servlet> - - <servlet-mapping> - <servlet-name>reststorage-servlet</servlet-name> - <url-pattern>/storage/*</url-pattern> - </servlet-mapping> - - <security-constraint> - <web-resource-collection> - <web-resource-name>Entire Application</web-resource-name> - <url-pattern>/*</url-pattern> - </web-resource-collection> - <auth-constraint> - <role-name>thermostat-realm</role-name> - </auth-constraint> - </security-constraint> - - <login-config> - <auth-method>BASIC</auth-method> - <realm-name>Thermostat Realm</realm-name> - </login-config> - - <security-role> - <role-name>thermostat-realm</role-name> - </security-role> - - <!-- - The system property THERMOSTAT_HOME is set via the listener below. - This hard-coded value is only used if this war is deployed into a web - server. It is ignored if the thermostat command is used to run this war - inside an embedded server. - --> - <context-param> - <param-name>THERMOSTAT_HOME</param-name> - <param-value>${thermostat.home}</param-value> - </context-param> - - <listener> - <listener-class>com.redhat.thermostat.web.server.PropertySettingServletContextListener</listener-class> - </listener> - -</web-app>