Class: Rack::SimpleAuth::HMAC

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/simple_auth/hmac.rb

Overview

HMAC Middleware uses HMAC Authorization for Securing an REST API

Instance Method Summary collapse

Constructor Details

#initialize(app, config) ⇒ HMAC

Constructor for Rack Middleware (passing the rack stack)

Parameters:

  • app (Rack Application)
    next middleware or rack app which gets called
  • config (Hash)
    config hash where tolerance, secret, signature etc.. are set


9
10
11
12
13
14
15
16
17
18
# File 'lib/rack/simple_auth/hmac.rb', line 9

def initialize(app, config)
  @app = app
  @signature = config['signature'] || ''
  @secret = config['secret'] || ''
  @tolerance = config['tolerance'] || 0 # 0 if tolerance not set in config hash
  @logpath = config['logpath']
  @steps = config['steps'] || 1

  @config = config
end

Instance Method Details

#build_allowed_messages(request) ⇒ Array (private)

Builds Array of allowed message hashs

Parameters:

  • request (Rack::Request)
    current Request

Returns:

  • (Array)

    hash_array [allowed message hashes as array]



60
61
62
63
64
65
66
67
68
69
# File 'lib/rack/simple_auth/hmac.rb', line 60

def build_allowed_messages(request)
  hash_array = []

  (-(@tolerance)..@tolerance).step(@steps) do |i|
    i = i.round(2)
    hash_array << OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @secret, message(request, i))
  end

  hash_array
end

#call(env) ⇒ Object

call Method for Rack Middleware/Application

Parameters:

  • env (Hash)
    Rack Env Hash which contains headers etc..


22
23
24
25
26
27
28
29
30
# File 'lib/rack/simple_auth/hmac.rb', line 22

def call(env)
  request = Rack::Request.new(env)
  if valid?(request)
    @app.call(env)
  else
    response = Rack::Response.new('Unauthorized', 401, 'Content-Type' => 'text/html')
    response.finish
  end
end

#log(request, hash_array) ⇒ Object (private)

Log to @logpath if request is unathorized

Parameters:

  • request (Rack::Request)
    current Request


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/rack/simple_auth/hmac.rb', line 110

def log(request, hash_array)
  if @logpath
    path = request.path
    method = request.request_method

    log = "#{Time.new} - #{method} #{path} - 400 Unauthorized - HTTP_AUTHORIZATION: #{request.env['HTTP_AUTHORIZATION']}\n"
    log << "Auth Message Config: #{@config[request.request_method]}\n"

    if hash_array
      log << "Allowed Encrypted Messages:\n"
      hash_array.each do |hash|
        log << "#{hash}\n"
      end
    end

    log << "Auth Signature: #{@signature}"

    open("#{@logpath}/#{ENV['RACK_ENV']}_error.log", 'a') do |f|
      f << "#{log}\n"
    end
  end
end

#message(request, delay = 0) ⇒ Hash (private)

Get Message for current Request and delay

Parameters:

  • request (Rack::Request)
    current Request
  • delay (Fixnum) (defaults to: 0)
    delay in timestamp format

Returns:

  • (Hash)

    message [message which will be encrypted]



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rack/simple_auth/hmac.rb', line 75

def message(request, delay = 0)
  date = Time.now.to_i + delay

  if delay.eql?(0.0)
    date = date.to_i
  end

  case request.request_method
  when 'GET'
    return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
  when 'POST'
    return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
  when 'DELETE'
    return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
  when 'PUT'
    return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
  when 'PATCH'
    return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
  end
end

#request_data(request, config) ⇒ String|Hash (private)

Get Request Data specified by Config

Parameters:

  • request (Rack::Request)
    current Request
  • config (Hash)
    Config Hash containing what type of info is data for each request

Returns:

  • (String|Hash)

    data [Data for each request]



100
101
102
103
104
105
106
# File 'lib/rack/simple_auth/hmac.rb', line 100

def request_data(request, config)
  if config[request.request_method] == 'path' || config[request.request_method] == 'params'
    request.send(config[request.request_method].to_sym)
  else
    fail "Not a valid option #{config[request.request_method]} - Use either params or path"
  end
end

#valid?(request) ⇒ boolean (private)

checks for valid HMAC Request

Parameters:

  • request (Rack::Request)
    current Request

Returns:

  • (boolean)

    ValidationStatus [If authorized returns true, else false]



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/rack/simple_auth/hmac.rb', line 35

def valid?(request)
  hash_array = build_allowed_messages(request)

  if request.env['HTTP_AUTHORIZATION'].nil?
    log(request, hash_array)

    return false
  end

  auth_array = request.env['HTTP_AUTHORIZATION'].split(':')
  message_hash = auth_array[0]
  signature = auth_array[1]

  if signature == @signature && hash_array.include?(message_hash)
    true
  else
    log(request, hash_array)

    false
  end
end