2

We have a new web app constructed by another developer. My job was to implement a backend API for other programs to use to exchange XML data with the database. It was going pretty well, until the main app implemented devise to authenticate users. I figured I'd be able to tweak the curl command to log in then submit/request data, but it isn't going very well. I'm trying things like

curl --cookie-jar ~/Desktop/cjar --data "user[login]=<username>" --data "user[password]=<pwd>" --data "commit=Sign in" localhost:3000/users/sign_in

followed by

curl --cookie ~/Desktop/cjar --data "<root_node></root_node>" localhost:3000/my_update_method

my latest error message is

WARNING: Can't verify CSRF token authenticity
Completed 401 Unauthorized in 1ms

I guess that's better than the redirection messages I was getting, but I'm still not close to knowing what's going on.

I've found a few related posts that make me think this is partly related to devise, and partly related to automatic authentication done by Rails. When I look at the info being passed by the web page, I see authenticity_token and utf8 params that I don't know how to construct for my curl command.

I can keep trying stuff, but I'm new to both curl and authentication, so I'm sort of shooting in the dark, and hoping that someone can save me some time. I guess my questions are:

  1. Can this be done?
  2. Should this be done? If not, what other options do I have?
  3. One post suggested a way around the authentication, but is is possible for only the curl commands to require a login/pwd, but bypass any other validation, without affecting the main web app?

UPDATE 1:

Thanks for all the help, I appreciate it. The response to the first curl command (listed above) is now just a redirection to the login page, so logging in doesn't seem to take. Does anyone have any suggestions about where to start debugging that? Nothing is ever getting into the application, so there's no logging there to look at. Here's the content of the cookie, if it means anything to anyone:

# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_localhost FALSE   /   FALSE   0   _glow_session   BAh7B0kiCmZsYXNoBjoGRUZvOiVBY3Rpb25EaXNwxhc2g6OkZsYXNoSGFzaAk6CkB1c2VkbzoIU2V0BjoKQGhhc2h7ADoMQGNsb3NlZEY6DUBmbGFzaGVzewY6C25vdGljZUkiHFNpZ25lZCBpbiBzdWNjZXNzZnVsbHkuBjsAVDoJQG5vdzBJIg9zZXNzaW9uX2lkBjsARkkiJTIwODc1Y2VjM2ViNzlmZDE3ZjA4ZjVmMDAxNWMxMDU4BjsAVA%3D%3D--d90722b6da386630b33f57902447b440f30d0b2a

I've added skip_before_filter :verify_authenticity_token to the controller that handles the api requests, and that eliminated the error I was seeing before.

UPDATE 2:

After some troubleshooting and debugging, I think I may actually be getting logged in okay, but when I execute the second curl, the development.log file shows

Started POST "/upsert_experiment" for 127.0.0.1 at 2013-10-16 12:14:12 -0500
Processing by WebServiceController#upsert_experiment as */*
  Parameters: {"experiment_xml"=>"<experiment></experiment>"}
Completed 401 Unauthorized in 1ms

which leads me to think that the authorization is still the problem.

UPDATE 3:

I think the problem is just that skip_before_filter :verify_authenticity_token isn't working.

I have

class ApplicationController < ActionController::Base
  rescue_from DeviseLdapAuthenticatable::LdapException do |exception|
    render :text => exception, :status => 500
  end
  protect_from_forgery
  before_filter :authenticate_user!
end

and

class WebServiceController < ApplicationController
  skip_before_filter :verify_authenticity_token
  ...
end

With this setup, I get "Completed 401 Unauthorized in 1ms". If I comment out the protect_from_forgery line in the superclass, it just works, so the forgery protection is definitely the problem. I just don't know how to solve it.

whognu
  • 439
  • 1
  • 5
  • 15

3 Answers3

2

You're missing a CSRF token. This is to prevent cross site request forgery.

NM Pennypacker
  • 6,704
  • 11
  • 36
  • 38
  • I'm not sure what you mean by making the request through the Rails app instead. How would another application access the Rails app if not through curl? – whognu Oct 15 '13 at 21:12
  • 1
    Edited original answer. Sorry, whognu, I just misunderstood the question. – NM Pennypacker Oct 16 '13 at 12:23
2

CSRF stands for Cross Site Request Forgery and is a security protection you can read more about here. Essentially rails generates a random token included in the form rendered on the page and it expects to get that token back on form submit. You don't need this protection for an api, but it is important for the web app side. See this question for methods to disable the CSRF token.

One approach you might take is to use the token_authenticable Devise module and authenticate your requests with auth_token=#{token}, then skip CSRF protection if an auth token is present.

Community
  • 1
  • 1
Alex.Bullard
  • 5,533
  • 2
  • 25
  • 32
2

Rails CSRF protection is preventing you from making this request.

From rails documentation

CSRF protection automatically include a security token, calculated from the current session and the server-side secret, in all forms and Ajax requests generated by Rails. You won't need the secret, if you use CookieStorage as session storage. If the security token doesn't match what was expected, the session will be reset. Note: In Rails versions prior to 3.0.4, this raised an ActionController::InvalidAuthenticityToken error.

If you want to skip it, add this line to your controller

skip_before_action :verify_authenticity_token, :only => ["your_update_action"]
usha
  • 28,973
  • 5
  • 72
  • 93
  • This looks promising! Does it still require the curl command to specify login/password? Also, what's the best way to specify multiple exempted actions? – whognu Oct 15 '13 at 21:11
  • You still have to specify username/password. `skip_before_action :verify_authenticity_token, :except => ["action1", "action2"]` – usha Oct 15 '13 at 21:40
  • I'm getting this error:

    Routing Error

    undefined method skip_before_action for ApplicationController:Class

    Try running rake routes for more information on available routes.

    I have this line in the application controller: `skip_before_action :verify_authenticity_token, :except => [:upsert_experiment, :upsert_workflow]` I also tried it with both method names in quotes, instead of as symbols, but I got the same error. I'll look at the documentation in the morning, but if you see an obvious problem, feel free to let me know. Thanks again.
    – whognu Oct 15 '13 at 22:45
  • Try `skip_before_filter` – usha Oct 16 '13 at 00:29
  • That removed the error, but I still can't log in (see edit in OP). – whognu Oct 16 '13 at 14:47