No commit activity in last 3 years
No release in over 3 years
Add AWS Signature 4 style authentication to grape API's.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

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