Skip to content

Commit

Permalink
AppSec Xml support for play 2.6
Browse files Browse the repository at this point in the history
  • Loading branch information
cataphract committed Oct 27, 2023
1 parent 29753c5 commit 7966052
Show file tree
Hide file tree
Showing 12 changed files with 332 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import play.routing.Router
import play.routing.RoutingDsl
import scala.collection.JavaConverters
import scala.concurrent.ExecutionContextExecutor
import scala.xml.NodeSeq

import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionStage
Expand All @@ -26,6 +27,7 @@ import java.util.function.Supplier
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_JSON
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_MULTIPART
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_URLENCODED
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_XML
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CUSTOM_EXCEPTION
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
Expand Down Expand Up @@ -151,6 +153,13 @@ class PlayRouters {
Results.status(BODY_JSON.status, Json$.MODULE$.stringify(json))
}
} as Supplier)
.POST(BODY_XML.path).routeTo({
->
controller(BODY_XML) {
NodeSeq node = body().asXml().get()
Results.status(BODY_XML.status, node.toString())
}
} as Supplier)
.build()
}

Expand Down Expand Up @@ -281,6 +290,16 @@ class PlayRouters {
}
}, execContext)
} as Supplier)
.POST(BODY_XML.path).routeAsync({
->
NodeSeq node = body().asXml().get()
CompletableFuture.supplyAsync({
->
controller(BODY_XML) {
Results.status(BODY_XML.status, node.toString())
}
}, execContext)
} as Supplier)
.build()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import datadog.trace.api.DDTags
import datadog.trace.bootstrap.instrumentation.api.Tags
import datadog.trace.instrumentation.play26.PlayHttpServerDecorator
import groovy.transform.CompileStatic
import okhttp3.MediaType
import okhttp3.RequestBody
import play.server.Server

import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_XML
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CUSTOM_EXCEPTION
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.FORWARDED
Expand Down Expand Up @@ -142,4 +145,29 @@ class PlayServerTest extends HttpServerTest<Server> {
}
}
}

def 'test instrumentation gateway xml request body'() {
setup:
def request = request(
BODY_XML, 'POST',
RequestBody.create(MediaType.get('text/xml'), '<foo attr="attr_value">mytext<bar></bar></foo>'))
.build()
def response = client.newCall(request).execute()
if (isDataStreamsEnabled()) {
TEST_DATA_STREAMS_WRITER.waitForGroups(1)
}
String body = response.body().charStream().text


expect:
body == BODY_XML.body || body == '<?xml version="1.0" encoding="UTF-8"?><foo attr="attr_value">mytext<bar/></foo>'

when:
TEST_WRITER.waitForTraces(1)

then:
TEST_WRITER.get(0).any {
it.getTag('request.body.converted') == '[[children:[mytext, [:]], attributes:[attr:attr_value]]]'
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import datadog.appsec.api.blocking.Blocking
import datadog.trace.agent.test.base.HttpServerTest
import datadog.trace.instrumentation.play26.server.TestHttpErrorHandler
import groovy.transform.CompileStatic
import org.w3c.dom.Document
import play.BuiltInComponents
import play.libs.concurrent.ClassLoaderExecution
import play.mvc.Http
Expand All @@ -16,13 +17,18 @@ import play.routing.Router
import play.routing.RoutingDsl
import scala.concurrent.ExecutionContextExecutor

import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionStage
import java.util.concurrent.ExecutorService

import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_JSON
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_MULTIPART
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_URLENCODED
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.BODY_XML
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CREATED
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.CUSTOM_EXCEPTION
import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR
Expand Down Expand Up @@ -118,6 +124,12 @@ class PlayRouters {
Results.status(BODY_JSON.status, new ObjectMapper().writeValueAsString(json))
}
} as RequestFunctions.Params0<Result>)
.POST(BODY_XML.path).routingTo({ Http.Request req ->
controller(BODY_XML) {
Document xml = req.body().asXml()
Results.status(BODY_XML.status, documentToString(xml))
}
} as RequestFunctions.Params0<Result>)
.build()
}

Expand Down Expand Up @@ -246,6 +258,15 @@ class PlayRouters {
}
}, execContext)
} as RequestFunctions.Params0<? extends CompletionStage<Result>>)
.POST(BODY_XML.path).routingAsync({ Http.Request req ->
Document xml = req.body().asXml()
CompletableFuture.supplyAsync({
->
controller(BODY_XML) {
Results.status(BODY_XML.status, documentToString(xml))
}
}, execContext)
} as RequestFunctions.Params0<? extends CompletionStage<Result>>)
.build()
}

Expand All @@ -263,4 +284,13 @@ class PlayRouters {
})
}
}

private static String documentToString(Document doc) {
StringWriter writer = new StringWriter()
TransformerFactory.newInstance().newTransformer().with {
setOutputProperty(OutputKeys.INDENT, "no")
transform(new DOMSource(doc), new StreamResult(writer))
}
writer.toString()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ POST /created datadog.trace.instrumentation.play26.server.
POST /body-urlencoded datadog.trace.instrumentation.play26.server.latestdep.PlayController.bodyUrlencoded()
POST /body-multipart datadog.trace.instrumentation.play26.server.latestdep.PlayController.bodyMultipart()
POST /body-json datadog.trace.instrumentation.play26.server.latestdep.PlayController.bodyJson()
POST /body-xml datadog.trace.instrumentation.play26.server.latestdep.PlayController.bodyXml()
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package datadog.trace.instrumentation.play26.server.latestdep

import scala.collection.Seq

object ImplicitConversions {
implicit class MapExtensions[A](m: Iterable[(String, A)]) {
def toStringAsGroovy: String = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import play.api.libs.json.{JsNull, JsValue, Json}
import play.api.mvc._

import scala.concurrent.{ExecutionContext, Future}
import scala.xml.NodeSeq

class PlayController(cc: ControllerComponents)(implicit ec: ExecutionContext) extends AbstractController(cc) {
def success() = controller(ServerEndpoint.SUCCESS) { _ =>
Expand Down Expand Up @@ -81,6 +82,11 @@ class PlayController(cc: ControllerComponents)(implicit ec: ExecutionContext) ex
Results.Ok(Json.stringify(body))
}

def bodyXml = controller(ServerEndpoint.BODY_XML) { request =>
val body : NodeSeq = request.body.asXml.getOrElse(NodeSeq.Empty)
Results.Ok(body.toString())
}

private def controller(endpoint: ServerEndpoint)(block: Request[AnyContent] => Result) : Action[AnyContent] = {
Action.async { request =>
Future {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import play.api.routing.sird._

import java.util.concurrent.ExecutorService
import scala.concurrent.{ExecutionContext, Future}
import scala.xml.NodeSeq

object PlayRoutersScala {

Expand Down Expand Up @@ -149,6 +150,13 @@ object PlayRoutersScala {
Results.Ok(Json.stringify(body))
}
}

case POST(p"/body-xml") => defaultActionBuilder.async(parser) { request =>
controller(BODY_XML) {
val body: NodeSeq = request.body.asXml.getOrElse(NodeSeq.Empty)
Results.Ok(body.toString())
}
}
}
}

Expand Down
Loading

0 comments on commit 7966052

Please sign in to comment.