How to do Basic Authentication using FireWatir on Ubuntu Linux?
I'm trying to use FireWatir (1.6.5) to access a site using Basic Authentication and I've been unable to find a solution that works on Firefox in Linux. Does FireWatir 1.6.5 support Basic Authentication on Linux? I've been searching the web for 2 days and can't get a straight answer anywhere as to how to do this.
The only thread I found that seemed helpful was this one ( http://groups.google.com/group/watir-general/browse_thread/thread/d8ab9a177d282ce4/fc1bf2319fb387d8?lnk=gst&q=basic+authentication#fc1bf2319fb387d8).
Aedorn Varanis says " Angrez's fork had the solution so I'm using that now. Thanks Angrez, works perfectly!", but he doesn't mention what he did to get things working.
Initially I tried to bypass the a开发者_Go百科uthentication dialog box by using:
browser.goto('http://admin:password@172.20.1.1')
However, this generates a "Confirm" dialog which says:
"You are about to log in to the site "172.20.1.1" with the username "admin"." [Cancel, OK]
This dialog blocks, and the goto call won't return until I click "OK".
Then I tried adding:
browser.startClicker("ok") browser.goto('http://admin:password@172.20.1.1')
But this ALSO generates the same "Confirm" dialog.
I tested out the startClicker functionality using the unit test /var/ lib/gems/1.8/gems/firewatir-1.6.5/unittests/html/JavascriptClick.html and it worked fine, which makes me think that using the startClicker method is NOT the correct way to take care of the Confirm dialog.
Anybody else found a way to get Basic Auth to work, or how to click the OK on the confirm dialog? I'm at my wits end...
This may be a long ugly workaround, and may also violate the simplicity of watir's philosophy, but since you are at your wits end ...
1) Sahi (http://sahi.co.in/) handles 401 authentication dialogs by converting them into regular web pages.
2) Sahi's proxy needs to be running, and you point your browser to use Sahi's proxy.
3) You can then navigate to your page and just use watir/firewatir to enter username password into a converted 401 authentication web page, (like a regular form).
You would incur the extra load of the proxy, but Sahi is fairly well behaved so you should be able to make it work.
You could post here or on Sahi's forums if you need further assistance.
Hope that helps. -Narayan
With help from Aedorn Varanis I've got things working on Firefox in Linux.
Aedorn sent me a "logon" method which issues a jssh command that checks for an "Authentication Required" dialog and if it exists, fills in the username/password and submits the dialog.
I've copied and pasted what he sent me below:
You use a method that looks like this:
def logon(username, password, wait=3)
jssh_command = "var length = getWindows().length; var win;var found=false; for(var i = 0; i < length; i++) { win = getWindows()[i]; if(win.document.title == \"Authentication Required\") { found = true; break; }} if(found) { var jsdocument = win.document; var dialog = jsdocument.getElementsByTagName(\"dialog\")[0];"
jssh_command << " jsdocument.getElementsByTagName(\"textbox\")[0].value = \"#{username}\";"
jssh_command << " jsdocument.getElementsByTagName(\"textbox\")[1].value = \"#{password}\";"
jssh_command << " dialog.getButton(\"accept\").click(); }\n"
sleep(wait)
$jssh_socket.send(jssh_command,0)
read_socket()
wait()
end
Then you can call it within its own thread just before going to the site with the login requirement:
Thread.new { logon(user, pass) } @ff.goto("http://some_url.com") sleep 3
Increase the wait and sleep time if the page takes awhile to load. If your main process tries to run while the command is being sent through the JSSH socket, it will stall and sit there forever until killed. Also, there's no real way to detect if the authentication window comes up. That means you need to make sure it always works the same way every time, or it, too, causes problems. Finally, the method will always have to be in another thread, because once the authentication window comes up, it stops all other processing until it goes away. Other than that, it works.
From this, I was able to subclass the FireWatir::Firefox class with a new Browser class which supports a "credentials=" method just like the Celerity::Browser does. So, just like using celerity, you can do:
require 'browser'
browser = Browser.new
browser.credentials = 'user:pass'
browser.goto('http://some.basic.auth.url')
This will automatically fill in the Basic Auth dialog and log you into the site.
I've posted the contents of my browser.rb file below (notice this works in ruby+firewatir and jruby+celerity in linux):
ENGINE = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
if ENGINE == 'ruby'
require 'firewatir'
class Browser < FireWatir::Firefox
def initialize(options={})
super(options)
@username = nil
@password = nil
end
def credentials=(string)
username, password = string.split(":")
if username.nil? or password.nil?
raise "Invalid credentials: #{string})"
else
@username = username
@password = password
end
end
def goto(url, wait=3)
if @username.nil? and @password.nil?
return super(url)
else
t = Thread.new { logon(@username, @password, wait) }
result = super(url)
t.join
return result
end
end
private
def logon(username, password, wait)
jssh_command = "
var length = getWindows().length;
var win;
var found = false;
for (var i = 0; i < length; i++) {
win = getWindows()[i];
if(win.document.title == \"Authentication Required\") {
found = true;
break;
}
}
if (found) {
var jsdocument = win.document;
var dialog = jsdocument.getElementsByTagName(\"dialog\")[0];
jsdocument.getElementsByTagName(\"textbox\")[0].value = \"#{username}\";
jsdocument.getElementsByTagName(\"textbox\")[1].value = \"#{password}\";
dialog.getButton(\"accept\").click();
}
\n"
sleep(wait)
$jssh_socket.send(jssh_command,0)
read_socket()
end
end
elsif ENGINE == 'jruby'
require 'celerity'
class Browser < Celerity::Browser; end
else
raise "Ruby ENGINE '#{ENGINE}' not supported."
end
I battled long and hard with this issue until today. Apparently i overlooked the answer many times because it didn't look plausible. However, the solution lies in Firefox's "network.http.phishy-userpass-length" profile configuration. If FireWatir allows you to modify your firefox instance Profile, then you can give the "network.http.phishy-userpass-length" a value of 255 which should make that dialog disappear. check http://kb.mozillazine.org/Network.http.phishy-userpass-length for more details.
Note: With Capybara + selenium-webdriver in Ruby, I did;
require 'capybara'
require 'selenium-webdriver'
profile = Selenium::WebDriver::Firefox::Profile.new
profile['network.http.phishy-userpass-length'] = 255
Capybara::Selenium::Driver.new(:profile => profile, :browser => :firefox)
精彩评论