|
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" + |
|
" }"; |
|
} |
|
} |
this is what I was looking for , but then I do not have admin right is there a way I could define location to Unpack ? getting loading of unpack