Yuri_
Yuri_

Reputation: 83

How to calculate AWS signature V4 in Swagger before request

For our AWS API Endpoints we use AWS_IAM authorization and want to make a call from Swagger UI. To make a successful call there must be 2 headers 'Authorization' and 'x-amz-date'. To form 'Authorization' we use following steps from aws doc. We must to change 'x-amz-date' with every call to go through authorization. The question is: How to write script in Swagger to sign request, which run every time before request send to aws? (We know how to specify both headers one time before loading Swagger page, but this process should be re-run before every call).

Thanks in advance.

Upvotes: 8

Views: 4276

Answers (3)

Oussama Mjihil
Oussama Mjihil

Reputation: 1

Signing at the client-side (the browser) means that aws credentials are used from the browser... which is not secure. I think backend signing or Cognito are more suitable to perform the signing correctly.

Upvotes: 0

prestomation
prestomation

Reputation: 7440

You can pretty easily monkeypatch signing from the AWS SDK into SwaggerJS(and thus SwaggerUI). See here

I have a slightly modified SwaggerUI here. Given some AWS credentials and an API ID, it will pull down the Swagger definition, display it in SwaggerUI, and then you can call the API using sigv4.

The Authorizer implementation looks like this:

var AWSSigv4RequestSigner = function(credentialProvider, aws) {
  this.name = "sigv4";
  this.aws = aws;
  this.credentialProvider = credentialProvider;
};

AWSSigv4RequestSigner.prototype.apply = function(options, authorizations) {
  var serviceName = "execute-api";

  //If we are loading the definition itself, then we need to sign for apigateway.
  if (options && options.url.indexOf("apigateway") >= 0) {
    serviceName = "apigateway";
  }

  if(serviceName == "apigateway" || (options.operation && options.operation.authorizations && options.operation.authorizations[0].sigv4))
  {
    /**
     * All of the below is an adapter to get this thing into the right form for the AWS JS SDK Signer
     */
    var parts = options.url.split('?');
    var host = parts[0].substr(8, parts[0].indexOf("/", 8) - 8);
    var path = parts[0].substr(parts[0].indexOf("/", 8));
    var querystring = parts[1];

    var now = new Date();
    if (!options.headers)
    {
     options.headers = [];
    }

    options.headers.host = host;
    if(serviceName == "apigateway")
    {
      //For the swagger endpoint, apigateway is strict about content-type
      options.headers.accept = "application/json";
    }

    options.pathname = function () {
      return path;
    };
    options.methodIndex = options.method;
    options.search = function () {
      return querystring ? querystring : "";
    };
    options.region = this.aws.config.region || 'us-east-1';

    //AWS uses CAPS for method names, but swagger does not.
    options.method = options.methodIndex.toUpperCase();

    var signer = new this.aws.Signers.V4(options, serviceName);


    //Actually add the Authorization header here
    signer.addAuthorization(this.credentialProvider, now);

    //SwaggerJS/yourbrowser complains if these are still around
    delete options.search;
    delete options.pathname;
    delete options.headers.host;
    return true;
  }
  return false;
};

Upvotes: 2

fehguy
fehguy

Reputation: 6824

There is built-in support in swagger-js to add requestInterceptors to do just this. The swagger-ui project uses swagger-js under the hood.

Simply create a request interceptor like such:

requestInterceptor: {
  apply: function (request) {
    // modify the request object here
    return request;
  }
}

and apply it to your swagger instance on creation:

window.swaggerUi = new SwaggerUi({
  url: url,
  dom_id: "swagger-ui-container",
  requestInterceptor: requestInterceptor,

Here you can set headers in the request object (note, this is not the standard javascript http request object, inspect it for details). But you do have access to all headers here, so you can calculate and inject them as needed.

Upvotes: 4

Related Questions