2012-06-11 18:33:05 +02:00
/* *
* Copyright ( C ) 2009 - 2012 Typesafe Inc . < http : //www.typesafe.com>
*/
2012-06-18 13:57:42 +02:00
package akka.remote
2012-06-11 18:33:05 +02:00
2012-06-25 16:29:08 +02:00
import language.postfixOps
2012-06-11 18:33:05 +02:00
import akka.testkit._
import akka.actor._
import com.typesafe.config._
2012-07-04 15:25:30 +02:00
import scala.concurrent.Future
2012-09-19 17:32:54 +02:00
import scala.reflect.classTag
2012-06-11 18:33:05 +02:00
import akka.pattern.ask
import java.io.File
2012-06-18 14:55:49 +02:00
import java.security. { NoSuchAlgorithmException , SecureRandom , PrivilegedAction , AccessController }
2012-06-29 13:33:20 +02:00
import akka.remote.netty. { NettySettings , NettySSLSupport }
2012-06-18 17:57:09 +02:00
import javax.net.ssl.SSLException
2012-06-29 13:33:20 +02:00
import akka.util.Timeout
2012-06-29 16:40:36 +02:00
import scala.concurrent.Await
2012-09-21 14:50:06 +02:00
import scala.concurrent.duration._
2012-06-19 22:44:01 +02:00
import akka.event. { Logging , NoLogging , LoggingAdapter }
2012-06-11 18:33:05 +02:00
object Configuration {
// set this in your JAVA_OPTS to see all ssl debug info: "-Djavax.net.debug=ssl,keymanager"
// The certificate will expire in 2109
2012-06-18 18:47:35 +02:00
private val trustStore = getClass . getClassLoader . getResource ( "truststore" ) . getPath
private val keyStore = getClass . getClassLoader . getResource ( "keystore" ) . getPath
2012-06-11 18:33:05 +02:00
private val conf = "" "
akka {
actor . provider = "akka.remote.RemoteActorRefProvider"
2012-06-18 19:31:36 +02:00
test {
2012-06-18 20:07:58 +02:00
single - expect - default = 10 s
filter - leeway = 10 s
default - timeout = 10 s
2012-06-18 19:31:36 +02:00
}
2012-06-11 18:33:05 +02:00
remote . netty {
hostname = localhost
2012-06-19 22:44:01 +02:00
port = % d
2012-06-11 18:33:05 +02:00
ssl {
enable = on
trust - store = "%s"
key - store = "%s"
random - number - generator = "%s"
2012-06-19 10:36:09 +02:00
enabled - algorithms = [ % s ]
2012-06-18 13:57:42 +02:00
sha1prng - random - source = "/dev/./urandom"
2012-06-11 18:33:05 +02:00
}
}
}
"" "
2012-06-19 22:44:01 +02:00
case class CipherConfig ( runTest : Boolean , config : Config , cipher : String , localPort : Int , remotePort : Int )
def getCipherConfig ( cipher : String , enabled : String * ) : CipherConfig = {
val localPort , remotePort = { val s = new java . net . ServerSocket ( 0 ) ; try s . getLocalPort finally s . close ( ) }
try {
//if (true) throw new IllegalArgumentException("Ticket1978*Spec isn't enabled")
2012-06-19 21:19:19 +02:00
2012-06-19 22:44:01 +02:00
val config = ConfigFactory . parseString ( conf . format ( localPort , trustStore , keyStore , cipher , enabled . mkString ( ", " ) ) )
val fullConfig = config . withFallback ( AkkaSpec . testConf ) . withFallback ( ConfigFactory . load ) . getConfig ( "akka.remote.netty" )
val settings = new NettySettings ( fullConfig , "placeholder" )
2012-06-18 17:57:09 +02:00
2012-06-19 22:44:01 +02:00
val rng = NettySSLSupport . initializeCustomSecureRandom ( settings . SSLRandomNumberGenerator , settings . SSLRandomSource , NoLogging )
2012-06-18 17:57:09 +02:00
2012-06-19 22:44:01 +02:00
rng . nextInt ( ) // Has to work
settings . SSLRandomNumberGenerator foreach { sRng ⇒ rng . getAlgorithm == sRng || ( throw new NoSuchAlgorithmException ( sRng ) ) }
2012-06-18 17:57:09 +02:00
2012-06-19 22:44:01 +02:00
val engine = NettySSLSupport . initializeClientSSL ( settings , NoLogging ) . getEngine
val gotAllSupported = enabled . toSet -- engine . getSupportedCipherSuites . toSet
val gotAllEnabled = enabled . toSet -- engine . getEnabledCipherSuites . toSet
gotAllSupported . isEmpty || ( throw new IllegalArgumentException ( "Cipher Suite not supported: " + gotAllSupported ) )
gotAllEnabled . isEmpty || ( throw new IllegalArgumentException ( "Cipher Suite not enabled: " + gotAllEnabled ) )
engine . getSupportedProtocols . contains ( settings . SSLProtocol . get ) || ( throw new IllegalArgumentException ( "Protocol not supported: " + settings . SSLProtocol . get ) )
2012-06-18 17:57:09 +02:00
2012-06-19 22:44:01 +02:00
CipherConfig ( true , config , cipher , localPort , remotePort )
} catch {
case ( _ : IllegalArgumentException ) | ( _ : NoSuchAlgorithmException ) ⇒ CipherConfig ( false , AkkaSpec . testConf , cipher , localPort , remotePort ) // Cannot match against the message since the message might be localized :S
}
2012-06-18 14:55:49 +02:00
}
2012-06-11 18:33:05 +02:00
}
2012-06-19 22:44:01 +02:00
import Configuration. { CipherConfig , getCipherConfig }
2012-06-15 16:08:07 +02:00
2012-06-11 18:33:05 +02:00
@org . junit . runner . RunWith ( classOf [ org . scalatest . junit . JUnitRunner ] )
2012-06-15 18:05:02 +02:00
class Ticket1978SHA1PRNGSpec extends Ticket1978CommunicationSpec ( getCipherConfig ( "SHA1PRNG" , "TLS_RSA_WITH_AES_128_CBC_SHA" ) )
2012-06-11 18:33:05 +02:00
@org . junit . runner . RunWith ( classOf [ org . scalatest . junit . JUnitRunner ] )
2012-06-20 19:06:12 +02:00
class Ticket1978AES128CounterSecureRNGSpec extends Ticket1978CommunicationSpec ( getCipherConfig ( "AES128CounterSecureRNG" , "TLS_RSA_WITH_AES_128_CBC_SHA" , "TLS_RSA_WITH_AES_256_CBC_SHA" ) )
2012-06-11 18:33:05 +02:00
2012-07-02 13:13:45 +02:00
@org . junit . runner . RunWith ( classOf [ org . scalatest . junit . JUnitRunner ] )
class Ticket1978AES256CounterSecureRNGSpec extends Ticket1978CommunicationSpec ( getCipherConfig ( "AES256CounterSecureRNG" , "TLS_RSA_WITH_AES_128_CBC_SHA" , "TLS_RSA_WITH_AES_256_CBC_SHA" ) )
2012-06-11 18:33:05 +02:00
/* *
2012-06-20 19:06:12 +02:00
* Both of the < quote > Inet </ quote > variants require access to the Internet to access random . org .
2012-06-11 18:33:05 +02:00
*/
2012-06-19 21:19:19 +02:00
@org . junit . runner . RunWith ( classOf [ org . scalatest . junit . JUnitRunner ] )
2012-06-20 19:06:12 +02:00
class Ticket1978AES128CounterInetRNGSpec extends Ticket1978CommunicationSpec ( getCipherConfig ( "AES128CounterInetRNG" , "TLS_RSA_WITH_AES_128_CBC_SHA" ) )
2012-06-11 18:33:05 +02:00
/* *
2012-06-20 19:06:12 +02:00
* Both of the < quote > Inet </ quote > variants require access to the Internet to access random . org .
2012-06-11 18:33:05 +02:00
*/
@org . junit . runner . RunWith ( classOf [ org . scalatest . junit . JUnitRunner ] )
2012-06-20 19:06:12 +02:00
class Ticket1978AES256CounterInetRNGSpec extends Ticket1978CommunicationSpec ( getCipherConfig ( "AES256CounterInetRNG" , "TLS_RSA_WITH_AES_256_CBC_SHA" ) )
2012-06-11 18:33:05 +02:00
2012-06-15 18:31:28 +02:00
@org . junit . runner . RunWith ( classOf [ org . scalatest . junit . JUnitRunner ] )
class Ticket1978DefaultRNGSecureSpec extends Ticket1978CommunicationSpec ( getCipherConfig ( "" , "TLS_RSA_WITH_AES_128_CBC_SHA" ) )
2012-06-11 18:33:05 +02:00
@org . junit . runner . RunWith ( classOf [ org . scalatest . junit . JUnitRunner ] )
2012-06-19 22:44:01 +02:00
class Ticket1978CrappyRSAWithMD5OnlyHereToMakeSureThingsWorkSpec extends Ticket1978CommunicationSpec ( getCipherConfig ( "" , "SSL_RSA_WITH_NULL_MD5" ) )
2012-06-11 18:33:05 +02:00
2012-06-19 22:44:01 +02:00
@org . junit . runner . RunWith ( classOf [ org . scalatest . junit . JUnitRunner ] )
class Ticket1978NonExistingRNGSecureSpec extends Ticket1978CommunicationSpec ( CipherConfig ( false , AkkaSpec . testConf , "NonExistingRNG" , 12345 , 12346 ) )
abstract class Ticket1978CommunicationSpec ( val cipherConfig : CipherConfig ) extends AkkaSpec ( cipherConfig . config ) with ImplicitSender {
2012-06-18 17:57:09 +02:00
2012-06-20 15:19:24 +02:00
implicit val timeout : Timeout = Timeout ( 10 seconds )
2012-06-11 18:33:05 +02:00
2012-06-15 16:08:07 +02:00
import RemoteCommunicationSpec._
2012-06-11 18:33:05 +02:00
2012-06-19 22:44:01 +02:00
lazy val other : ActorSystem = ActorSystem (
"remote-sys" ,
ConfigFactory . parseString ( "akka.remote.netty.port=" + cipherConfig . remotePort ) . withFallback ( system . settings . config ) )
2012-06-11 18:33:05 +02:00
override def atTermination ( ) {
2012-06-19 22:44:01 +02:00
if ( cipherConfig . runTest ) {
other . shutdown ( )
other . awaitTermination ( )
}
2012-06-11 18:33:05 +02:00
}
2012-06-20 14:43:11 +02:00
( "-" ) must {
2012-06-19 22:44:01 +02:00
if ( cipherConfig . runTest ) {
val ignoreMe = other . actorOf ( Props ( new Actor { def receive = { case ( "ping" , x ) ⇒ sender ! ( ( ( "pong" , x ) , sender ) ) } } ) , "echo" )
val otherAddress = other . asInstanceOf [ ExtendedActorSystem ] . provider . asInstanceOf [ RemoteActorRefProvider ] . transport . address
2012-06-18 14:02:08 +02:00
2012-06-19 22:44:01 +02:00
"support tell" in {
val here = system . actorFor ( otherAddress . toString + "/user/echo" )
2012-06-20 14:43:11 +02:00
2012-06-20 15:19:24 +02:00
for ( i ← 1 to 1000 ) here ! ( ( "ping" , i ) )
for ( i ← 1 to 1000 ) expectMsgPF ( timeout . duration ) { case ( ( "pong" , i ) , `testActor` ) ⇒ true }
2012-06-11 18:33:05 +02:00
}
2012-06-15 15:04:54 +02:00
"support ask" in {
2012-07-21 18:30:14 +02:00
import system.dispatcher
2012-06-19 22:44:01 +02:00
val here = system . actorFor ( otherAddress . toString + "/user/echo" )
2012-06-20 14:43:11 +02:00
2012-09-19 17:32:54 +02:00
val f = for ( i ← 1 to 1000 ) yield here ? ( ( "ping" , i ) ) mapTo classTag [ ( ( String , Int ) , ActorRef ) ]
2012-06-19 22:44:01 +02:00
Await . result ( Future . sequence ( f ) , timeout . duration ) . map ( _ . _1 . _1 ) . toSet must be ( Set ( "pong" ) )
2012-06-11 18:33:05 +02:00
}
2012-06-15 15:04:54 +02:00
} else {
"not be run when the cipher is not supported by the platform this test is currently being executed on" ignore {
2012-06-11 18:33:05 +02:00
2012-06-15 15:04:54 +02:00
}
2012-06-11 18:33:05 +02:00
}
}
2012-06-18 13:57:42 +02:00
}