warden-hmac-authentication 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,68 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'warden-hmac-authentication' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
2
8
 
3
- begin
4
- require 'trollop'
5
- rescue LoadError => e
6
- puts ""
7
- puts ""
8
- puts "============= ERROR ================"
9
- puts ""
10
- puts "You need trollop installed or in your gemfile to use the signer"
11
- puts ""
12
- puts "============= ERROR ================"
13
- puts ""
14
- puts ""
15
- exit(-1)
16
- end
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
17
12
 
18
- require 'hmac/signer'
13
+ require 'rubygems'
14
+ require 'bundler/setup'
19
15
 
20
- opts = Trollop::options do
21
-
22
- version "warden-hmac-sign 0.3.0 (c) 2011 Felix Gilcher, Florian Gilcher"
23
- banner <<-EOS
24
- warden-hmac-authentication is used to create and validate signed urls for
25
- usage with the HMAC authentication scheme used by
26
- https://github.com/Asquera/warden-hmac-authentication
27
-
28
- Usage:
29
- warden-hmac-authentication [options] <command> url
30
-
31
- where command is one of
32
-
33
- sign: signs the given url
34
- validate: validates the given url
35
-
36
- and where [options] are:
37
-
38
- EOS
39
-
40
- opt :algorithm, "The hashing algorithm to use for the HMAC", :type => :string, :default => "sha1"
41
- opt :secret, "The shared secret for the HMAC", :type => :string, :required => true
42
- opt :"auth-param", "The name for the auth param in the url", :default => "auth"
43
- opt :"date", "The date to use for the signature (defaults to now)"
44
- end
45
-
46
- cmd = ARGV.shift
47
- Trollop::die "You must give a command" if cmd.nil?
48
- Trollop::die "You command must be one of [sign, validate]" unless ["sign", "validate"].include? cmd
49
- Trollop::die "You must provide a URL" if ARGV.empty?
50
- url = ARGV.shift
51
-
52
- secret = opts.delete(:secret)
53
- algorithm = opts.delete(:algorithm)
54
-
55
- signer = HMAC::Signer.new(algorithm)
56
-
57
- if "sign" == cmd
58
- puts signer.sign_url(url, secret, opts)
59
- else
60
- success = signer.validate_url_signature(url, secret, opts)
61
- if success
62
- puts "URL #{url} is valid"
63
- exit 0
64
- else
65
- puts "URL #{url} does not contain a valid signature"
66
- exit 1
67
- end
68
- end
16
+ load Gem.bin_path('warden-hmac-authentication', 'warden-hmac-authentication')
@@ -12,6 +12,17 @@ module HMAC
12
12
  class Signer
13
13
  attr_accessor :secret, :algorithm, :default_opts
14
14
 
15
+ DEFAULT_OPTS = {
16
+ :auth_scheme => "HMAC",
17
+ :auth_param => "auth",
18
+ :auth_header => "Authorization",
19
+ :auth_header_format => "%{auth_scheme} %{signature}",
20
+ :query_based => false,
21
+ :use_alternate_date_header => false,
22
+ :extra_auth_params => {},
23
+ :ignore_params => []
24
+ }
25
+
15
26
  # create a new HMAC instance
16
27
  #
17
28
  # @param [String] algorithm The hashing-algorithm to use. See the openssl documentation for valid values.
@@ -25,25 +36,18 @@ module HMAC
25
36
  # @option default_opts [String] :alternate_date_header ('X-#{auth_scheme}-Date') The header name for the alternate date header
26
37
  # @option default_opts [Bool] :query_based (false) Whether to use query based authentication
27
38
  # @option default_opts [Bool] :use_alternate_date_header (false) Use the alternate date header instead of `Date`
39
+ # @option default_opts [Hash] :extra_auth_params ({}) Additional parameters to inject in the auth parameter
40
+ # @option default_opts [Array<Symbol>] :ignore_params ([]) Params to ignore for signing
28
41
  #
29
42
  def initialize(algorithm = "sha1", default_opts = {})
30
43
  self.algorithm = algorithm
31
- self.default_opts = {
32
- :auth_scheme => "HMAC",
33
- :auth_param => "auth",
34
- :auth_header => "Authorization",
35
- :auth_header_format => "%{auth_scheme} %{signature}",
36
- :nonce_header => "X-%{scheme}-Nonce" % {:scheme => (default_opts[:auth_scheme] || "HMAC")},
37
- :alternate_date_header => "X-%{scheme}-Date" % {:scheme => (default_opts[:auth_scheme] || "HMAC")},
38
- :query_based => false,
39
- :use_alternate_date_header => false,
40
- :extra_auth_params => {}
41
- }.merge(default_opts)
42
-
44
+ default_opts[:nonce_header] ||="X-%{scheme}-Nonce" % {:scheme => (default_opts[:auth_scheme] || "HMAC")}
45
+ default_opts[:alternate_date_header] ||= "X-%{scheme}-Date" % {:scheme => (default_opts[:auth_scheme] || "HMAC")}
46
+ self.default_opts = DEFAULT_OPTS.merge(default_opts)
43
47
  end
44
-
48
+
45
49
  # Generate the signature from a hash representation
46
- #
50
+ #
47
51
  # returns nil if no secret or an empty secret was given
48
52
  #
49
53
  # @param [Hash] params the parameters to create the representation with
@@ -57,6 +61,7 @@ module HMAC
57
61
  # @option params [String] :auth_scheme ('HMAC') The name of the authorization scheme used in the Authorization header and to construct various header-names
58
62
  # @option params [String] :auth_param ('auth') The name of the authentication param to use for query based authentication
59
63
  # @option params [Hash] :extra_auth_params ({}) Additional parameters to inject in the auth parameter
64
+ # @option params [Array<Symbol>] :ignore_params ([]) Params to ignore for signing
60
65
  # @option params [String] :auth_header ('Authorization') The name of the authorization header to use
61
66
  # @option params [String] :auth_header_format ('%{auth_scheme} %{signature}') The format of the authorization header. Will be interpolated with the given options and the signature.
62
67
  # @option params [String] :nonce_header ('X-#{auth_scheme}-Nonce') The header name for the request nonce
@@ -67,7 +72,7 @@ module HMAC
67
72
  # @return [String] the signature
68
73
  def generate_signature(params)
69
74
  secret = params.delete(:secret)
70
-
75
+
71
76
  # jruby stumbles over empty secrets, we regard them as invalid anyways, so we return an empty digest if no scret was given
72
77
  if '' == secret.to_s
73
78
  nil
@@ -75,7 +80,7 @@ module HMAC
75
80
  OpenSSL::HMAC.hexdigest(algorithm, secret, canonical_representation(params))
76
81
  end
77
82
  end
78
-
83
+
79
84
  # compares the given signature with the signature created from a hash representation
80
85
  #
81
86
  # @param [String] signature the signature to compare with
@@ -90,6 +95,7 @@ module HMAC
90
95
  # @option params [String] :auth_scheme ('HMAC') The name of the authorization scheme used in the Authorization header and to construct various header-names
91
96
  # @option params [String] :auth_param ('auth') The name of the authentication param to use for query based authentication
92
97
  # @option params [Hash] :extra_auth_params ({}) Additional parameters to inject in the auth parameter
98
+ # @option params [Array<Symbol>] :ignore_params ([]) Params to ignore for signing
93
99
  # @option params [String] :auth_header ('Authorization') The name of the authorization header to use
94
100
  # @option params [String] :auth_header_format ('%{auth_scheme} %{signature}') The format of the authorization header. Will be interpolated with the given options and the signature.
95
101
  # @option params [String] :nonce_header ('X-#{auth_scheme}-Nonce') The header name for the request nonce
@@ -101,7 +107,7 @@ module HMAC
101
107
  def validate_signature(signature, params)
102
108
  signature == generate_signature(params)
103
109
  end
104
-
110
+
105
111
  # convienience method to check the signature of a url with query-based authentication
106
112
  #
107
113
  # @param [String] url the url to test
@@ -114,18 +120,20 @@ module HMAC
114
120
  def validate_url_signature(url, secret, opts = {})
115
121
  opts = default_opts.merge(opts)
116
122
  opts[:query_based] = true
117
-
123
+
118
124
  uri = Addressable::URI.parse(url)
119
125
  query_values = uri.query_values
120
126
  auth_params = query_values.delete(opts[:auth_param])
121
-
127
+
128
+ return false unless auth_params
129
+
122
130
  date = auth_params["date"]
123
131
  nonce = auth_params["nonce"]
124
132
  validate_signature(auth_params["signature"], :secret => secret, :method => "GET", :path => uri.path, :date => date, :nonce => nonce, :query => query_values, :headers => {})
125
133
  end
126
-
134
+
127
135
  # generates the canonical representation for a given request
128
- #
136
+ #
129
137
  # @param [Hash] params the parameters to create the representation with
130
138
  # @option params [String] :method The HTTP Verb of the request
131
139
  # @option params [String] :date The date of the request as it was formatted in the request
@@ -136,6 +144,7 @@ module HMAC
136
144
  # @option params [String] :auth_scheme ('HMAC') The name of the authorization scheme used in the Authorization header and to construct various header-names
137
145
  # @option params [String] :auth_param ('auth') The name of the authentication param to use for query based authentication
138
146
  # @option params [Hash] :extra_auth_params ({}) Additional parameters to inject in the auth parameter
147
+ # @option params [Array<Symbol>] :ignore_params ([]) Params to ignore for signing
139
148
  # @option params [String] :auth_header ('Authorization') The name of the authorization header to use
140
149
  # @option params [String] :auth_header_format ('%{auth_scheme} %{signature}') The format of the authorization header. Will be interpolated with the given options and the signature.
141
150
  # @option params [String] :nonce_header ('X-#{auth_scheme}-Nonce') The header name for the request nonce
@@ -146,20 +155,20 @@ module HMAC
146
155
  # @return [String] the canonical representation
147
156
  def canonical_representation(params)
148
157
  rep = ""
149
-
150
- rep << "#{params[:method].upcase}\n"
158
+
159
+ rep << "#{params[:method].upcase}\n"
151
160
  rep << "date:#{params[:date]}\n"
152
161
  rep << "nonce:#{params[:nonce]}\n"
153
-
162
+
154
163
  (params[:headers] || {}).sort.each do |pair|
155
164
  name,value = *pair
156
165
  rep << "#{name.downcase}:#{value}\n"
157
166
  end
158
-
167
+
159
168
  rep << params[:path]
160
-
169
+
161
170
  p = (params[:query] || {}).dup
162
-
171
+
163
172
  if !p.empty?
164
173
  query = p.sort.map do |key, value|
165
174
  "%{key}=%{value}" % {
@@ -169,10 +178,10 @@ module HMAC
169
178
  end.join("&")
170
179
  rep << "?#{query}"
171
180
  end
172
-
181
+
173
182
  rep
174
183
  end
175
-
184
+
176
185
  # sign the given request
177
186
  #
178
187
  # @param [String] url The url of the request
@@ -183,10 +192,11 @@ module HMAC
183
192
  # @option opts [String, #strftime] :date (Time.now) The date to use in the signature
184
193
  # @option opts [Hash] :headers ({}) A list of optional headers to include in the signature
185
194
  # @option opts [String,Symbol] :method ('GET') The HTTP method to use in the signature
186
- #
195
+ #
187
196
  # @option opts [String] :auth_scheme ('HMAC') The name of the authorization scheme used in the Authorization header and to construct various header-names
188
197
  # @option opts [String] :auth_param ('auth') The name of the authentication param to use for query based authentication
189
198
  # @option opts [Hash] :extra_auth_params ({}) Additional parameters to inject in the auth parameter
199
+ # @option opts [Array<Symbol>] :ignore_params ([]) Params to ignore for signing
190
200
  # @option opts [String] :auth_header ('Authorization') The name of the authorization header to use
191
201
  # @option opts [String] :auth_header_format ('%{auth_scheme} %{signature}') The format of the authorization header. Will be interpolated with the given options and the signature.
192
202
  # @option opts [String] :nonce_header ('X-#{auth_scheme}-Nonce') The header name for the request nonce
@@ -196,41 +206,49 @@ module HMAC
196
206
  #
197
207
  def sign_request(url, secret, opts = {})
198
208
  opts = default_opts.merge(opts)
199
-
209
+
200
210
  uri = Addressable::URI.parse(url)
201
211
  headers = opts[:headers] || {}
202
-
212
+
203
213
  date = opts[:date] || Time.now.gmtime
204
214
  date = date.gmtime.strftime('%a, %e %b %Y %T GMT') if date.respond_to? :strftime
205
215
 
206
216
  method = opts[:method] ? opts[:method].to_s.upcase : "GET"
207
-
208
- signature = generate_signature(:secret => secret, :method => method, :path => uri.path, :date => date, :nonce => opts[:nonce], :query => uri.query_values, :headers => opts[:headers])
209
-
217
+
218
+ query_values = uri.query_values
219
+
220
+ if query_values
221
+ query_values.delete_if do |k,v|
222
+ opts[:ignore_params].one? { |param| (k == param) || (k == param.to_s) }
223
+ end
224
+ end
225
+
226
+ signature = generate_signature(:secret => secret, :method => method, :path => uri.path, :date => date, :nonce => opts[:nonce], :query => query_values, :headers => opts[:headers], :ignore_params => opts[:ignore_params])
227
+
210
228
  if opts[:query_based]
211
229
  auth_params = opts[:extra_auth_params].merge({
212
230
  "date" => date,
213
231
  "signature" => signature
214
232
  })
215
233
  auth_params[:nonce] = opts[:nonce] unless opts[:nonce].nil?
216
-
234
+
217
235
  query_values = uri.query_values || {}
218
236
  query_values[opts[:auth_param]] = auth_params
219
237
  uri.query_values = query_values
220
238
  else
221
239
  headers[opts[:auth_header]] = opts[:auth_header_format] % opts.merge({:signature => signature})
222
240
  headers[opts[:nonce_header]] = opts[:nonce] unless opts[:nonce].nil?
223
-
224
- if opts[:use_alternate_date_header]
241
+
242
+ if opts[:use_alternate_date_header]
225
243
  headers[opts[:alternate_date_header]] = date
226
244
  else
227
245
  headers["Date"] = date
228
246
  end
229
247
  end
230
-
248
+
231
249
  [headers, uri.to_s]
232
250
  end
233
-
251
+
234
252
  # convienience method to sign a url for use with query-based authentication
235
253
  #
236
254
  # @param [String] url the url to sign
@@ -244,11 +262,10 @@ module HMAC
244
262
  def sign_url(url, secret, opts = {})
245
263
  opts = default_opts.merge(opts)
246
264
  opts[:query_based] = true
247
-
265
+
248
266
  headers, url = *sign_request(url, secret, opts)
249
- url
267
+ url
250
268
  end
251
-
252
-
269
+
253
270
  end
254
271
  end
@@ -1,6 +1,6 @@
1
- # this is a ruby workaround for jruby issue http://jira.codehaus.org/browse/JRUBY-5338
1
+ # this is a ruby workaround for jruby issue http://jira.codehaus.org/browse/JRUBY-5338 which was fixed in jruby-1.6.6
2
2
 
3
- if defined?(JRUBY_VERSION) && RUBY_VERSION =~ /^1\.9/
3
+ if defined?(JRUBY_VERSION) && RUBY_VERSION =~ /^1\.9/ && JRUBY_VERSION < "1.6.6"
4
4
  class KeyError < IndexError
5
5
  end
6
6
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: warden-hmac-authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-01-15 00:00:00.000000000Z
13
+ date: 2012-04-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: addressable
17
- requirement: &2157827400 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,15 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2157827400
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
26
31
  - !ruby/object:Gem::Dependency
27
32
  name: rack
28
- requirement: &2157826460 !ruby/object:Gem::Requirement
33
+ requirement: !ruby/object:Gem::Requirement
29
34
  none: false
30
35
  requirements:
31
36
  - - ! '>='
@@ -33,10 +38,15 @@ dependencies:
33
38
  version: '0'
34
39
  type: :runtime
35
40
  prerelease: false
36
- version_requirements: *2157826460
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
37
47
  - !ruby/object:Gem::Dependency
38
48
  name: warden
39
- requirement: &2157825640 !ruby/object:Gem::Requirement
49
+ requirement: !ruby/object:Gem::Requirement
40
50
  none: false
41
51
  requirements:
42
52
  - - ! '>='
@@ -44,10 +54,15 @@ dependencies:
44
54
  version: '0'
45
55
  type: :runtime
46
56
  prerelease: false
47
- version_requirements: *2157825640
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
48
63
  - !ruby/object:Gem::Dependency
49
64
  name: rake
50
- requirement: &2157824460 !ruby/object:Gem::Requirement
65
+ requirement: !ruby/object:Gem::Requirement
51
66
  none: false
52
67
  requirements:
53
68
  - - ! '>='
@@ -55,10 +70,15 @@ dependencies:
55
70
  version: '0'
56
71
  type: :development
57
72
  prerelease: false
58
- version_requirements: *2157824460
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
59
79
  - !ruby/object:Gem::Dependency
60
80
  name: rack-test
61
- requirement: &2157823380 !ruby/object:Gem::Requirement
81
+ requirement: !ruby/object:Gem::Requirement
62
82
  none: false
63
83
  requirements:
64
84
  - - ! '>='
@@ -66,10 +86,15 @@ dependencies:
66
86
  version: '0'
67
87
  type: :development
68
88
  prerelease: false
69
- version_requirements: *2157823380
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
70
95
  - !ruby/object:Gem::Dependency
71
96
  name: riot
72
- requirement: &2157822860 !ruby/object:Gem::Requirement
97
+ requirement: !ruby/object:Gem::Requirement
73
98
  none: false
74
99
  requirements:
75
100
  - - ! '>='
@@ -77,10 +102,15 @@ dependencies:
77
102
  version: '0'
78
103
  type: :development
79
104
  prerelease: false
80
- version_requirements: *2157822860
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
81
111
  - !ruby/object:Gem::Dependency
82
112
  name: timecop
83
- requirement: &2157822400 !ruby/object:Gem::Requirement
113
+ requirement: !ruby/object:Gem::Requirement
84
114
  none: false
85
115
  requirements:
86
116
  - - ! '>='
@@ -88,10 +118,15 @@ dependencies:
88
118
  version: '0'
89
119
  type: :development
90
120
  prerelease: false
91
- version_requirements: *2157822400
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
92
127
  - !ruby/object:Gem::Dependency
93
128
  name: simplecov
94
- requirement: &2157821680 !ruby/object:Gem::Requirement
129
+ requirement: !ruby/object:Gem::Requirement
95
130
  none: false
96
131
  requirements:
97
132
  - - ! '>='
@@ -99,10 +134,15 @@ dependencies:
99
134
  version: '0'
100
135
  type: :development
101
136
  prerelease: false
102
- version_requirements: *2157821680
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
103
143
  - !ruby/object:Gem::Dependency
104
144
  name: simplecov-html
105
- requirement: &2157820800 !ruby/object:Gem::Requirement
145
+ requirement: !ruby/object:Gem::Requirement
106
146
  none: false
107
147
  requirements:
108
148
  - - ! '>='
@@ -110,10 +150,15 @@ dependencies:
110
150
  version: '0'
111
151
  type: :development
112
152
  prerelease: false
113
- version_requirements: *2157820800
153
+ version_requirements: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
114
159
  - !ruby/object:Gem::Dependency
115
160
  name: trollop
116
- requirement: &2157820020 !ruby/object:Gem::Requirement
161
+ requirement: !ruby/object:Gem::Requirement
117
162
  none: false
118
163
  requirements:
119
164
  - - ! '>='
@@ -121,7 +166,12 @@ dependencies:
121
166
  version: '0'
122
167
  type: :development
123
168
  prerelease: false
124
- version_requirements: *2157820020
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ none: false
171
+ requirements:
172
+ - - ! '>='
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
125
175
  description: ! "This gem provides request authentication via [HMAC](http://en.wikipedia.org/wiki/Hmac).
126
176
  The main usage is request based, noninteractive\n authentication for API implementations.
127
177
  Two strategies are supported that differ mainly in how the authentication information
@@ -147,7 +197,8 @@ files:
147
197
  - lib/hmac/strategies/header.rb
148
198
  - lib/hmac/strategies/query.rb
149
199
  - lib/hmac/string/jruby.rb
150
- - bin/warden-hmac-authentication
200
+ - !binary |-
201
+ YmluL3dhcmRlbi1obWFjLWF1dGhlbnRpY2F0aW9u
151
202
  homepage: https://github.com/Asquera/warden-hmac-authentication
152
203
  licenses: []
153
204
  post_install_message:
@@ -168,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
219
  version: '0'
169
220
  requirements: []
170
221
  rubyforge_project:
171
- rubygems_version: 1.8.6
222
+ rubygems_version: 1.8.21
172
223
  signing_key:
173
224
  specification_version: 3
174
225
  summary: Provides request based, non-interactive authentication for APIs