简体   繁体   中英

How to generate a HMAC signature using common module Gatling3.1

I'm making test-script for the micro-service which authorize by HMAC Authentication. The script is written by gatling-3.1 I'm facing a problem the process of generating HMAC signature is redundant.

I referred sample code in Github like this: https://github.com/gatling/gatling/blob/ace52b37bc60e5ebc168385694a283c4851cb3f9/gatling-http/src/test/scala/io/gatling/http/compile/HttpCompileTest.scala#L229-L245

I made code and confirmed that calculated signature is added to Authorization header in each request. But I don't know how to generate signature by module, As a result, my code still be redundant.

Please pay attention to (1) and (2).

package computerdatabase

class BasicSimulation extends Simulation {

  val httpProtocol = http
    .baseUrl("http://computer-database.gatling.io") // Here is the root for all relative URLs

  val scn = scenario("Scenario Name") // A scenario is a chain of requests and pauses
    .exec(http("request_1")
    .get("/")
    //---------- (1) Calculate signature in "request_1" by customized logic ----------
    .sign(new SignatureCalculator {                   
      override def sign(request: Request): Unit = {
        import java.util.Base64
        import javax.crypto.Mac
        import javax.crypto.spec.SecretKeySpec
        val mac = Mac.getInstance("HmacSHA256")
        mac.init(new SecretKeySpec("THE_SECRET_KEY".getBytes("UTF-8"), "HmacSHA256"))
        val rawSignature = mac.doFinal("".getBytes("UTF-8"))
        val authorization = Base64.getEncoder.encodeToString(rawSignature)
        request.getHeaders.add("Authorization", authorization)
      }
    })
    //---------- (1) End ----------
    )
    .pause(7) // Note that Gatling has recorded real time pauses
    .exec(http("request_2")
    .get("/computers?f=macbook")
    //---------- (2) Calculate signature in "request_2". Same logic as (1)...It is redundant----------
    .sign(new SignatureCalculator {
      override def sign(request: Request): Unit = {
        import java.util.Base64
        import javax.crypto.Mac
        import javax.crypto.spec.SecretKeySpec
        val mac = Mac.getInstance("HmacSHA256")
        mac.init(new SecretKeySpec("THE_SECRET_KEY".getBytes("UTF-8"), "HmacSHA256"))
        val rawSignature = mac.doFinal("".getBytes("UTF-8"))
        val authorization = Base64.getEncoder.encodeToString(rawSignature)
        request.getHeaders.add("Authorization", authorization)
      }
    })
    //---------- (2) End ----------
    )
  setUp(scn.inject(atOnceUsers(1)).protocols(httpProtocol))
}

I want to calculate signature of request_1 and request_2 using a module for maintainability. Please let me know if you know.

Solution: Thank you for George. I could remove redundant code as below.

package computerdatabase

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._

object Hmac {
  val signatureCalculator = new SignatureCalculator {
    override def sign(request: Request): Unit = {
      import java.util.Base64
      import javax.crypto.Mac
      import javax.crypto.spec.SecretKeySpec
      val mac = Mac.getInstance("HmacSHA256")
      mac.init(new SecretKeySpec("THE_SECRET_KEY".getBytes("UTF-8"), "HmacSHA256"))
      val rawSignature = mac.doFinal("".getBytes("UTF-8"))
      val authorization = Base64.getEncoder.encodeToString(rawSignature)
      request.getHeaders.add("Authorization", authorization)
    }
  }
}

Just use a variable to hold your SignatureCalculator .

val signatureCalculator = new SignatureCalculator {
  // ...

Or use the lambda syntax .

val signatureCalculator: SignatureCalculator = { request =>

Then you can do

.exec(http("request_2")
  .get("/computers?f=macbook")
  .sign(signatureCalculator)
)

If your secret key is different for the virtual users, you will have to make it an Expression . To depend on the session attribute, you can write something like:

val signatureCalculator: Expression[SignatureCalculator] = { session =>
  session("secretKey")
    .validate[String]
    .map { secretKey =>
      { request =>
        // ...
      }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM