AWS 4 style signature for grape api
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
app/assets/javascripts
lib
spec
vendor/assets/javascripts
.consolerc
.gitignore
.rspec
.rubocop.yml
.rubocop_todo.yml
.travis.yml
.versions.conf
Gemfile
LICENSE.txt
README.md
Rakefile
grape_api_signature.gemspec

README.md

Gem Version Build Status Code Climate Coverage Status

GrapeAPISignature

GrapeAPISignature provides a AWS 4 style Authentication middleware to be used with grape. It calculates the 'AWS4-HMAC-SHA256' style signature and compares it against the HTTP_AUTHORIZATION header within the request.

Installation

Add this line to your application's Gemfile:

gem 'grape_api_signature'

And then execute:

$ bundle

Or install it yourself as:

$ gem install grape_api_signature

Usage

In your API

Example usage:

 
  class YourAPI < Grape::API
    Grape::Middleware::Auth::Strategies.add(:aws4_auth,
                                            GrapeAPISignature::Middleware::GrapeAuth,
                                            ->(options) { [options[:max_request_age] || 900, options[:user_setter]] })
     
    GrapeAPISignature::Middleware::GrapeAuth.default_authenticator do |_access_key, _region, _service|
     user = ... # find the user, this block is executed in the context of your Endpoint
     { user: user, secret_key: user.key }
    end
    
    helpers do
      attr_accessor :current_user
    end
    
    auth :aws4_auth,
        max_request_age: 100,
        user_setter: :'current_user=',
        &GrapeAPISignature::Middleware::GrapeAuth.default_authenticator
    
    get '/aws4_authorized' do
     'DONE'
    end
  end
  

Options:

  • max_request_age => Time in seconds how long a request is valid
  • user_setter => When provided this is be used to set the user on your Endtpoint instance if the validations was successful

If the validation was successful env['REMOTE_USER'] is set to the access_key.

If the validation was not successful HTTP-Status 401 is set via Grape#error! when the signature was wrong and 400 if Scheme does not match 'AWS4-HMAC-SHA256'

In your rspecs

The following code only supports 'application/json' as Content-Type.

# spec_helper.rb

require 'grape_api_signature/rspec'

# in your spec

describe 'your wishes' do
  include GrapeAPISignature::RSpec
  
  let(:secret_key) { 'SUPERSUPERSUPERSECRET' }
  let(:access_key) { 'MyUser' }
  
  
  # if you don't use Rails
  let(:hostname) { Rack::Test::DEFAULT_HOST }
  let(:port) { 80 }
  let(:host) { "#{hostname}:#{port}" }
  
  def https?
    port == 443
  end
  
  it 'should do' do
     get_with_auth '/'
  end
  
  it 'should also do' do
    post_with_auth '/', request_params
  end
  
end

In your Rails-App

This gem provides a coffee script to authenticate swagger demo requests via AWS 4.

# application.js.coffee

#= require aws-signature
# your swagger index.html, or what you use

<div id="header">
  <div class="swagger-ui-wrap">
    <form id="api_selector">
      <div class="input">
        <input type="text" placeholder="Username" id="input_apiUser" name="user">
      </div>
      <div class="input">
        <input type="password" placeholder="Password" id="input_apiPassword" name="password">
      </div>
    </form>
   </div>
</div>

Standalone RackMiddleware

Example usage:

...

max_request_age = 200

use GrapeAPISignature::Middleware::Auth, max_request_age  do |_access_key, _region, _service|
  user = ... 
  user.secret_key # different return value as for grape API's return only the key
end

run app

...

Standalone Authenticator/Signer

Example usage:

# Gemfile
gem 'grape_api_signature', require: 'grape_api_signature/signer_components'

# In your ruby file validate a request

auth = Authorization.new(request_method,
                         headers,
                         URI(url),
                         body,
                         max_request_age)
                         
auth.authentic?(secret_key)

# OR use the signer

signer = GrapeAPISignature::AWSSigner.new(
          access_key: user_id,
          secret_key: secret_key,
          region: authorization.region
)

signer.signature_only(request_method, uri, headers_to_sign, body)

# OR

signer.sign(request_method, uri, headers_to_sign, body)

Contributing

  1. Fork it ( https://github.com/faber-lotto/grape_api_signature/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request