| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.atlas.web.service; |
| |
| import com.sun.jersey.api.client.Client; |
| import com.sun.jersey.api.client.WebResource; |
| import com.sun.jersey.api.client.config.DefaultClientConfig; |
| import org.apache.atlas.ApplicationProperties; |
| import org.apache.atlas.Atlas; |
| import org.apache.atlas.AtlasException; |
| import org.apache.atlas.web.TestUtils; |
| import org.apache.atlas.web.integration.AdminJerseyResourceIT; |
| import org.apache.atlas.web.integration.EntityJerseyResourceIT; |
| import org.apache.atlas.web.integration.MetadataDiscoveryJerseyResourceIT; |
| import org.apache.atlas.web.integration.TypesJerseyResourceIT; |
| import org.apache.commons.configuration.PropertiesConfiguration; |
| import org.apache.hadoop.conf.Configuration; |
| import org.apache.hadoop.fs.Path; |
| import org.apache.hadoop.security.alias.CredentialProvider; |
| import org.apache.hadoop.security.alias.CredentialProviderFactory; |
| import org.apache.hadoop.security.alias.JavaKeyStoreProvider; |
| import org.testng.Assert; |
| import org.testng.TestListenerAdapter; |
| import org.testng.TestNG; |
| import org.testng.annotations.BeforeClass; |
| import org.testng.annotations.BeforeMethod; |
| import org.testng.annotations.Test; |
| |
| import javax.ws.rs.core.UriBuilder; |
| import java.io.File; |
| import java.io.IOException; |
| import java.nio.file.Files; |
| |
| import static org.apache.atlas.security.SecurityProperties.CERT_STORES_CREDENTIAL_PROVIDER_PATH; |
| import static org.apache.atlas.security.SecurityProperties.DEFAULT_KEYSTORE_FILE_LOCATION; |
| import static org.apache.atlas.security.SecurityProperties.KEYSTORE_PASSWORD_KEY; |
| import static org.apache.atlas.security.SecurityProperties.SERVER_CERT_PASSWORD_KEY; |
| import static org.apache.atlas.security.SecurityProperties.TRUSTSTORE_PASSWORD_KEY; |
| |
| /** |
| * Secure Test class for jersey resources. |
| */ |
| public class SecureEmbeddedServerTestBase { |
| |
| |
| public static final int ATLAS_DEFAULT_HTTPS_PORT = 21443; |
| private SecureEmbeddedServer secureEmbeddedServer; |
| protected String providerUrl; |
| private Path jksPath; |
| protected WebResource service; |
| private int securePort; |
| |
| static { |
| //for localhost testing only |
| javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() { |
| |
| public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { |
| return hostname.equals("localhost"); |
| } |
| }); |
| System.setProperty("javax.net.ssl.trustStore", DEFAULT_KEYSTORE_FILE_LOCATION); |
| System.setProperty("javax.net.ssl.trustStorePassword", "keypass"); |
| System.setProperty("javax.net.ssl.trustStoreType", "JKS"); |
| System.setProperty("https.protocols", "TLSv1.2"); |
| } |
| |
| @BeforeClass |
| public void setupSecurePort() throws AtlasException { |
| org.apache.commons.configuration.Configuration configuration = ApplicationProperties.get(); |
| securePort = configuration.getInt(Atlas.ATLAS_SERVER_HTTPS_PORT, ATLAS_DEFAULT_HTTPS_PORT); |
| } |
| |
| @BeforeMethod |
| public void setup() throws Exception { |
| jksPath = new Path(Files.createTempDirectory("tempproviders").toString(), "test.jks"); |
| providerUrl = JavaKeyStoreProvider.SCHEME_NAME + "://file/" + jksPath.toUri(); |
| |
| String baseUrl = String.format("https://localhost:%d/", securePort); |
| |
| DefaultClientConfig config = new DefaultClientConfig(); |
| Client client = Client.create(config); |
| client.resource(UriBuilder.fromUri(baseUrl).build()); |
| |
| service = client.resource(UriBuilder.fromUri(baseUrl).build()); |
| } |
| |
| @Test |
| public void testNoConfiguredCredentialProvider() throws Exception { |
| String originalConf = null; |
| try { |
| originalConf = System.getProperty("atlas.conf"); |
| System.clearProperty("atlas.conf"); |
| ApplicationProperties.forceReload(); |
| secureEmbeddedServer = new SecureEmbeddedServer(securePort, TestUtils.getWarPath()); |
| secureEmbeddedServer.server.start(); |
| |
| Assert.fail("Should have thrown an exception"); |
| } catch (IOException e) { |
| Assert.assertEquals(e.getMessage(), |
| "No credential provider path configured for storage of certificate store passwords"); |
| } finally { |
| if (secureEmbeddedServer != null) { |
| secureEmbeddedServer.server.stop(); |
| } |
| |
| if (originalConf == null) { |
| System.clearProperty("atlas.conf"); |
| } else { |
| System.setProperty("atlas.conf", originalConf); |
| } |
| } |
| } |
| |
| @Test |
| public void testMissingEntriesInCredentialProvider() throws Exception { |
| // setup the configuration |
| final PropertiesConfiguration configuration = new PropertiesConfiguration(); |
| configuration.setProperty(CERT_STORES_CREDENTIAL_PROVIDER_PATH, providerUrl); |
| |
| try { |
| secureEmbeddedServer = new SecureEmbeddedServer(securePort, TestUtils.getWarPath()) { |
| @Override |
| protected PropertiesConfiguration getConfiguration() { |
| return configuration; |
| } |
| }; |
| Assert.fail("No entries should generate an exception"); |
| } catch (IOException e) { |
| Assert.assertTrue(e.getMessage().startsWith("No credential entry found for")); |
| } finally { |
| secureEmbeddedServer.server.stop(); |
| } |
| |
| } |
| |
| /** |
| * Runs the existing webapp test cases, this time against the initiated secure server instance. |
| * @throws Exception |
| */ |
| @Test |
| public void runOtherSuitesAgainstSecureServer() throws Exception { |
| final PropertiesConfiguration configuration = new PropertiesConfiguration(); |
| configuration.setProperty(CERT_STORES_CREDENTIAL_PROVIDER_PATH, providerUrl); |
| // setup the credential provider |
| setupCredentials(); |
| |
| try { |
| secureEmbeddedServer = new SecureEmbeddedServer(securePort, TestUtils.getWarPath()) { |
| @Override |
| protected PropertiesConfiguration getConfiguration() { |
| return configuration; |
| } |
| }; |
| secureEmbeddedServer.server.start(); |
| |
| TestListenerAdapter tla = new TestListenerAdapter(); |
| TestNG testng = new TestNG(); |
| testng.setTestClasses(new Class[]{AdminJerseyResourceIT.class, EntityJerseyResourceIT.class, |
| MetadataDiscoveryJerseyResourceIT.class, |
| TypesJerseyResourceIT.class}); |
| testng.addListener(tla); |
| testng.run(); |
| |
| } finally { |
| secureEmbeddedServer.server.stop(); |
| } |
| |
| } |
| |
| protected void setupCredentials() throws Exception { |
| Configuration conf = new Configuration(false); |
| |
| File file = new File(jksPath.toUri().getPath()); |
| file.delete(); |
| conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, providerUrl); |
| |
| CredentialProvider provider = CredentialProviderFactory.getProviders(conf).get(0); |
| |
| // create new aliases |
| try { |
| |
| char[] storepass = {'k', 'e', 'y', 'p', 'a', 's', 's'}; |
| provider.createCredentialEntry(KEYSTORE_PASSWORD_KEY, storepass); |
| |
| char[] trustpass = {'k', 'e', 'y', 'p', 'a', 's', 's'}; |
| provider.createCredentialEntry(TRUSTSTORE_PASSWORD_KEY, trustpass); |
| |
| char[] certpass = {'k', 'e', 'y', 'p', 'a', 's', 's'}; |
| provider.createCredentialEntry(SERVER_CERT_PASSWORD_KEY, certpass); |
| |
| // write out so that it can be found in checks |
| provider.flush(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| throw e; |
| } |
| } |
| } |