Class: Signet::OAuth1::Server
- Inherits:
-
Object
- Object
- Signet::OAuth1::Server
- Defined in:
- lib/signet/oauth_1/server.rb
Instance Attribute Summary collapse
-
#client_credential ⇒ Proc
Lookup the value from this Proc.
-
#nonce_timestamp ⇒ Proc
Lookup the value from this Proc.
-
#temporary_credential ⇒ Proc
Lookup the value from this Proc.
-
#token_credential ⇒ Proc
Lookup the value from this Proc.
-
#verifier ⇒ Proc
Lookup the value from this Proc.
Instance Method Summary collapse
-
#authenticate_resource_request(options) ⇒ Hash
Authenticates a request for a protected resource.
-
#authenticate_temporary_credential_request(options) ⇒ String
Authenticates a temporary credential request.
-
#authenticate_token_credential_request(options) ⇒ Hash
Authenticates a token credential request.
-
#call_credential_lookup(credential, key) ⇒ Signet::OAuth1::Credential
Call a credential lookup, and cast the result to a proper Credential.
-
#find_client_credential(key) ⇒ Signet::OAuth1::Credential
Find the appropriate client credential by calling the #client_credential Proc.
-
#find_temporary_credential(key) ⇒ Signet::OAuth1::Credential
Find the appropriate client credential by calling the #temporary_credential Proc.
-
#find_token_credential(key) ⇒ Signet::OAuth1::Credential
Find the appropriate client credential by calling the #token_credential Proc.
-
#find_verifier(verifier) ⇒ Boolean
Determine if the verifier is valid by calling the Proc in #verifier.
-
#initialize(options) ⇒ Server
constructor
Creates an OAuth 1.0 server.
-
#request_realm(options) ⇒ String
The Authorization realm(see RFC 2617) of the request.
-
#safe_equals?(left, right) ⇒ Boolean
Constant time string comparison.
-
#validate_nonce_timestamp(nonce, timestamp) ⇒ Boolean
Determine if the supplied nonce/timestamp pair is valid by calling the #nonce_timestamp Proc.
-
#verify_auth_header_components(headers) ⇒ Hash
Validate and normalize the HTTP Authorization header.
-
#verify_request_components(options) ⇒ Hash
Validate and normalize the components from an HTTP request.
Constructor Details
#initialize(options) ⇒ Server
Creates an OAuth 1.0 server.
52 53 54 55 56 57 |
# File 'lib/signet/oauth_1/server.rb', line 52 def initialize = {} [:nonce_timestamp, :client_credential, :token_credential, :temporary_credential, :verifier].each do |attr| instance_variable_set "@#{attr}", [attr] end end |
Instance Attribute Details
#client_credential ⇒ Proc
Returns lookup the value from this Proc.
27 28 29 |
# File 'lib/signet/oauth_1/server.rb', line 27 def client_credential @client_credential end |
#nonce_timestamp ⇒ Proc
Returns lookup the value from this Proc.
27 28 29 |
# File 'lib/signet/oauth_1/server.rb', line 27 def @nonce_timestamp end |
#temporary_credential ⇒ Proc
Returns lookup the value from this Proc.
27 28 29 |
# File 'lib/signet/oauth_1/server.rb', line 27 def temporary_credential @temporary_credential end |
#token_credential ⇒ Proc
Returns lookup the value from this Proc.
27 28 29 |
# File 'lib/signet/oauth_1/server.rb', line 27 def token_credential @token_credential end |
#verifier ⇒ Proc
Returns lookup the value from this Proc.
27 28 29 |
# File 'lib/signet/oauth_1/server.rb', line 27 def verifier @verifier end |
Instance Method Details
#authenticate_resource_request(options) ⇒ Hash
Authenticates a request for a protected resource.
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 |
# File 'lib/signet/oauth_1/server.rb', line 380 def authenticate_resource_request = {} verifications = { client_credential: lambda do |_x| ::Signet::OAuth1::Credential.new("Client credential key", "Client credential secret") end } unless [:two_legged] == true verifications.update( token_credential: lambda do |_x| ::Signet::OAuth1::Credential.new("Token credential key", "Token credential secret") end ) end # Make sure all required state is set verifications.each do |(key, _value)| raise ArgumentError, "#{key} was not set." unless send key end request_components = if [:request] verify_request_components( request: [:request], adapter: [:adapter] ) else verify_request_components( method: [:method], uri: [:uri], headers: [:headers], body: [:body] ) end method = request_components[:method] uri = request_components[:uri] headers = request_components[:headers] body = request_components[:body] if !body.is_a?(String) && body.respond_to?(:each) # Just in case we get a chunked body merged_body = StringIO.new body.each do |chunk| merged_body.write chunk end body = merged_body.string end raise TypeError, "Expected String, got #{body.class}." unless body.is_a? String media_type = nil headers.each do |(header, value)| media_type = value.gsub(/^([^;]+)(;.*?)?$/, '\1') if header.casecmp("Content-Type").zero? end auth_hash = verify_auth_header_components headers auth_token = auth_hash["oauth_token"] unless [:two_legged] return nil if auth_token.nil? return nil unless (token_credential = find_token_credential auth_token) token_credential_secret = token_credential.secret if token_credential end return nil unless (client_credential = find_client_credential auth_hash["oauth_consumer_key"]) return nil unless (auth_hash["oauth_nonce"], auth_hash["oauth_timestamp"]) if method == ("POST" || "PUT") && media_type == "application/x-www-form-urlencoded" request_components[:body] = body post_parameters = Addressable::URI.form_unencode body post_parameters.each { |param| param[1] = "" if param[1].nil? } # If the auth header doesn't have the same params as the body, it # can't have been signed correctly(5849#3.4.1.3) unless post_parameters.sort == auth_hash.reject { |k, _v| k.index "oauth_" }.to_a.sort raise MalformedAuthorizationError, "Request is of type application/x-www-form-urlencoded " \ "but Authentication header did not include form values" end end client_credential_secret = client_credential.secret if client_credential computed_signature = ::Signet::OAuth1.sign_parameters( method, uri, # Realm isn't used, and will throw the signature off. auth_hash.reject { |k, _v| k == "realm" }.to_a, client_credential_secret, token_credential_secret ) return nil unless safe_equals? computed_signature, auth_hash["oauth_signature"] { client_credential: client_credential, token_credential: token_credential, realm: auth_hash["realm"] } end |
#authenticate_temporary_credential_request(options) ⇒ String
Authenticates a temporary credential request. If no oauth_callback is
present in the request, oob
will be returned.
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
# File 'lib/signet/oauth_1/server.rb', line 241 def authenticate_temporary_credential_request = {} verifications = { client_credential: lambda { |_x| ::Signet::OAuth1::Credential.new("Client credential key", "Client credential secret") } } verifications.each do |(key, _value)| raise ArgumentError, "#{key} was not set." unless send key end request_components = if [:request] verify_request_components( request: [:request], adapter: [:adapter] ) else verify_request_components( method: [:method], uri: [:uri], headers: [:headers] ) end # body should be blank; we don't care in any case. method = request_components[:method] uri = request_components[:uri] headers = request_components[:headers] auth_hash = verify_auth_header_components headers return false unless (client_credential = find_client_credential( auth_hash["oauth_consumer_key"] )) return false unless (auth_hash["oauth_nonce"], auth_hash["oauth_timestamp"]) client_credential_secret = client_credential.secret if client_credential computed_signature = ::Signet::OAuth1.sign_parameters( method, uri, # Realm isn't used, and will throw the signature off. auth_hash.reject { |k, _v| k == "realm" }.to_a, client_credential_secret, nil ) if safe_equals? computed_signature, auth_hash["oauth_signature"] if auth_hash.fetch("oauth_callback", "oob").empty? "oob" else auth_hash.fetch "oauth_callback" end else false end end |
#authenticate_token_credential_request(options) ⇒ Hash
Authenticates a token credential request.
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/signet/oauth_1/server.rb', line 308 def authenticate_token_credential_request = {} verifications = { client_credential: lambda { |_x| ::Signet::OAuth1::Credential.new("Client credential key", "Client credential secret") }, temporary_credential: lambda { |_x| ::Signet::OAuth1::Credential.new("Temporary credential key", "Temporary credential secret") }, verifier: ->(_x) { "Verifier" } } verifications.each do |(key, _value)| raise ArgumentError, "#{key} was not set." unless send key end request_components = if [:request] verify_request_components( request: [:request], adapter: [:adapter] ) else verify_request_components( method: [:method], uri: [:uri], headers: [:headers], body: [:body] ) end # body should be blank; we don't care in any case. method = request_components[:method] uri = request_components[:uri] headers = request_components[:headers] auth_hash = verify_auth_header_components headers return false unless ( client_credential = find_client_credential auth_hash["oauth_consumer_key"] ) return false unless ( temporary_credential = find_temporary_credential auth_hash["oauth_token"] ) return false unless ( auth_hash["oauth_nonce"], auth_hash["oauth_timestamp"] ) computed_signature = ::Signet::OAuth1.sign_parameters( method, uri, # Realm isn't used, and will throw the signature off. auth_hash.reject { |k, _v| k == "realm" }.to_a, client_credential.secret, temporary_credential.secret ) return nil unless safe_equals? computed_signature, auth_hash["oauth_signature"] { client_credential: client_credential, temporary_credential: temporary_credential, realm: auth_hash["realm"] } end |
#call_credential_lookup(credential, key) ⇒ Signet::OAuth1::Credential
Call a credential lookup, and cast the result to a proper Credential.
118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/signet/oauth_1/server.rb', line 118 def call_credential_lookup credential, key cred = credential.call key if credential.respond_to? :call return nil if cred.nil? return nil unless cred.respond_to?(:to_str) || cred.respond_to?(:to_ary) || cred.respond_to?(:to_hash) if cred.instance_of? ::Signet::OAuth1::Credential cred else ::Signet::OAuth1::Credential.new cred end end |
#find_client_credential(key) ⇒ Signet::OAuth1::Credential
Find the appropriate client credential by calling the #client_credential Proc.
87 88 89 |
# File 'lib/signet/oauth_1/server.rb', line 87 def find_client_credential key call_credential_lookup @client_credential, key end |
#find_temporary_credential(key) ⇒ Signet::OAuth1::Credential
Find the appropriate client credential by calling the #temporary_credential Proc.
107 108 109 |
# File 'lib/signet/oauth_1/server.rb', line 107 def find_temporary_credential key call_credential_lookup @temporary_credential, key end |
#find_token_credential(key) ⇒ Signet::OAuth1::Credential
Find the appropriate client credential by calling the #token_credential Proc.
97 98 99 |
# File 'lib/signet/oauth_1/server.rb', line 97 def find_token_credential key call_credential_lookup @token_credential, key end |
#find_verifier(verifier) ⇒ Boolean
Determine if the verifier is valid by calling the Proc in #verifier.
138 139 140 141 |
# File 'lib/signet/oauth_1/server.rb', line 138 def find_verifier verifier verified = @verifier.call verifier if @verifier.respond_to? :call verified ? true : false end |
#request_realm(options) ⇒ String
Returns The Authorization realm(see RFC 2617) of the request.
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/signet/oauth_1/server.rb', line 208 def request_realm = {} request_components = if [:request] verify_request_components( request: [:request], adapter: [:adapter] ) else verify_request_components( method: [:method], uri: [:uri], headers: [:headers], body: [:body] ) end auth_header = request_components[:headers].find { |x| x[0] == "Authorization" } raise MalformedAuthorizationError, "Authorization header is missing" if auth_header.nil? || auth_header[1] == "" auth_hash = ::Signet::OAuth1.(auth_header[1]).to_h.transform_keys(&:downcase) auth_hash["realm"] end |
#safe_equals?(left, right) ⇒ Boolean
Constant time string comparison.
60 61 62 63 64 |
# File 'lib/signet/oauth_1/server.rb', line 60 def safe_equals? left, right check = left.bytesize ^ right.bytesize left.bytes.zip(right.bytes) { |x, y| check |= x ^ y.to_i } check.zero? end |
#validate_nonce_timestamp(nonce, timestamp) ⇒ Boolean
Determine if the supplied nonce/timestamp pair is valid by calling the #nonce_timestamp Proc.
73 74 75 76 77 78 79 |
# File 'lib/signet/oauth_1/server.rb', line 73 def nonce, if @nonce_timestamp.respond_to? :call nonce = @nonce_timestamp.call nonce, end nonce ? true : false end |
#verify_auth_header_components(headers) ⇒ Hash
Validate and normalize the HTTP Authorization header.
193 194 195 196 197 |
# File 'lib/signet/oauth_1/server.rb', line 193 def verify_auth_header_components headers auth_header = headers.find { |x| x[0] == "Authorization" } raise MalformedAuthorizationError, "Authorization header is missing" if auth_header.nil? || auth_header[1] == "" ::Signet::OAuth1.(auth_header[1]).to_h.transform_keys(&:downcase) end |
#verify_request_components(options) ⇒ Hash
Validate and normalize the components from an HTTP request.
153 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 182 183 184 185 186 |
# File 'lib/signet/oauth_1/server.rb', line 153 def verify_request_components = {} if [:request] if [:request].is_a? Faraday::Request request = [:request] elsif [:adapter] request = [:adapter].adapt_request [:request] end method = request.http_method uri = request.path headers = request.headers body = request.body else method = [:method] || :get uri = [:uri] headers = [:headers] || [] body = [:body] || "" end headers = headers.to_a if headers.is_a? Hash method = method.to_s.upcase request_components = { method: method, uri: uri, headers: headers } # Verify that we have all the pieces required to validate the HTTP request request_components.each do |(key, value)| raise ArgumentError, "Missing :#{key} parameter." unless value end request_components[:body] = body request_components end |