rack-simple_auth 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: