mgomes / api_auth

HMAC authentication for Rails and HTTP Clients
MIT License
480 stars 147 forks source link

Having problems with RestClient + ApiAuth #46

Closed mikeys closed 9 years ago

mikeys commented 10 years ago

On the Client side I have the following:

ACCESS_ID = "1"
SECRET_KEY = "abcd"
request = RestClient::Request.new(url: api_url + "/something/#{app_uid}", method: :get)
ApiAuth.sign!(request, ACCESS_ID, SECRET_KEY)

On the server side (Rails) I have:

class ApiController < ActionController::Base
  SECRET_KEY = "abcd"

  before_filter :api_authenticate

  def api_authenticate
     unless ApiAuth.authentic?(request, SECRET_KEY)
       unauthorized!("Invalid api authentication.")
       return
     end
   end
end

I don't need an access id since there's only one user which is actually using this api. Can you see something I'm doing wrong? Do I need any special headers on my own?

kjg commented 10 years ago

That looks right to me. What version of api_auth are you using on the client and server? There were a few bugs with the rest adapter in 1.2.0 and 1.2.1. Please make sure you are using 1.2.2 or later on both the client and the server.

If it still isn't working on with 1.2.2 or later, try inspecting the generated canonical string on both the client and the server to see if they properly match.

You can do this by doing something along the lines of:

headers = ApiAuth::Headers.new(request)
logger.info headers.canonical_string

(make sure you do this after ApiAuth.sign!(request, ACCESS_ID, SECRET_KEY) on the client side)

mikeys commented 10 years ago

I'm using version 1.2.3, I'll try inspecting the canonical string.

kjg commented 10 years ago

Another thing to keep in mind: requests are considered no longer authentic after 15 minutes (to prevent reply attacks), so if either the client or the server aren't synced with a time server and have their times greatly differ from one another, that could also cause issues.

karl-petter commented 10 years ago

I have same problem that I cannot get ApiAuth.authentic? to return true. I'm using 1.2.5 and I have checked that the timestamp does not differ from the server time(client and server on same machine).

mikeys: did you solve it or what happened?

karl-petter commented 10 years ago

I found what is causing this: the raw_post method in ActionDispatch::Request sets RAW_POST_DATA only if raw_post is called:

def raw_post
  unless @env.include? 'RAW_POST_DATA'
    raw_post_body = body
    @env['RAW_POST_DATA'] = raw_post_body.read(content_length)
    raw_post_body.rewind if raw_post_body.respond_to?(:rewind)
  end
  @env['RAW_POST_DATA']
end

and in https://github.com/mgomes/api_auth/blob/master/lib/api_auth/request_drivers/action_controller.rb#L22 there is a check if RAW_POST_DATA is set before raw_post is called which will never be the case and thus the wrong MD5 is calculated.

If logger.info request.raw_postis added before ApiAuth.authentic?(request, @current_probe.secret) it returns true, if commented out it returns false.

mikeys commented 10 years ago

Pull request maybe? :)

karl-petter commented 10 years ago

Will give it a try

karl-petter commented 10 years ago

When I change calculated_md5 to

      def calculated_md5
        body = @request.raw_post
        md5_base64digest(body)
      end

5 of the tests will fail due to what I believe is due to the tests do not mock the request object correct. Since raw_postin ActionDispatch never checks if bodyis nil or not. But the tests fails due to body is nil and read cannot be called on nil. So its a bit bigger than just to change the calculated_md5method.

karl-petter commented 10 years ago

Now I think I managed to write correct tests as well. Pull request submitted as issue #53

mhuggins commented 9 years ago

Looks like this can be closed since #53 was accepted.