Upload doesn't work in remote server: Unsupported Command Exception - selenium

We have a complicated Java/Selenium framework at my job and I am having a hard time uploading an image wit sendKeys() in a remote server. The code works locally, but not on our Selenoid server. I've done lots of research and found out this was stemming from W3C standards but I'm assuming it is fixed now.
Here is a piece of our code:
protected void sendKeysUploadPhoto(By by, String path) {
executeScript("arguments[0].style.display = 'block';", driver.findElement(by));
((RemoteWebDriver) driver).setFileDetector(new LocalFileDetector());
try {
driver.findElement(by).clear();
driver.findElement(by).sendKeys(path);
} catch (WebDriverException wex) {
Logger.fail("WebDriver Exception: ", wex);
}
}
I get the following error for the sendKeys() step:
org.openqa.selenium.UnsupportedCommandException: unknown command: unknown command: session/efe1d404f94de0019443b240970829d1/se/file

Related

javafx 16 WebEngine Exception "SSL Handshake failed"

I am porting an android app to javaFX for windows deployment, i'm new to javaFX and desktop deployment, but not so new to java.
The app contains a WebView that loads a url obtained from a server via Json (so could be essentially anything).
openJDK 14 , openJfx 16, intellij idea ultimate 2021.1.3, gradle: plugins: org.beryx.jlink & org.openjfx.javafxplugin
This works fine when I run the program in development and testing (on a windows 10 machine), but when it is packaged and deployed on a windows machine (any windows 10 so far) I get an "java.lang.Throwable: SSL handshake failed" exception when the page is loaded.
This is the stack trace:
[ERROR] 2021-07-14 14:13:53.737 [JavaFX Application Thread] MediaElementWeb - WebView Failed:
java.lang.Throwable: SSL handshake failed
at javafx.scene.web.WebEngine$LoadWorker.describeError(WebEngine.java:1440) ~[javafx.web:?]
at javafx.scene.web.WebEngine$LoadWorker.dispatchLoadEvent(WebEngine.java:1379) ~[javafx.web:?]
at javafx.scene.web.WebEngine$PageLoadListener.dispatchLoadEvent(WebEngine.java:1240) ~[javafx.web:?]
at com.sun.webkit.WebPage.fireLoadEvent(WebPage.java:2524) ~[javafx.web:?]
at com.sun.webkit.WebPage.fwkFireLoadEvent(WebPage.java:2369) ~[javafx.web:?]
at com.sun.webkit.network.URLLoaderBase.twkDidFail(Native Method) ~[javafx.web:?]
at com.sun.webkit.network.URLLoader.notifyDidFail(URLLoader.java:799) ~[javafx.web:?]
at com.sun.webkit.network.URLLoader.lambda$didFail$6(URLLoader.java:782) ~[javafx.web:?]
at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:447) ~[javafx.graphics:?]
at java.security.AccessController.doPrivileged(AccessController.java:391) ~[?:?]
at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:446) ~[javafx.graphics:?]
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96) ~[javafx.graphics:?]
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) ~[javafx.graphics:?]
at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174) ~[javafx.graphics:?]
at java.lang.Thread.run(Thread.java:832) [?:?]
The problem is not specific to any particular certificate, so I know it is not a problem specifically with the certificate generally, tested with many sites. and I ONLY get this error in the deployed app.
The page is being loaded in a standard way: WebEngine.load(targetURL);
I am capturing the error with:
tNode.getEngine().getLoadWorker().stateProperty().addListener((o, ov, nv) -> {
if (nv == Worker.State.FAILED) {
logger.error("WebView Failed: ", tNode.getEngine().getLoadWorker().getException());
}
});
I have searched and tried solutions offered by other people that seem to have experienced similar errors, such as:
Setting a trust manager before calling load(page):
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
logger.error("SSLContext Failed: ", e);
}
(No errors or effect here)
and
settings the JVMarg on the deployment
-Dcom.sun.webkit.useHTTP2Loader=false
Which I can see has the effect of "com.sun.webkit.network.URLLoader" being shown in the stack trace instead of http2 (as was suggested on other threads) but also no change here either.
Has anyone any thoughts (bearing in mind I'm a novice at java desktop deployment) at what the issue can be and how to resolve it?
Many thanks
Update:
Trace from console on deployed test https://pastebin.com/R5SkR4w1
First few rows:
javax.net.ssl|WARNING|2C|URL-Loader-1|2021-07-15 10:46:45.991 BST|SignatureScheme.java:295|Signature algorithm, ed25519, is not supported by the underlying providers
javax.net.ssl|WARNING|2C|URL-Loader-1|2021-07-15 10:46:45.992 BST|SignatureScheme.java:295|Signature algorithm, ed448, is not supported by the underlying providers
javax.net.ssl|WARNING|2C|URL-Loader-1|2021-07-15 10:46:45.995 BST|NamedGroup.java:297|No AlgorithmParameters for x25519 (
"throwable" : {
java.security.NoSuchAlgorithmException: Algorithm x25519 not available
at java.base/javax.crypto.KeyAgreement.getInstance(KeyAgreement.java:192)
at java.base/sun.security.ssl.NamedGroup.<init>(NamedGroup.java:286)
at java.base/sun.security.ssl.NamedGroup.<clinit>(NamedGroup.java:184)
at java.base/sun.security.ssl.SignatureScheme.<clinit>(SignatureScheme.java:59)
at java.base/sun.security.ssl.SSLSessionImpl.<clinit>(SSLSessionImpl.java:823)
at java.base/sun.security.ssl.TransportContext.<init>(TransportContext.java:133)
at java.base/sun.security.ssl.TransportContext.<init>(TransportContext.java:103)
at java.base/sun.security.ssl.SSLSocketImpl.<init>(SSLSocketImpl.java:111)
at java.base/sun.security.ssl.SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:72)
at java.base/sun.net.www.protocol.https.HttpsClient.createSocket(HttpsClient.java:413)
at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:162)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474)
at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569)
at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:265)
at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:372)
at ...
Managed to solve this with helpful comments from #slaw about a suggestion I had tried initially, but ultimately not implemented correctly, and help from #dave_thompson_085 with how to provide extra debugging info. So the resolution, and a few tips for people in the same boat:
1. The solution:
The Badass Jlink Plugin for gradle on Intellij IDEA, for Java 14 and JavaFX 16 was not correctly merging the security provider classes.
This was resolved by adding "jdk.crypto.ec" to the merged modules list.
2. Adding the module manually
The org.beryx.jlink plugin (2.24.0) is really complex and powerful, so it was a struggle to work out how to do it with my implementation.
I tried many combinations, but the following code did it for me in my build.gradle:
jlink {
//... Other jlink \ jpackage stuff
mergedModule {
additive = true
requires 'jdk.crypto.ec'
}
//... Other jlink \ jpackage stuff
}
3. Debugging packaged java binary for windows
Some Jlink config changes that helped along the way.
jlink {
//..
jpackage {
//..
imageOptions = [
"--win-console"
]
}
//..
launcher {
jvmArgs = ['-Dcom.sun.webkit.useHTTP2Loader=false','-Djavax.net.debug=ssl:handshake']
}
}
--win-console opens a console window when you start your program so you can see the logging out put
-Djavax.net.debug=ssl:handshake gives more information about the SSL process and handshaking so you can see what is happening.

MPI cannot execute with machine file or hosts from SSH using JSch exec channel [duplicate]

I have a piece of code which connects to a Unix server and executes commands.
I have been trying with simple commands and they work fine.
I am able to login and get the output of the commands.
I need to run an Ab-initio graph through Java.
I am using the air sandbox run graph command for this.
It runs fine, when I login using SSH client and run the command. I am able to run the graph. However, when I try to run the command through Java it gives me a "air not found" error.
Is there any kind of limit on what kind of Unix commands JSch supports?
Any idea why I'm not able to run the command through my Java code?
Here's the code:
public static void connect(){
try{
JSch jsch=new JSch();
String host="*****";
String user="*****";
String config =
"Host foo\n"+
" User "+user+"\n"+
" Hostname "+host+"\n";
ConfigRepository configRepository =
com.jcraft.jsch.OpenSSHConfig.parse(config);
jsch.setConfigRepository(configRepository);
Session session=jsch.getSession("foo");
String passwd ="*****";
session.setPassword(passwd);
UserInfo ui = new MyUserInfo(){
public boolean promptYesNo(String message){
int foo = 0;
return foo==0;
}
};
session.setUserInfo(ui);
session.connect();
String command="air sandbox run <graph-path>";
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command);
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
channel.connect();
byte[] tmp=new byte[1024];
while(true){
while(in.available()>0){
int i=in.read(tmp, 0, 1024);
if(i<0)break;
page_message=new String(tmp, 0, i);
System.out.print(page_message);
}
if(channel.isClosed()){
if(in.available()>0) continue;
System.out.println("exit-status: "+channel.getExitStatus());
break;
}
try{Thread.sleep(1000);}catch(Exception ee){}
}
channel.disconnect();
session.disconnect();
}
catch(Exception e){
System.out.println(e);
}
}
public static void main(String arg[]){
connect();
}
public String return_message(){
String ret_message=page_message;
return ret_message;
}
public static abstract class MyUserInfo
implements UserInfo, UIKeyboardInteractive{
public String getPassword(){ return null; }
public boolean promptYesNo(String str){ return false; }
public String getPassphrase(){ return null; }
public boolean promptPassphrase(String message){ return false; }
public boolean promptPassword(String message){ return false; }
public void showMessage(String message){ }
public String[] promptKeyboardInteractive(String destination,
String name,
String instruction,
String[] prompt,
boolean[] echo){
return null;
}
}
The "exec" channel in the JSch (rightfully) does not allocate a pseudo terminal (PTY) for the session. As a consequence a different set of startup scripts is (might be) sourced (particularly for non-interactive sessions, .bash_profile is not sourced). And/or different branches in the scripts are taken, based on absence/presence of the TERM environment variable. So the environment might differ from the interactive session, you use with your SSH client.
So, in your case, the PATH is probably set differently; and consequently the air executable cannot be found.
To verify that this is the root cause, disable the pseudo terminal allocation in your SSH client. For example in PuTTY, it's Connection > SSH > TTY > Don't allocate a pseudo terminal. Then, go to Connection > SSH > Remote command and enter your air ... command. Check Session > Close window on exit > Never and open the session. You should get the same "air not found" error.
Ways to fix this, in preference order:
Fix the command not to rely on a specific environment. Use a full path to air in the command. E.g.:
/bin/air sandbox run <graph-path>
If you do not know the full path, on common *nix systems, you can use which air command in your interactive SSH session.
Fix your startup scripts to set the PATH the same for both interactive and non-interactive sessions.
Try running the script explicitly via login shell (use --login switch with common *nix shells):
bash --login -c "air sandbox run sandbox run <graph-path>"
If the command itself relies on a specific environment setup and you cannot fix the startup scripts, you can change the environment in the command itself. Syntax for that depends on the remote system and/or the shell. In common *nix systems, this works:
String command="PATH=\"$PATH;/path/to/air\" && air sandbox run <graph-path>";
Another (not recommended) approach is to force the pseudo terminal allocation for the "exec" channel using the .setPty method:
Channel channel = session.openChannel("exec");
((ChannelExec)channel).setPty(true);
Using the pseudo terminal to automate a command execution can bring you nasty side effects. See for example Is there a simple way to get rid of junk values that come when you SSH using Python's Paramiko library and fetch output from CLI of a remote machine?
For a similar issues, see
Certain Unix commands fail with "... not found", when executed through Java using JSch even with setPty enabled
Commands executed using JSch behaves differently than in SSH terminal (bypasses confirm prompt message of "yes/"no")
JSch: Is there a way to expose user environment variables to "exec" channel?
Command (.4gl) executed with SSH.NET SshClient.RunCommand fails with "No such file or directory"
you could try to find out where "air" resides with
whereis air
and then use this outcome.
something like
/usr/bin/air sandbox run graph
You can use an ~/.ssh/environment file to set your AB_HOME and PATH variables.

Issue with SSH.NET UWP

I am having issues using SSh.net in a UWP App. This app will run on Win10.
I get the following error:
An attempt was made to access a socket in a way forbidden by its access permissions. I have looked online and there is no one actually dealing with this.The exact same code works in a standard Desktop App (WPF)
The key is the key string and I had to replace \r with \n because the PrivateKeyFile creation gave an error message and I tracked this down to carriage return placed instead of new line (by the textbox).
key = key.Replace("\r", "\n");
PrivateKeyFile(stringToStream(key));
client = new SshClient(ip, port, username, pkf);
if (!client.IsConnected)
{
try
{
client.Connect();
connected = true;
}
catch (Exception ex)
{
exception = ex.Message.ToString();
connected = false;
}
}
Finally resolved this issue - Look here: An attempt was made to access a socket in a way forbidden by its access permissions
Go down to the following line:
If you're getting the same error in Windows 8 development, it could be that you haven't enabled access over Private Networks in your Package.appxmanifest file:
Select the Private Networks (Client & Server) option as shown on the image.
Click here for the image

Phantomjs caching issue

I'm following This to get a website's dynamic content inside an MVC application.
I've received the data once or twice, but after that I'm getting an error -
ApplicationCache driver.ApplicationCache threw an exception of type
'System.InvalidOperationException' OpenQA.Selenium.Html5.IApplicationCache {System.InvalidOperationException}
Message:
Driver does not support manipulating the HTML5 application cache. Use the HasApplicationCache property to test for the driver capability
The error that you're encountering is due to the fact that PhantomJS can't find anything in the appCache and hence throws this exception. Please see the underlying code here, which states
public IApplicationCache ApplicationCache
{
get
{
if (this.appCache == null)
{
throw new InvalidOperationException("Driver does not support manipulating the HTML5 application cache. Use the HasApplicationCache property to test for the driver capability");
}
return this.appCache;
}
}
And the reason, why this is coming to be null is that currently PhantomJS doesn't supports this app caching. The default capabilities for this is set to false in the PhantomJS code . You can see this here, which mentions
_defaultCapabilities{
"applicationCacheEnabled" : false,
}

OperaDriver getting timed out waiting for opera launcher

I am trying to integrate OperaDriver for Java (ver. 0.11) into my test suite. Here's the code snippet:
DesiredCapabilities operaCapabilities = DesiredCapabilities.opera();
operaCapabilities.setCapability("opera.host", "127.0.0.1");
operaCapabilities.setCapability("opera.port", 7001);
operaCapabilities.setCapability("opera.profile", "");
webDriver = new OperaDriver(operaCapabilities);
The above code snippet fails to return a webdriver reference with a SocketTimeoutException Timeout waiting for launcher to connect on port 29392. I can see that the browser (opera ver. 11.62) is launched with speed dial tab loaded, and the launcher is also executing, but somehow OperaDriver seems to be unable to connect.
The exception I see is:
com.opera.core.systems.runner.OperaRunnerException: Timeout waiting for launcher to connect on port 29392
at com.opera.core.systems.runner.launcher.OperaLauncherRunner.<init>(OperaLauncherRunner.java:159)
at com.opera.core.systems.OperaDriver.<init>(OperaDriver.java:322)
at com.opera.core.systems.OperaDriver.<init>(OperaDriver.java:224)
at com.test.TestMain.main(TestMain.java:31)
Caused by: java.net.SocketTimeoutException: Accept timed out
at java.net.PlainSocketImpl.socketAccept(Native Method)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:408)
at java.net.ServerSocket.implAccept(ServerSocket.java:462)
at java.net.ServerSocket.accept(ServerSocket.java:430)
at com.opera.core.systems.runner.launcher.OperaLauncherRunner.<init>
(OperaLauncherRunner.java:140)
... 3 more
I have tried -1 for "opera.port" and also 7001, but the capability setting seems to be ignored, since it is attempting to connect with a random port each time. I have my firewalls temporarily turned off as well.
First, let's isolate the exception being hit here:
private final int launcherPort = PortProber.findFreePort();
...
public OperaLauncherRunner(OperaSettings s) {
super(s);
// Locate the bundled launcher from OperaLaunchers project and copy it to its default location
// on users system if it's not there or outdated
bundledLauncher =
OperaLaunchers.class.getClassLoader().getResource("launchers/" + launcherNameForOS());
if (bundledLauncher == null) {
throw new OperaRunnerException("Not able to locate bundled launcher: " + bundledLauncher);
}
if (settings.getLauncher() == launcherDefaultLocation() &&
(!settings.getLauncher().exists() || isLauncherOutdated(settings.getLauncher()))) {
extractLauncher(bundledLauncher, settings.getLauncher());
}
makeLauncherExecutable(settings.getLauncher());
// Find an available Opera if present
if (settings.getBinary() == null) {
settings.setBinary(new File(OperaPaths.operaPath()));
}
// Create list of arguments for launcher binary
ImmutableList<String> arguments = buildArguments();
logger.config("launcher arguments: " + arguments);
try {
launcherRunner = new OperaLauncherBinary(settings.getLauncher().getPath(),
arguments.toArray(new String[]{}));
} catch (IOException e) {
throw new OperaRunnerException("Unable to start launcher: " + e.getMessage());
}
logger.fine("Waiting for launcher connection on port " + launcherPort);
try {
// Setup listener server
ServerSocket listenerServer = new ServerSocket(launcherPort);
listenerServer.setSoTimeout((int) OperaIntervals.LAUNCHER_TIMEOUT.getValue());
// Try to connect
launcherProtocol = new OperaLauncherProtocol(listenerServer.accept());
// We did it!
logger.fine("Connected with launcher on port " + launcherPort);
listenerServer.close();
// Do the handshake!
LauncherHandshakeRequest.Builder request = LauncherHandshakeRequest.newBuilder();
ResponseEncapsulation res = launcherProtocol.sendRequest(
MessageType.MSG_HELLO, request.build().toByteArray());
// Are we happy?
if (res.isSuccess()) {
logger.finer("Got launcher handshake: " + res.getResponse().toString());
} else {
throw new OperaRunnerException(
"Did not get launcher handshake: " + res.getResponse().toString());
}
} catch (SocketTimeoutException e) {
throw new OperaRunnerException("Timeout waiting for launcher to connect on port " +
launcherPort, e);
} catch (IOException e) {
throw new OperaRunnerException("Unable to listen to launcher port " + launcherPort, e);
}
}
We learn a few things from this code:
private final int launcherPort =PortProber.findFreePort(); sets our launcherPort, and this variable is uniquely used to establish the connect.
Indeed, your configuration of opera.port is completely ignored in this block. That seems less than desirable, and it may indeed be a bug or an unexpected regression.
Once we establish the local port, a connection attempt is made immediately:
// Setup listener server
ServerSocket listenerServer = new ServerSocket(launcherPort);
listenerServer.setSoTimeout((int) OperaIntervals.LAUNCHER_TIMEOUT.getValue());
// Try to connect
launcherProtocol = new OperaLauncherProtocol(listenerServer.accept());
So, we have a tightly coupled binding to the local server. The port is ignored in favor of a free one on your system, but simultaneously, it should always be able to use that port.
If your firewall is indeed not preventing the connection (as you've discussed), let's assume you desire Opera to be connected to programmatically, instead of manually opening the connection.
According to some documentation, opera.host carries the following caveat:
opera.host (String) The host Opera should connect to. Unless you're
starting Opera manually you won't need this.
(Additional emphasis mine.)
Needless to say, the caveat concerns me. Likewise, despite its apparent inapplicability:
opera.port (Integer) The port to Opera should connect to. 0 = Random,
-1 = Opera default (for use with Opera > 12).
(Additional emphasis mine.)
In short: try running your application as illustrated here:
DesiredCapabilities capabilities = new DesiredCapabilities.opera();
capabilities.setCapability("opera.binary", "/path/to/your/opera");
capabilities.setCapability("opera.log.level", "CONFIG");
WebDriver driver = new OperaDriver(capabilities);
If this doesn't work, something else is wrong, either with your project or with your current Opera binary, be it version-related or otherwise.