diff --git a/ask-sdk-servlet-support/pom.xml b/ask-sdk-servlet-support/pom.xml index 50bfde2c..17623052 100644 --- a/ask-sdk-servlet-support/pom.xml +++ b/ask-sdk-servlet-support/pom.xml @@ -40,9 +40,9 @@ 2.86.0 - javax.servlet - javax.servlet-api - 3.0.1 + jakarta.servlet + jakarta.servlet-api + 6.0.0 provided diff --git a/ask-sdk-servlet-support/src/com/amazon/ask/servlet/SkillServlet.java b/ask-sdk-servlet-support/src/com/amazon/ask/servlet/SkillServlet.java index f8f21277..7fa1526e 100644 --- a/ask-sdk-servlet-support/src/com/amazon/ask/servlet/SkillServlet.java +++ b/ask-sdk-servlet-support/src/com/amazon/ask/servlet/SkillServlet.java @@ -13,22 +13,6 @@ package com.amazon.ask.servlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.net.Proxy; -import java.util.ArrayList; -import java.util.List; - import com.amazon.ask.Skill; import com.amazon.ask.exception.AskSdkException; import com.amazon.ask.model.RequestEnvelope; @@ -36,16 +20,20 @@ import com.amazon.ask.request.impl.BaseSkillRequest; import com.amazon.ask.response.SkillResponse; import com.amazon.ask.servlet.util.ServletUtils; -import com.amazon.ask.servlet.verifiers.AlexaHttpRequest; -import com.amazon.ask.servlet.verifiers.ServletRequest; -import com.amazon.ask.servlet.verifiers.SkillRequestSignatureVerifier; -import com.amazon.ask.servlet.verifiers.SkillRequestTimestampVerifier; -import com.amazon.ask.servlet.verifiers.SkillServletVerifier; +import com.amazon.ask.servlet.verifiers.*; import com.amazon.ask.util.JacksonSerializer; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.*; +import java.net.Proxy; +import java.util.ArrayList; +import java.util.List; + import static com.amazon.ask.servlet.ServletConstants.DEFAULT_TOLERANCE_MILLIS; /** @@ -58,7 +46,6 @@ * invocation of the right method of the provided {@code Skill} . It also handles sending back * modified session attributes, user attributes and authentication tokens when needed and handles * exception cases. - * */ public class SkillServlet extends HttpServlet { /** @@ -90,6 +77,7 @@ public class SkillServlet extends HttpServlet { /** * Constructor to build an instance of SkillServlet. + * * @param skill an Alexa skill instance. */ public SkillServlet(final Skill skill) { @@ -106,7 +94,8 @@ public SkillServlet(final Skill skill) { /** * Constructor to build an instance of SkillServlet. - * @param skill instance of {@link Skill}. + * + * @param skill instance of {@link Skill}. * @param verifiers list of {@link SkillServletVerifier}. */ SkillServlet(final Skill skill, final List verifiers) { @@ -166,7 +155,7 @@ protected void doPost(final HttpServletRequest request, final HttpServletRespons * {@code SkillServlet} determines the type of request and passes the request to * the configured {@code Skill}. * - * @param input - input stream of the request. + * @param input - input stream of the request. * @param output - output stream of the response. * @throws IOException if an input or output error is detected when the servlet handles the request */ @@ -198,8 +187,9 @@ public void setProxy(final Proxy proxy) { /** * Method throws an {@link NotSerializableException} if the servlet is not serializable. + * * @param in instance of {@link ObjectInputStream}. - * @throws IOException I/O exception. + * @throws IOException I/O exception. * @throws ClassNotFoundException cannot a class through its fully-qualified name and can not find its definition on the classpath. */ private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { @@ -208,6 +198,7 @@ private void readObject(final ObjectInputStream in) throws IOException, ClassNot /** * Method throws an {@link NotSerializableException} if the servlet is not serializable. + * * @param out instance of {@link ObjectOutputStream}. * @throws IOException I/O exception. */ diff --git a/ask-sdk-servlet-support/src/com/amazon/ask/servlet/verifiers/ServletRequest.java b/ask-sdk-servlet-support/src/com/amazon/ask/servlet/verifiers/ServletRequest.java index 0c6d2d1f..c3629656 100644 --- a/ask-sdk-servlet-support/src/com/amazon/ask/servlet/verifiers/ServletRequest.java +++ b/ask-sdk-servlet-support/src/com/amazon/ask/servlet/verifiers/ServletRequest.java @@ -15,8 +15,7 @@ import com.amazon.ask.model.RequestEnvelope; import com.amazon.ask.servlet.ServletConstants; - -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; /** * Servlet specific implementation of {@link AlexaHttpRequest}. @@ -45,8 +44,9 @@ public class ServletRequest implements AlexaHttpRequest { /** * Constructor to build an instance of ServletRequest. - * @param httpServletRequest instance of type {@link HttpServletRequest}. - * @param serializedRequestEnvelope serialized request envelope. + * + * @param httpServletRequest instance of type {@link HttpServletRequest}. + * @param serializedRequestEnvelope serialized request envelope. * @param deserializedRequestEnvelope de-serialized request envelope. */ public ServletRequest(final HttpServletRequest httpServletRequest, final byte[] serializedRequestEnvelope, diff --git a/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/SkillServletTest.java b/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/SkillServletTest.java index f4cff54c..2e9d6f20 100644 --- a/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/SkillServletTest.java +++ b/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/SkillServletTest.java @@ -13,27 +13,16 @@ package com.amazon.ask.servlet; -import static com.amazon.ask.util.SdkConstants.FORMAT_VERSION; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.doThrow; - -import javax.servlet.http.HttpServletResponse; - import com.amazon.ask.Skill; import com.amazon.ask.exception.AskSdkException; import com.amazon.ask.model.LaunchRequest; import com.amazon.ask.model.Response; import com.amazon.ask.model.ResponseEnvelope; +import com.amazon.ask.response.impl.BaseSkillResponse; import com.amazon.ask.servlet.verifiers.SkillRequestSignatureVerifier; import com.amazon.ask.servlet.verifiers.SkillServletVerifier; -import com.amazon.ask.response.impl.BaseSkillResponse; import com.amazon.ask.util.impl.JacksonJsonMarshaller; +import jakarta.servlet.http.HttpServletResponse; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,6 +38,12 @@ import java.util.Collections; import java.util.Date; +import static com.amazon.ask.util.SdkConstants.FORMAT_VERSION; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; +import static org.powermock.api.mockito.PowerMockito.doThrow; + /** * Tests that the {@link SkillServlet} respects the provided environment variables controlling * its behavior. diff --git a/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/SkillServletTestBase.java b/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/SkillServletTestBase.java index 3c4a778a..edd51202 100644 --- a/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/SkillServletTestBase.java +++ b/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/SkillServletTestBase.java @@ -13,102 +13,40 @@ package com.amazon.ask.servlet; -import static com.amazon.ask.util.SdkConstants.FORMAT_VERSION; -import static org.mockito.Mockito.when; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import javax.servlet.ServletInputStream; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.amazon.ask.model.Application; -import com.amazon.ask.model.Request; -import com.amazon.ask.model.RequestEnvelope; -import com.amazon.ask.model.Session; -import com.amazon.ask.model.User; +import com.amazon.ask.model.*; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.mockito.Mockito; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.*; + +import static com.amazon.ask.util.SdkConstants.FORMAT_VERSION; +import static org.mockito.Mockito.when; public class SkillServletTestBase { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + static { OBJECT_MAPPER.registerModule(new JavaTimeModule()); OBJECT_MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL); } - /** - * Tuple for useful parameters for a servlet invocation. - */ - protected static final class ServletInvocationParameters { - public final HttpServletRequest request; - public final HttpServletResponse response; - public final ByteArrayOutputStream output; - - public ServletInvocationParameters(final HttpServletRequest request, - final HttpServletResponse response, final ByteArrayOutputStream output) { - this.request = request; - this.response = response; - this.output = output; - } - } - - /** - * Trivial implementation of the ServletInputStream that wraps an InputStream. - */ - private static class MyServletInputStream extends ServletInputStream { - private final InputStream in; - - public MyServletInputStream(final InputStream in) { - this.in = in; - } - - @Override - public int read() throws IOException { - return in.read(); - } - } - - /** - * Trivial implementation of the ServletOutputStream that wraps an OutputStream. - */ - private static class MyServletOutputStream extends ServletOutputStream { - private final OutputStream out; - - public MyServletOutputStream(final OutputStream out) { - this.out = out; - } - - @Override - public void write(int b) throws IOException { - out.write(b); - } - } - - // ------------------------------ - // Helper methods for subclasses - /** * Common logic for all the tests. * - * @param version - * the envelope version for the request envelope - * @param request - * a SkillRequest - * @param session - * a session for this invocation + * @param version the envelope version for the request envelope + * @param request a SkillRequest + * @param session a session for this invocation * @return invocation parameters for a Skill - * * @throws IOException */ protected ServletInvocationParameters build(final String version, final Request request, final Session session) throws IOException { @@ -143,12 +81,9 @@ protected ServletInvocationParameters build(final String version, final Request *
  • The current SDK version as a version
  • * * - * @param request - * a SkillRequest or OnSessionEndedRequest - * @param session - * a session for this invocation + * @param request a SkillRequest or OnSessionEndedRequest + * @param session a session for this invocation * @return invocation parameters for a Skill - * * @throws IOException */ protected ServletInvocationParameters build(final Request request, @@ -159,10 +94,8 @@ protected ServletInvocationParameters build(final Request request, /** * Same as above using a simple Session and User. * - * @param request - * a skill request + * @param request a skill request * @return invocation parameters for a Skill - * * @throws IOException */ protected ServletInvocationParameters build(final Request request) @@ -170,6 +103,9 @@ protected ServletInvocationParameters build(final Request request) return build(request, buildSession()); } + // ------------------------------ + // Helper methods for subclasses + /** * @return a test session. */ @@ -186,4 +122,77 @@ protected Session buildSession(String applicationId) { .build(); } + /** + * Tuple for useful parameters for a servlet invocation. + */ + protected static final class ServletInvocationParameters { + public final HttpServletRequest request; + public final HttpServletResponse response; + public final ByteArrayOutputStream output; + + public ServletInvocationParameters(final HttpServletRequest request, + final HttpServletResponse response, final ByteArrayOutputStream output) { + this.request = request; + this.response = response; + this.output = output; + } + } + + /** + * Trivial implementation of the ServletInputStream that wraps an InputStream. + */ + private static class MyServletInputStream extends ServletInputStream { + private final InputStream in; + + public MyServletInputStream(final InputStream in) { + this.in = in; + } + + @Override + public int read() throws IOException { + return in.read(); + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + } + + /** + * Trivial implementation of the ServletOutputStream that wraps an OutputStream. + */ + private static class MyServletOutputStream extends ServletOutputStream { + private final OutputStream out; + + public MyServletOutputStream(final OutputStream out) { + this.out = out; + } + + @Override + public void write(int b) throws IOException { + out.write(b); + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + + } + } + } \ No newline at end of file diff --git a/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/verifiers/SkillRequestSignatureVerifierTest.java b/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/verifiers/SkillRequestSignatureVerifierTest.java index e629e253..4650c917 100644 --- a/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/verifiers/SkillRequestSignatureVerifierTest.java +++ b/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/verifiers/SkillRequestSignatureVerifierTest.java @@ -13,30 +13,9 @@ package com.amazon.ask.servlet.verifiers; -import static com.amazon.ask.servlet.verifiers.SkillRequestSignatureVerifier.getAndVerifySigningCertificateChainUrl; -import static java.security.Security.addProvider; -import static org.hamcrest.Matchers.isA; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.powermock.api.mockito.PowerMockito.whenNew; - -import java.math.BigInteger; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.Signature; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Date; -import java.util.concurrent.ConcurrentHashMap; - -import javax.security.auth.x500.X500Principal; -import javax.servlet.http.HttpServletRequest; - import com.amazon.ask.model.RequestEnvelope; import com.amazon.ask.servlet.ServletConstants; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.codec.binary.Base64; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.x509.X509V3CertificateGenerator; @@ -50,6 +29,22 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; +import javax.security.auth.x500.X500Principal; +import java.math.BigInteger; +import java.security.*; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.concurrent.ConcurrentHashMap; + +import static com.amazon.ask.servlet.verifiers.SkillRequestSignatureVerifier.getAndVerifySigningCertificateChainUrl; +import static java.security.Security.addProvider; +import static org.hamcrest.Matchers.isA; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.whenNew; + @RunWith(PowerMockRunner.class) @PowerMockIgnore("javax.security.auth.x500.X500Principal") @PrepareForTest(SkillRequestSignatureVerifier.class) @@ -77,10 +72,9 @@ public class SkillRequestSignatureVerifierTest { private static PrivateKey validPrivateKey = null; private static RequestEnvelope deserializedRequestEnvelope; private static SkillRequestSignatureVerifier verifier; - private HttpServletRequest mockServletRequest; - @Rule public ExpectedException thrown = ExpectedException.none(); + private HttpServletRequest mockServletRequest; @BeforeClass @SuppressWarnings("deprecation") @@ -108,6 +102,19 @@ public static void initializeCertMap() throws Exception { deserializedRequestEnvelope = RequestEnvelope.builder().build(); } + private static KeyPair generateKeyPair() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ServletConstants.SIGNATURE_TYPE); + keyPairGenerator.initialize(512); + return keyPairGenerator.generateKeyPair(); + } + + private static byte[] signContent(String content, PrivateKey key) throws Exception { + Signature signature = Signature.getInstance(ServletConstants.SIGNATURE_ALGORITHM); + signature.initSign(key); + signature.update(content.getBytes()); + return signature.sign(); + } + @Before public void setUp() { mockServletRequest = mock(HttpServletRequest.class); @@ -222,17 +229,4 @@ public void checkRequestSignature_validSignatureInvalidPrivateKey_securityExcept verifier.verify(new ServletRequest(mockServletRequest, testContent.getBytes(), deserializedRequestEnvelope)); } - - private static KeyPair generateKeyPair() throws NoSuchAlgorithmException { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ServletConstants.SIGNATURE_TYPE); - keyPairGenerator.initialize(512); - return keyPairGenerator.generateKeyPair(); - } - - private static byte[] signContent(String content, PrivateKey key) throws Exception { - Signature signature = Signature.getInstance(ServletConstants.SIGNATURE_ALGORITHM); - signature.initSign(key); - signature.update(content.getBytes()); - return signature.sign(); - } } \ No newline at end of file diff --git a/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/verifiers/SkillRequestTimestampVerifierTest.java b/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/verifiers/SkillRequestTimestampVerifierTest.java index e5883651..2d9577ed 100644 --- a/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/verifiers/SkillRequestTimestampVerifierTest.java +++ b/ask-sdk-servlet-support/tst/com/amazon/ask/servlet/verifiers/SkillRequestTimestampVerifierTest.java @@ -17,13 +17,12 @@ import com.amazon.ask.model.LaunchRequest; import com.amazon.ask.model.RequestEnvelope; import com.amazon.ask.model.events.skillevents.SkillEnabledRequest; - +import jakarta.servlet.http.HttpServletRequest; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import javax.servlet.http.HttpServletRequest; import java.time.OffsetDateTime; import java.time.ZoneId; import java.util.Arrays; @@ -38,12 +37,10 @@ @RunWith(Parameterized.class) public class SkillRequestTimestampVerifierTest { - private SkillRequestTimestampVerifier verifier; - private static final long TOLERANCE_IN_MILLIS = 2000; - private static HttpServletRequest mockServletRequest; private static byte[] serializedRequestEnvelope; + private final SkillRequestTimestampVerifier verifier; public SkillRequestTimestampVerifierTest(SkillRequestTimestampVerifier verifier) { this.verifier = verifier; @@ -60,7 +57,7 @@ public static void setUp() { serializedRequestEnvelope = "".getBytes(); } - @Test (expected = IllegalArgumentException.class) + @Test(expected = IllegalArgumentException.class) public void construct_withNegativeTolerance_throwsIllegalArgumentException() { new SkillRequestTimestampVerifier(-1); } @@ -115,7 +112,7 @@ public void verify_nullTimestamp_throws_exception() { verifier.verify(new ServletRequest(mockServletRequest, serializedRequestEnvelope, RequestEnvelope.builder().withRequest(IntentRequest.builder().build()).build())); } - @Test (expected = IllegalArgumentException.class) + @Test(expected = IllegalArgumentException.class) public void construct_withNullTimeUnit_throwsIllegalArgumentException() { new SkillRequestTimestampVerifier(TOLERANCE_IN_MILLIS / 1000, null); }