Class: AuthHMAC
- Inherits:
-
Object
- Object
- AuthHMAC
- Includes:
- Headers
- Defined in:
- lib/auth-hmac.rb,
lib/auth-hmac/version.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
Constant Summary collapse
- @@default_signature_class =
CanonicalString
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, )
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/auth-hmac.rb', line 172 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 |
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.
222 223 224 225 |
# File 'lib/auth-hmac.rb', line 222 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.
194 195 196 |
# File 'lib/auth-hmac.rb', line 194 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.
212 213 214 215 |
# File 'lib/auth-hmac.rb', line 212 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.
203 204 205 |
# File 'lib/auth-hmac.rb', line 203 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.
252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/auth-hmac.rb', line 252 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
277 278 279 |
# File 'lib/auth-hmac.rb', line 277 def (request, access_key_id, secret) "#{@service_id} #{access_key_id}:#{signature(request, secret)}" end |
#authorization_header(request) ⇒ Object
273 274 275 |
# File 'lib/auth-hmac.rb', line 273 def (request) find_header(%w(Authorization HTTP_AUTHORIZATION), headers(request)) end |
#canonical_string(request, authenticate_referrer = false) ⇒ Object
269 270 271 |
# File 'lib/auth-hmac.rb', line 269 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.
236 237 238 239 240 241 242 243 244 |
# File 'lib/auth-hmac.rb', line 236 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
264 265 266 267 |
# File 'lib/auth-hmac.rb', line 264 def signature(request, secret) digest = OpenSSL::Digest::Digest.new('sha1') [OpenSSL::HMAC.digest(digest, secret, canonical_string(request, @authenticate_referrer))].pack('m').strip end |