class Stormpath::Http::Authc::Sauthc1Signer
Constants
- ALGORITHM
- AUTHENTICATION_SCHEME
- AUTHORIZATION_HEADER
- DATE_FORMAT
- DEFAULT_ALGORITHM
- HOST_HEADER
- ID_TERMINATOR
- NL
noinspection RubyConstantNamingConvention
- SAUTHC1_ID
- SAUTHC1_SIGNATURE
- SAUTHC1_SIGNED_HEADERS
- STORMPATH_DATE_HEADER
- TIMESTAMP_FORMAT
Public Class Methods
new(uuid_generator = UUID.method(:random_create))
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 39 def initialize(uuid_generator = UUID.method(:random_create)) 40 @uuid_generator = uuid_generator 41 end
Public Instance Methods
sign_request(request)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 43 def sign_request(request) 44 request.http_headers.delete(Sauthc1Signer::AUTHORIZATION_HEADER) 45 request.http_headers.delete(Sauthc1Signer::STORMPATH_DATE_HEADER) 46 47 time = Time.now 48 time_stamp = time.utc.strftime TIMESTAMP_FORMAT 49 date_stamp = time.utc.strftime DATE_FORMAT 50 51 nonce = @uuid_generator.call.to_s 52 53 uri = request.resource_uri 54 55 # SAuthc1 requires that we sign the Host header so we 56 # have to have it in the request by the time we sign. 57 host_header = uri.host 58 59 host_header << ':' << uri.port.to_s unless default_port?(uri) 60 61 request.http_headers.store HOST_HEADER, host_header 62 63 request.http_headers.store STORMPATH_DATE_HEADER, time_stamp 64 65 method = request.http_method 66 canonical_resource_path = canonicalize_resource_path uri.path 67 canonical_query_string = canonicalize_query_string request 68 canonical_headers_string = canonicalize_headers request 69 signed_headers_string = get_signed_headers request 70 request_payload_hash_hex = to_hex(hash_text(get_request_payload(request))) 71 72 canonical_request = [method, 73 canonical_resource_path, 74 canonical_query_string, 75 canonical_headers_string, 76 signed_headers_string, 77 request_payload_hash_hex].join(NL) 78 79 id = [request.api_key.id, date_stamp, nonce, ID_TERMINATOR].join('/') 80 81 canonical_request_hash_hex = to_hex(hash_text(canonical_request)) 82 83 string_to_sign = [ALGORITHM, time_stamp, id, canonical_request_hash_hex].join(NL) 84 85 # SAuthc1 uses a series of derived keys, formed by hashing different pieces of data 86 k_secret = to_utf8 AUTHENTICATION_SCHEME + request.api_key.secret 87 k_date = sign date_stamp, k_secret, DEFAULT_ALGORITHM 88 k_nonce = sign nonce, k_date, DEFAULT_ALGORITHM 89 k_signing = sign ID_TERMINATOR, k_nonce, DEFAULT_ALGORITHM 90 91 signature = sign to_utf8(string_to_sign), k_signing, DEFAULT_ALGORITHM 92 signature_hex = to_hex signature 93 94 authorization_header = AUTHENTICATION_SCHEME + ' ' + 95 create_name_value_pair(SAUTHC1_ID, id) + ', ' + 96 create_name_value_pair(SAUTHC1_SIGNED_HEADERS, signed_headers_string) + ', ' + 97 create_name_value_pair(SAUTHC1_SIGNATURE, signature_hex) 98 99 request.http_headers.store AUTHORIZATION_HEADER, authorization_header 100 end
to_hex(data)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 102 def to_hex(data) 103 result = '' 104 105 data.each_byte do |val| 106 hex = val.to_s(16) 107 108 if hex.length == 1 109 result << '0' 110 elsif hex.length == 8 111 hex = hex[0..6] 112 end 113 114 result << hex 115 end 116 result 117 end
Private Instance Methods
canonicalize_headers(request)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 160 def canonicalize_headers(request) 161 sorted_headers = request.http_headers.keys.sort! 162 result = '' 163 164 sorted_headers.each do |header| 165 result << header.downcase << ':' << request.http_headers[header].to_s 166 result << NL 167 end 168 result 169 end
canonicalize_query_string(request)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 121 def canonicalize_query_string(request) 122 request.to_s_query_string true 123 end
canonicalize_resource_path(resource_path)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 152 def canonicalize_resource_path(resource_path) 153 if resource_path.nil? || resource_path.empty? 154 '/' 155 else 156 encode_url resource_path, true, true 157 end 158 end
create_name_value_pair(name, value)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 148 def create_name_value_pair(name, value) 149 "#{name}=#{value}" 150 end
get_request_payload(request)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 140 def get_request_payload(request) 141 get_request_payload_without_query_params request 142 end
get_request_payload_without_query_params(request)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 144 def get_request_payload_without_query_params(request) 145 request.body || '' 146 end
get_signed_headers(request)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 171 def get_signed_headers(request) 172 sorted_headers = request.http_headers.keys.sort! 173 result = '' 174 sorted_headers.each do |header| 175 if result.empty? 176 result << header 177 else 178 result << ';' << header 179 end 180 end 181 result.downcase 182 end
hash_text(text)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 125 def hash_text(text) 126 Digest.digest DEFAULT_ALGORITHM, to_utf8(text) 127 end
sign(data, key, algorithm)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 129 def sign(data, key, algorithm) 130 digest_data = to_utf8 data 131 digest = Digest.new(algorithm) 132 HMAC.digest(digest, key, digest_data) 133 end
to_utf8(str)
click to toggle source
# File lib/stormpath-sdk/http/authc/sauthc1_signer.rb 135 def to_utf8(str) 136 # we ask for multi line UTF-8 text 137 str.scan(/./mu).join 138 end