Merge pull request #374 from DataDog/mar-kolya/add-servlet-auth-tests

Add tests to servlet intrumentation to verify that username is set co…
This commit is contained in:
Tyler Benson 2018-06-26 15:16:49 +10:00 committed by GitHub
commit 05ef9ce8bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 17 deletions

View File

@ -5,10 +5,18 @@ import datadog.trace.agent.test.TestUtils
import datadog.trace.api.DDSpanTypes import datadog.trace.api.DDSpanTypes
import datadog.trace.common.writer.ListWriter import datadog.trace.common.writer.ListWriter
import io.opentracing.util.GlobalTracer import io.opentracing.util.GlobalTracer
import okhttp3.Credentials
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response 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.server.Server
import org.eclipse.jetty.servlet.ServletContextHandler import org.eclipse.jetty.servlet.ServletContextHandler
@ -34,9 +42,9 @@ class JettyServlet2Test extends AgentTestRunner {
} }
}) })
// Uncomment when debugging: // Uncomment when debugging:
.connectTimeout(1, TimeUnit.HOURS) // .connectTimeout(1, TimeUnit.HOURS)
.writeTimeout(1, TimeUnit.HOURS) // .writeTimeout(1, TimeUnit.HOURS)
.readTimeout(1, TimeUnit.HOURS) // .readTimeout(1, TimeUnit.HOURS)
.build() .build()
private Server jettyServer private Server jettyServer
@ -55,7 +63,11 @@ class JettyServlet2Test extends AgentTestRunner {
jettyServer = new Server(PORT) jettyServer = new Server(PORT)
servletContext = new ServletContextHandler() servletContext = new ServletContextHandler()
ConstraintSecurityHandler security = setupAuthentication(jettyServer)
servletContext.setSecurityHandler(security)
servletContext.addServlet(TestServlet2.Sync, "/sync") servletContext.addServlet(TestServlet2.Sync, "/sync")
servletContext.addServlet(TestServlet2.Sync, "/auth/sync")
jettyServer.setHandler(servletContext) jettyServer.setHandler(servletContext)
jettyServer.start() jettyServer.start()
@ -82,11 +94,13 @@ class JettyServlet2Test extends AgentTestRunner {
def "test #path servlet call"() { def "test #path servlet call"() {
setup: setup:
def request = new Request.Builder() def requestBuilder = new Request.Builder()
.url("http://localhost:$PORT/$path") .url("http://localhost:$PORT/$path")
.get() .get()
.build() if (auth) {
def response = client.newCall(request).execute() requestBuilder.header(HttpHeaders.AUTHORIZATION, Credentials.basic("user", "password"))
}
def response = client.newCall(requestBuilder.build()).execute()
expect: expect:
response.body().string().trim() == expectedResponse response.body().string().trim() == expectedResponse
@ -107,6 +121,9 @@ class JettyServlet2Test extends AgentTestRunner {
"component" "java-web-servlet" "component" "java-web-servlet"
"span.type" DDSpanTypes.WEB_SERVLET "span.type" DDSpanTypes.WEB_SERVLET
"servlet.context" "" "servlet.context" ""
if (auth) {
"user.principal" "user"
}
defaultTags() defaultTags()
} }
} }
@ -114,8 +131,9 @@ class JettyServlet2Test extends AgentTestRunner {
} }
where: where:
path | expectedResponse path | expectedResponse | auth
"sync" | "Hello Sync" "sync" | "Hello Sync" | false
"auth/sync" | "Hello Sync" | true
} }
def "test #path error servlet call"() { def "test #path error servlet call"() {
@ -195,4 +213,37 @@ class JettyServlet2Test extends AgentTestRunner {
path | expectedResponse path | expectedResponse
"sync" | "Hello Sync" "sync" | "Hello Sync"
} }
/**
* Setup simple authentication for tests
* <p>
* requests to {@code /auth/*} need login 'user' and password 'password'
* <p>
* For details @see <a href="http://www.eclipse.org/jetty/documentation/9.3.x/embedded-examples.html">http://www.eclipse.org/jetty/documentation/9.3.x/embedded-examples.html</a>
*
* @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
}
} }

View File

@ -0,0 +1 @@
user: password,role

View File

@ -5,12 +5,20 @@ import datadog.trace.agent.test.TestUtils
import datadog.trace.api.DDSpanTypes import datadog.trace.api.DDSpanTypes
import datadog.trace.common.writer.ListWriter import datadog.trace.common.writer.ListWriter
import io.opentracing.util.GlobalTracer import io.opentracing.util.GlobalTracer
import okhttp3.Credentials
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response 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.server.Server
import org.eclipse.jetty.servlet.ServletContextHandler import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.util.security.Constraint
import java.lang.reflect.Field import java.lang.reflect.Field
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
@ -56,8 +64,13 @@ class JettyServlet3Test extends AgentTestRunner {
jettyServer = new Server(PORT) jettyServer = new Server(PORT)
servletContext = new ServletContextHandler() servletContext = new ServletContextHandler()
ConstraintSecurityHandler security = setupAuthentication(jettyServer)
servletContext.setSecurityHandler(security)
servletContext.addServlet(TestServlet3.Sync, "/sync") servletContext.addServlet(TestServlet3.Sync, "/sync")
servletContext.addServlet(TestServlet3.Sync, "/auth/sync")
servletContext.addServlet(TestServlet3.Async, "/async") servletContext.addServlet(TestServlet3.Async, "/async")
servletContext.addServlet(TestServlet3.Async, "/auth/async")
jettyServer.setHandler(servletContext) jettyServer.setHandler(servletContext)
jettyServer.start() jettyServer.start()
@ -84,11 +97,13 @@ class JettyServlet3Test extends AgentTestRunner {
def "test #path servlet call"() { def "test #path servlet call"() {
setup: setup:
def request = new Request.Builder() def requestBuilder = new Request.Builder()
.url("http://localhost:$PORT/$path") .url("http://localhost:$PORT/$path")
.get() .get()
.build() if (auth) {
def response = client.newCall(request).execute() requestBuilder.header(HttpHeaders.AUTHORIZATION, Credentials.basic("user", "password"))
}
def response = client.newCall(requestBuilder.build()).execute()
expect: expect:
response.body().string().trim() == expectedResponse response.body().string().trim() == expectedResponse
@ -110,6 +125,9 @@ class JettyServlet3Test extends AgentTestRunner {
"span.type" DDSpanTypes.WEB_SERVLET "span.type" DDSpanTypes.WEB_SERVLET
"servlet.context" "" "servlet.context" ""
"http.status_code" 200 "http.status_code" 200
if (auth) {
"user.principal" "user"
}
defaultTags() defaultTags()
} }
} }
@ -117,9 +135,11 @@ class JettyServlet3Test extends AgentTestRunner {
} }
where: where:
path | expectedResponse path | expectedResponse | auth
"async" | "Hello Async" "async" | "Hello Async" | false
"sync" | "Hello Sync" "sync" | "Hello Sync" | false
"auth/async" | "Hello Async" | true
"auth/sync" | "Hello Sync" | true
} }
def "servlet instrumentation clears state after async request"() { def "servlet instrumentation clears state after async request"() {
@ -227,4 +247,37 @@ class JettyServlet3Test extends AgentTestRunner {
path | expectedResponse path | expectedResponse
"sync" | "Hello Sync" "sync" | "Hello Sync"
} }
/**
* Setup simple authentication for tests
* <p>
* requests to {@code /auth/*} need login 'user' and password 'password'
* <p>
* For details @see <a href="http://www.eclipse.org/jetty/documentation/9.3.x/embedded-examples.html">http://www.eclipse.org/jetty/documentation/9.3.x/embedded-examples.html</a>
*
* @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
}
} }

View File

@ -0,0 +1 @@
user: password,role