diff --git a/dd-java-agent/instrumentation/servlet-2/src/test/groovy/JettyServlet2Test.groovy b/dd-java-agent/instrumentation/servlet-2/src/test/groovy/JettyServlet2Test.groovy index 53fc9fab2f..a5804f62a4 100644 --- a/dd-java-agent/instrumentation/servlet-2/src/test/groovy/JettyServlet2Test.groovy +++ b/dd-java-agent/instrumentation/servlet-2/src/test/groovy/JettyServlet2Test.groovy @@ -5,10 +5,18 @@ import datadog.trace.agent.test.TestUtils import datadog.trace.api.DDSpanTypes import datadog.trace.common.writer.ListWriter import io.opentracing.util.GlobalTracer +import okhttp3.Credentials import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import org.eclipse.jetty.http.HttpHeaders +import org.eclipse.jetty.http.security.Constraint +import org.eclipse.jetty.security.ConstraintMapping +import org.eclipse.jetty.security.ConstraintSecurityHandler +import org.eclipse.jetty.security.HashLoginService +import org.eclipse.jetty.security.LoginService +import org.eclipse.jetty.security.authentication.BasicAuthenticator import org.eclipse.jetty.server.Server import org.eclipse.jetty.servlet.ServletContextHandler @@ -34,9 +42,9 @@ class JettyServlet2Test extends AgentTestRunner { } }) // Uncomment when debugging: - .connectTimeout(1, TimeUnit.HOURS) - .writeTimeout(1, TimeUnit.HOURS) - .readTimeout(1, TimeUnit.HOURS) + // .connectTimeout(1, TimeUnit.HOURS) + // .writeTimeout(1, TimeUnit.HOURS) + // .readTimeout(1, TimeUnit.HOURS) .build() private Server jettyServer @@ -55,7 +63,11 @@ class JettyServlet2Test extends AgentTestRunner { jettyServer = new Server(PORT) servletContext = new ServletContextHandler() + ConstraintSecurityHandler security = setupAuthentication(jettyServer) + + servletContext.setSecurityHandler(security) servletContext.addServlet(TestServlet2.Sync, "/sync") + servletContext.addServlet(TestServlet2.Sync, "/auth/sync") jettyServer.setHandler(servletContext) jettyServer.start() @@ -82,11 +94,13 @@ class JettyServlet2Test extends AgentTestRunner { def "test #path servlet call"() { setup: - def request = new Request.Builder() + def requestBuilder = new Request.Builder() .url("http://localhost:$PORT/$path") .get() - .build() - def response = client.newCall(request).execute() + if (auth) { + requestBuilder.header(HttpHeaders.AUTHORIZATION, Credentials.basic("user", "password")) + } + def response = client.newCall(requestBuilder.build()).execute() expect: response.body().string().trim() == expectedResponse @@ -107,6 +121,9 @@ class JettyServlet2Test extends AgentTestRunner { "component" "java-web-servlet" "span.type" DDSpanTypes.WEB_SERVLET "servlet.context" "" + if (auth) { + "user.principal" "user" + } defaultTags() } } @@ -114,8 +131,9 @@ class JettyServlet2Test extends AgentTestRunner { } where: - path | expectedResponse - "sync" | "Hello Sync" + path | expectedResponse | auth + "sync" | "Hello Sync" | false + "auth/sync" | "Hello Sync" | true } def "test #path error servlet call"() { @@ -195,4 +213,37 @@ class JettyServlet2Test extends AgentTestRunner { path | expectedResponse "sync" | "Hello Sync" } + + /** + * Setup simple authentication for tests + *

+ * requests to {@code /auth/*} need login 'user' and password 'password' + *

+ * For details @see http://www.eclipse.org/jetty/documentation/9.3.x/embedded-examples.html + * + * @param jettyServer server to attach login service + * @return SecurityHandler that can be assigned to servlet + */ + private ConstraintSecurityHandler setupAuthentication(Server jettyServer) { + ConstraintSecurityHandler security = new ConstraintSecurityHandler() + + Constraint constraint = new Constraint() + constraint.setName("auth") + constraint.setAuthenticate(true) + constraint.setRoles("role") + + ConstraintMapping mapping = new ConstraintMapping() + mapping.setPathSpec("/auth/*") + mapping.setConstraint(constraint) + + security.setConstraintMappings(mapping) + security.setAuthenticator(new BasicAuthenticator()) + + LoginService loginService = new HashLoginService("TestRealm", + "src/test/resources/realm.properties") + security.setLoginService(loginService) + jettyServer.addBean(loginService) + + security + } } diff --git a/dd-java-agent/instrumentation/servlet-2/src/test/resources/realm.properties b/dd-java-agent/instrumentation/servlet-2/src/test/resources/realm.properties new file mode 100644 index 0000000000..7395dd168b --- /dev/null +++ b/dd-java-agent/instrumentation/servlet-2/src/test/resources/realm.properties @@ -0,0 +1 @@ +user: password,role diff --git a/dd-java-agent/instrumentation/servlet-3/src/test/groovy/JettyServlet3Test.groovy b/dd-java-agent/instrumentation/servlet-3/src/test/groovy/JettyServlet3Test.groovy index ab3a373f1f..473b8f7467 100644 --- a/dd-java-agent/instrumentation/servlet-3/src/test/groovy/JettyServlet3Test.groovy +++ b/dd-java-agent/instrumentation/servlet-3/src/test/groovy/JettyServlet3Test.groovy @@ -5,12 +5,20 @@ import datadog.trace.agent.test.TestUtils import datadog.trace.api.DDSpanTypes import datadog.trace.common.writer.ListWriter import io.opentracing.util.GlobalTracer +import okhttp3.Credentials import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import org.eclipse.jetty.http.HttpHeaders +import org.eclipse.jetty.security.ConstraintMapping +import org.eclipse.jetty.security.ConstraintSecurityHandler +import org.eclipse.jetty.security.HashLoginService +import org.eclipse.jetty.security.LoginService +import org.eclipse.jetty.security.authentication.BasicAuthenticator import org.eclipse.jetty.server.Server import org.eclipse.jetty.servlet.ServletContextHandler +import org.eclipse.jetty.util.security.Constraint import java.lang.reflect.Field import java.util.concurrent.CountDownLatch @@ -35,9 +43,9 @@ class JettyServlet3Test extends AgentTestRunner { } }) // Uncomment when debugging: -// .connectTimeout(1, TimeUnit.HOURS) -// .writeTimeout(1, TimeUnit.HOURS) -// .readTimeout(1, TimeUnit.HOURS) + // .connectTimeout(1, TimeUnit.HOURS) + // .writeTimeout(1, TimeUnit.HOURS) + // .readTimeout(1, TimeUnit.HOURS) .build() private Server jettyServer @@ -56,8 +64,13 @@ class JettyServlet3Test extends AgentTestRunner { jettyServer = new Server(PORT) servletContext = new ServletContextHandler() + ConstraintSecurityHandler security = setupAuthentication(jettyServer) + + servletContext.setSecurityHandler(security) servletContext.addServlet(TestServlet3.Sync, "/sync") + servletContext.addServlet(TestServlet3.Sync, "/auth/sync") servletContext.addServlet(TestServlet3.Async, "/async") + servletContext.addServlet(TestServlet3.Async, "/auth/async") jettyServer.setHandler(servletContext) jettyServer.start() @@ -84,11 +97,13 @@ class JettyServlet3Test extends AgentTestRunner { def "test #path servlet call"() { setup: - def request = new Request.Builder() + def requestBuilder = new Request.Builder() .url("http://localhost:$PORT/$path") .get() - .build() - def response = client.newCall(request).execute() + if (auth) { + requestBuilder.header(HttpHeaders.AUTHORIZATION, Credentials.basic("user", "password")) + } + def response = client.newCall(requestBuilder.build()).execute() expect: response.body().string().trim() == expectedResponse @@ -110,6 +125,9 @@ class JettyServlet3Test extends AgentTestRunner { "span.type" DDSpanTypes.WEB_SERVLET "servlet.context" "" "http.status_code" 200 + if (auth) { + "user.principal" "user" + } defaultTags() } } @@ -117,9 +135,11 @@ class JettyServlet3Test extends AgentTestRunner { } where: - path | expectedResponse - "async" | "Hello Async" - "sync" | "Hello Sync" + path | expectedResponse | auth + "async" | "Hello Async" | false + "sync" | "Hello Sync" | false + "auth/async" | "Hello Async" | true + "auth/sync" | "Hello Sync" | true } def "servlet instrumentation clears state after async request"() { @@ -227,4 +247,37 @@ class JettyServlet3Test extends AgentTestRunner { path | expectedResponse "sync" | "Hello Sync" } + + /** + * Setup simple authentication for tests + *

+ * requests to {@code /auth/*} need login 'user' and password 'password' + *

+ * For details @see http://www.eclipse.org/jetty/documentation/9.3.x/embedded-examples.html + * + * @param jettyServer server to attach login service + * @return SecurityHandler that can be assigned to servlet + */ + private ConstraintSecurityHandler setupAuthentication(Server jettyServer) { + ConstraintSecurityHandler security = new ConstraintSecurityHandler() + + Constraint constraint = new Constraint() + constraint.setName("auth") + constraint.setAuthenticate(true) + constraint.setRoles("role") + + ConstraintMapping mapping = new ConstraintMapping() + mapping.setPathSpec("/auth/*") + mapping.setConstraint(constraint) + + security.setConstraintMappings(mapping) + security.setAuthenticator(new BasicAuthenticator()) + + LoginService loginService = new HashLoginService("TestRealm", + "src/test/resources/realm.properties") + security.setLoginService(loginService) + jettyServer.addBean(loginService) + + security + } } diff --git a/dd-java-agent/instrumentation/servlet-3/src/test/resources/realm.properties b/dd-java-agent/instrumentation/servlet-3/src/test/resources/realm.properties new file mode 100644 index 0000000000..7395dd168b --- /dev/null +++ b/dd-java-agent/instrumentation/servlet-3/src/test/resources/realm.properties @@ -0,0 +1 @@ +user: password,role