warden-hmac-authentication 0.5.5 → 0.6.0

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.
@@ -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