There are no Limits…

Bruce had me up to three miles a day, really at a good pace. We’d run the three miles in twenty-one or twenty-two minutes. Just under eight minutes a mile [Note: when running on his own in 1968, Lee would get his time down to six-and-a-half minutes per mile].

So this morning he said to me “We’re going to go five.”

I said, “Bruce, I can’t go five. I’m a helluva lot older than you are, and I can’t do five.”

He said, “When we get to three, we’ll shift gears and it’s only two more and you’ll do it.”

I said “Okay, hell, I’ll go for it.”

So we get to three, we go into the fourth mile and I’m okay for three or four minutes, and then I really begin to give out.

I’m tired, my heart’s pounding, I can’t go any more and so I say to him, “Bruce if I run any more,” — and we’re still running — “if I run any more I’m liable to have a heart attack and die.” He said, “Then die.” It made me so mad that I went the full five miles.

Afterward I went to the shower and then I wanted to talk to him about it. I said, you know, “Why did you say that?” He said, “Because you might as well be dead. Seriously, if you always put limits on what you can do, physical or anything else, it’ll spread over into the rest of your life. It’ll spread into your work, into your morality, into your entire being. There are no limits. There are plateaus, but you must not stay there, you must go beyond them. If it kills you, it kills you. A man must constantly exceed his level.

– The Art of Expressing the Human Body by Bruce Lee and John Little

Java + HTTPS: Unable to Find Valid Certification Path to Requested Target

PROBLEM

When invoking a HTTPS URL from Java, for example…

final RestTemplate restTemplate = new RestTemplate();
restTemplate.execute("https://www.google.com/some-api", HttpMethod.GET, null, ...);

…the following exception is thrown…

org.springframework.web.client.ResourceAccessException: I/O error on GET 
request for "https://www.google.com":sun.security.validator.ValidatorException: 
PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target; nested exception 
is 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
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:607)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557)

SOLUTION 1: Disable SSL Validation – NOT RECOMMENDED

One way is to simply disable the SSL validation by configuring SSLContext to trust all X.509 certificates before invoking the intended HTTPS URL.

@Configuration
class MyAppConfig {
    @Bean
    public Boolean disableSSLValidation() throws Exception {
        final SSLContext sslContext = SSLContext.getInstance("TLS");

        sslContext.init(null, new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }}, null);

        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });

        return true;
    }
}

Unless you are writing test cases or implementing non-production code, this approach is highly discouraged because it doesn’t prevent the man-in-the-middle attacks.

SOLUTION 2: Import Certificate into Java Keystore – RECOMMENDED

The reason we see this exception is because the certificate used by the HTTPS URL doesn’t exist in the Java Keystore. Hence, the SSL validation fails.

To fix this, we can download the website’s certificate using a browser to be added into Java Keystore.

Access the website (in this example, I use https://www.google.com) and click on the pad lock.

Find the button that allows you to view and export the certificate as a PEM file. In this example, I named that file google.cer.

The content of the downloaded PEM file should look like this:-

-----BEGIN CERTIFICATE-----
MIIEgDCCA2igAwIBAgIITq9JKLrGf5EwDQYJKoZIhvcNAQELBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
eoV23mHmV6/0mOwocVYt/Th96WNGGmhANkFW//HCphRWnhaOqIG6yFRQ/jxArTvZ
QJEGI5AiYHzQn7LdUM8mH1o3ifR+lX+QiAwyeU9oegdlRslI2KMoPOuOFj329NFx
Bw+XVQXMsRJITPg8pnegPmLCOjpz8y7pBxbxGnfaI66I8X4dArsaXX4r5mkfhk2e
mm7fxQ8qUaW9mKoW0XvwGxU0AwKI8OopuXHoD97vr2GSK0QNZ19A96mtTWnQ2cu2
i9qjGw==
-----END CERTIFICATE-----

Go to the Terminal.

If you have multiple versions of java, make sure you choose the correct version first:-

export JAVA_HOME="`/usr/libexec/java_home -v '1.7*'`"

Import the certificate into Java Keystore:-

sudo keytool -import -trustcacerts -file /path/to/google.cer -alias google -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

Now, you should be able to invoke the HTTPS URL without any exception.

If for some reason you need to remove the imported certificate from Java Keystore, you can refer to that certificate using the alias and run this command:-

sudo keytool -delete -alias google -keystore $JAVA_HOME/jre/lib/security/cacerts

Java + HTTPS: Handling ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY

PROBLEM

When accessing HTTPS links from a local application server, the modern browser throws the following error message(s):-

  • SSL received a weak ephemeral Diffie-Hellman key in Server Key Exchange handshake message. (Error code: ssl_error_weak_server_ephemeral_dh_key)
  • Server has a weak ephemeral Diffie-Hellman public key

SOLUTIONS

There are multiple solutions to this problem.

SOLUTION 1: Disable browser check

One way is to completely disable this check on the browser.

For example, in Firefox, go to about:config and set security.ssl3.dhe_rsa_aes_128_sha and security.ssl3.dhe_rsa_aes_256_sha to false.

The downside is the browser is exposed to Logjam attacks.

SOLUTION 2: Use Java 8

The easiest solution is to use Java 8 because it has better cipher support.

The downside is sometimes using Java 8 is not an option if you don’t have control on the application server.

SOLUTION 3: Use Bouncy Castle

If you are using Java 6 or Java 7, you can download Bouncy Castle crypto implementation and store them in $JAVA_HOME/jre/lib/ext.

Then, register this provider in $JAVA_HOME/jre/lib/security/java.security, for example:-

#
# List of providers and their preference orders (see above):
#
# MacOSX added com.apple.crypto.provider.Apple as #3
security.provider.1=sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/sunpkcs11-macosx.cfg
security.provider.2=sun.security.provider.Sun
security.provider.3=com.apple.crypto.provider.Apple
security.provider.4=sun.security.rsa.SunRsaSign
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=com.sun.crypto.provider.SunJCE
security.provider.7=sun.security.jgss.SunProvider
security.provider.8=com.sun.security.sasl.Provider
security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.10=sun.security.smartcardio.SunPCSC
security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider

The downside is if your team is doing local application development, all team members have to perform these steps on their machines too.

SOLUTION 4: Disable all weak Diffie-Hellman ciphers

Another solution is to configure the server by disabling all the weak Diffie-Hellman ciphers.

You can either enable the strong ciphers or disable the weak ciphers.

However, it is preferable (in my opinion) to disable weak ciphers so that newer (and stronger) ciphers will automatically be included when Java version is updated in the future.

Here is a working example for Jetty server:-

<plugin>
    <groupId>org.mortbay.jetty</groupId>
    <artifactId>jetty-maven-plugin</artifactId>
    <version>8.1.16.v20140903</version>
    <configuration>
        <stopKey>jetty-stop-key</stopKey>
        <stopPort>7778</stopPort>
        <scanIntervalSeconds>1</scanIntervalSeconds>
        <requestLog implementation="org.eclipse.jetty.server.NCSARequestLog">
            <extended>true</extended>
            <logTimeZone>CST</logTimeZone>
        </requestLog>
        <webApp>
            <contextPath>/${project.artifactId}</contextPath>
            <webInfIncludeJarPattern>.*/.*jsp-api-[^/]\.jar$|./.*jsp-[^/]\.jar$|./.*taglibs[^/]*\.jar$</webInfIncludeJarPattern>
        </webApp>
        <connectors>
            <connector implementation="org.eclipse.jetty.server.bio.SocketConnector">
                <port>7777</port>
            </connector>
            <connector implementation="org.eclipse.jetty.server.ssl.SslSocketConnector">
                <port>7443</port>
                <keystore>${project.basedir}/src/main/config/keystore.jks</keystore>
                <keyPassword>jetty8</keyPassword>
                <password>jetty8</password>
                <excludeCipherSuites>
                    <excludeCipherSuites>SSL_RSA_WITH_DES_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>SSL_DHE_RSA_WITH_DES_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>SSL_DHE_DSS_WITH_DES_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>SSL_RSA_EXPORT_WITH_RC4_40_MD5</excludeCipherSuites>
                    <excludeCipherSuites>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>TLS_DHE_RSA_WITH_AES_256_CBC_SHA256</excludeCipherSuites>
                    <excludeCipherSuites>TLS_DHE_DSS_WITH_AES_256_CBC_SHA256</excludeCipherSuites>
                    <excludeCipherSuites>TLS_DHE_RSA_WITH_AES_256_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>TLS_DHE_DSS_WITH_AES_256_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>TLS_DHE_RSA_WITH_AES_128_CBC_SHA256</excludeCipherSuites>
                    <excludeCipherSuites>TLS_DHE_DSS_WITH_AES_128_CBC_SHA256</excludeCipherSuites>
                    <excludeCipherSuites>TLS_DHE_RSA_WITH_AES_128_CBC_SHA</excludeCipherSuites>
                    <excludeCipherSuites>TLS_DHE_DSS_WITH_AES_128_CBC_SHA</excludeCipherSuites>
                </excludeCipherSuites>
            </connector>
        </connectors>
    </configuration>
</plugin>

The downside is the server configuration gets a little lengthy.

Maven: Bundling and Unpacking Native Libraries

Introduction

Steps to bundle the native libraries to be pushed to Nexus, and to unpack the native libraries on mvn package.

Bundling Native Libraries into a JAR File

Let’s assume we have the following native libraries for multiple platforms:-

➜  tree native 
native
├── linux
│   ├── x86
│   │   └── libnative_synchronization.so
│   └── x86_64
│       └── libnative_synchronization.so
├── macosx
│   └── libnative_synchronization.jnilib
└── win32
    ├── x86
    │   └── native_synchronization.dll
    └── x86_64
        └── native_synchronization.dll

Create a jar that contains these native libraries. The -C options prevents the native folder from being created in the JAR file.

➜  jar cMf my-project-native.jar -C native .   

Pushing JAR to Nexus

When pushing this native JAR file to Nexus, make sure to use the natives-* classifier. In this example, I called it natives-all.

<dependency>
	<groupId>my.project</groupId>
	<artifactId>native</artifactId>
	<version>1.0</version>
	<classifier>natives-all</classifier>
</dependency>

Configuring pom.xml

First, add LWJGL and the native JAR dependencies.

<dependencies>
    <dependency>
        <groupId>org.lwjgl.lwjgl</groupId>
        <artifactId>lwjgl</artifactId>
        <version>2.9.3</version>
    </dependency>
    <dependency>
		<groupId>my.project</groupId>
		<artifactId>native</artifactId>
		<version>1.0</version>
		<classifier>natives-all</classifier>
    </dependency>
</dependencies>

Then, add the following plugin:-

<build>
    <plugins>
		<plugin>
		    <groupId>com.googlecode.mavennatives</groupId>
		    <artifactId>maven-nativedependencies-plugin</artifactId>
		    <version>0.0.7</version>
		    <executions>
		        <execution>
		            <id>unpacknatives</id>
		            <phase>generate-resources</phase>
		            <goals>
		                <goal>copy</goal>
		            </goals>
		        </execution>
		    </executions>
		</plugin>
    </plugins>
</build>

This plugin searches for dependencies with natives-* classifier and unpacks the content to target/natives folder.

Testing

Run mvn clean package.

Inspect target/natives. The native libraries should be unpacked here:-

target/natives
├── META-INF
│   └── MANIFEST.MF
├── OpenAL32.dll
├── OpenAL64.dll
├── jinput-dx8.dll
├── jinput-dx8_64.dll
├── jinput-raw.dll
├── jinput-raw_64.dll
├── jinput-wintab.dll
├── libjinput-linux.so
├── libjinput-linux64.so
├── libjinput-osx.jnilib
├── liblwjgl.dylib
├── liblwjgl.so
├── liblwjgl64.so
├── libopenal.so
├── libopenal64.so
├── linux
│   ├── x86
│   │   └── libnative_synchronization.so
│   └── x86_64
│       └── libnative_synchronization.so
├── lwjgl.dll
├── lwjgl64.dll
├── macosx
│   └── libnative_synchronization.jnilib
├── openal.dylib
└── win32
    ├── x86
    │   └── native_synchronization.dll
    └── x86_64
        └── native_synchronization.dll

IntelliJ IDEA: Configuring Default Project Settings

PROBLEM

When creating or checking out a project for the first time in IntelliJ IDEA, we may need to reconfigure the project settings. My biggest pain is IntelliJ IDEA will always use the wrong Maven version when I check out the project from the source control.

SOLUTION

The good news is there is a way to set up default project settings in IntelliJ IDEA.

In the Welcome dialog, select Configure -> Project Defaults.

From here, we can create all the default project settings, such as JDK version, Maven version, code style formatter and so on.

Rest Template: Could Not Extract Response – No Suitable HttpMessageConverter Found for Response Type [X] and Content Type [application/json;charset=UTF-8]

PROBLEM

When invoking a web service using RestTemplate:-

restTemplate.getForObject("http://server/api", MyBean[].class));

… the following exception occurs:-

Exception in thread "main" org.springframework.web.client.RestClientException: 
Could not extract response: no suitable HttpMessageConverter found for response 
type [class [LMyBean;] and content type [application/json;charset=UTF-8]
	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:110)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:572)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:530)
	at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:237)

SOLUTION

If the content type is JSON, add the following dependency:-

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.6.0</version>
</dependency>

Spring Data JPA: Requested bean is currently in creation: Is there an unresolvable circular reference?

PROBLEM

Let’s assume we have the following Spring Data JPA repository…

public interface ProjectRepository extends JpaRepository<Project, Long>, ProjectRepositoryCustom {
    Project findByName(String name);
}

… this repository has some custom implementation…

public interface ProjectRepositoryCustom {
    Project doCustom(String name);
}

… this custom implementation depends on the original repository to reuse existing APIs…

public final class ProjectRepositoryImpl implements ProjectRepositoryCustom {
    private final ProjectRepository projectRepository;

    @Autowired
    public ProjectRepositoryImpl(final ProjectRepository projectRepository) {
        this.projectRepository = projectRepository;
    }

    @Override
    public Project doCustom(final String name) {
        final Project project = projectRepository.findByName(name);
        return ...
    }
}

When we run the code, we get the following exception:-

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: 
Error creating bean with name 'projectRepositoryImpl': Requested bean 
is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:347)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)

SOLUTION

To fix the circular reference problem, instead of auto-wiring ProjectRepository using the constructor, auto-wire using the field or setter method:-

public final class ProjectRepositoryImpl implements ProjectRepositoryCustom {
    // this field cannot be `final` anymore
    private ProjectRepository projectRepository;

    @Autowired
    public void setProjectRepository(final ProjectRepository projectRepository) {
        this.projectRepository = projectRepository;
    }

    @Override
    public Project doCustom(final String name) {
        final Project project = projectRepository.findByName(name);
        return ...
    }
}