diff options
author | Bjørn Christian Seime <bjorncs@oath.com> | 2017-11-16 13:23:36 +0100 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@oath.com> | 2017-11-17 13:04:36 +0100 |
commit | 332a1c17e472a9816ed638db94dfc34fce1f8392 (patch) | |
tree | c4640fa1fae79e1340ec27a2e97ff511b12ef66f /athenz-identity-provider-service | |
parent | 29f7dbc63afe64683288d6552aaede77b92cb434 (diff) |
Rewrite InstanceConfirmationServlet as jax-rs resource
Diffstat (limited to 'athenz-identity-provider-service')
4 files changed, 55 insertions, 127 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 b26b3e8ee18..c4b54d73ec3 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 @@ -15,7 +15,6 @@ import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProvid import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.AthenzCertificateClient; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.CertificateClient; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.IdentityDocumentGenerator; -import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.InstanceConfirmationServlet; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.InstanceValidator; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.KeyProvider; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.SecretStoreKeyProvider; @@ -115,9 +114,6 @@ public class AthenzInstanceProviderService extends AbstractComponent { CertificateSignerServlet certificateSignerServlet = new CertificateSignerServlet(certificateSigner); handler.addServletWithMapping(new ServletHolder(certificateSignerServlet), config.apiPath() + "/sign"); - InstanceConfirmationServlet instanceConfirmationServlet = new InstanceConfirmationServlet(instanceValidator); - handler.addServletWithMapping(new ServletHolder(instanceConfirmationServlet), config.apiPath() + "/instance"); - handler.addServletWithMapping(StatusServlet.class, "/status.html"); server.setHandler(handler); return server; diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceConfirmationResource.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceConfirmationResource.java new file mode 100644 index 00000000000..a8b837a3486 --- /dev/null +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceConfirmationResource.java @@ -0,0 +1,53 @@ +// 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.impl; + +import com.google.inject.Inject; +import com.yahoo.config.model.api.SuperModelProvider; +import com.yahoo.config.provision.Zone; +import com.yahoo.container.jaxrs.annotation.Component; +import com.yahoo.jdisc.http.SecretStore; +import com.yahoo.log.LogLevel; +import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig; +import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.InstanceConfirmation; + +import javax.ws.rs.Consumes; +import javax.ws.rs.ForbiddenException; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import java.util.logging.Logger; + +import static com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.Utils.getZoneConfig; + +/** + * @author bjorncs + */ +@Path("/instance") +public class InstanceConfirmationResource { + + private static final Logger log = Logger.getLogger(InstanceConfirmationResource.class.getName()); + + private final InstanceValidator instanceValidator; + + @Inject + public InstanceConfirmationResource(@Component AthenzProviderServiceConfig config, + @Component SecretStore secretStore, + @Component SuperModelProvider superModelProvider, + @Component Zone zone) { + AthenzProviderServiceConfig.Zones zoneConfig = getZoneConfig(config, zone); + SecretStoreKeyProvider keyProvider = new SecretStoreKeyProvider(secretStore, zoneConfig.secretName()); + this.instanceValidator = new InstanceValidator(keyProvider, superModelProvider); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public InstanceConfirmation confirmInstance(InstanceConfirmation instanceConfirmation) { + if (!instanceValidator.isValidInstance(instanceConfirmation)) { + log.log(LogLevel.ERROR, "Invalid instance: " + instanceConfirmation); + throw new ForbiddenException("Instance is invalid"); + } + return instanceConfirmation; + } +} diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceConfirmationServlet.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceConfirmationServlet.java deleted file mode 100644 index 766b95b443b..00000000000 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceConfirmationServlet.java +++ /dev/null @@ -1,65 +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.impl; - -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.yahoo.log.LogLevel; -import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.InstanceConfirmation; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - * A Servlet implementing the Athenz Service Provider InstanceConfirmation API - * - * @author bjorncs - */ -public class InstanceConfirmationServlet extends HttpServlet { - - private static final Logger log = Logger.getLogger(InstanceConfirmationServlet.class.getName()); - - private final InstanceValidator instanceValidator; - - public InstanceConfirmationServlet(InstanceValidator instanceValidator) { - this.instanceValidator = instanceValidator; - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - // TODO Validate that request originates from ZTS - try { - String confirmationContent = toString(req.getReader()); - log.log(LogLevel.DEBUG, () -> "Confirmation content: " + confirmationContent); - InstanceConfirmation instanceConfirmation = - Utils.getMapper().readValue(confirmationContent, InstanceConfirmation.class); - log.log(LogLevel.DEBUG, () -> "Parsed confirmation content: " + instanceConfirmation.toString()); - if (!instanceValidator.isValidInstance(instanceConfirmation)) { - String message = "Invalid instance: " + instanceConfirmation; - log.log(LogLevel.ERROR, message); - resp.sendError(HttpServletResponse.SC_FORBIDDEN, message); - } else { - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType("application/json"); - resp.getWriter().write(Utils.getMapper().writeValueAsString(instanceConfirmation)); - } - } catch (JsonParseException | JsonMappingException e) { - String message = "InstanceConfirmation is not valid JSON"; - log.log(LogLevel.ERROR, message, e); - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message); - } - } - - private static String toString(Reader reader) throws IOException { - try (BufferedReader bufferedReader = new BufferedReader(reader)) { - return bufferedReader.lines().collect(Collectors.joining("\n")); - } - } - -} 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 c8c3826fc39..c58e86f7585 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 @@ -2,7 +2,6 @@ package com.yahoo.vespa.hosted.athenz.instanceproviderservice; import athenz.shade.zts.jersey.repackaged.com.google.common.collect.ImmutableMap; -import com.fasterxml.jackson.databind.ObjectMapper; import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; @@ -15,19 +14,11 @@ import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.CertificateCli import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.IdentityDocumentGenerator; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.InstanceValidator; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.KeyProvider; -import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.Utils; -import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.model.IdentityDocument; -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 org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; @@ -45,7 +36,6 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import org.junit.Test; import javax.net.ssl.SSLContext; -import java.io.IOException; import java.math.BigInteger; import java.security.KeyManagementException; import java.security.KeyPair; @@ -54,20 +44,15 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; -import java.security.Signature; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.time.Instant; import java.time.temporal.TemporalAmount; -import java.util.Base64; import java.util.Calendar; import java.util.Date; import java.util.concurrent.ScheduledExecutorService; import java.util.logging.Logger; -import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; @@ -89,11 +74,10 @@ public class AthenzInstanceProviderServiceTest { String service = "service"; AutoGeneratedKeyProvider keyProvider = new AutoGeneratedKeyProvider(); - PrivateKey privateKey = keyProvider.getPrivateKey(0); AthenzProviderServiceConfig config = getAthenzProviderConfig(domain, service, "vespa.dns.suffix", ZONE); SslContextFactory sslContextFactory = AthenzInstanceProviderService.createSslContextFactory(); AthenzCertificateUpdater certificateUpdater = new AthenzCertificateUpdater( - new SelfSignedCertificateClient(keyProvider.getKeyPair(), config, getZoneConfig(config, ZONE)), + new SelfSignedCertificateClient(keyProvider.getKeyPair(), getZoneConfig(config, ZONE)), sslContextFactory, keyProvider, config, @@ -117,10 +101,8 @@ public class AthenzInstanceProviderServiceTest { assertFalse(getStatus(client)); certificateUpdater.run(); assertTrue(getStatus(client)); - assertInstanceConfirmationSucceeds(client, privateKey); certificateUpdater.run(); assertTrue(getStatus(client)); - assertInstanceConfirmationSucceeds(client, privateKey); } finally { athenzInstanceProviderService.deconstruct(); } @@ -159,13 +141,6 @@ public class AthenzInstanceProviderServiceTest { } } - private static void assertInstanceConfirmationSucceeds(HttpClient client, PrivateKey privateKey) throws IOException { - HttpPost httpPost = new HttpPost("https://localhost:" + PORT + "/instance"); - httpPost.setEntity(createInstanceConfirmation(privateKey)); - HttpResponse response = client.execute(httpPost); - assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); - } - private static CloseableHttpClient createHttpClient(String domain, String service) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException { SSLContext sslContext = new SSLContextBuilder() @@ -179,35 +154,6 @@ public class AthenzInstanceProviderServiceTest { .build(); } - private static HttpEntity createInstanceConfirmation(PrivateKey privateKey) { - IdentityDocument identityDocument = new IdentityDocument( - new ProviderUniqueId("tenant", "application", "environment", "region", "instance", "cluster-id", 0), - "hostname", - "instance-hostname", - Instant.now()); - try { - ObjectMapper mapper = Utils.getMapper(); - String encodedIdentityDocument = - Base64.getEncoder().encodeToString(mapper.writeValueAsString(identityDocument).getBytes()); - Signature sigGenerator = Signature.getInstance("SHA512withRSA"); - sigGenerator.initSign(privateKey); - sigGenerator.update(encodedIdentityDocument.getBytes()); - - InstanceConfirmation instanceConfirmation = new InstanceConfirmation( - "provider", "domain", "service", - new SignedIdentityDocument(encodedIdentityDocument, - Base64.getEncoder().encodeToString(sigGenerator.sign()), - 0, - identityDocument.providerUniqueId.asString(), - "dnssuffix", - "service", - "localhost/zts", - 1)); - return new StringEntity(mapper.writeValueAsString(instanceConfirmation)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } public static class AutoGeneratedKeyProvider implements KeyProvider { @@ -241,13 +187,11 @@ public class AthenzInstanceProviderServiceTest { private static class SelfSignedCertificateClient implements CertificateClient { private final KeyPair keyPair; - private final AthenzProviderServiceConfig config; private final AthenzProviderServiceConfig.Zones zoneConfig; - private SelfSignedCertificateClient(KeyPair keyPair, AthenzProviderServiceConfig config, + private SelfSignedCertificateClient(KeyPair keyPair, AthenzProviderServiceConfig.Zones zoneConfig) { this.keyPair = keyPair; - this.config = config; this.zoneConfig = zoneConfig; } |