|
import org.apache.commons.lang3.StringEscapeUtils; |
|
|
|
import java.io.File; |
|
import java.io.FileOutputStream; |
|
import java.nio.charset.StandardCharsets; |
|
import java.util.Base64; |
|
import java.util.zip.ZipEntry; |
|
import java.util.zip.ZipOutputStream; |
|
|
|
/** |
|
* This class can be used to generate a minimal browser extension that |
|
* will force Chrome to send out an Authorize header on every request. |
|
* |
|
* This is the only reliable way that has worked for me with Selenium 3 |
|
* to use basic auth. |
|
* |
|
* Alternatives to this approach: |
|
* - Add the basic auth credentials to the url (does not work in recent versions of FF and Chrome) |
|
* - Using a proxy that adds the header (LittleProxy). This should probably work, |
|
* but https with proxies can be a pain in the ass. Also the last release of LittleProxy is from 2017. |
|
* Launching an extra server for every test would also unnecessarily increase the complexity of tests. |
|
* - Using selenium as the user would by filling out the username, password text boxes and clicking on the login button. |
|
* This works, but with login forms adding captcha and other deterrents to stop bots can be unreliable. |
|
* - Use a cookie for authentication and add that to the selenium browser. This works great if you can get |
|
* a valid session cookie. |
|
* |
|
* Useful links: |
|
* - https://stackoverflow.com/a/35293026 |
|
* - https://devopsqa.wordpress.com/2018/08/05/handle-basic-authentication-in-selenium-for-chrome-browser/ |
|
* - https://stackoverflow.com/a/27936481 |
|
* - https://sqa.stackexchange.com/questions/12892/how-to-send-basic-authentication-headers-in-selenium |
|
*/ |
|
public class SeleniumChromeAuthExtensionBuilder { |
|
private String headerJsCode = ""; |
|
private String baseUrl = "<all_urls>"; |
|
|
|
/** |
|
* Add a header to every request. |
|
* |
|
* @param name The name of the header to add. |
|
* @param value The value of the header. |
|
*/ |
|
public SeleniumChromeAuthExtensionBuilder withStaticHeader(String name, String value) { |
|
String nameEscaped = StringEscapeUtils.escapeEcmaScript(name); |
|
String valueEscaped = StringEscapeUtils.escapeEcmaScript(value); |
|
headerJsCode += "headers.push({name: \"" + nameEscaped + "\", value: \"" + valueEscaped + "\"});\n"; |
|
return this; |
|
} |
|
|
|
/** |
|
* Add basic auth credentials to every requests. |
|
* |
|
* @param username The username for authentication |
|
* @param password The password for authentication |
|
*/ |
|
public SeleniumChromeAuthExtensionBuilder withBasicAuth(String username, String password) { |
|
String encodeUserPass = Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8)); |
|
return withStaticHeader("Authorization", "Basic " + encodeUserPass); |
|
} |
|
|
|
/** |
|
* If you set a base url only requests to urls starting with this base url will be modified. |
|
* Can contain wildcards (*). The special value <all_urls> matches all urls (default). |
|
*/ |
|
public SeleniumChromeAuthExtensionBuilder withBaseUrl(String baseUrl) { |
|
this.baseUrl = baseUrl; |
|
return this; |
|
} |
|
|
|
/** |
|
* Builds the extension as a zip archive. |
|
* Please delete this file after installing it. |
|
* |
|
* @return The generated zip file |
|
*/ |
|
public File build() throws Exception { |
|
File tempFile = File.createTempFile("selenium-chrome-auth-", ".tmp.zip"); |
|
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(tempFile)); |
|
|
|
// Add manifest.json |
|
{ |
|
ZipEntry e = new ZipEntry("manifest.json"); |
|
out.putNextEntry(e); |
|
out.write(generateManifestJson().getBytes(StandardCharsets.UTF_8)); |
|
out.closeEntry(); |
|
} |
|
|
|
// Add background.js |
|
{ |
|
ZipEntry e = new ZipEntry("background.js"); |
|
out.putNextEntry(e); |
|
out.write(generateBackroundJs().getBytes(StandardCharsets.UTF_8)); |
|
out.closeEntry(); |
|
} |
|
|
|
out.close(); |
|
|
|
return tempFile; |
|
} |
|
|
|
private String generateBackroundJs() { |
|
return "chrome.webRequest.onBeforeSendHeaders.addListener(\n" + |
|
" function(e) {\n" + |
|
" var headers = e.requestHeaders;\n" + |
|
headerJsCode + |
|
" return { requestHeaders: headers };\n" + |
|
" },\n" + |
|
" {urls: [\"" + StringEscapeUtils.escapeEcmaScript(baseUrl) + "\"]},\n" + |
|
" ['blocking', 'requestHeaders' , 'extraHeaders']\n" + |
|
");"; |
|
} |
|
|
|
private String generateManifestJson() { |
|
return "{\n" + |
|
" \"manifest_version\": 2,\n" + |
|
" \"name\": \"Authentication for selenium tests\",\n" + |
|
" \"version\": \"1.0.0\",\n" + |
|
" \"permissions\": [\"<all_urls>\", \"webRequest\", \"webRequestBlocking\"],\n" + |
|
" \"background\": {\n" + |
|
" \"scripts\": [\"background.js\"]\n" + |
|
" }\n" + |
|
" }"; |
|
} |
|
} |
Hi @saai32,
The code should work fine without admin rights. But if your organization has disabled loading extensions in Chrome as it appears to be in your case then this code won't work. Unfortunately I don't know of any way to bypass this restriction in selenium.
Greetings,
Sebastian