Class: AuthHMAC
- Inherits:
-
Object
- Object
- AuthHMAC
- Includes:
- Headers
- Defined in:
- lib/auth-hmac.rb,
lib/auth-hmac/version.rb,
lib/auth-hmac/middleware.rb
Overview
This module provides a HMAC Authentication method for HTTP requests. It should work with net/http request classes and CGIRequest classes and hence Rails.
It is loosely based on the Amazon Web Services Authentication mechanism but generalized to be useful to any application that requires HMAC based authentication. As a result of the generalization, it won’t work with AWS because it doesn’t support the Amazon extension headers.
References
- Cryptographic Hash functions
- SHA-1 Hash function
- HMAC algorithm
- RFC 2104
Defined Under Namespace
Modules: Headers, VERSION Classes: CanonicalString, Middleware
Constant Summary collapse
- @@default_signature_class =
CanonicalString
Instance Attribute Summary collapse
-
#service_id ⇒ Object
readonly
Returns the value of attribute service_id.
Class Method Summary collapse
-
.authenticated?(request, access_key_id, secret, options) ⇒ Boolean
Authenticates a request using HMAC.
-
.canonical_string(request, options = nil) ⇒ Object
Generates canonical signing string for given request.
-
.sign!(request, access_key_id, secret, options = nil) ⇒ Object
Signs a request using a given access key id and secret.
-
.signature(request, secret, options = nil) ⇒ Object
Generates signature string for a given secret.
Instance Method Summary collapse
-
#authenticated?(request) ⇒ Boolean
Authenticates a request using HMAC.
- #authorization(request, access_key_id, secret) ⇒ Object
- #authorization_header(request) ⇒ Object
- #canonical_string(request, authenticate_referrer = false) ⇒ Object
-
#initialize(credential_store, options = nil) ⇒ AuthHMAC
constructor
Create an AuthHMAC instance using the given credential store.
-
#sign!(request, access_key_id) ⇒ Object
Signs a request using the access_key_id and the secret associated with that id in the credential store.
- #signature(request, secret) ⇒ Object
Methods included from Headers
Constructor Details
#initialize(credential_store, options = nil) ⇒ AuthHMAC
Create an AuthHMAC instance using the given credential store
Credential Store:
-
Credential store must respond to the [] method and return a secret for access key id
Options: Override default options
-
:service_id
- Service ID used in the AUTHORIZATION header string. Default is AuthHMAC. -
:signature_method
- Proc object that takes request and produces the signature stringused for authentication. Default is CanonicalString.
Examples:
my_hmac = AuthHMAC.new('access_id1' => 'secret1', 'access_id2' => 'secret2')
cred_store = { 'access_id1' => 'secret1', 'access_id2' => 'secret2' }
= { :service_id => 'MyApp', :signature_method => lambda { |r| MyRequestString.new(r) } }
my_hmac = AuthHMAC.new(cred_store, )
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/auth-hmac.rb', line 179 def initialize(credential_store, = nil) @credential_store = credential_store # Defaults @service_id = self.class.name @signature_class = @@default_signature_class @authenticate_referrer = false unless .nil? @service_id = [:service_id] if .key?(:service_id) @signature_class = [:signature] if .key?(:signature) && [:signature].is_a?(Class) @authenticate_referrer = [:authenticate_referrer] || [:authenticate_referer] end @signature_method = lambda { |r,ar| @signature_class.send(:new, r, ar) } end |
Instance Attribute Details
#service_id ⇒ Object (readonly)
Returns the value of attribute service_id.
196 197 198 |
# File 'lib/auth-hmac.rb', line 196 def service_id @service_id end |
Class Method Details
.authenticated?(request, access_key_id, secret, options) ⇒ Boolean
Authenticates a request using HMAC
Supports same options as AuthHMAC.initialize for overriding service_id and signature method.
231 232 233 234 |
# File 'lib/auth-hmac.rb', line 231 def AuthHMAC.authenticated?(request, access_key_id, secret, ) credentials = { access_key_id => secret } self.new(credentials, ).authenticated?(request) end |
.canonical_string(request, options = nil) ⇒ Object
Generates canonical signing string for given request
Supports same options as AuthHMAC.initialize for overriding service_id and signature method.
203 204 205 |
# File 'lib/auth-hmac.rb', line 203 def AuthHMAC.canonical_string(request, = nil) self.new(nil, ).canonical_string(request) end |
.sign!(request, access_key_id, secret, options = nil) ⇒ Object
Signs a request using a given access key id and secret.
Supports same options as AuthHMAC.initialize for overriding service_id and signature method.
221 222 223 224 |
# File 'lib/auth-hmac.rb', line 221 def AuthHMAC.sign!(request, access_key_id, secret, = nil) credentials = { access_key_id => secret } self.new(credentials, ).sign!(request, access_key_id) end |
.signature(request, secret, options = nil) ⇒ Object
Generates signature string for a given secret
Supports same options as AuthHMAC.initialize for overriding service_id and signature method.
212 213 214 |
# File 'lib/auth-hmac.rb', line 212 def AuthHMAC.signature(request, secret, = nil) self.new(nil, ).signature(request, secret) end |
Instance Method Details
#authenticated?(request) ⇒ Boolean
Authenticates a request using HMAC
Returns true if the request has an AuthHMAC Authorization header and the access id and HMAC match an id and HMAC produced for the secret in the credential store. Otherwise returns false.
261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/auth-hmac.rb', line 261 def authenticated?(request) rx = Regexp.new("#{@service_id} ([^:]+):(.+)$") if md = rx.match((request)) access_key_id = md[1] hmac = md[2] secret = @credential_store[access_key_id] !secret.nil? && hmac == signature(request, secret) else false end end |
#authorization(request, access_key_id, secret) ⇒ Object
286 287 288 |
# File 'lib/auth-hmac.rb', line 286 def (request, access_key_id, secret) "#{@service_id} #{access_key_id}:#{signature(request, secret)}" end |
#authorization_header(request) ⇒ Object
282 283 284 |
# File 'lib/auth-hmac.rb', line 282 def (request) find_header(%w(Authorization HTTP_AUTHORIZATION), headers(request)) end |
#canonical_string(request, authenticate_referrer = false) ⇒ Object
278 279 280 |
# File 'lib/auth-hmac.rb', line 278 def canonical_string(request, authenticate_referrer=false) @signature_method.call(request, authenticate_referrer) end |
#sign!(request, access_key_id) ⇒ Object
Signs a request using the access_key_id and the secret associated with that id in the credential store.
Signing a requests adds an Authorization header to the request in the format:
<service_id> <access_key_id>:<signature>
where <signature> is the Base64 encoded HMAC-SHA1 of the CanonicalString and the secret.
245 246 247 248 249 250 251 252 253 |
# File 'lib/auth-hmac.rb', line 245 def sign!(request, access_key_id) secret = @credential_store[access_key_id] raise ArgumentError, "No secret found for key id '#{access_key_id}'" if secret.nil? if request.respond_to?(:headers) request.headers['Authorization'] = (request, access_key_id, secret) else request['Authorization'] = (request, access_key_id, secret) end end |
#signature(request, secret) ⇒ Object
273 274 275 276 |
# File 'lib/auth-hmac.rb', line 273 def signature(request, secret) digest = OpenSSL::Digest::Digest.new('sha1') [OpenSSL::HMAC.digest(digest, secret, canonical_string(request, @authenticate_referrer))].pack('m').strip end |