diff --git a/otoroshi/app/wasm/proxywasm/api.scala b/otoroshi/app/wasm/proxywasm/api.scala index c8a9d2ef0..9fe07597b 100644 --- a/otoroshi/app/wasm/proxywasm/api.scala +++ b/otoroshi/app/wasm/proxywasm/api.scala @@ -6,6 +6,7 @@ import io.otoroshi.wasm4s.scaladsl.WasmVmData import org.extism.sdk.{ExtismCurrentPlugin, HostUserData} import org.extism.sdk.wasmotoroshi._ import otoroshi.env.Env +import otoroshi.next.models.NgRoute import otoroshi.next.plugins.api.NgPluginHttpResponse import otoroshi.utils.TypedMap import otoroshi.utils.http.RequestImplicits._ @@ -23,10 +24,12 @@ object VmData { tickPeriod = -1, respRef = new AtomicReference[mvc.Result](null), bodyInRef = new AtomicReference[ByteString](null), - bodyOutRef = new AtomicReference[ByteString](null) + bodyOutRef = new AtomicReference[ByteString](null), + requestRef = None, + routeRef = None, ) def withRules(rules: JsValue): VmData = VmData.empty().copy(configuration = rules.stringify) - def from(request: RequestHeader, attrs: TypedMap)(implicit env: Env): VmData = { + def from(request: RequestHeader, route: Option[NgRoute], attrs: TypedMap)(implicit env: Env): VmData = { val remote = request.headers .get("remote-address") .getOrElse(s"${request.connection.remoteAddress.toString.substring(1)}:${1234}") @@ -35,6 +38,8 @@ object VmData { respRef = new AtomicReference[play.api.mvc.Result](null), bodyInRef = new AtomicReference[ByteString](null), bodyOutRef = new AtomicReference[ByteString](null), + requestRef = Some(request), + routeRef = route, tickPeriod = -1, properties = Map( "plugin_name" -> "foo".bytes, @@ -83,23 +88,25 @@ object VmData { } case class VmData( - configuration: String, - properties: Map[String, Array[Byte]], - tickPeriod: Int = -1, - respRef: AtomicReference[play.api.mvc.Result], - bodyInRef: AtomicReference[ByteString], - bodyOutRef: AtomicReference[ByteString] + configuration: String, + properties: Map[String, Array[Byte]], + tickPeriod: Int = -1, + respRef: AtomicReference[play.api.mvc.Result], + bodyInRef: AtomicReference[ByteString], + bodyOutRef: AtomicReference[ByteString], + requestRef: Option[RequestHeader], + routeRef: Option[NgRoute], ) extends HostUserData with WasmVmData { - def withRequest(request: RequestHeader, attrs: TypedMap)(implicit env: Env): VmData = { + def withRequest(request: RequestHeader, route: Option[NgRoute], attrs: TypedMap)(implicit env: Env): VmData = { VmData - .from(request, attrs) + .from(request, route, attrs) .copy( configuration = configuration, tickPeriod = tickPeriod, respRef = respRef, bodyInRef = bodyInRef, - bodyOutRef = bodyOutRef + bodyOutRef = bodyOutRef, ) } def withResponse(response: NgPluginHttpResponse, attrs: TypedMap, body_bytes: Option[ByteString])(implicit @@ -129,17 +136,21 @@ case class VmData( tickPeriod = tickPeriod, respRef = respRef, bodyInRef = bodyInRef, - bodyOutRef = bodyOutRef + bodyOutRef = bodyOutRef, + requestRef = requestRef, + routeRef = routeRef, ) } def httpResponse: Option[play.api.mvc.Result] = Option(respRef.get()) def bodyIn: Option[ByteString] = Option(bodyInRef.get()) def bodyOut: Option[ByteString] = Option(bodyOutRef.get()) + def request: Option[RequestHeader] = requestRef + def route: Option[NgRoute] = routeRef } trait Api { - def proxyLog(plugin: ExtismCurrentPlugin, logLevel: Int, messageData: Int, messageSize: Int): Result + def proxyLog(plugin: ExtismCurrentPlugin, logLevel: Int, messageData: Int, messageSize: Int, data: VmData): Result def proxyResumeStream(plugin: ExtismCurrentPlugin, streamType: StreamType): Result diff --git a/otoroshi/app/wasm/proxywasm/coraza.scala b/otoroshi/app/wasm/proxywasm/coraza.scala index daaecf375..1c8a17b12 100644 --- a/otoroshi/app/wasm/proxywasm/coraza.scala +++ b/otoroshi/app/wasm/proxywasm/coraza.scala @@ -12,7 +12,9 @@ import otoroshi.env.Env import otoroshi.events.AnalyticEvent import otoroshi.models.{EntityLocation, EntityLocationSupport} import otoroshi.next.extensions._ +import otoroshi.next.models.NgRoute import otoroshi.next.plugins.api._ +import otoroshi.next.utils.JsonHelpers import otoroshi.security.IdGenerator import otoroshi.storage.{BasicStore, RedisLike, RedisLikeStore} import otoroshi.utils.{ReplaceAllWith, TypedMap} @@ -79,11 +81,11 @@ class CorazaPlugin(wasm: WasmConfig, val config: CorazaWafConfig, key: String, e private lazy val pluginConfigurationSize = rules.stringify.byteString.length private lazy val contextId = new AtomicInteger(0) private lazy val state = - new ProxyWasmState(CorazaPlugin.rootContextIds.incrementAndGet(), contextId, Some((l, m) => logCallback(l, m)), env) + new ProxyWasmState(CorazaPlugin.rootContextIds.incrementAndGet(), contextId, Some((l, m, vmd) => logCallback(l, m, vmd)), env) private lazy val pool: WasmVmPool = WasmVmPool.forConfigurationWithId(key, wasm)(env.wasmIntegration.context) - def logCallback(level: org.slf4j.event.Level, msg: String): Unit = { - CorazaTrailEvent(level, msg).toAnalytics() + def logCallback(level: org.slf4j.event.Level, msg: String, data: VmData): Unit = { + CorazaTrailEvent(level, msg, data.request, data.route).debug(evt => evt.toJson.prettify.debugPrintln).toAnalytics() } def isStarted(): Boolean = started.get() @@ -217,7 +219,7 @@ class CorazaPlugin(wasm: WasmConfig, val config: CorazaWafConfig, key: String, e attrs: TypedMap ): Future[Either[play.api.mvc.Result, Unit]] = { val vm = attrs.get(otoroshi.wasm.proxywasm.CorazaPluginKeys.CorazaWasmVmKey).get - val data = VmData.empty().withRequest(request, attrs)(env) + val data = VmData.empty().withRequest(request, attrs.get(otoroshi.next.plugins.Keys.RouteKey), attrs)(env) val endOfStream = 1 val sizeHeaders = 0 val prs = new Parameters(3).pushInts(contextId, sizeHeaders, endOfStream) @@ -249,7 +251,7 @@ class CorazaPlugin(wasm: WasmConfig, val config: CorazaWafConfig, key: String, e attrs: TypedMap ): Future[Either[play.api.mvc.Result, Unit]] = { val vm = attrs.get(otoroshi.wasm.proxywasm.CorazaPluginKeys.CorazaWasmVmKey).get - val data = VmData.empty().withRequest(request, attrs)(env) + val data = VmData.empty().withRequest(request, attrs.get(otoroshi.next.plugins.Keys.RouteKey), attrs)(env) data.bodyInRef.set(body_bytes) val endOfStream = 1 val sizeBody = body_bytes.size.bytes.length @@ -760,7 +762,7 @@ class CorazaWafAdminExtension(val env: Env) extends AdminExtension { } } -case class CorazaTrailEvent(level: org.slf4j.event.Level, msg: String) extends AnalyticEvent { +case class CorazaTrailEvent(level: org.slf4j.event.Level, msg: String, request: Option[RequestHeader], route: Option[NgRoute]) extends AnalyticEvent { override def `@service`: String = "--" override def `@serviceId`: String = "--" @@ -799,7 +801,9 @@ case class CorazaTrailEvent(level: org.slf4j.event.Level, msg: String) extends A "level" -> level.name(), "raw" -> msg, "msg" -> txt, - "fields" -> JsObject(fields.mapValues(JsString.apply)) + "fields" -> JsObject(fields.mapValues(JsString.apply)), + "route" -> route.map(_.json).getOrElse(JsNull).asValue, + "request" -> request.map(JsonHelpers.requestToJson).getOrElse(JsNull).asValue, ) } } diff --git a/otoroshi/app/wasm/proxywasm/functions.scala b/otoroshi/app/wasm/proxywasm/functions.scala index d410f44ab..4ab110403 100644 --- a/otoroshi/app/wasm/proxywasm/functions.scala +++ b/otoroshi/app/wasm/proxywasm/functions.scala @@ -46,7 +46,7 @@ object ProxyWasmFunctions { params: Array[LibExtism.ExtismVal], returns: Array[LibExtism.ExtismVal], data: Optional[EnvUserData] - ) => state.proxyLog(plugin, params(0).v.i32, params(1).v.i32, params(2).v.i32), + ) => state.proxyLog(plugin, params(0).v.i32, params(1).v.i32, params(2).v.i32, getCurrentVmData()), Optional.empty[EnvUserData]() ).withNamespace("env"), new HostFunction[EnvUserData]( diff --git a/otoroshi/app/wasm/proxywasm/state.scala b/otoroshi/app/wasm/proxywasm/state.scala index ee54311d5..2be48d4fe 100644 --- a/otoroshi/app/wasm/proxywasm/state.scala +++ b/otoroshi/app/wasm/proxywasm/state.scala @@ -19,7 +19,7 @@ import java.util.concurrent.atomic.AtomicInteger class ProxyWasmState( val rootContextId: Int, val contextId: AtomicInteger, - logCallback: Option[Function2[org.slf4j.event.Level, String, Unit]], + logCallback: Option[Function3[org.slf4j.event.Level, String, VmData, Unit]], env: Env ) extends Api { @@ -32,7 +32,7 @@ class ProxyWasmState( throw new NotImplementedError(s"proxy state method '${name}' is not implemented") } - override def proxyLog(plugin: ExtismCurrentPlugin, logLevel: Int, messageData: Int, messageSize: Int): Result = { + override def proxyLog(plugin: ExtismCurrentPlugin, logLevel: Int, messageData: Int, messageSize: Int, data: VmData): Result = { // println(s"proxyLog: $logLevel - $messageData - $messageSize") getMemory(plugin, messageData, messageSize) .fold( @@ -42,19 +42,19 @@ class ProxyWasmState( logLevel match { case 0 => logger.trace(message) - logCallback.foreach(_.apply(org.slf4j.event.Level.TRACE, message)) + logCallback.foreach(_.apply(org.slf4j.event.Level.TRACE, message, data)) case 1 => logger.debug(message) - logCallback.foreach(_.apply(org.slf4j.event.Level.DEBUG, message)) + logCallback.foreach(_.apply(org.slf4j.event.Level.DEBUG, message, data)) case 2 => logger.info(message) - logCallback.foreach(_.apply(org.slf4j.event.Level.INFO, message)) + logCallback.foreach(_.apply(org.slf4j.event.Level.INFO, message, data)) case 3 => logger.warn(message) - logCallback.foreach(_.apply(org.slf4j.event.Level.WARN, message)) + logCallback.foreach(_.apply(org.slf4j.event.Level.WARN, message, data)) case _ => logger.error(message) - logCallback.foreach(_.apply(org.slf4j.event.Level.ERROR, message)) + logCallback.foreach(_.apply(org.slf4j.event.Level.ERROR, message, data)) } ResultOk }