From 93870cd17f7c97f88ee0098ebffea95ef77b0f06 Mon Sep 17 00:00:00 2001 From: Bjørn Christian Seime Date: Thu, 26 Oct 2017 16:49:49 +0200 Subject: Move identity document endpoint to separate servlet In addition, use 'identity-document' as path suffix for the servlet. --- .../AthenzInstanceProviderService.java | 17 +++-- .../impl/IdentityDocumentServlet.java | 51 ++++++++++++++ .../impl/InstanceConfirmationServlet.java | 65 +++++++++++++++++ .../impl/ProviderServiceServlet.java | 81 ---------------------- .../configdefinitions/athenz-provider-service.def | 2 +- .../AthenzInstanceProviderServiceTest.java | 6 +- 6 files changed, 130 insertions(+), 92 deletions(-) create mode 100644 athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentServlet.java create mode 100644 athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceConfirmationServlet.java delete mode 100644 athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/ProviderServiceServlet.java (limited to 'athenz-identity-provider-service') 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 745aae62d3a..668444e2769 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 @@ -2,7 +2,6 @@ package com.yahoo.vespa.hosted.athenz.instanceproviderservice; import com.google.inject.Inject; -import com.yahoo.athenz.auth.util.Crypto; import com.yahoo.component.AbstractComponent; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.Zone; @@ -12,9 +11,10 @@ import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.AthenzCertific import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.CertificateClient; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.FileBackedKeyProvider; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.IdentityDocumentGenerator; +import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.IdentityDocumentServlet; +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.ProviderServiceServlet; import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.StatusServlet; import com.yahoo.vespa.hosted.provision.NodeRepository; import org.eclipse.jetty.server.Server; @@ -89,11 +89,14 @@ public class AthenzInstanceProviderService extends AbstractComponent { server.addConnector(connector); ServletHandler handler = new ServletHandler(); - ProviderServiceServlet providerServiceServlet = - new ProviderServiceServlet( - new InstanceValidator(keyProvider), - new IdentityDocumentGenerator(config, nodeRepository, zone, keyProvider)); - handler.addServletWithMapping(new ServletHolder(providerServiceServlet), config.apiPath()); + InstanceConfirmationServlet instanceConfirmationServlet = + new InstanceConfirmationServlet(new InstanceValidator(keyProvider)); + handler.addServletWithMapping(new ServletHolder(instanceConfirmationServlet), config.apiPath() + "/instance"); + + IdentityDocumentServlet identityDocumentServlet = + new IdentityDocumentServlet(new IdentityDocumentGenerator(config, nodeRepository, zone, keyProvider)); + handler.addServletWithMapping(new ServletHolder(identityDocumentServlet), config.apiPath() + "/identity-document"); + 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/IdentityDocumentServlet.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentServlet.java new file mode 100644 index 00000000000..a66fdf9d82f --- /dev/null +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentServlet.java @@ -0,0 +1,51 @@ +// 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.yahoo.log.LogLevel; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.logging.Logger; + +/** + * @author bjorncs + */ +public class IdentityDocumentServlet extends HttpServlet { + + private static final Logger log = Logger.getLogger(IdentityDocumentServlet.class.getName()); + + private final IdentityDocumentGenerator identityDocumentGenerator; + + public IdentityDocumentServlet(IdentityDocumentGenerator identityDocumentGenerator) { + this.identityDocumentGenerator = identityDocumentGenerator; + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + // TODO verify tls client cert + String hostname = req.getParameter("hostname"); + if (hostname == null) { + String message = "The 'hostname' parameter is missing"; + log.log(LogLevel.ERROR, message); + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message); + return; + } + try { + log.log(LogLevel.INFO, "Generating identity document for " + hostname); + String signedIdentityDocument = identityDocumentGenerator.generateSignedIdentityDocument(hostname); + resp.setContentType("application/json"); + PrintWriter writer = resp.getWriter(); + writer.print(signedIdentityDocument); + writer.flush(); + } catch (Exception e) { + String message = String.format("Unable to generate identity doument [%s]", e.getMessage()); + log.log(LogLevel.ERROR, message); + resp.sendError(HttpServletResponse.SC_NOT_FOUND, message); + } + } + +} 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 new file mode 100644 index 00000000000..766b95b443b --- /dev/null +++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/InstanceConfirmationServlet.java @@ -0,0 +1,65 @@ +// 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/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/ProviderServiceServlet.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/ProviderServiceServlet.java deleted file mode 100644 index 7766dc9cc3c..00000000000 --- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/ProviderServiceServlet.java +++ /dev/null @@ -1,81 +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.PrintWriter; -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 ProviderServiceServlet extends HttpServlet { - - private static final Logger log = Logger.getLogger(ProviderServiceServlet.class.getName()); - - private final InstanceValidator instanceValidator; - private final IdentityDocumentGenerator identityDocumentGenerator; - - public ProviderServiceServlet(InstanceValidator instanceValidator, IdentityDocumentGenerator identityDocumentGenerator) { - this.instanceValidator = instanceValidator; - this.identityDocumentGenerator = identityDocumentGenerator; - } - - @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)) { - log.log(LogLevel.ERROR, "Invalid instance: " + instanceConfirmation); - resp.setStatus(HttpServletResponse.SC_FORBIDDEN); - } else { - resp.setStatus(HttpServletResponse.SC_OK); - resp.setContentType("application/json"); - resp.getWriter().write(Utils.getMapper().writeValueAsString(instanceConfirmation)); - } - } catch (JsonParseException | JsonMappingException e) { - log.log(LogLevel.ERROR, "InstanceConfirmation is not valid JSON", e); - resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); - } - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - // TODO verify tls client cert - String hostname = req.getParameter("hostname"); - try { - String signedIdentityDocument = identityDocumentGenerator.generateSignedIdentityDocument(hostname); - resp.setContentType("application/json"); - PrintWriter writer = resp.getWriter(); - writer.print(signedIdentityDocument); - writer.flush(); - } catch (Exception e) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND, String.format("Unable to generate identity doument [%s]", e.getMessage())); - } - } - - 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/main/resources/configdefinitions/athenz-provider-service.def b/athenz-identity-provider-service/src/main/resources/configdefinitions/athenz-provider-service.def index af3abd8631b..7e9c19cb86a 100644 --- a/athenz-identity-provider-service/src/main/resources/configdefinitions/athenz-provider-service.def +++ b/athenz-identity-provider-service/src/main/resources/configdefinitions/athenz-provider-service.def @@ -17,7 +17,7 @@ port int default=8443 keyPathPrefix string # InstanceConfirmation API path -apiPath string default="/athenz/v1/provider/instance" +apiPath string default="/athenz/v1/provider" # Athenz principal authority header name athenzPrincipalHeaderName string default="Athenz-Principal-Auth" 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 a15d681de39..c32f8e18c00 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 @@ -184,8 +184,8 @@ public class AthenzInstanceProviderServiceTest { .keyPathPrefix("dummy-path") .certDnsSuffix("dnsSuffix") .ztsUrl("localhost/zts") - .athenzPrincipalHeaderName("Yahoo-Principal-Auth") - .apiPath("/")); + .athenzPrincipalHeaderName("Athenz-Principal-Auth") + .apiPath("")); } private static boolean getStatus(HttpClient client) { @@ -199,7 +199,7 @@ public class AthenzInstanceProviderServiceTest { } private static void assertInstanceConfirmationSucceeds(HttpClient client, PrivateKey privateKey) throws IOException { - HttpPost httpPost = new HttpPost("https://localhost:" + PORT + "/"); + HttpPost httpPost = new HttpPost("https://localhost:" + PORT + "/instance"); httpPost.setEntity(createInstanceConfirmation(privateKey)); HttpResponse response = client.execute(httpPost); assertThat(response.getStatusLine().getStatusCode(), equalTo(200)); -- cgit v1.2.3