1: TestProbe subscriber = TestProbe.apply(system);
2: system().eventStream().subscribe(subscriber.ref(), UnhandledMessages.class);
3: // send your message here
4: subscriber.expectMsgClass(duration("1 second"), UnhandledMessage.class);
You simply need to create a TestProbe that subscribes to the system's event stream and watch for UnhandledMessage.class. In line 4, the expectMsgClass will throw an assertion error if the message you sent is not unhandled by the actor. You can, of course, come up with more complex scenarios, but this handles the simple case.
This, That, and Something Else
Thursday, December 12, 2013
Testing Unhandled Messages in Akka
I had an occasion to verify that a message was truly not being handled by an actor when sending it a message while not yet initialized. After doing a little research, I didn't find any simple method signatures that would test for that, but the setup is simple enough.
Tuesday, May 14, 2013
Bouncy Castle, Self-Signed Certificates, XMPP, and Keystores, oh my...
I had the opportunity recently to implement a method to dynamically generate a self-signed certificate to use with the Apache Vypser XMPP server. For our needs, we needed to have the ability to configure a domain from a web console, generate the keystore for use with Vysper, and then download the certificate from the keystore to use with federated servers.
Starting out, I thought this was going to be a simple task. As it turned out, there were a few complications, but in the end, it works pretty well. I used bouncy-castle v 1.48 to generate the certificate.
The problem I kept running in to was that all of the documentation I could find used the deprecated bouncy-castle APIs. I wanted to make sure that while generating new code, I wasn't using APIs that were already known to be obsolete. Unfortunately, there is not a lot of documentation available yet for the new APIs.
Adding to the challenge is that certificates used with XMPP server federation have to include the subject alternative name extension in the certificate. Finding the right sequence of magic included reverse engineering a certificate generated from OpenSSL.
The following code is what I ended up with.
Starting out, I thought this was going to be a simple task. As it turned out, there were a few complications, but in the end, it works pretty well. I used bouncy-castle v 1.48 to generate the certificate.
The problem I kept running in to was that all of the documentation I could find used the deprecated bouncy-castle APIs. I wanted to make sure that while generating new code, I wasn't using APIs that were already known to be obsolete. Unfortunately, there is not a lot of documentation available yet for the new APIs.
Adding to the challenge is that certificates used with XMPP server federation have to include the subject alternative name extension in the certificate. Finding the right sequence of magic included reverse engineering a certificate generated from OpenSSL.
The following code is what I ended up with.
final ASN1ObjectIdentifier XMPP_ADDR_OID = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.8.5");
RSAKeyPairGenerator kpg = new RSAKeyPairGenerator();
kpg.init(new RSAKeyGenerationParameters(
BigInteger.valueOf(0x1001), new SecureRandom(), 1024, 25));
AsymmetricCipherKeyPair keyPair = kpg.generateKeyPair();
X500Name subject = new X500Name("CN=" + domainName);
DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
AlgorithmIdentifier sigAlgId = sigAlgFinder.find("SHA1withRSA");
AlgorithmIdentifier digAlgId = digAlgFinder.find(sigAlgId);
ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(keyPair.getPrivate());
// Create the extension for subjectAltName
DERUTF8String derDomainName = new DERUTF8String(domainName);
DERTaggedObject derTaggedDomainName = new DERTaggedObject(0, derDomainName);
DLSequence otherName = new DLSequence(new ASN1Encodable[]{XMPP_ADDR_OID, derTaggedDomainName});
GeneralNames generalNames = new GeneralNames(new GeneralName(GeneralName.otherName, otherName));
// Create the certificate
BcX509v3CertificateBuilder certBuilder = new BcX509v3CertificateBuilder(subject, BigInteger.valueOf(1),
new Date(
System.currentTimeMillis() - 50000),
new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 3650)),
subject, keyPair.getPublic());
certBuilder.addExtension(Extension.subjectAlternativeName, false, generalNames);
X509CertificateHolder cert = certBuilder.build(sigGen);
// Convert to standard Java objects to be able to create the keystore
RSAKeyParameters privateKey = (RSAKeyParameters) keyPair.getPrivate();
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(privateKey.getModulus(), privateKey.getExponent());
PrivateKey jPrivateKey = KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec);
final X509CertificateObject x509CertificateObject = new X509CertificateObject(cert.toASN1Structure());
// Create a keystore with a randomly generated password to secure it
final String password = RandomStringUtils.randomAlphanumeric(24);
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null, null);
keystore.setKeyEntry("xmpp", jPrivateKey, password.toCharArray(), new Certificate[]{x509CertificateObject});
OutputStream fos = new FileOutputStream(keystoreFile);
keystore.store(fos, password.toCharArray());
fos.close();
Subscribe to:
Posts (Atom)