I am trying to login to a website and redirect to a secured page from a rails action. My code looks something like this.
def redirect_to_external
agent = Mechanize.new
page = agent.get('http://example.com/home.asp')
login_form = page.form_with(:name => "loginForm")
login_form.login = 'username'
login_form.password = 'password'
agent.submit(login_form)
#cookies = agent.cookie_jar.store.map {|i| i} #need to store the cookie with a specific in browser
redirect_to('http://example.com/admin.asp') #page behind password protection
end
Login is successful in the background, but actual redirection to the admin page is asking again for authentication in the browser, as the session cookie is not stored in the browser. Tried storing the cookies from cookie_jar
, but couldn't find the exact way to do that. Can someone help me in this?
I struggled with this one for a long time! The other answers on StackOverflow didn't exactly address how to cache the cookies and retrieve them, so I'm combining my experience with the other answers I've read, into one solution here.
(See:
Rails 3 - Log into another site and keep cookie in session
Store login session cookie in browser using ruby mechanize
Get Mechanize to handle cookies from an arbitrary POST (to log into a website programmatically)
keep mechanize page over request boundaries
).
I used this solution to create a custom OAuth2.0 for a website that doesn't support the real OAuth2.0.
The user gave me credentials for the other site. I passed them onto the site via Mechanize in the create method of my Sessions controller and immediately destroyed them (I don't want to touch someone else's secure stuff as much as possible. That's why this all takes place under an SSL as well).
That means my Mechanize instance with the cookies I need will get destroyed once I redirect anywhere else in my app. For example, in my app, I next redirected to the index
method of my Sessions Controller
. If you're new to rails you might think the same instance variables (like the mechanize agent with those cookies) would be available from create
to index
, but that's wrong, each redirect will destroy everything! (basically)
So before the redirect, you need to store the cookies. The only way to store something like this between requests is via the cache, and the cache doesn't like to store the whole mechanize instance. Instead you need to store serialized cookies. The only trouble is, Mechanize doesn't have a method for outputting its cookies as a string, it can only save them as a file. What to do?
StringIO to the rescue! You can essentially fake a file with StringIO. After all that talking, here's the code:
@agent = Mechanize.new
#handle the sign in stuff
stringio = StringIO.new
@agent.cookie_jar.save(stringio, session: true)
cookies = stringio.string
session[:login_cookies] = cookies
Note that I passed session: true
to the save method of cookie_jar
. Without that parameter, the cookie will only save non-session cookies.
So now our session cache has a string that has all of the cookies from mechanize. To get them back after a redirect you'll need StringIO again:
@agent = Mechanize.new
cookies = session[:login_cookies]
@agent.cookie_jar.load StringIO.new(cookies)
And voila! Your new agent is ready to act just like the old one.
Please refer following code.This create a code within a block this will maintain authentication,
def redirect_to_external
@agent = Mechanize.new
@agent.get('http://example.com/home.asp') do | home_page | # Need to pass the others requests into the block
login_form = home_page.form_with(:name => "loginForm")
login_form.login = 'username'
login_form.password = 'password'
@agent.submit(login_form)
#cookies = agent.cookie_jar.store.map {|i| i} #need to store the cookie with a specific in browser
@agent.get('http://example.com/admin.asp') #page behind password protection
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With