views:

411

answers:

3

Hi,

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 authentication dialog box by using:

browser.goto('http://admin:[email protected]')

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:[email protected]')

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...

A: 

Did you read this?

http://wiki.openqa.org/display/WTR/Basic+Authentication

Željko Filipin
Zeljko, doesn't autoit work only on windows?
Narayan Raman
@Narayan Raman: I think autoit works only on windows. I did not have the time to look at all examples at the page, do all of them use autoit?
Željko Filipin
@Željko: You made me go through it again :). Except the first comment all the others use autoit. The first comment looks like an IE only solution.
Narayan Raman
@Narayan Raman: I thought we had Firefox solution too.
Željko Filipin
A: 

Hi lotharsmash,

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

Narayan Raman
A: 

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
cdwilson
I have added a link to this post to http://wiki.openqa.org/display/WTR/Basic+Authentication, would you add more detail there?
Željko Filipin
Sorry, didn't see your comment till now. I updated the page.
cdwilson