Category Archives: Java

Feign + Eureka: UnknownHostException when Attempting to Invoke a Service

PROBLEM

When attempting use Feign to invoke a service through Eureka, the following exception occurs:-

MY-HOST-NAME executing GET http://donkey-kong-service/throw/barrels/10
feign.RetryableException: MY-HOST-NAME executing GET http://donkey-kong-service/throw/barrels/10
	at feign.FeignException.errorExecuting(FeignException.java:84)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:113)
	...
Caused by: java.net.UnknownHostException: MY-HOST-NAME
		at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:184)

SOLUTION

Go to the donkey-kong-service app and add the following line to the application.properties:-

eureka.instance.prefer-ip-address=true

Now, when Feign tries to invoke the service, the IP address will be used instead of the OS’ reported hostname.

Spring Boot: Restarting App using Dev Tools with IntelliJ IDEA

Spring Boot provides spring-boot-devtools module that allows the app to “smartly” restart whenever the files on the classpath have changed.

Because the rarely changed classes (ex: 3rd party JARs) are separated out into a different classloader from the app’s actively developed classes’ classloader, it allows Spring Boot to quickly restart the app compared to “cold start”.

DEPENDENCY

First, add the following dependency:-

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<scope>runtime</scope>
</dependency>

CONFIGURING INTELLIJ IDEA

In IntelliJ IDEA:-

  • Click SHIFT twice to bring up the “Search History” dialog.
  • Select “Actions” tab.
  • Type “Registry” in the search box.
  • Select “Registry…”.

In the “Registry” dialog:-

  • Find “compiler.automake.allow.when.app.running” key.
  • Check the checkbox.
  • Close the dialog.

In IntelliJ IDEA “Preferences” dialog:-

  • Go to “Build, Execution, Deployment” » “Compiler”.
  • Check “Build project automatically”.
  • Close the dialog.

Finally, instead of running Maven goals to run the Spring Boot app, select the Application class (annotated with @SpringBootApplication) and run it from IntelliJ IDEA.

Anytime the app’s class files have changed, IntelliJ IDEA will compile the app, which will then trigger Spring Boot Dev Tools to restart the app.

Spring Boot: Connecting to IBM MQ over JMS using non-IBM JRE

There are several ways to connect to IBM MQ:-

  • com.ibm.mq.MQQueueManager
  • com.ibm.mq.jms.MQQueueConnectionFactory
  • com.ibm.msg.client.jms.JmsConnectionFactory

This article shows you how to connect with Spring’s JmsTemplate.

CONNECTIVITY INFO

Typically, the MQ admin will provide the following connectivity info that allows you to connect to MQ:-

  • Queue manager name, ex: MY.QUEUE.MANAGER
  • Host name, ex: server.com
  • Port, ex: 1415
  • Channel name, ex: MY.SSL.CHANNEL
  • SSL Cipher Suite, ex: SSL_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • User, ex: user
  • Password, ex: password
  • Queue name, ex: MY.QUEUE

DEPENDENCY

Add the following dependency:-

dependencies {
  compile 'com.ibm.mq:mq-jms-spring-boot-starter:2.1.1'
}

SPRING CONFIGURATION

While the connectivity info can be hardcoded in Spring Boot’s application.properties, it’s probably more logical to use Spring @Configuration to dynamically set the values especially dealing with credential.

So, create a Spring configuration that looks something like this:-

// while all the value are hardcoded here for simplicity sake, you can inject
// sensitive values from DB, through <code>Environment</code>, etc.
@EnableJms
@Configuration
class JmsConfig {
  // Adding @Primary will force Spring Boot to use this bean
  // instead of the one provided by the dependency 
  @Primary
  @Bean
  MQConfigurationProperties mqConfigurationProperties() {
    System.setProperty('javax.net.ssl.keyStore', '/path/to/keystore.jks')
    System.setProperty('javax.net.ssl.keyStorePassword', 'XXXXXXX')

    return new MQConfigurationProperties(
      queueManager: 'MY.QUEUE.MANAGER',
      channel: 'MY.SSL.CHANNEL',
      connName: 'server.com(1415)',
      user: 'user',
      password: 'password',
      userAuthenticationMQCSP: true,
				
      // If the provided SSL cipher suite begins with "SSL", 
      // replace it with "TLS" instead.
      // SSL_* is IBM JRE CipherSuite name.
      // TLS_* is Oracle JRE CipherSuite name. 
      sslCipherSuite: 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',
				
      // true - if using IBM JRE
      // false - if using non-IBM JRE, ex: Oracle, OpenJDK, etc
      useIBMCipherMappings: false
    )
  }
}

USING JMS TEMPLATE

Finally, to listen to the given queue, it is as easy as autowiring JmsTemplate and start using it.

@Autowired
JmsTemplate jmsTemplate

...

final Message message = jmsTemplate.receive('MY.QUEUE')
println message

Groovy/Java: Handling Byte Order Marks When Reading a File

PROBLEM

Given a file with the following content:-

10,20

When reading the file:-

def inputStream = new FileInputStream('test.csv')
def value = inputStream.text.trim()

println "|${value}|"

… the following values are printed:-

| 10,20|

Even though the value is trimmed, there is still a leading space in front of text.

A further inspection reveals the leading space is not a regular space:-

// first character is not a space
assert value.charAt(0) != (char) ' '

// ASCII value: 65279 vs 32
assert (int) value.charAt(0) != (int) ((char) ' ').charValue()

SOLUTION

Some editors prepend a special Unicode character called a byte order mark (BOM) to the file.

The simplest way to remove this special character is to leverage Apache Commons IO’s BOMInputStream:-

def inputStream = new BOMInputStream(new FileInputStream('test.csv'))
def value = inputStream.text.trim()

println "|${value}|"

… and now, the values are printed correctly:-

|10,20|

Spring Web: Encode ‘+’ Value Using UriComponentsBuilder

PROBLEM

Given the following code…

final String url = UriComponentsBuilder.
        fromHttpUrl('https://server').
        queryParam('var', '{var}').
        buildAndExpand('1 2+3').
        encode().
        toString()

When using Spring Web 4.3.18.RELEASE, the URL is properly encoded:-

https://server?var=1%202%2B3

However, when using version between 5.0.0.RELEASE and 5.0.7.RELEASE, the URL containing “+” value does not get encoded:-

https://server?var=1%202+3

SOLUTION

There is a ticket opened regarding this breaking change.

To properly encode “+” value, use 5.0.8.RELEASE or later.

Then, ensure encode() is invoked before buildAndExpand(..):-

// Produces https://server?var=1%202%2B3
final String url = UriComponentsBuilder.
        fromHttpUrl('https://server').
        queryParam('var', '{var}').
        encode().
        buildAndExpand('1 2+3').
        toString()

The above code can be further shorten to this:-

// Produces https://server?var=1%202%2B3
final String url = UriComponentsBuilder.
        fromHttpUrl('https://server').
        queryParam('var', '{var}').
        build('1 2+3').
        toString()

 

 

Spring Security: Propagating Security Context to Spawned Threads

PROBLEM

Let’s assume we have the following Parent class…

@Service
class Parent {
    @Autowired
    Child child

    void run() {
        println "Parent: ${SecurityContextHolder.context.authentication?.principal}"

        child.run()

        println "Parent: Done"
    }
}

… and Child class…

@Service
class Child {
    @Async
    void run() {
        Thread.sleep(500)
        println "Child: ${SecurityContextHolder.context.authentication?.principal}"
    }
}

Let’s also assume the user has successfully logged in and Spring Security has set up the user authentication info.

The Parent will spawn a new thread (through @Async) to run Child.

When invoking the Parent, this is what we see:-

Parent: USER_PRINCIPAL
Parent: Done
Child: null

The Child, for some reason, doesn’t get the receive the user authentication info.

SOLUTION

By default, SecurityContextHolder uses MODE_THREADLOCAL to store the user authentication info. As a result, this info is not accessible to methods outside the current execution thread.

To fix this, configure SecurityContextHolder to use MODE_INHERITABLETHREADLOCAL to pass the user authentication info to other spawned threads.

@Configuration
@EnableAsync
class AppConfig {
    AppConfig() {
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)
    }
}

When invoking the Parent again, now the Child will also receive the user authentication object:-

Parent: USER_PRINCIPAL
Parent: Done
Child: USER_PRINCIPAL

JEE Security: Preventing Clickjacking Attacks

PROBLEM

Clickjacking is an attack that tricks the users to perform unintended actions… see OWASP’s Testing for Clickjacking (OTG-CLIENT-009)

SOLUTION

To prevent clickjacking attacks, the app must set X-FRAME-OPTIONS header with an appropriate value:-

  • DENY: this denies any domain using the page as an iFrame source. This is the best option.
  • SAMEORIGIN: this allows pages within the same domain to use other application pages as iFrame sources.
  • ALLOW-FROM [whitelisted domains]: this declares a list of domains that are allowed to include the pages as iFrame sources.

If set correctly, the HTTPS response should show X-FRAME-OPTIONS header:-

➜  ~ curl -i -k https://localhost:8443/
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
X-Application-Context: application:local:8443
Set-Cookie: JSESSIONID=04ADDAF886A20AA561021E869E980BCC; Path=/; Secure; HttpOnly
Content-Type: text/html;charset=UTF-8
Content-Language: en-US
Content-Length: 631
Date: Thu, 31 Aug 2017 14:56:57 GMT

There are several ways to set this header.

Solution 1: Using a servlet filter

You may create a servlet filter that sets X-FRAME-OPTIONS in the response header.

Here’s an example using web.xml-less Spring Boot:-

@SpringBootApplication
class Application extends SpringBootServletInitializer {
    static void main(String[] args) {
        SpringApplication.run(Application, args)
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(Application)
    }

    @Bean
    FilterRegistrationBean clickjackingPreventionFilter() {
        return new FilterRegistrationBean(
                urlPatterns: ['/**'],
                filter: new Filter() {
                    @Override
                    void init(final FilterConfig filterConfig) throws ServletException {
                    }

                    @Override
                    void doFilter(final ServletRequest servletRequest,
                                  final ServletResponse servletResponse,
                                  final FilterChain filterChain) throws IOException, ServletException {
                        final HttpServletResponse response = (HttpServletResponse) servletResponse
                        response.addHeader('X-FRAME-OPTIONS', 'DENY')
                        filterChain.doFilter(servletRequest, servletResponse)
                    }

                    @Override
                    void destroy() {
                    }
                }
        )
    }
}

Solution 2: Using Spring Security

Spring Security provides a very easy way to set the X-FRAME-OPTIONS header:-

@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.
                headers().frameOptions().deny(). 
                and().
                authorizeRequests().
                antMatchers('/**').permitAll()
    }
}