Tracing Requests & Responses with Spring Boot Actuator

Spring Boot Actuator is a sub-project that provides endpoints allow you to monitor and interact with your application. You can take a look at complete list of endpoints but we will focus on trace and its customization in this post.

By default, trace endpoint is enabled for all HTTP requests and shows last 100 of them with 5 default properties:

  • Request Headers
  • Response Headers
  • Cookies
  • Errors
  • Time Taken

So, when you hit /trace, the typical response will be like:

The question is: how can we customize these properties? Is there any way to exclude some of them or include even more properties? The answer is YES.

Here, you can see all available properties. Sometimes, the best documentation is the source code :).

In your configuration file you can specify the properties you want to trace:

management.trace.include = remote_address, parameters

Note that this will override default properties. If you want to keep them, you have to specify them along with additional properties you want.

In the introduction part we said that it’s enabled for all HTTP requests. It really is. If you played with it, probably you saw that requests made to /trace also traced. Let’s say you don’t want some endpoints to be traced such as /admin/**, /trace and endpoints provide static files like /css/** and /js/**.

To be able to prevent those endpoints to be traced, we need to extend WebRequestTraceFilter and override its shouldNotFilter method which inherited from OncePerRequestFilter.

shouldNotFilter’s default implementation was always returning false. Now with this implementation, it returns true for the endpoints we don’t want to trace. By annotating this class with @Component, we tell Spring to register it as a bean instead inherited WebRequestTraceFilter. No more configuration needed for this to work.

It’s not over yet, we need more customization!

In the introduction part we also said that, trace endpoint shows last 100 requests by default. Unfortunately, there is no way to change it from configuration file directly but still it’s a piece of cake.

By default, InMemoryTraceRepository is used as an implementation of TraceRepository. By extending it, we can expand the capacity, log requests explicitly or even persist them. It’s up to you.

Here is the source code of sample application.

Intercepting and modifying logs in Logback

Actually, Logback does not offer a direct way to modify logs but there is a workaround we can achieve our goal by using filter even though it looks like a bit hacky.

Let’s say that you logged some id no of some user hundreds of times, it scattered through all over the application and now you have a new requirement that says you have to encrypt this id number. Of course you’re smart enough to write an interceptor for this task instead of go find and change necessary logs manually. And also with this way, we can be sure that we’ll never log that id number accidentally.

For this case, we’re gonna extend TurboFilter and override its decide method.

If the log matches our criteria and we want to change it, we deny it by returning FilterReply.DENY and log again with the changed object.

Here, I used info as log level for the sake of simplicity but if you don’t want to change log level, you can easily check which level coming log has and use that level.

It’s that easy once you deal with recursion and not forget to declare your custom filter in configuration file properly.

CORS and Authentication

Let’s say that you have an API which stands on xdomain.com and you have a Javascript application that consuming this API from ydomain.com. For ydomain.com to consume the API, xdomain.com has to send CORS header Access-Control-Allow-Origin in its response.

The simplest way to do this in Spring is annotate whole controller or just handler method with the annotation CrossOrigin.

It’s all what you need when your API does not require authentication.

On the other hand, when your API requires authentication, things get a bit complicated. For example, let’s say that you authenticate your API with HTTP Basic Authentication. So, consumers of this API must send an Authorization header which contains user credentials in their request. Since this is a non-simple request, OPTIONS request will be send firstly. The thing is that, even if you send Authorization header with correct credentials in your request, you will face something like below:

response

The reason of this is, according to CORS spec, it excludes your Authorization header. Hence, you should permit OPTIONS requests in your security configuration class explicitly.

Last of all, I suggest you to read these two posts:

http://stackoverflow.com/a/15734032/3099704 https://code.google.com/archive/p/twitter-api/issues/2273

REST Authentication using Spring Security & Spring Session

In this post, I will try to demonstrate how easily we can implement an authentication mechanism for REST services using Spring Security and Spring Session with the help of Redis.

The authentication scheme that we will use:

  1. Client requests an authenticated URL with its credentials. (first request to the server)
  2. Server gives some unique string besides the normal response.
    (unique string is session id in our case)
  3. Client has to send this string with every request using an HTTP header.
  4. Server recognizes this unique string and logs client in.

Let’s start implementing the scheme above.

For this application to work, you must install Redis 2.8+ on localhost and run it with the default port (6379).

We will create very simple Spring Boot application which you can get source code and dependencies here.

Our security configuration looks like:

configureGlobal method is pretty straightforward, we just create a user with username sedooe and password password.

configure method is also straightforward but I want to emphasize two things here.

  1. We are using HTTP Basic Authentication since it is simplest way to deal with authentication. As you probably know, Basic Authentication is just a standard HTTP header with the username:password encoded in base64:
    Authorization: Basic c2Vkb29lOnBhc3N3b3Jk
    Keep in mind that encoding is not encrypting. Therefore, you must use HTTPS instead of HTTP to make sure that user credentials are sent securely.

  2. NullRequestCache prevents creation of session when user is not authenticated so that we have only authenticated users’ session ids stored in Redis.

In httpSessionStrategy method, Spring Session comes into play.
Thanks to HeaderHttpSessionStrategy, when a session is created, the HTTP response will have a response header of the specified name and the value of the session id. Default header name is x-auth-token and we will use it.

Here is our simple controller:

There is nothing to mention about this controller specifically so let’s start trying things out.

$ curl -v http://localhost:8080/api/resource

Yeah, authentication is required to access this resource. So try:
$ curl -v http://localhost:8080/api/resource -u sedooe:password

Now you are authenticated and you have access to the resource. Take a look at response headers and you will see that:
x-auth-token: 00661f53-8453-4daf-89f1-e748a3326040

For further requests, we can use x-auth-token instead of username and password.
$ curl -v http://localhost:8080/api/resource -H "x-auth-token: 00661f53-8453-4daf-89f1-e748a3326040"

If you want to see all stored tokens:
$ redis-cli keys '*'

To invalidate the session and delete it from Redis:
$ curl -v http://localhost:8080/api/logout -H "x-auth-token: 00661f53-8453-4daf-89f1-e748a3326040"

Note:

You may wonder how our application connected to Redis without writing any code for that.

Since we use Spring Boot 1.3.3 in this project and Spring Session and Spring Data Redis are both on the classpath, Spring Boot will auto-configure Spring Session to connect to Redis.

If you use earlier Spring Boot versions than 1.3.1 or don’t use it at all, you should add @EnableRedisHttpSession to your configuration class.