Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually login into website with Typheous

Recently I was using Mechanize for this kind of thing, but I want to use Typhoeus, which I'm already using everywhere else. I want to mimic Mechanize's behavior, the issue is that I would like to log in into a site and perform requests as logged in user. Here is generalised version of the script:

require 'rubygems'
require 'typhoeus'

GET_URL = 'http://localhost:3000'
POST_URL = "http://localhost:3000/admins/sign_in"
URL = "http://localhost:3000/dashboard"
USERNAME_FIELD = 'admin[email]'
PASSWORD_FIELD = 'admin[password]'
USERNAME = "[email protected]"
PASSWORD = "my_secret_password"

def merge_cookies_into_cookie_jar(response)                            
  if response.headers_hash['set-cookie'].instance_of? Array
    response.headers_hash['set-cookie'].each do |cookie|
      @cookie_jar << cookie.split('; ')[0]
    end
  elsif response.headers_hash['set-cookie'].instance_of? String
    @cookie_jar << response.headers_hash['set-cookie'].split('; ')[0]
  end        
end

# initialize cookie jar
@cookie_jar = []

# for server to establish me a session
response = Typhoeus::Request.get( GET_URL, :follow_location => true )
merge_cookies_into_cookie_jar(response)                                                   

# like submiting a log in form
response = Typhoeus::Request.post( POST_URL,
                                   :params => { USERNAME_FIELD => USERNAME, PASSWORD_FIELD => PASSWORD },
                                   :headers => { 'Cookie' => @cookie_jar.join('; ') }
                                 )
merge_cookies_into_cookie_jar(response)                                                   

# the page I'd like to get in a first place, 
# but not working, redirects me back to login form with 401 Unauthorized :-(                 
response = Typhoeus::Request.get( URL, 
                                  :follow_location => true,
                                  :headers => { 'Cookie' => @cookie_jar.join('; ') }
                                 )

The cookie gets sent to the server, but for some reason I'm not logged in. I tested it on two different sites (which one of them was my Rails application's administration). Any idea what am I doing wrong or maybe a better or more widely applicable solution to this problem?

like image 700
Kreeki Avatar asked Mar 21 '12 17:03

Kreeki


2 Answers

Are your sites using Rails forgery protection?

If so, when you get the form page, Rails is sending a hidden field that is a CSRF token.

It will look something like this in HTML:

<input type="hidden" name="csrf" value="abcdef">

You need to use this hidden value when you post your form:

:params => {"csrf" => "abcdef", USERNAME_FIELD => USERNAME, ...

The hidden field tells Rails that you are the person who made the request for the form page, thus you (and only you) are allowed to post.

Here are my notes on CSRF with links to more info:

http://sixarm.com/about/rails-session-csrf-token-jquery-ajaxprefilter.html

Related StackOverflow CSRF info:

http://stackoverflow.com/questions/941594/understand-rails-authenticity-token
like image 119
joelparkerhenderson Avatar answered Nov 03 '22 00:11

joelparkerhenderson


I've fixed @joelparkerhenderson's CookieJar (since it wasn't working here). Here the result:

class CookieJar < Hash
  def to_s
    self.map { |key, value| "#{key}=#{value}"}.join("; ")
  end

  def parse(cookie_strings)
    cookie_strings.each { |s|
      key, value = s.split('; ').first.split('=', 2)
      self[key] = value
    }
    self
  end
end

# Use like this:
response = Typhoeus::Request.get("http://www.example.com")
cookies = CookieJar.new.parse(response.headers_hash["Set-Cookie"])
Typhoeus::Request.get("http://www.example.com", headers: {Cookie: cookies.to_s})
like image 42
iGEL Avatar answered Nov 02 '22 23:11

iGEL