rack-simple_auth 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4ed00cc40f3111fa03accfd030db1def811ad27a
4
- data.tar.gz: cc12d38b646cb6f258e1914e42467258e1da1598
3
+ metadata.gz: 7da6de52a27fba5b232011cb9259c8c31ba95473
4
+ data.tar.gz: 35f166b707a7da786ed0358eb958591bd82ecb67
5
5
  SHA512:
6
- metadata.gz: ee8ef0e6b86dc1d199fb32db40721ea0ac79be6d0ad2d1d561c2b9b8acb71b218bd96ddc1591cc5929f8f2cd967445c8d21de7994df700eb419cc0de7ac5d30e
7
- data.tar.gz: 44443667ba5df710dfd7fd0340397eb2e6e45fd02f91ef8d208dc060a6a3a50fa12dfb3f14ea6719476042a542aebb20a8542109773853896c14554b23640ff5
6
+ metadata.gz: b7f297881cad83bf4a6123fc2f072e8d487b32f2440f667a9902c16e9ac8af608d07190c88a79a038f51869ec4a795ed39929f0ea9f0fd2932444efe818f90ba
7
+ data.tar.gz: 758c2e12bc71f147f0a9bce5c5ba9072efc37ca2a6fca980c5f20dc7aa258a0c53ac2698e71a4ca56ba1d8a94670b54c557da74d3d89fb4f216b61a7529f0f57
data/.rubocop.yml CHANGED
@@ -1,2 +1 @@
1
- LineLength:
2
- Max: 160
1
+ inherit_from: rubocop-todo.yml
data/README.md CHANGED
@@ -25,20 +25,12 @@ Or install it yourself as:
25
25
  [![Gem Version](https://badge.fury.io/rb/rack-simple_auth.png)](http://badge.fury.io/rb/rack-simple_auth)
26
26
  [![Dependency Status](https://gemnasium.com/Benny1992/rack-simple_auth.png)](https://gemnasium.com/Benny1992/rack-simple_auth)
27
27
 
28
-
29
-
30
-
31
28
  ## Usage
32
29
 
33
30
  ### HMAC Authorization
34
31
 
35
32
  HMAC should be used for communication between website backend and api server/controller/whatever..
36
33
 
37
- ~~For usage between Server <-> Client a sniffer could easily extract the signature/public key and
38
- the encrypted message which is for now the same for the same request (see TODO implement timestamp).~~
39
-
40
- ~~With these 2 informations a "secure" backend could be easily seen public...~~
41
-
42
34
  In version 0.0.5 the timestamp has been added to the msg which will be encrypted, also the possibility to configure the allowed delay a request can have has been added.
43
35
 
44
36
  Uses Authorization HTTP Header, example:
@@ -56,7 +48,8 @@ config = {
56
48
  'DELETE' => 'path',
57
49
  'PUT' => 'path',
58
50
  'PATCH' => 'path'
59
- 'tolerance' => 2,
51
+ 'tolerance' => 1,
52
+ 'steps' => 0.1,
60
53
  'signature' => 'signature',
61
54
  'secret' => 'secret',
62
55
  'logpath' => '/path/to/log/file'
@@ -73,6 +66,7 @@ Note: Private Key and Signature should be served by a file which is not checked
73
66
 
74
67
 
75
68
 
69
+
76
70
  #### Config Hash
77
71
 
78
72
 
@@ -109,6 +103,14 @@ The tolerance which is configureable in the config hash sets the possible delay
109
103
 
110
104
  Notice: For a set tolerance a Encrypted Message array will be generated and compared with the MessageHash from the AUTH Header
111
105
 
106
+ In Version 0.1.0 the stepsize option has been added
107
+
108
+ You can now specify how many valid hashes are created in a range between eg.: (-1..1) (= tolerance)
109
+
110
+ A minimum stepsize of 0.01 is required (0.01 are 10 milliseconds, this is the minimum because of ruby's float disaster and therefore the gem has to use Float#round(2))
111
+
112
+ Let me know if you need a smaller stepsize...
113
+
112
114
 
113
115
  #### Logging
114
116
 
@@ -123,9 +125,6 @@ It contains following information:
123
125
  - The Encrypted Message Array which was expected
124
126
  - The Signature which was expected
125
127
 
126
-
127
-
128
-
129
128
  ## TODO
130
129
 
131
130
  ~~Add Timestamp to encryption..~~
@@ -154,3 +153,4 @@ It contains following information:
154
153
 
155
154
 
156
155
 
156
+
@@ -10,18 +10,22 @@ module Rack
10
10
  @app = app
11
11
  @signature = config['signature'] || ''
12
12
  @secret = config['secret'] || ''
13
- @tolerance = config['tolerance'] || 0 # 0 if tolerance not set in config hash
13
+ @tolerance = config['tolerance'] || 1 # 0 if tolerance not set in config hash
14
14
  @logpath = config['logpath']
15
15
  @steps = config['steps'] || 1
16
16
 
17
+ valid_stepsize?(0.01)
18
+ valid_tolerance?
19
+
17
20
  @config = config
18
21
  end
19
22
 
20
23
  # call Method for Rack Middleware/Application
21
24
  # @param [Hash] env [Rack Env Hash which contains headers etc..]
22
25
  def call(env)
23
- request = Rack::Request.new(env)
24
- if valid?(request)
26
+ @request = Rack::Request.new(env)
27
+
28
+ if valid_request?
25
29
  @app.call(env)
26
30
  else
27
31
  response = Rack::Response.new('Unauthorized', 401, 'Content-Type' => 'text/html')
@@ -30,90 +34,91 @@ module Rack
30
34
  end
31
35
 
32
36
  # checks for valid HMAC Request
33
- # @param [Rack::Request] request [current Request]
34
37
  # @return [boolean] ValidationStatus [If authorized returns true, else false]
35
- def valid?(request)
36
- hash_array = build_allowed_messages(request)
37
-
38
- if request.env['HTTP_AUTHORIZATION'].nil?
39
- log(request, hash_array)
38
+ def valid_request?
39
+ if @request.env['HTTP_AUTHORIZATION'].nil?
40
+ log(allowed_messages)
40
41
 
41
42
  return false
42
43
  end
43
44
 
44
- auth_array = request.env['HTTP_AUTHORIZATION'].split(':')
45
- message_hash = auth_array[0]
46
- signature = auth_array[1]
47
-
48
- if signature == @signature && hash_array.include?(message_hash)
45
+ if request_signature == @signature && allowed_messages.include?(request_message)
49
46
  true
50
47
  else
51
- log(request, hash_array)
48
+ log(allowed_messages)
52
49
 
53
50
  false
54
51
  end
55
52
  end
56
53
 
54
+ private
55
+
56
+ # Get request signature
57
+ def request_signature
58
+ @request.env['HTTP_AUTHORIZATION'].split(':').last
59
+ end
60
+
61
+ # Get encrypted request message
62
+ def request_message
63
+ @request.env['HTTP_AUTHORIZATION'].split(':').first
64
+ end
65
+
57
66
  # Builds Array of allowed message hashs
58
- # @param [Rack::Request] request [current Request]
59
67
  # @return [Array] hash_array [allowed message hashes as array]
60
- def build_allowed_messages(request)
61
- hash_array = []
68
+ def allowed_messages
69
+ messages = []
62
70
 
63
71
  (-(@tolerance)..@tolerance).step(@steps) do |i|
64
72
  i = i.round(2)
65
- hash_array << OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @secret, message(request, i))
73
+ messages << OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @secret, message(i))
66
74
  end
67
75
 
68
- hash_array
76
+ messages
69
77
  end
70
78
 
71
79
  # Get Message for current Request and delay
72
- # @param [Rack::Request] request [current Request]
73
80
  # @param [Fixnum] delay [delay in timestamp format]
74
81
  # @return [Hash] message [message which will be encrypted]
75
- def message(request, delay = 0)
82
+ def message(delay = 0)
76
83
  date = Time.now.to_i + delay
84
+ date = date.to_i if delay.eql?(0.0)
77
85
 
78
- if delay.eql?(0.0)
79
- date = date.to_i
80
- end
81
-
82
- case request.request_method
86
+ case @request.request_method
83
87
  when 'GET'
84
- return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
88
+ return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json
85
89
  when 'POST'
86
- return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
90
+ return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json
87
91
  when 'DELETE'
88
- return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
92
+ return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json
89
93
  when 'PUT'
90
- return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
94
+ return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json
91
95
  when 'PATCH'
92
- return { 'method' => request.request_method, 'date' => date, 'data' => request_data(request, @config) }.to_json
96
+ return { 'method' => @request.request_method, 'date' => date, 'data' => request_data(@config) }.to_json
93
97
  end
94
98
  end
95
99
 
96
100
  # Get Request Data specified by Config
97
- # @param [Rack::Request] request [current Request]
98
101
  # @param [Hash] config [Config Hash containing what type of info is data for each request]
99
102
  # @return [String|Hash] data [Data for each request]
100
- def request_data(request, config)
101
- if config[request.request_method] == 'path' || config[request.request_method] == 'params'
102
- request.send(config[request.request_method].to_sym)
103
+ def request_data(config)
104
+ if config[@request.request_method] == 'path' || config[@request.request_method] == 'params'
105
+ @request.send(config[@request.request_method].to_sym)
103
106
  else
104
- fail "Not a valid option #{config[request.request_method]} - Use either params or path"
107
+ fail "Not a valid option #{config[@request.request_method]} - Use either params or path"
105
108
  end
106
109
  end
107
110
 
108
111
  # Log to @logpath if request is unathorized
109
- # @param [Rack::Request] request [current Request]
110
- def log(request, hash_array)
112
+ # Contains:
113
+ # - allowed messages and received message
114
+ # - time when request was made
115
+ # - type of request
116
+ # - requested path
117
+ def log(hash_array)
111
118
  if @logpath
112
- path = request.path
113
- method = request.request_method
114
-
115
- log = "#{Time.new} - #{method} #{path} - 400 Unauthorized - HTTP_AUTHORIZATION: #{request.env['HTTP_AUTHORIZATION']}\n"
116
- log << "Auth Message Config: #{@config[request.request_method]}\n"
119
+ log = "#{Time.new} - #{@request.request_method} #{@request.path} - 400 Unauthorized\n"
120
+ log << "HTTP_AUTHORIZATION: #{@request.env['HTTP_AUTHORIZATION']}\n"
121
+ log << "Auth Message Config: #{@config[@request.request_method]}\n"
117
122
 
118
123
  if hash_array
119
124
  log << "Allowed Encrypted Messages:\n"
@@ -130,7 +135,21 @@ module Rack
130
135
  end
131
136
  end
132
137
 
133
- private :log, :request_data, :message, :valid?, :build_allowed_messages
138
+ # Check if Stepsize is valid, if > min ensure stepsize is min stepsize
139
+ # @param [float] min [minimum allowed stepsize]
140
+ def valid_stepsize?(min)
141
+ if @steps < min
142
+ puts "Warning: Minimum allowed stepsize is #{min}"
143
+ @steps = min
144
+ end
145
+ end
146
+
147
+ # Check if tolerance is valid, tolerance must be greater than stepsize
148
+ def valid_tolerance?
149
+ if @tolerance < @steps
150
+ fail "Tolerance must be greater than stepsize - Tolerance: #{@tolerance}, Stepsize: #{@steps}"
151
+ end
152
+ end
134
153
  end
135
154
  end
136
155
  end
@@ -2,6 +2,6 @@ module Rack
2
2
  # Module which Contains different Authorization / Authentication Classes (HMAC, ..)
3
3
  module SimpleAuth
4
4
  # Current Gem Version
5
- VERSION = '0.1.0'
5
+ VERSION = '0.1.1'
6
6
  end
7
7
  end
data/test/config.ru CHANGED
@@ -7,11 +7,11 @@ config = {
7
7
  'DELETE' => 'path',
8
8
  'PUT' => 'path',
9
9
  'PATCH' => 'path',
10
- 'tolerance' => 1,
10
+ 'tolerance' => 0.5,
11
11
  'signature' => 'test_signature',
12
12
  'secret' => 'test_secret',
13
13
  'logpath' => "#{File.expand_path('..', __FILE__)}/logs",
14
- 'steps' => 0.1
14
+ 'steps' => 0.01
15
15
  }
16
16
 
17
17
  use Rack::SimpleAuth::HMAC, config
@@ -21,6 +21,18 @@ class HMACFailTest < MiniTest::Unit::TestCase
21
21
  assert_raises(RuntimeError) { get uri, {}, 'HTTP_AUTHORIZATION' => "#{hash}:#{@signature}" }
22
22
  end
23
23
 
24
+ def test_fail_step
25
+ out, err = capture_io do
26
+ Rack::Builder.parse_file("#{Rack::SimpleAuth.root}/test/config_fail_step.ru").first
27
+ end
28
+
29
+ assert_match('Warning: Minimum allowed stepsize is 0.01', out, 'Warning should be printed if stepsize is below 0.01')
30
+ end
31
+
32
+ def test_fail_tolerance
33
+ assert_raises(RuntimeError) { Rack::Builder.parse_file("#{Rack::SimpleAuth.root}/test/config_fail_tolerance.ru").first }
34
+ end
35
+
24
36
  def teardown
25
37
  end
26
38
  end
@@ -41,7 +41,7 @@ class HMACTest < MiniTest::Unit::TestCase
41
41
  get uri, {}, 'HTTP_AUTHORIZATION' => "#{hash}:#{@signature}"
42
42
 
43
43
  assert_equal(200, last_response.status, 'Delay in tolerance range should receive 200')
44
- end
44
+ end
45
45
 
46
46
  def test_get_with_too_big_delay
47
47
  uri = '/'
@@ -55,7 +55,7 @@ class HMACTest < MiniTest::Unit::TestCase
55
55
 
56
56
  def test_get_with_wrong_step
57
57
  uri = '/'
58
- message = { 'method' => 'GET', 'date' => Time.now.to_i + 0.03, 'data' => uri }.to_json
58
+ message = { 'method' => 'GET', 'date' => Time.now.to_i + 0.035, 'data' => uri }.to_json
59
59
  hash = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @secret, message)
60
60
 
61
61
  get uri, {}, 'HTTP_AUTHORIZATION' => "#{hash}:#{@signature}"
data/test/test_helper.rb CHANGED
@@ -1,4 +1,4 @@
1
- ENV['RACK_ENV']='test'
1
+ ENV['RACK_ENV'] = 'test'
2
2
 
3
3
  require 'simplecov'
4
4
  require 'coveralls'
@@ -44,4 +44,3 @@ Rack::SimpleAuth.failapp = Rack::Builder.parse_file("#{Rack::SimpleAuth.root}/te
44
44
 
45
45
  @logpath = "#{File.expand_path("..", __FILE__)}/logs"
46
46
  system("mkdir #{@logpath}")
47
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-simple_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benny1992
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-21 00:00:00.000000000 Z
11
+ date: 2014-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -135,3 +135,4 @@ signing_key:
135
135
  specification_version: 4
136
136
  summary: SimpleAuth HMAC authentication
137
137
  test_files: []
138
+ has_rdoc: