Code Obfuscation: Anonymous Inner Class Death
Java, like most other modern languages, will let you get away with some really ugly code. Inspired by my recent gaze into GWT generated JavaScript, I decided to crank out this little gem. I’ve pretty formatted it here because it doesn’t need any assistance to confuse from lack of white space. See if you can figure out what it does and, more importantly, how it does it.
new Object() {
public void eval(int i) {
if (new Object() {
public boolean eval(int i) {
return i == new Object() {
public int getSomeNumber() {
return 1000;
}
}.getSomeNumber();
}
}.eval(i))
return;
System.out.println(String.format("%c", i));
this.eval(new Object() {
public int next(int i) {
return i + new Object() {
public int leap() {
return 1;
}
}.leap();
}
}.next(i));
}
}.eval(0);
Take a moment and really drink this in. Its fairly simple to obfuscate just about any simple algorithm using this terrible approach. I don’t even want to think about what this is doing to the JVM’s memory, let alone mine.
Mailing List Question: @Autowired Ambiguities
Today a question went out on a Spring mailing list asking about @Autowired dependencies, AOP proxies, and interfaces. I thought this was a great foundation question. So I thought I'd share it here.
Say you have a bean class, Foo which implements FooInterface. On top of that, the bean is advised via Spring AOP it is the proxy class which is referenced by the context (IOC). Now, let's say you want to autowire that dependency in another bean. So you mark the Foo field @Autowired. You fire up you application. Much to your dismay, you'll get an error message on context initialization which goes something like, "unsatisfied dependency." This is due to the fact that you are trying to autowire an object by its class but that class has been proxied. Meaning that there are no beans of this type in context.
So, you remember that its a great idea to code against interfaces rather than concrete classes. So you adjust your field type to FooInterface and fire up the application again. Unfortunately, you forgot that there are several instances of FooInterface in context and you get another error on startup. "No unique bean of type..."
So how would I autowire a specific bean out of a set? The answer is the handy @Qualifier annotation. Adding this to your autowired field let's you specify the bean id/name to inject. In this case you'd use something like @Qualifier("stevesFoo"). Boom. Done.
Ditching JCL for SLF4J
When discussing these two logging API's it really comes down to dynamic discovery vs. statically bound bridging mechanisms. As Ceki Gülcü wrote in his 2009 article detailing the problems with JCL:
Class loading problems encountered when using JCL fall into three main categories:- Type-I: A
java.lang.NoClassDefFoundError
thrown when a class is inaccessible from a parent class loader even if the said class is available to a child class loader - Type-II: Assignment incompatibility of two classes loaded by distinct class loaders, even in case where the two classes are bit-wise identical.
- Type-III: Holding references to a given class loader will prevent the resources loaded by that class loader from being garbage collected.
The article goes on to provide highly detailed descriptions of the problem while including code samples demonstrating the bugs in action.Well, it turns out that on seeing these problems with the JCL, the good people on the log4j project decided to go another direction and create the Simple Logging Facade for Java (SLF4J) project. From the SLF4J site:
The Simple Logging Facade for Java or (SLF4J) serves as a simple facade or abstraction for various logging frameworks, e.g. java.util.logging, log4j and logback, allowing the end user to plug in the desired logging framework at deployment time.
What does it do?
SLF4J provides logging related interface to code against. By doing so, the resultant code is implementation agnostic and has only a single build-time dependency (the SLF4J library). Implementations are specified by runtime classpath configuration. The inclusion of a single library either bridging to a specific logging framework (log4j, JUL, or even JCL) or a direct implementation such as Logback will trigger the use of that implementation by SLF4J's static binding mechanism. Finally, this API provides parameterized logging which improve performance.
How does this work?
Well, I'm summarizing here but, the core of the static binding code works by discovering implementations of org.slf4j.impl.StaticLoggerBinder on the application classpath. This magic is done in the LoggerFactory. Specifically at:
private final static void bind() {
try {
// the next line does the binding
StaticLoggerBinder.getSingleton();
...
StaticLoggerBinder classes provided by SLF4J bridges or implementations tie the API to the concrete frameworks. Here's an example in Logback.
Just Use It
Coding against SLF4J will make your life a bit easier. Bridges erode excuses based on inheriting logging frameworks from your dependencies. Projects can freely float between logging implementations as capability and configuration requirements change. To quote Ceki Gülcü, "In summary, statically bound discovery provides better functionality, with none of the painful bugs associated with JCL's dynamic discovery."
Spring's Alternative Configuration Features
A primary complaint about Spring is the heavy XML configuration traditionally required to use it in a non-trivial way. More and more recent releases have made significant strides away from this model. With the introduction of annotation-based container configuration, Component beans, component scanning, and finally configuration beans, that argument has been largely deflated. These tools move significant portions of configuration from XML into annotation based equivalents. Combined with highly configurable classpath scanning, many traditional component beans like services or repositories can be auto instantiated and auto wired. This is a miracle for larger projects with hundreds of these singleton beans. But some of you might just be saying, "Doesn't this just move configuration from one common place, outside of code, into the code itself?" For those of you who have spent years fighting to get configuration out of code, this might seem all kinds of wrong. Well, if you find yourself in either of these groups - you're not alone - you are both right and wrong.
The reason is simple. All of that configuration, really isn't application configuration at all is it? Think of it this way, if you were not using a dependency injection pattern, all of this bean wiring is something that you would be doing in code by passing dependencies along in method signatures, or some other mechanism. We've all been there, and none of us want to go back. It is Spring configuration, not application configuration. In many instances these tools provide more powerful means of accessing your actual application configuration, which is why we use these frameworks. These make our lives more simple.
Simple is nice. But powerful is awesome. Enter the Spring configuration bean. These are beans which, when loaded via XML or component scanning, define beans to be loaded into the context. With these tools you can finally debug and unit test Spring configuration at a granular level, as well as create configuration inheritance models. Boom. But maybe the best reason to use this stuff is that it makes your Spring configuration much more reusable. No more copying chunks of XML, no more massive efforts to upgrade code bases. So, before you dismiss this stuff too quickly, take a few moments and try to think about how you could use it without violating your personal coding ethics. It will pay out in spades.
Oh, and for those of you who are still a bit buried in your XML configuration bunkers, good luck with the Servlet 3 specification.
Importing Non-Well Known CA Certificates
A while ago my good friend, Neil Fritz wrote a nice little article describing basic manipulation of SSL certificates in Java keystores. This is one of those things that I do just rarely enough to forget the keytool command options. So, dreading the keytool man page, I'm reposting this article here.
From time to time it may be necessary to integrate with APIs that are served using SSL certificates issued by non-well known CAs. Typically you will encounter a situation like this when a developer has issued a self-signed certificate, or is using a cert issued by a free CA like cacert.org. Java, by default, does not trust these CAs and will not allow you to connect to remote servers that have SSL certificates issued in this manner. The technical reason for this is that there is no clear trust path that can be established when negotiating the SSL connection. When a certificate is received, the signer must be a known and trusted certifcate. The JVM will look at the signer of the certificate presented and climb the chain of trust until it finds a root CA certificate that it trusts. If a trust chain cannot be established, it can be identified by a stack trace containing something similar to:
...
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
...
The easiest way to prevent this from occurring is to import the CA certificates into the JVM's cacerts keystore. This keystore is located at JDK_HOME/jre/lib/security/cacerts and can be manipulated using the keytool command.
Listing Certificates
You can view the current list of certificates in a keystore using keytool but the output is somewhat cumbersome to work with. In addition to this, the aliases assigned to the certificates are free-form, so there is no clear convention that we can rely on the easily identify the certificate based on alias. To list the contents of a keystore you do something similar to:
$ keytool -list -keystore cacerts
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 78 entries
digicertassuredidrootca, Jan 7, 2008, trustedCertEntry,
Certificate fingerprint (MD5): 87:CE:0B:7B:2A:0E:49:00:E1:58:71:9B:37:A8:93:72
trustcenterclass2caii, Jan 7, 2008, trustedCertEntry,
Certificate fingerprint (MD5): CE:78:33:5C:59:78:01:6E:18:EA:B9:36:A0:B9:2E:23
thawtepremiumserverca, Dec 2, 2009, trustedCertEntry,
Certificate fingerprint (MD5): A6:6B:60:90:23:9B:3F:2D:BB:98:6F:D6:A7:19:0D:46
swisssignplatinumg2ca, Aug 13, 2008, trustedCertEntry,
Certificate fingerprint (MD5): C9:98:27:77:28:1E:3D:0E:15:3C:84:00:B8:85:03:E6
swisssignsilverg2ca, Aug 13, 2008, trustedCertEntry,
Certificate fingerprint (MD5): E0:06:A1:C9:7D:CF:C9:FC:0D:C0:56:75:96:D8:62:13
thawteserverca, Dec 2, 2009, trustedCertEntry,
...
As you can see, this is not an easy list to search through. But wait, we have the MD5 hashes of the certificates, so we can search on these and be sure that the certificate has been imported to the keystore regardless of the alias used. The MD5 fingerprint can be obtained from the CA certificate using openssl as follows:
$ openssl x509 -noout -md5 -fingerprint -in class3.crt
MD5 Fingerprint=73:3F:35:54:1D:44:C9:E9:5A:4A:EF:51:AD:03:06:B6
We can now use this to grep the output of the certificate list from keytool.
$ keytool -list -keystore cacerts | grep 73:3F:35:54:1D:44:C9:E9:5A:4A:EF:51:AD:03:06:B6
Enter keystore password:
Certificate fingerprint (MD5): 73:3F:35:54:1D:44:C9:E9:5A:4A:EF:51:AD:03:06:B6
In this case, we have verified that the class3.crt has been imported into the cacerts keystore. If the specified fingerprint hash did not exist, no results would be returned by the above command.
Importing a Certificate
To import a certificate into a keystore, you will first need to download the certificate, preferably in PEM format and save it somewhere on your computer. Once you have saved this file, you can import it as follows:
$ keytool -import -alias cacert-root -file /tmp/root.crt -keystore cacerts
Enter keystore password:
Owner: EMAILADDRESS=support@cacert.org, CN=CA Cert Signing Authority, OU=http://www.cacert.org, O=Root CA
Issuer: EMAILADDRESS=support@cacert.org, CN=CA Cert Signing Authority, OU=http://www.cacert.org, O=Root CA
Serial number: 0
Valid from: Sun Mar 30 05:29:49 MST 2003 until: Tue Mar 29 05:29:49 MST 2033
Certificate fingerprints:
MD5: A6:1B:37:5E:39:0D:9C:36:54:EE:BD:20:31:46:1F:6B
SHA1: 13:5C:EC:36:F4:9C:B8:E9:3B:1A:B2:70:CD:80:88:46:76:CE:8F:33
Signature algorithm name: MD5withRSA
Version: 3
Extensions:
#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:true
PathLen:2147483647
]
#2: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 16 B5 32 1B D4 C7 F3 E0 E6 8E F3 BD D2 B0 3A EE ..2...........:.
0010: B2 39 18 D1 .9..
]
]
#3: ObjectId: 2.16.840.1.113730.1.8 Criticality=false
#4: ObjectId: 2.16.840.1.113730.1.4 Criticality=false
#5: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: https://www.cacert.org/revoke.crl]
]]
#6: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 16 B5 32 1B D4 C7 F3 E0 E6 8E F3 BD D2 B0 3A EE ..2...........:.
0010: B2 39 18 D1 .9..
]
[EMAILADDRESS=support@cacert.org, CN=CA Cert Signing Authority, OU=http://www.cacert.org, O=Root CA]
SerialNumber: [ 00]
]
#7: ObjectId: 2.16.840.1.113730.1.13 Criticality=false
Trust this certificate? [no]: yes
Certificate was added to keystore
The user input from the above command is highlighted in bold. Basically, what we did was tell Java to import the certificate saved at /tmp/root.crt into the keystore cacerts with the alias cacert-root. When importing this information, you will be asked to enter the password for the keystore, typically, this is the default 'changeit' password. So, in this example we now have the root certificate for cacert.org in the cacerts keystore. Now lets import the class-3 certificate. This will illustrate how the trust chain operates. In the above operation, you can see that the owner and signer were the same. This indicates that the certificate was self signed and is the highest link in the trust chain. The class-3 certificate is itself signed by the root certificate, which now exists in our keystore, so adding the class-3 certificate will no longer require the verification and complex output that the above command produced as the JVM now trusts the signer.
$ keytool -import -alias cacert-class-3 -file class3.crt -keystore cacerts
Enter keystore password:
Certificate was added to keystore
We are still asked for the password for the keystore, but notice that we are not prompted to install the certificate. Since the necessary trust chain can automatically established, this is no longer necessary.
To further illustrate the chained relationship of the certificates used above, we can inspect the signer and issues using openssl.
$ openssl x509 -subject -subject_hash -issuer -issuer_hash -noout -in root.crt
subject= /O=Root CA/OU=http://www.cacert.org/CN=CA Cert Signing Authority/emailAddress=support@cacert.org
5ed36f99
issuer= /O=Root CA/OU=http://www.cacert.org/CN=CA Cert Signing Authority/emailAddress=support@cacert.org
5ed36f99
Now inspecting the class3.crt, we see:
$ openssl x509 -subject -subject_hash -issuer -issuer_hash -noout -in class3.crt
subject= /O=CAcert Inc./OU=http://www.CAcert.org/CN=CAcert Class 3 Root
e5662767
issuer= /O=Root CA/OU=http://www.cacert.org/CN=CA Cert Signing Authority/emailAddress=support@cacert.org
5ed36f99
We can see that the subject and issuer match, as do the hashes, in root.crt, so we have verified that this certificate is self-signed. The class3.crt has a different subject, as would be expected, and the issue and issuer hash match the root's subject and subject hash.