don't allow wrong system in ActorRefResolver, #27373 (#27391)

This commit is contained in:
Christopher Batey 2019-09-09 15:42:18 +01:00 committed by Patrik Nordwall
parent 9aa0e593b0
commit 9a4674f42f
2 changed files with 77 additions and 3 deletions

View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2019 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.actor.typed
import akka.actor.ActorPath
import akka.actor.ActorRefProvider
import akka.actor.ActorSystemImpl
import akka.actor.MinimalActorRef
import akka.actor.RootActorPath
import akka.actor.typed.scaladsl.Behaviors
import org.scalatest.Matchers
import org.scalatest.WordSpec
import org.scalatest.concurrent.ScalaFutures
class ActorRefResolverSpec extends WordSpec with ScalaFutures with Matchers {
"ActorRefResolver" should {
"not allow serialization of ref originating from other system" in {
val system1 = ActorSystem(Behaviors.empty[String], "sys1")
val system2 = ActorSystem(Behaviors.empty[String], "sys2")
try {
val ref1 = system1.systemActorOf(Behaviors.empty, "ref1")
val serialized = ActorRefResolver(system1).toSerializationFormat(ref1)
serialized should startWith("akka://sys1/")
intercept[IllegalArgumentException] {
// wrong system
ActorRefResolver(system2).toSerializationFormat(ref1)
}
// we can't detect that for MinimalActorRef
import akka.actor.typed.scaladsl.adapter._
val minRef1: akka.actor.ActorRef = new MinimalActorRef {
override def provider: ActorRefProvider = system1.toClassic.asInstanceOf[ActorSystemImpl].provider
override def path: ActorPath = RootActorPath(provider.getDefaultAddress) / "minRef1"
}
val minRef1Serialized = ActorRefResolver(system2).toSerializationFormat(minRef1)
minRef1Serialized should startWith("akka://sys2/")
} finally {
system1.terminate()
system2.terminate()
}
}
}
}

View file

@ -4,6 +4,7 @@
package akka.actor.typed
import akka.actor.ActorRefWithCell
import akka.actor.ExtendedActorSystem
import akka.annotation.DoNotInherit
import akka.annotation.InternalApi
@ -35,7 +36,7 @@ abstract class ActorRefResolver extends Extension {
def toSerializationFormat[T](ref: ActorRef[T]): String
/**
* Deserialize an `ActorRef` in the [[#toSerializationFormat]].
* Deserialize an `ActorRef` in the [[ActorRefResolver#toSerializationFormat]].
*/
def resolveActorRef[T](serializedActorRef: String): ActorRef[T]
@ -49,8 +50,30 @@ abstract class ActorRefResolver extends Extension {
private val classicSystem = system.toClassic.asInstanceOf[ExtendedActorSystem]
override def toSerializationFormat[T](ref: ActorRef[T]): String =
ref.path.toSerializationFormatWithAddress(classicSystem.provider.getDefaultAddress)
override def toSerializationFormat[T](ref: ActorRef[T]): String = {
def toSerializationFormatWithAddress =
ref.path.toSerializationFormatWithAddress(classicSystem.provider.getDefaultAddress)
ref.toClassic match {
case a: ActorRefWithCell =>
val originSystem = a.underlying.system.asInstanceOf[ExtendedActorSystem]
if (originSystem eq classicSystem)
toSerializationFormatWithAddress
else
throw new IllegalArgumentException(
s"ActorRefResolver for ActorSystem [${classicSystem.provider.getDefaultAddress}] shouldn't be used for " +
"serialization of ActorRef that originates from another ActorSystem " +
s"[${originSystem.provider.getDefaultAddress}]. Use the ActorRefResolver for that system instead.")
case _ =>
// no origin system information for RemoteActorRef or MinimalActorRef, so just use the
// one for this extension. That is correct for RemoteActorRef, but MinimalActorRef
// could be wrong. However, since we don't allow usage of "wrong" ActorSystem for
// ordinary ActorRef the users will learn not to make that mistake.
toSerializationFormatWithAddress
}
}
override def resolveActorRef[T](serializedActorRef: String): ActorRef[T] =
classicSystem.provider.resolveActorRef(serializedActorRef)