【问题标题】:How Can I Tell Controller Specs to Use the Signed OAuth Request我如何告诉控制器规范使用签名的 OAuth 请求
【发布时间】:2012-02-27 12:10:31
【问题描述】:

我正在为我的 api 构建一个 2-Legged OAuth 提供程序。一切都已正确连接,我可以从 rails 控制台进行签名调用。我遇到的问题是我无法将 OAuth 集成到 controller_spec 中。

这是我的服务器上的工作调用示例:

coneybeare $ rails c test
Loading test environment (Rails 3.2.0)
rails test: main 
>> consumer = OAuth::Consumer.new("one_key", "MyString", :site => [REDACTED])
# => #<OAuth::Consumer:0x007f9d01252268 @key="one_key", @secret="MyString", @options={:signature_method=>"HMAC-SHA1", :request_token_path=>"/oauth/request_token", :authorize_path=>"/oauth/authorize", :access_token_path=>"/oauth/access_token", :proxy=>nil, :scheme=>:header, :http_method=>:post, :oauth_version=>"1.0", :site=>[REDACTED]}>  

ruby: main 
>> req = consumer.create_signed_request(:get, "/api/v1/client_applications.json", nil)
# => #<Net::HTTP::Get GET>  

ruby: main 
>> res = Net::HTTP.start([REDACTED]) {|http| http.request(req) }
# => #<Net::HTTPOK 200 OK readbody=true>  

ruby: main 
>> puts res.body
{"client_applications":[{"id":119059960,"name":"FooBar1","url":"http://test1.com"},{"id":504489040,"name":"FooBar2","url":"http://test2.com"}]}
# => nil  

这是我在控制器测试中所做的:

require 'oauth/client/action_controller_request'
describe Api::ClientApplicationsController do
  include OAuthControllerSpecHelper
  …
  … 
    it "assigns all client_applications as @client_applications" do
      consumer = OAuth::Consumer.new("one_key", "MyString", :site => [REDACTED])
      ActionController::TestRequest.use_oauth=true
      @request.configure_oauth(consumer)
      @request.apply_oauth!
      puts "request.env['Authorization'] = #{@request.env['Authorization']}"
      get :index, {:api_version => 'v1', :format => :json}
      response.should be_success # Just this for now until I can get authorization, then proper controller testing
    end
end

该测试的输出:

request.env['Authorization'] = OAuth oauth_consumer_key="one_key", oauth_nonce="gzAbvBSWyFtIYKfuokMAdu6VnH39EHeXvebbH2qUtE", oauth_signature="juBkJo5K0WLu9mYqHVC3Ar%2FATUs%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1328474800", oauth_version="1.0"
1) Api::ClientApplicationsController GET index assigns all client_applications as @client_applications
   Failure/Error: response.should be_success
     expected success? to return true, got false

以及来自 rails 日志的相应服务器调用:

Processing by Api::ClientApplicationsController#index as JSON
  Parameters: {"api_version"=>1}
  Rendered text template (0.0ms)
Filter chain halted as #<OAuth::Controllers::ApplicationControllerMethods::Filter:0x007f85a51a8858 @options={:interactive=>false, :strategies=>:two_legged}, @strategies=[:two_legged]> rendered or redirected
Completed 401 Unauthorized in 15ms (Views: 14.1ms | ActiveRecord: 0.0ms)
   (0.2ms)  ROLLBACK

我只是不知道为什么它不起作用:/我犯了一个明显的错误吗?

【问题讨论】:

  • 听起来它并不是真正的控制器规范。您是否尝试将其作为请求规范?
  • 这是一个控制器规格。该示例仅被简化为基本要素。如果您是正确的,并且这种类型的测试应该进入请求规范,那么当我的控制器受到 OAuth 保护时,我还应该如何测试它?
  • 这些天我正在测试一个 API,在控制器规范中,我只是在标题中传递了正确的值。对不起,我真的不知道 OAuth。我担心你的情况是create_signed_request 没有得到预期的结果。您是否尝试调试它?只是想:你可以在测试时绕过一些before_filters
  • 我拥有的唯一过滤器是来自 oauth-plugin gem 的 oauthenticate 方法。 create_signed_request 是一个正在工作的,它是控制器测试不是。我认为可能发生的情况是 apply_oauth! 在调用 get :index 之前完成,导致路径不在签名中。我可能必须围绕get 调用创建自己的包装器,以找出路径是什么,设置它,对其进行签名,然后调用get 的超级实现。不过,这似乎是很多不必要的工作......
  • 好吧,我试着解释一下,我怀疑create_signed_request 是否达到了它的预期,因为没有在控制器规范中运行任何服务器。如果您只是想测试控制器的其余部分,请绕过before_filter。如果您想测试身份验证,请尝试在请求规范中。

标签: ruby-on-rails ruby-on-rails-3 oauth rspec 2-legged


【解决方案1】:

如果您想在请求规范中对其进行测试,并且实际上需要在没有存根的情况下进行测试,您可以构建一个 OAuth 使用者并签署这样的请求:

    @access_token = FactoryGirl.create :access_token
    @consumer = OAuth::Consumer.new(@access_token.app.key, @access_token.app.secret, :site => "http://www.example.com/")
    @path = "/path/to/request"
    @request = @consumer.create_signed_request(:get, @path, OAuth::AccessToken.new(@consumer, @access_token.token, @access_token.secret))
    get @path, nil, { 'HTTP_AUTHORIZATION' => @request.get_fields('authorization').first }

【讨论】:

    【解决方案2】:

    事实证明,测试我的控制器的最佳方法也是最简单的。我没有尝试签署每个测试以使控制器获得正确的信息(确实属于请求规范而不是控制器规范的信息),我发现我可以手动向控制器提供所需的信息。

    为此,我只需要存根 2 个方法:

    fixtures :client_applications
    before(:each) do
      @client_application1 = client_applications(:client_application1)
      Api::ClientApplicationsController::Authenticator.any_instance.stub(:allow?).and_return(true)
      controller.stub(:client_application).and_return(@client_application1)
    end
    

    存根allow? 方法导致机架身份验证被愚弄以为它已通过身份验证。 allow? 也设置了 client_application 基于凭据,所以我也必须存根。现在身份验证已经结束,我可以正确地测试我的控制器了。

    【讨论】:

      【解决方案3】:

      我会看看 Omniauth 测试助手是如何工作的,特别是这些文件:https://github.com/intridea/omniauth/tree/master/lib/omniauth/test。有关如何设置的想法,请参阅他们的 wiki page on integration testing。我意识到您正在构建一个提供程序,而不是一个客户端,但这可能是一个很好的起点。另外,正如一些评论者已经说过的,我不知道您是否可以通过控制器测试来做到这一点;您可能需要请求或集成测试来完全模拟机架环境。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-25
        • 1970-01-01
        • 1970-01-01
        • 2012-01-30
        相关资源
        最近更新 更多