Class: Cyclid::HMAC::Signer
- Inherits:
-
Object
- Object
- Cyclid::HMAC::Signer
- Defined in:
- lib/cyclid/hmac.rb
Overview
Helper class that provides signing capabilites for the hmac strategies.
Constant Summary collapse
- DEFAULT_OPTS =
HMAC defaults
{ auth_scheme: 'HMAC', auth_param: 'auth', auth_header: 'Authorization', auth_header_format: '%{auth_scheme} %{signature}', query_based: false, use_alternate_date_header: false, extra_auth_params: {}, ignore_params: [] }.freeze
Instance Attribute Summary collapse
-
#algorithm ⇒ Object
Returns the value of attribute algorithm.
-
#default_opts ⇒ Object
Returns the value of attribute default_opts.
-
#secret ⇒ Object
Returns the value of attribute secret.
Instance Method Summary collapse
-
#canonical_representation(params) ⇒ String
generates the canonical representation for a given request.
-
#generate_signature(params) ⇒ String
Generate the signature from a hash representation.
-
#initialize(algorithm = 'sha256', default_opts = {}) ⇒ Signer
constructor
create a new HMAC instance.
-
#sign_request(url, secret, opts = {}) ⇒ Object
sign the given request.
-
#validate_signature(signature, params) ⇒ Bool
compares the given signature with the signature created from a hash representation.
Constructor Details
#initialize(algorithm = 'sha256', default_opts = {}) ⇒ Signer
create a new HMAC instance
64 65 66 67 68 69 |
# File 'lib/cyclid/hmac.rb', line 64 def initialize(algorithm = 'sha256', default_opts = {}) self.algorithm = algorithm default_opts[:nonce_header] ||= 'X-%{scheme}-Nonce' % { scheme: (default_opts[:auth_scheme] || 'HMAC') } default_opts[:alternate_date_header] ||= 'X-%{scheme}-Date' % { scheme: (default_opts[:auth_scheme] || 'HMAC') } self.default_opts = DEFAULT_OPTS.merge(default_opts) end |
Instance Attribute Details
#algorithm ⇒ Object
Returns the value of attribute algorithm.
34 35 36 |
# File 'lib/cyclid/hmac.rb', line 34 def algorithm @algorithm end |
#default_opts ⇒ Object
Returns the value of attribute default_opts.
34 35 36 |
# File 'lib/cyclid/hmac.rb', line 34 def default_opts @default_opts end |
#secret ⇒ Object
Returns the value of attribute secret.
34 35 36 |
# File 'lib/cyclid/hmac.rb', line 34 def secret @secret end |
Instance Method Details
#canonical_representation(params) ⇒ String
generates the canonical representation for a given request
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/cyclid/hmac.rb', line 154 def canonical_representation(params) rep = '' rep << "#{params[:method].upcase}\n" rep << "date:#{params[:date]}\n" rep << "nonce:#{params[:nonce]}\n" (params[:headers] || {}).sort.each do |pair| name, value = *pair rep << "#{name.downcase}:#{value}\n" end rep << params[:path] p = (params[:query] || {}).dup unless p.empty? query = p.sort.map do |key, value| '%{key}=%{value}' % { key: Rack::Utils.unescape(key.to_s), value: Rack::Utils.unescape(value.to_s) } end.join('&') rep << "?#{query}" end rep end |
#generate_signature(params) ⇒ String
Generate the signature from a hash representation
returns nil if no secret or an empty secret was given
95 96 97 98 99 100 101 102 103 104 |
# File 'lib/cyclid/hmac.rb', line 95 def generate_signature(params) secret = params.delete(:secret) # jruby stumbles over empty secrets, we regard them as invalid anyways, so we return an empty digest if no scret was given if '' == secret.to_s nil else OpenSSL::HMAC.hexdigest(algorithm, secret, canonical_representation(params)) end end |
#sign_request(url, secret, opts = {}) ⇒ Object
sign the given request
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
# File 'lib/cyclid/hmac.rb', line 205 def sign_request(url, secret, opts = {}) opts = default_opts.merge(opts) uri = parse_url(url) headers = opts[:headers] || {} date = opts[:date] || Time.now.gmtime date = date.gmtime.strftime('%a, %d %b %Y %T GMT') if date.respond_to? :strftime method = opts[:method] ? opts[:method].to_s.upcase : 'GET' query_values = Rack::Utils.parse_nested_query(uri.query) if query_values query_values.delete_if do |k, _v| opts[:ignore_params].one? { |param| (k == param) || (k == param.to_s) } end end 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]) if opts[:query_based] auth_params = opts[:extra_auth_params].merge('date' => date, 'signature' => signature) auth_params[:nonce] = opts[:nonce] unless opts[:nonce].nil? query_values ||= {} query_values[opts[:auth_param]] = auth_params uri.query = Rack::Utils.build_nested_query(query_values) else headers[opts[:auth_header]] = opts[:auth_header_format] % opts.merge(signature: signature) headers[opts[:nonce_header]] = opts[:nonce] unless opts[:nonce].nil? if opts[:use_alternate_date_header] headers[opts[:alternate_date_header]] = date else headers['Date'] = date end end [headers, uri.to_s] end |
#validate_signature(signature, params) ⇒ Bool
compares the given signature with the signature created from a hash representation
129 130 131 |
# File 'lib/cyclid/hmac.rb', line 129 def validate_signature(signature, params) compare_hashes(signature, generate_signature(params)) end |