playframework / playframework/play-ws

[2.5.1] Request body not available in `WsSignatureCalculator`

Open
#154 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status:backlog
Dominant language
Scala
Stars
224
Forks
92
Avg merge
1d 19h
Merged PRs (30d)
28

Description

Moved from https://github.com/playframework/playframework/issues/5996

Play Version (2.5.x / etc)

Play 2.5.1

API (Scala / Java / Neither / Both)

Scala

Operating System (Ubuntu 15.10 / MacOS 10.10 / Windows 10)

Ubuntu 14.04
Arch Linux Kernel 4.4.5-1

JDK (Oracle 1.8.0_72, OpenJDK 1.8.x, Azul Zing)

openjdk version "1.8.0_77"
OpenJDK Runtime Environment (build 1.8.0_77-b03)
OpenJDK 64-Bit Server VM (build 25.77-b03, mixed mode)

Expected Behavior

First let me give you some context: In order to secure our services we use HMAC signatures. So, when a client sends a request it calculates a signature based on some header fields and the body. It set the Authorization header to the signature and some meta data. On der server side, we implemented an Action which also calculates the signature and then verifies it is the same as the one in the request provided by the client.

On the server side everything works fine. For clients we implemented a WsSignatureCalculator which can be added to a WSRequest like this:

wsClient
        .url("https:/localhost:9000/upload-some-file")
        .sign(hmacSignatureCalculator)
        .post(file)

And I also tried:

wsClient
        .url("https:/localhost:9000/upload-some-file")
        .withBody(FileBody(file))
        .sign(hmacSignatureCalculator)
        .execute("POST")

Please describe the expected behavior of the issue, starting from the first action.

  1. During AhcWSRequest.buildRequest the hmacSignatureCalculator is called with a Request which provides the body of the actual request.
  2. The SHA1 hash of the body is calculated and used to calculate the HMAC signature.
  3. The server accepts the request because the signature provided by the client is valid.
Actual Behavior

The body of the Request provided to hmacSignatureCalculator is alwaysnull. The same is true for Request.getFile and Request.getBodyGenerator.

  1. The body of the Request provided to hmacSignatureCalculator is not set.
  2. The SHA1 hash cannot be calculated.
  3. The server calculates the SHA1 and thus a different HMAC signature and rejects the request.

With the underlying AsyncHttpClient the Request.getBody is not null.

val client: AsyncHttpClient = wsClient.underlying
val request = client
  .preparePost(urls.uploadOrder(processId).toString)
  .setSignatureCalculator(hmacSignatureCalculator)
  .setBody(file)
  .build()

val result = Promise[AhcWSResponse]()
client.executeRequest(request, new AsyncCompletionHandler[Response]() {
  override def onCompleted(response: Response) = {
    result.success(AhcWSResponse(response))
    response
  }

  override def onThrowable(t: Throwable) = {
    result.failure(t)
  }
})
val responseFuture = result.future

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at AhcWSRequest.buildRequest and trace how the WSRequest body is passed to WsSignatureCalculator. Reproduce the reported post and withBody examples, comparing the Request passed to the calculator with the underlying AsyncHttpClient request. Done means the calculator can access the actual request body so the client and server compute the same HMAC signature.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, scala
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
43/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.