oauth-xx / oauth-ruby

OAuth for Ruby
MIT License
668 stars 267 forks source link

OAuth::RequestProxy::UnknownRequestType (ActionDispatch::Request): #131

Closed Lukahm closed 2 years ago

Lukahm commented 8 years ago

I did update for rails app form 4 to 5 recently.

Then IMS::LTI::ToolProvider is not working properly.

Here is the code:

private_key = res[:body]["private_key"]
provider = IMS::LTI::ToolProvider.new(public_key, private_key, params.to_unsafe_h)
unless provider.valid_request?(request)
  if provider.context_student? || provider.institution_student?
    return render :participant_wait_for_activity
  else
    return render :invalid_key
  end
end

I got an error when provider.valid_request?(request) is excuted.

Here is the error: OAuth::RequestProxy::UnknownRequestType (ActionDispatch::Request):

ch1ago commented 8 years ago

@lhmmry I understand this code is working on your machine.

But if I open IRB and put your code, it will say res is nil

Could you please add sample values for the variables that replicate this error so I can properly evaluate it?

Thanks for reporting :)

ch1ago commented 8 years ago

note to self:

Lukahm commented 8 years ago

@thejamespinto Thanks for your reply. I used random private key and public key. Therefore res can be ignored in this case.

I just noticed that ActionDispatch::Request is not inherited from Rack::Request anymore. It is inherited from Object in Rails 5. I thought this change could be the reason why I got this error OAuth::RequestProxy::UnknownRequestType (ActionDispatch::Request):

Then I had a look at the source code of validator method in IMS::LTI::RequestValidator Module

def valid_request?(request, handle_error=true)
  begin
    @oauth_signature_validator = OAuth::Signature.build(request, :consumer_secret => @consumer_secret)
    @oauth_signature_validator.verify() or raise OAuth::Unauthorized
    true
  rescue OAuth::Signature::UnknownSignatureMethod, OAuth::Unauthorized
    if handle_error
      false
    else
      raise $!
    end
  end
end

The error could be related to OAuth::Signature.build method, so I went to oauth gem; In oauth-0.4.7/lib/oauth/signature/base.rb line 35, I found this: raise TypeError unless request.kind_of?(OAuth::RequestProxy::Base)

Can you have a look? Thx

ch1ago commented 8 years ago

Again @lhmmry,

please fill in the follow template show me how to replicate the error it takes a lot of time to draw these scenarios, please, optimize my evaluation.

gem 'rails', '5.0.0'
gem 'oauth', '0.5.1'
require 'rails'
require 'oauth'

x = OAuth::SomeClass.new
x.some_method
Lukahm commented 8 years ago

Because I'm using the ims-lti gem which depends on oauth (~> 0.4.5). I think you may need to use this particular version of oauth to replicate the error.

ims-lti (1.1.11)
      builder
      oauth (~> 0.4.5)

Here is the scenario in my app:

gem 'rails', '5.0.0'
gem 'oauth', '0.4.5'
require 'rails'
require 'oauth'

@oauth_signature_validator = OAuth::Signature.build initialize(request, options = {}, &block)

I found the initialize method in oauth-0.4.7/lib/oauth/signature/base.rb

def initialize(request, options = {}, &block)
      raise TypeError unless request.kind_of?(OAuth::RequestProxy::Base)
      @request = request
      @options = options

      ## consumer secret was determined beforehand

      @consumer_secret = options[:consumer].secret if options[:consumer]

      # presence of :consumer_secret option will override any Consumer that's provided
      @consumer_secret = options[:consumer_secret] if options[:consumer_secret]

      ## token secret was determined beforehand

      @token_secret = options[:token].secret if options[:token]

      # presence of :token_secret option will override any Token that's provided
      @token_secret = options[:token_secret] if options[:token_secret]

      # override secrets based on the values returned from the block (if any)
      if block_given?
        # consumer secret and token secret need to be looked up based on pieces of the request
        secrets = yield block.arity == 1 ? request : [token, consumer_key, nonce, request.timestamp]
        if secrets.is_a?(Array) && secrets.size == 2
          @token_secret = secrets[0]
          @consumer_secret = secrets[1]
        end
      end
    end    

I got the TypeError after my code excuted.

ch1ago commented 8 years ago

I get a different error.

I would love to help, but I cannot lose time trying to reconstruct your scenario. That's the part you have to do for me.

I have already spent some time trying to simulate that in Rails 5 and the error simply does not happen to me.

image

bracken commented 8 years ago

I don't have the answer, but I think I found the problem.

Rails 4.2 looks like this: (https://github.com/rails/rails/blob/4-2-stable/actionpack/lib/action_dispatch/http/request.rb)

module ActionDispatch
  class Request < Rack::Request

And Rails 5.0 looks like this: (https://github.com/rails/rails/blob/5-0-stable/actionpack/lib/action_dispatch/http/request.rb)

module ActionDispatch
  class Request

For Rails 3/4 and Sinatra to make it use the correct request proxy you do:

require 'oauth/request_proxy/rack_request'

So in Rails 5 it is no longer a Rack::Request which means the OAuth Signature part doesn't know how to get info out of that ActionDispatch::Request object.

ch1ago commented 8 years ago

@bracken could you please implement those changes in this in-progress PR? https://github.com/oauth-xx/oauth-ruby/pull/132

wjordan commented 8 years ago

I don't think any PR is needed for this library to support Rails 5, since a request proxy supporting ActionDispatch::Request already exists. To support Rails 5's ActionDispatch::Request you just need to require the different request proxy- change the line from:

require 'oauth/request_proxy/rack_request'

to:

require 'oauth/request_proxy/action_controller_request'

This worked fine in my tests.

Lukahm commented 8 years ago

Thanks for all the replies.

Hi @wjordan,

I've tried to fix it in this way, but I got an error during testing---LoadError: no such file to load -- action_controller/request.

Also I found Rails 4.0 deprecated ActionController::Request in favor of ActionDispatch::Request in Rails upgrade documentation.

Do you know how to fix the loadError? thx

wjordan commented 8 years ago

@lhmmry you need to upgrade to oauth v0.5.x since it already contains a fix for the LoadError issue (Shopify/oauth-ruby#2, specifically this change). See my comment in instructure/ims-lti#89 as well as PR instructure/ims-lti#90 for the dependency change needed to that gem.

tristantao commented 8 years ago

@lhmmry also, make sure you followed the LTI setup req:

To validate the OAuth signatures you need to require the appropriate request proxy for your application. For example:

For a Rails 5 (and 2.3) app:

require 'oauth/request_proxy/action_controller_request'

For a Sinatra or a Rails 3 or 4 app:

require 'oauth/request_proxy/rack_request'

You also need to explicitly enable OAuth 1 support in the environment.rb or an initializer:

OAUTH_10_SUPPORT = true

As a quick debugging note, if you forget that step, you'll get an error like:

OAuth::RequestProxy::UnknownRequestType

pboling commented 2 years ago

Closing as this appears to be fixed.