From 9701685897951e097c2a29f10ced25881bdcf4e0 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 27 Dec 2011 17:30:05 +0100 Subject: [PATCH] Adding support for verifying serializability of Props.creator as well --- .../akka/serialization/SerializeSpec.scala | 59 +++++++++++++++++++ .../src/main/scala/akka/actor/Actor.scala | 9 +++ .../src/main/scala/akka/actor/ActorCell.scala | 2 +- .../akka/dispatch/AbstractDispatcher.scala | 2 +- .../src/main/scala/akka/event/Logging.scala | 2 +- 5 files changed, 71 insertions(+), 3 deletions(-) diff --git a/akka-actor-tests/src/test/scala/akka/serialization/SerializeSpec.scala b/akka-actor-tests/src/test/scala/akka/serialization/SerializeSpec.scala index cceb608452..12fe90bbec 100644 --- a/akka-actor-tests/src/test/scala/akka/serialization/SerializeSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/serialization/SerializeSpec.scala @@ -10,6 +10,9 @@ import akka.testkit.AkkaSpec import com.typesafe.config.ConfigFactory import akka.actor._ import java.io._ +import akka.dispatch.Await +import akka.util.Timeout +import akka.util.duration._ object SerializeSpec { @@ -129,3 +132,59 @@ class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) { } } } + +object VerifySerializabilitySpec { + val conf = ConfigFactory.parseString(""" + akka { + actor { + serialize-messages = on + + serialize-creators = on + + serializers { + java = "akka.serialization.JavaSerializer" + proto = "akka.testing.ProtobufSerializer" + sjson = "akka.testing.SJSONSerializer" + default = "akka.serialization.JavaSerializer" + } + + serialization-bindings { + java = ["akka.serialization.SerializeSpec$Address", "akka.serialization.MyJavaSerializableActor", "akka.serialization.MyStatelessActorWithMessagesInMailbox", "akka.serialization.MyActorWithProtobufMessagesInMailbox"] + sjson = ["akka.serialization.SerializeSpec$Person"] + proto = ["com.google.protobuf.Message", "akka.actor.ProtobufProtocol$MyMessage"] + } + } + } + """) + + class FooActor extends Actor { + def receive = { + case s: String ⇒ sender ! s + } + } + + class NonSerializableActor(system: ActorSystem) extends Actor { + def receive = { + case s: String ⇒ sender ! s + } + } +} + +class VerifySerializabilitySpec extends AkkaSpec(VerifySerializabilitySpec.conf) { + import VerifySerializabilitySpec._ + + "verify creators and messages" in { + implicit val timeout = Timeout(5 seconds) + system.settings.SerializeAllCreators must be(true) + system.settings.SerializeAllMessages must be(true) + + val a = system.actorOf(Props[FooActor]) + Await.result(a ? "pigdog", timeout.duration) must be("pigdog") + intercept[NotSerializableException] { + Await.result(a ? new AnyRef, timeout.duration) + } + intercept[java.io.NotSerializableException] { + val b = system.actorOf(Props(new NonSerializableActor(system))) + } + } +} diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 2c44ec70c6..8713df95b4 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -25,8 +25,17 @@ import java.util.regex.Pattern */ trait AutoReceivedMessage extends Serializable +/** + * Marker trait to indicate that a message might be potentially harmful, + * this is used to block messages coming in over remoting. + */ trait PossiblyHarmful +/** + * Marker trait to signal that this class should not be verified for serializability. + */ +trait NoSerializationVerificationNeeded + case class Failed(cause: Throwable) extends AutoReceivedMessage with PossiblyHarmful case object PoisonPill extends AutoReceivedMessage with PossiblyHarmful diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala index a214e234d0..69b8c0b6c9 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala @@ -215,7 +215,7 @@ private[akka] class ActorCell( final var childrenRefs: TreeMap[String, ChildRestartStats] = emptyChildrenRefs private def _actorOf(props: Props, name: String): ActorRef = { - if (system.settings.SerializeAllCreators) { + if (system.settings.SerializeAllCreators && !props.creator.isInstanceOf[NoSerializationVerificationNeeded]) { val ser = SerializationExtension(system) ser.serialize(props.creator) match { case Left(t) ⇒ throw t diff --git a/akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala b/akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala index 90c68a4996..24b9da4447 100644 --- a/akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala +++ b/akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala @@ -19,7 +19,7 @@ final case class Envelope(val message: Any, val sender: ActorRef)(system: ActorS if (message.isInstanceOf[AnyRef]) { val msg = message.asInstanceOf[AnyRef] if (msg eq null) throw new InvalidMessageException("Message is null") - if (system.settings.SerializeAllMessages) { + if (system.settings.SerializeAllMessages && !msg.isInstanceOf[NoSerializationVerificationNeeded]) { val ser = SerializationExtension(system) ser.serialize(msg) match { //Verify serializability case Left(t) ⇒ throw t diff --git a/akka-actor/src/main/scala/akka/event/Logging.scala b/akka-actor/src/main/scala/akka/event/Logging.scala index 1797eb9d18..fbceb6973d 100644 --- a/akka-actor/src/main/scala/akka/event/Logging.scala +++ b/akka-actor/src/main/scala/akka/event/Logging.scala @@ -363,7 +363,7 @@ object Logging { * message. This is necessary to ensure that additional subscriptions are in * effect when the logging system finished starting. */ - case class InitializeLogger(bus: LoggingBus) + case class InitializeLogger(bus: LoggingBus) extends NoSerializationVerificationNeeded /** * Response message each logger must send within 1 second after receiving the