diff options
author | Valerij Fredriksen <valerijf@oath.com> | 2017-11-02 14:37:55 +0100 |
---|---|---|
committer | Valerij Fredriksen <valerijf@oath.com> | 2017-11-02 14:37:55 +0100 |
commit | 34c8cd72f3c9d54873e2f204c41875d3633864a4 (patch) | |
tree | 27aef90f5ddbef3a810ea2d7fede4f9376e2b3b3 /athenz-identity-provider-service | |
parent | 52f764682095c08f654e59d3041a704b9ac9551c (diff) |
Refactor testing
Diffstat (limited to 'athenz-identity-provider-service')
4 files changed, 152 insertions, 224 deletions
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java index c417675f16d..89ea4301398 100644 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java @@ -51,24 +51,35 @@ public class AthenzInstanceProviderService extends AbstractComponent { public AthenzInstanceProviderService(AthenzProviderServiceConfig config, SuperModelProvider superModelProvider, NodeRepository nodeRepository, Zone zone) { this(config, new FileBackedKeyProvider(config.keyPathPrefix()), Executors.newSingleThreadScheduledExecutor(), - superModelProvider, nodeRepository, zone, new AthenzCertificateClient(config)); + superModelProvider, nodeRepository, zone, new AthenzCertificateClient(config), createSslContextFactory()); + } + + private AthenzInstanceProviderService(AthenzProviderServiceConfig config, + KeyProvider keyProvider, + ScheduledExecutorService scheduler, + SuperModelProvider superModelProvider, + NodeRepository nodeRepository, + Zone zone, + CertificateClient certificateClient, + SslContextFactory sslContextFactory) { + this(config, scheduler, zone, sslContextFactory, + new InstanceValidator(keyProvider, superModelProvider), + new IdentityDocumentGenerator(config, nodeRepository, zone, keyProvider), + new AthenzCertificateUpdater(certificateClient, sslContextFactory, keyProvider, config)); } AthenzInstanceProviderService(AthenzProviderServiceConfig config, - KeyProvider keyProvider, ScheduledExecutorService scheduler, - SuperModelProvider superModelProvider, - NodeRepository nodeRepository, Zone zone, - CertificateClient certificateClient) { + SslContextFactory sslContextFactory, + InstanceValidator instanceValidator, + IdentityDocumentGenerator identityDocumentGenerator, + AthenzCertificateUpdater reloader) { // TODO: Enable for all systems. Currently enabled for CD system only if (SystemName.cd.equals(zone.system())) { this.scheduler = scheduler; - SslContextFactory sslContextFactory = createSslContextFactory(); - this.jetty = createJettyServer( - config, keyProvider, sslContextFactory, superModelProvider, nodeRepository, zone); - AthenzCertificateUpdater reloader = - new AthenzCertificateUpdater(certificateClient, sslContextFactory, keyProvider, config); + this.jetty = createJettyServer(config, sslContextFactory, instanceValidator, identityDocumentGenerator); + // TODO Configurable update frequency scheduler.scheduleAtFixedRate(reloader, 0, 1, TimeUnit.DAYS); try { @@ -83,23 +94,19 @@ public class AthenzInstanceProviderService extends AbstractComponent { } private static Server createJettyServer(AthenzProviderServiceConfig config, - KeyProvider keyProvider, SslContextFactory sslContextFactory, - SuperModelProvider superModelProvider, - NodeRepository nodeRepository, - Zone zone) { + InstanceValidator instanceValidator, + IdentityDocumentGenerator identityDocumentGenerator) { Server server = new Server(); ServerConnector connector = new ServerConnector(server, sslContextFactory); connector.setPort(config.port()); server.addConnector(connector); ServletHandler handler = new ServletHandler(); - InstanceConfirmationServlet instanceConfirmationServlet = - new InstanceConfirmationServlet(new InstanceValidator(keyProvider, superModelProvider)); + InstanceConfirmationServlet instanceConfirmationServlet = new InstanceConfirmationServlet(instanceValidator); handler.addServletWithMapping(new ServletHolder(instanceConfirmationServlet), config.apiPath() + "/instance"); - IdentityDocumentServlet identityDocumentServlet = - new IdentityDocumentServlet(new IdentityDocumentGenerator(config, nodeRepository, zone, keyProvider)); + IdentityDocumentServlet identityDocumentServlet = new IdentityDocumentServlet(identityDocumentGenerator); handler.addServletWithMapping(new ServletHolder(identityDocumentServlet), config.apiPath() + "/identity-document"); handler.addServletWithMapping(StatusServlet.class, "/status.html"); @@ -108,7 +115,7 @@ public class AthenzInstanceProviderService extends AbstractComponent { } - private static SslContextFactory createSslContextFactory() { + static SslContextFactory createSslContextFactory() { try { SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setWantClientAuth(true); @@ -120,7 +127,7 @@ public class AthenzInstanceProviderService extends AbstractComponent { } } - private static class AthenzCertificateUpdater implements Runnable { + static class AthenzCertificateUpdater implements Runnable { // TODO Make expiry a configuration parameter private static final TemporalAmount EXPIRY_TIME = Duration.ofDays(30); @@ -131,10 +138,10 @@ public class AthenzInstanceProviderService extends AbstractComponent { private final KeyProvider keyProvider; private final AthenzProviderServiceConfig config; - private AthenzCertificateUpdater(CertificateClient certificateClient, - SslContextFactory sslContextFactory, - KeyProvider keyProvider, - AthenzProviderServiceConfig config) { + AthenzCertificateUpdater(CertificateClient certificateClient, + SslContextFactory sslContextFactory, + KeyProvider keyProvider, + AthenzProviderServiceConfig config) { this.certificateClient = certificateClient; this.sslContextFactory = sslContextFactory; this.keyProvider = keyProvider; @@ -174,7 +181,7 @@ public class AthenzInstanceProviderService extends AbstractComponent { log.log(LogLevel.INFO, "Deconstructing Athenz provider service"); if(scheduler != null) scheduler.shutdown(); - if(jetty !=null) + if(jetty != null) jetty.stop(); if (scheduler != null && !scheduler.awaitTermination(1, TimeUnit.MINUTES)) { log.log(LogLevel.ERROR, "Failed to stop certificate updater"); diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java index c49122a07b8..6fac9b549b5 100644 --- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java +++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java @@ -3,19 +3,12 @@ package com.yahoo.vespa.hosted.athenz.instanceproviderservice; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.ImmutableSet; -import com.yahoo.component.Version; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.ApplicationName; -import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.Environment; -import com.yahoo.config.provision.InstanceName; -import com.yahoo.config.provision.NodeType; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; -import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.Zone; import com.yahoo.log.LogLevel; +import com.yahoo.vespa.hosted.athenz.instanceproviderservice.AthenzInstanceProviderService.AthenzCertificateUpdater; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.CertificateClient; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.IdentityDocumentGenerator; @@ -26,11 +19,6 @@ import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.Identity import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.InstanceConfirmation; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.ProviderUniqueId; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.SignedIdentityDocument; -import com.yahoo.vespa.hosted.provision.Node; -import com.yahoo.vespa.hosted.provision.NodeRepository; -import com.yahoo.vespa.hosted.provision.node.Allocation; -import com.yahoo.vespa.hosted.provision.node.Generation; -import com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; @@ -52,6 +40,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Test; import javax.net.ssl.SSLContext; @@ -75,16 +64,15 @@ import java.time.temporal.TemporalAmount; import java.util.Base64; import java.util.Calendar; import java.util.Date; -import java.util.HashSet; -import java.util.Optional; +import java.util.concurrent.ScheduledExecutorService; import java.util.logging.Logger; import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -101,27 +89,34 @@ public class AthenzInstanceProviderServiceTest { public void provider_service_hosts_endpoint_secured_with_tls() throws Exception { String domain = "domain"; String service = "service"; + AutoGeneratedKeyProvider keyProvider = new AutoGeneratedKeyProvider(); PrivateKey privateKey = keyProvider.getPrivateKey(0); AthenzProviderServiceConfig config = getAthenzProviderConfig(domain, service, "vespa.dns.suffix"); - ScheduledExecutorServiceMock executor = new ScheduledExecutorServiceMock(); + SslContextFactory sslContextFactory = AthenzInstanceProviderService.createSslContextFactory(); + AthenzCertificateUpdater certificateUpdater = new AthenzCertificateUpdater( + new SelfSignedCertificateClient(keyProvider.getKeyPair(), config), + sslContextFactory, + keyProvider, + config); + + ScheduledExecutorService executor = mock(ScheduledExecutorService.class); + when(executor.awaitTermination(anyLong(), any())).thenReturn(true); + + InstanceValidator instanceValidator = mock(InstanceValidator.class); + when(instanceValidator.isValidInstance(any())).thenReturn(true); - AthenzInstanceProviderService athenzInstanceProviderService = - new AthenzInstanceProviderService(config, - keyProvider, - executor, - mock(NodeRepository.class), - ZONE, - new SelfSignedCertificateClient(keyProvider.getKeyPair(), config)); + IdentityDocumentGenerator identityDocumentGenerator = mock(IdentityDocumentGenerator.class); + + AthenzInstanceProviderService athenzInstanceProviderService = new AthenzInstanceProviderService( + config, executor, ZONE, sslContextFactory, instanceValidator, identityDocumentGenerator, certificateUpdater); try (CloseableHttpClient client = createHttpClient(domain, service)) { - Runnable certificateRefreshCommand = executor.getCommand() - .orElseThrow(() -> new AssertionError("Command not present")); assertFalse(getStatus(client)); - certificateRefreshCommand.run(); + certificateUpdater.run(); assertTrue(getStatus(client)); assertInstanceConfirmationSucceeds(client, privateKey); - certificateRefreshCommand.run(); + certificateUpdater.run(); assertTrue(getStatus(client)); assertInstanceConfirmationSucceeds(client, privateKey); } finally { @@ -129,60 +124,7 @@ public class AthenzInstanceProviderServiceTest { } } - @Test - public void generates_valid_identity_document() throws Exception { - String hostname = "x.y.com"; - - ApplicationId appid = ApplicationId.from( - TenantName.from("tenant"), ApplicationName.from("application"), InstanceName.from("default")); - Allocation allocation = new Allocation(appid, - ClusterMembership.from("container/default/0/0", Version.fromString("1.2.3")), - Generation.inital(), - false); - Node n = Node.create("ostkid", - ImmutableSet.of("127.0.0.1"), - new HashSet<>(), - hostname, - Optional.empty(), - new MockNodeFlavors().getFlavorOrThrow("default"), - NodeType.tenant) - .with(allocation); - - NodeRepository nodeRepository = mock(NodeRepository.class); - when(nodeRepository.getNode(eq(hostname))).thenReturn(Optional.of(n)); - AutoGeneratedKeyProvider keyProvider = new AutoGeneratedKeyProvider(); - - String dnsSuffix = "vespa.dns.suffix"; - IdentityDocumentGenerator identityDocumentGenerator = new IdentityDocumentGenerator( - getAthenzProviderConfig("domain", "service", dnsSuffix), - nodeRepository, - ZONE, - keyProvider); - String rawSignedIdentityDocument = identityDocumentGenerator.generateSignedIdentityDocument(hostname); - - - SignedIdentityDocument signedIdentityDocument = - Utils.getMapper().readValue(rawSignedIdentityDocument, SignedIdentityDocument.class); - - // Verify attributes - assertEquals(hostname, signedIdentityDocument.identityDocument.instanceHostname); - - String environment = "dev"; - String region = "us-north-1"; - String expectedZoneDnsSuffix = environment + "-" + region + "." + dnsSuffix; - assertEquals(expectedZoneDnsSuffix, signedIdentityDocument.dnsSuffix); - - ProviderUniqueId expectedProviderUniqueId = - new ProviderUniqueId("tenant", "application", environment, region, "default", "default", 0); - assertEquals(expectedProviderUniqueId, signedIdentityDocument.identityDocument.providerUniqueId); - - // Validate signature - assertTrue("Message", InstanceValidator.isSignatureValid(keyProvider.getPublicKey(0), - signedIdentityDocument.rawIdentityDocument, - signedIdentityDocument.signature)); - } - - private static AthenzProviderServiceConfig getAthenzProviderConfig(String domain, String service, String dnsSuffix) { + public static AthenzProviderServiceConfig getAthenzProviderConfig(String domain, String service, String dnsSuffix) { return new AthenzProviderServiceConfig( new AthenzProviderServiceConfig.Builder() .domain(domain) @@ -259,7 +201,7 @@ public class AthenzInstanceProviderServiceTest { } } - private static class AutoGeneratedKeyProvider implements KeyProvider { + public static class AutoGeneratedKeyProvider implements KeyProvider { private final KeyPair keyPair; diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ScheduledExecutorServiceMock.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ScheduledExecutorServiceMock.java deleted file mode 100644 index 45cb82a0c0a..00000000000 --- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/ScheduledExecutorServiceMock.java +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.athenz.instanceproviderservice; - -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * @author bjorncs - */ -public class ScheduledExecutorServiceMock implements ScheduledExecutorService { - - private Runnable runnable; - - public Optional<Runnable> getCommand() { - return Optional.ofNullable(runnable); - } - - @Override - public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { - throw new UnsupportedOperationException(); - } - - @Override - public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) { - throw new UnsupportedOperationException(); - } - - @Override - public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { - if (runnable != null) { - throw new IllegalStateException("Can only register single command"); - } - runnable = Objects.requireNonNull(command); - return null; - } - - @Override - public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { - throw new UnsupportedOperationException(); - } - - @Override - public void shutdown() { - // do nothing - } - - @Override - public List<Runnable> shutdownNow() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isShutdown() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isTerminated() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - return true; - } - - @Override - public <T> Future<T> submit(Callable<T> task) { - throw new UnsupportedOperationException(); - } - - @Override - public <T> Future<T> submit(Runnable task, T result) { - throw new UnsupportedOperationException(); - } - - @Override - public Future<?> submit(Runnable task) { - throw new UnsupportedOperationException(); - } - - @Override - public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { - throw new UnsupportedOperationException(); - } - - @Override - public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { - throw new UnsupportedOperationException(); - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { - throw new UnsupportedOperationException(); - } - - @Override - public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - throw new UnsupportedOperationException(); - } - - @Override - public void execute(Runnable command) { - throw new UnsupportedOperationException(); - } -} diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentGeneratorTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentGeneratorTest.java new file mode 100644 index 00000000000..faa166602cc --- /dev/null +++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentGeneratorTest.java @@ -0,0 +1,94 @@ +package com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl; + + +import com.google.common.collect.ImmutableSet; +import com.yahoo.component.Version; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ApplicationName; +import com.yahoo.config.provision.ClusterMembership; +import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.InstanceName; +import com.yahoo.config.provision.NodeType; +import com.yahoo.config.provision.RegionName; +import com.yahoo.config.provision.SystemName; +import com.yahoo.config.provision.TenantName; +import com.yahoo.config.provision.Zone; +import com.yahoo.vespa.hosted.athenz.instanceproviderservice.AthenzInstanceProviderServiceTest; +import com.yahoo.vespa.hosted.athenz.instanceproviderservice.AthenzInstanceProviderServiceTest.AutoGeneratedKeyProvider; +import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.ProviderUniqueId; +import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.SignedIdentityDocument; +import com.yahoo.vespa.hosted.provision.Node; +import com.yahoo.vespa.hosted.provision.NodeRepository; +import com.yahoo.vespa.hosted.provision.node.Allocation; +import com.yahoo.vespa.hosted.provision.node.Generation; +import com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author valerijf + */ +public class IdentityDocumentGeneratorTest { + private static final Zone ZONE = new Zone(SystemName.cd, Environment.dev, RegionName.from("us-north-1")); + + @Test + public void generates_valid_identity_document() throws Exception { + String hostname = "x.y.com"; + + ApplicationId appid = ApplicationId.from( + TenantName.from("tenant"), ApplicationName.from("application"), InstanceName.from("default")); + Allocation allocation = new Allocation(appid, + ClusterMembership.from("container/default/0/0", Version.fromString("1.2.3")), + Generation.inital(), + false); + Node n = Node.create("ostkid", + ImmutableSet.of("127.0.0.1"), + new HashSet<>(), + hostname, + Optional.empty(), + new MockNodeFlavors().getFlavorOrThrow("default"), + NodeType.tenant) + .with(allocation); + + NodeRepository nodeRepository = mock(NodeRepository.class); + when(nodeRepository.getNode(eq(hostname))).thenReturn(Optional.of(n)); + AutoGeneratedKeyProvider keyProvider = new AutoGeneratedKeyProvider(); + + String dnsSuffix = "vespa.dns.suffix"; + IdentityDocumentGenerator identityDocumentGenerator = new IdentityDocumentGenerator( + AthenzInstanceProviderServiceTest.getAthenzProviderConfig("domain", "service", dnsSuffix), + nodeRepository, + ZONE, + keyProvider); + String rawSignedIdentityDocument = identityDocumentGenerator.generateSignedIdentityDocument(hostname); + + + SignedIdentityDocument signedIdentityDocument = + Utils.getMapper().readValue(rawSignedIdentityDocument, SignedIdentityDocument.class); + + // Verify attributes + assertEquals(hostname, signedIdentityDocument.identityDocument.instanceHostname); + + String environment = "dev"; + String region = "us-north-1"; + String expectedZoneDnsSuffix = environment + "-" + region + "." + dnsSuffix; + assertEquals(expectedZoneDnsSuffix, signedIdentityDocument.dnsSuffix); + + ProviderUniqueId expectedProviderUniqueId = + new ProviderUniqueId("tenant", "application", environment, region, "default", "default", 0); + assertEquals(expectedProviderUniqueId, signedIdentityDocument.identityDocument.providerUniqueId); + + // Validate signature + assertTrue("Message", InstanceValidator.isSignatureValid(keyProvider.getPublicKey(0), + signedIdentityDocument.rawIdentityDocument, + signedIdentityDocument.signature)); + } +}
\ No newline at end of file |