11

I'm using webdriver.Firefox and I'm trying to send the following custom header:

self.headers = { 'Authorization': 'Basic %s' % b64encode(bytes(self.args.user + ':' + self.args.password, "utf-8")).decode("ascii") }

in the following way:

self.driver.get(self.base_url + "/", headers=self.headers)

which is similar way as shown here, but I'm guessing it's using completely different driver.

However I've the error:

TypeError: get() got an unexpected keyword argument 'headers'

I've checked the old issue #2047: How to add a header to a request?, but it's closed as duplicate of another Won't Fix issue.

Is there any way of simply test the site using Selenium which is behind Basic Authentication?

One suggestion is to use proxy, however I don't believe such simple functionality doesn't exist.

Any suggestions?

2
  • Are you testing the authentication or are you testing functionality behind a secured login? May 4 '15 at 10:57
  • @NielsvanReijmersdal I'm trying to test the site it-self. I've tested and actually it works when I'm using http://user:pass@host as host.
    – kenorb
    May 4 '15 at 11:24
14

I've tested using format http://user:pass@host and it works.

So in Python (in setUp() of MyClass(unittest.TestCase) class) this should look like:

self.base_url = "http://user:pass@host"

In Java based on #34 at code.google, the following code should work as well:

public void login(String username, String password){
    WebDriver driver = getDriver();
    String URL = "http:// + username + ":" + password + "@" + "link";
    driver.get(URL);
    driver.manage().window().maximize();
}

or:

FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("network.http.phishy-userpass-length", 255);
driver = new FirefoxDriver(profile);
driver.get(http://username:password@www.basicauthprotected.com/);

or:

FirefoxProfile profile = new FirefoxProfile();
profile.setPreference("network.http.phishy-userpass-length", 255);
profile.setPreference("network.automatic-ntlm-auth.trusted-uris", "<host>");
driver = new FirefoxDriver();
selenium = new WebDriverBackedSelenium(driver, "http://<user>:<password>@<host>");

or:

selenium.start("addCustomRequestHeader=true");
selenium.windowMaximize();
selenium.addCustomRequestHeader( "Authorization","Basic "+"YWRpZGFzOmFkaWRhczEyMyM=" );

or eventually by sending keys using SendKeys():

SendKeys("myUser");
SendKeys("{TAB}");
SendKeys("MyPassword");
SendKeys("~"); // Enter

or by using Alert API.

See also: Basic Authentication for FirefoxDriver, ChromeDriver and IEdriver?

For Chrome, please follow: How to override basic authentication in selenium2 chrome driver?

However each one of above has some downsides, so the feature needs to be more portable and there are some plans to do that (see: #453 at GitHub).

2
  • I tried self.driver.addCustomRequestHeader and self.driver.add_custom_request_header and neither work on Selenium 2.0 (Webdriver). Is this method only available on Selenium RC which is no longer supported? github.com/SeleniumHQ/selenium-google-code-issue-archive/issues/…
    – Cynic
    Aug 15 '17 at 17:25
  • 3
    The format user:pass in the URL is now a deprecated standard, and as such should not be used.
    – Frank H.
    Apr 13 '18 at 6:54
2

I would like to add one more point:

If your application is making AJAX requests then this solution will not work directly. The HTTP authentication prompt will be shown. In order to bypass that what can be done is from the test case directly fire the URL for which the Ajax request will be sent by the application later. This will create the HTTP authorization header which will be carried in all subsequent requests including the Ajax requests and the authentication prompt will not be shown thus enabling smooth execution of the test case.

0

What I did for FirefoxDriver is this approach (this only uses for the base url, not for any further requests to other sites which may require basic authentification):

  • configuring Firefox not to ask/warn about logging in with basic auth
  • Passing user and password with the URL: http://user:pass@host.tld

See here or my pull request.

2
  • 1
    The format user:pass in the URL is now a deprecated standard, and as such should not be used
    – Frank H.
    Apr 13 '18 at 6:55
  • Yes, unfortunately it does not work any more, and there is for now, no other way to achieve it. Apr 14 '18 at 8:25
0

Here is a solution that will work in recent versions of Google Chrome with recent versions of selenium. It generates a tiny chrome extension (~30 lines of code) that will add the headers for you. I've created a Java builder class to easily generate the extension. Here is how you can use it:

// Add basic auth header with a chrome extension on every request
File authExtension = new SeleniumChromeAuthExtensionBuilder()
    .withBasicAuth("Ali Baba", "Open sesame")
    .withBaseUrl("https://example.org/*")
    .build();

try {
    ChromeOptions chromeOptions = new ChromeOptions();
    chromeOptions = chromeOptions.addExtensions(authExtension);
    webDriver = new ChromeDriver(chromeOptions);
} finally {
    authExtension.delete();
}

And that's all. Chrome will then use basic auth on every sub url of https://example.org.

You can get the builder class here: https://gist.github.com/gellweiler/ab0ecb67afb8063a1d276c116bfb26e2.

0

This problem is still relevant in 2021. However the solution from accepted answer is no longer valid.

The general solution now is to set up proxy that would serve the headers for your test. In python that could be Proxy Py tool that can be run directly from your test code.

You can implement a plugin that would be handing requests from your browser by adding corresponding headers:

from proxy.http.proxy import HttpProxyBasePlugin
from proxy.http.parser import HttpParser
from typing import Optional
import base64


class BasicAuthorizationPlugin(HttpProxyBasePlugin):
    """Modifies request headers."""

    def before_upstream_connection(
            self, request: HttpParser) -> Optional[HttpParser]:
        return request

    def handle_client_request(
            self, request: HttpParser) -> Optional[HttpParser]:
        basic_auth_header = 'Basic ' + base64.b64encode('webelement:click'.encode('utf-8')).decode('utf-8')
        request.add_header('Authorization'.encode('utf-8'), basic_auth_header.encode('utf-8'))
        return request

    def on_upstream_connection_close(self) -> None:
        pass

    def handle_upstream_chunk(self, chunk: memoryview) -> memoryview:
        return chunk

One more thing you need to consider is that you cannot easily modify HTTPs traffic. However Proxy Py allows to do that.

You can find complete solution in Four simple steps to add custom HTTP headers in Selenium Webdriver tests in Python

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.