Friday, January 29, 2016

Spring Cloud Ribbon - Making a secured call

Something simple, but I struggled with this recently - I had to make a Netflix Ribbon based client call to a secured remote service. It turns out there are two ways to do this using Netflix Ribbon, I will demonstrate this through Spring Cloud's excellent support for Ribbon library.

In two previous blog posts I have touched on Spring Cloud Ribbon basics and some advanced customizations, continuing with the same example, assuming that I have a configuration along these lines:

sampleservice:
  ribbon:
    listOfServers: someserver:80
    ReadTimeout: 5000
    MaxAutoRetries: 2


Given this configuration, I can call the service this way:

public class RestTemplateSample {
 
    @Autowired
    private RestTemplate restTemplate;
 
    @Override
    public MessageAcknowledgement sendMessage(Message message) {
        String pongServiceUrl = "http://sampleservice/message";
        HttpEntity<Message> requestEntity = new HttpEntity<>(message);
        ResponseEntity<MessageAcknowledgement> response =  this.restTemplate.exchange(pongServiceUrl, HttpMethod.POST, requestEntity, MessageAcknowledgement.class, Maps.newHashMap());
        return response.getBody();
    }
 
}



So now if the remote service were secured, the first approach and likely the preferred way is actually quite simple, just add an additional configuration to the "named" client to indicate that the remote service is secure, note that the port also has to be appropriately specified.

sampleservice:
  ribbon:
    listOfServers: someserver:443
    ReadTimeout: 5000
    MaxAutoRetries: 2
    IsSecure: true


The second approach that also works is to simply change the url to indicate that you are calling a https endpoint, this time the "IsSecure" configuration is not required:

public class RestTemplateSample {
 
    @Autowired
    private RestTemplate restTemplate;
 
    @Override
    public MessageAcknowledgement sendMessage(Message message) {
        String pongServiceUrl = "https://sampleservice/message";
        HttpEntity<Message> requestEntity = new HttpEntity<>(message);
        ResponseEntity<MessageAcknowledgement> response =  this.restTemplate.exchange(pongServiceUrl, HttpMethod.POST, requestEntity, MessageAcknowledgement.class, Maps.newHashMap());
        return response.getBody();
    }
 
}

Saturday, January 16, 2016

Spring Cloud with Turbine

Netflix Hystrix has a neat feature called the Hystrix stream that provides real-time metrics on the state of the Hystrix commands in an application. This data tends to be very raw though, a very cool interface called the Hystrix Dashboard consumes this raw data and presents a graphical information based on the underlying raw data:



Integrating Hystrix Support and Dashboard

In a Spring-Cloud project it is very trivial to expose the Hystrix stream, all it requires is a starter application for Hystrix to be added in as a dependency and the stream functionality is available to the web application.

Step 1: Add the Spring-Cloud-Starter-hystrix:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

Step 2: Enable Hystrix support for the Application, this will expose the hystrix stream at a "/hystrix.stream" uri:

@SpringBootApplication
@EnableHystrix
public class SpringCloudApp {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudApp.class, args);
    }
}

Now for the Hystrix Dashboard application to graphically view the Hystrix stream, the following annotation will enable that and the application should be available at "/hystrix" uri:

@SpringBootApplication
@EnableHystrixDashboard
public class AggregateApp {

    public static void main(String[] args) {
        SpringApplication.run(AggregateApp.class, args);
    }
}


Spring Cloud with Turbine

Hystrix stream provides information on a single application, Turbine provides a way to aggregate this information across all installations of an application in a cluster. Integrating turbine into a Spring-Cloud based application is straightforward, all it requires is information on which clusters to expose information on and how to aggregate information about the specific clusters. As before to pull in the dependencies of Turbine:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-turbine</artifactId>
    <exclusions>
        <exclusion>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>

And to enable Turbine support in a Spring Boot based application:

@SpringBootApplication
@EnableHystrixDashboard
@EnableTurbine
public class MonitorApplication {

    public static void main(String[] args) {
        SpringApplication.run(MonitorApplication.class, args);
    }

}

This application is playing the role of both showing the Hystrix Dashboard and exposing turbine stream. Finally the configuration for turbine:

turbine:
  aggregator:
    clusterConfig: SAMPLE-HYSTRIX-AGGREGATE
  appConfig: SAMPLE-HYSTRIX-AGGREGATE

Given this configuration a turbine stream for SAMPLE-HYSTRIX-AGGREGATE cluster is available at "/turbine.stream?cluster=SAMPLE-HYSTRIX-AGGREGATE" uri, it would figure out the instances of the cluster using Eureka, source the hystrix stream from each instance and aggregate it into the turbine stream. If we were to view the Hystrix dashboard against this stream:



If you look at the counts against the host now, it indicates the 2 hosts for which the stream is being aggregated.

I have brushed over a lot of details here, an easier way to check the details may be to check my github project here

Tuesday, January 5, 2016

JWT - Generating and validating a token - Samples

JWT provides a very interesting way to represent claims between applications that can be verified and trusted. My objective here is to show a small sample to generate and validate a token using the excellent Nimbus JOSE + JWT library.

Overview

One of the best places to get an intro is here. In brief, to borrow from the material from the jwt.io site, claims are represented as an encoded json in three parts separated with a dot (.)


header.payload.signature


The header is a json that contains the type of algorithm used for signing the content(RSA in this instance) which is then url and Base64 encoded:

{
  "alg": "RS512"
}

The payload is a json containing all the claims, there are claims which are reserved but private claims are also allowed:

{
  "sub": "samplesubject",
  "name": "John Doe",
  "iss": "sampleissueer",
  "admin": true,
  "exp": 1451849539
}


here "sub"(subject), "iss"(issuer) and "exp"(expiry) are reserved claims but "name" and "admin" are private claims. The content is then Base64Url encoded.

Finally the header and payload together is signed using either a shared key or a private key and the signature is Base64 url encoded and appended to the token with a (.) separator.



Generating a Keypair

My sample is RSA based one, so the first step is to generate a Key pair. JWK is a neat way to store the Keys as a JSON representation and Nimbus library provides support for that:


import java.security.KeyPairGenerator
import java.security.interfaces.{RSAPrivateKey, RSAPublicKey}

import com.google.gson.{GsonBuilder, JsonElement, JsonParser}
import com.nimbusds.jose.Algorithm
import com.nimbusds.jose.jwk.{JWKSet, KeyUse, RSAKey}

object JWKGenerator {

  def make(keySize: Integer, keyUse: KeyUse, keyAlg: Algorithm, keyId: String) = {
    val generator = KeyPairGenerator.getInstance("RSA")
    generator.initialize(keySize)
    val kp = generator.generateKeyPair()
    val publicKey = kp.getPublic().asInstanceOf[RSAPublicKey]
    val privateKey = kp.getPrivate().asInstanceOf[RSAPrivateKey]
    new RSAKey.Builder(publicKey)
      .privateKey(privateKey)
      .keyUse(keyUse)
      .algorithm(keyAlg)
      .keyID(keyId)
      .build()
  }
 ...

}

Given this Key Pair, a JWK can be generated from this using Gson:

  def generateJWKKeypair(rsaKey: RSAKey): JsonElement = {
    val jwkSet = new JWKSet(rsaKey)
    new JsonParser().parse(jwkSet.toJSONObject(false).toJSONString)
  }

  def generateJWKJson(rsaKey: RSAKey): String = {
    val jsonElement  = generateJWKKeypair(rsaKey)
    val gson = new GsonBuilder().setPrettyPrinting().create()
    gson.toJson(jsonElement)
  }


A sample JWK based keypair looks like this:

{
  "keys": [
    {
      "p": "2_Fb6K50ayAsnnQl55pPegE_JNTeAjpDo9HThZPp6daX7Cm2s2fShtWuM8JBv42qelKIrypAAVOedLCM75VoRQ",
      "kty": "RSA",
      "q": "ye5BeGtkx_9z3V4ImX2Pfljhye7QT2rMhO8chMcCGI4JGMsaDBGUmGz56MHvWIlcqBcYbPXIWORidtMPdzp1wQ",
      "d": "gSjAIty6uDAm8ZjEHUU4wsJ8VVSJInk9iR2BSKVAAxJUQUrCVN---DKLr7tCKgWH0zlV0DjGtrfy7pO-5tcurKkK59489mOD4-1kYvnqSZmHC_zF9IrCyZWpOiHnI5VnJEeNwRz7EU8y47NjpUHWIaLl_Qsu6gOiku41Vpb14QE",
      "e": "AQAB",
      "use": "sig",
      "kid": "sample",
      "qi": "0bbcYShpGL4XNhBVrMI8fKUpUw1bWghgoyp4XeZe-EZ-wsc43REE6ZItCe1B3u14RKU2J2G57Mi9f_gGIP_FqQ",
      "dp": "O_qF5d4tQUl04YErFQ2vvsW4QoMKR_E7oOEHndXIZExxAaYefK5DayG6b8L5yxMG-nSncZ1D9ximjYvX4z4LQQ",
      "alg": "RS512",
      "dq": "jCy-eg9i-IrWLZc3NQW6dKTSqFEFffvPWYB7NZjIVa9TlUh4HmSd2Gnd2bu2oKlKDs1pgUnk-AAicgX1uHh2gQ",
      "n": "rX0zzOEJOTtv7h39VbRBoLPQ4dRutCiRn5wnd73Z1gF_QBXYkrafKIIvSUcJbMLAozRn6suVXCd8cVivYoq5hkAmcRiy0v7C4VuB1_Fou7HHoi2ISbwlv-kiZwTmXCn9YSHDBVivCwfMI87L2143ZfYUcNxNTxPt9nY6HJrtJQU"
    }
  ]
}

Generating a JWT

Now that we have a good sample keypair, load up the private and public keys:

import java.time.{LocalDateTime, ZoneOffset}
import java.util.Date

import com.nimbusds.jose._
import com.nimbusds.jose.crypto._
import com.nimbusds.jose.jwk.{JWKSet, RSAKey}
import com.nimbusds.jwt.JWTClaimsSet.Builder
import com.nimbusds.jwt._

object JwtSample {
  def main(args: Array[String]): Unit = {
    val jwkSet = JWKSet.load(JwtSample.getClass.getResource("/sample.json").toURI.toURL)
    val jwk = jwkSet.getKeyByKeyId("sample").asInstanceOf[RSAKey]

    val publicKey = jwk.toRSAPublicKey
    val privateKey = jwk.toRSAPrivateKey
 ...
}

Build a payload, sign it and generate the JWT:

    val claimsSetBuilder = new Builder()
      .subject("samplesubject")
      .claim("name", "John Doe")
      .claim("admin", true)
      .issuer("sampleissueer")
      .expirationTime(Date.from(LocalDateTime.now().plusHours(1).toInstant(ZoneOffset.UTC)))

    val signer = new RSASSASigner(privateKey)


    val signedJWT: SignedJWT = new SignedJWT(
      new JWSHeader(JWSAlgorithm.RS512),
      claimsSetBuilder.build())

    signedJWT.sign(signer)

    val s = signedJWT.serialize()


The consumer of this JWT can read the payload and validate it using the public key:

    val cSignedJWT = SignedJWT.parse(s)

    val verifier = new RSASSAVerifier(publicKey)

    println(cSignedJWT.verify(verifier))
    println(signedJWT.getJWTClaimsSet().getSubject())

Conclusion

This sample is entirely based on samples provided at the Nimbus JOSE + JWT site, you should definitely refer to the Nimbus site if you are interested in exploring this further. My samples are here