Android : Jetty's HttpClient not working with Https - java

I am working on an Android project in which I am trying to connect HttpClient to an Https endpoint. For this, I found out that I had to add an SSLContextFactory while instantiating. After doing that, when I run the code, I get the an error mentioned below.
How can I setup HttpClient to work with https?
Error log :
java.lang.NoSuchMethodError: No virtual method setEndpointIdentificationAlgorithm(Ljava/lang/String;)V in class Ljavax/net/ssl/SSLParameters; or its super classes (declaration of 'javax.net.ssl.SSLParameters' appears in /system/framework/core-libart.jar)
at org.eclipse.jetty.util.ssl.SslContextFactory.customize(SslContextFactory.java:1382)
at org.eclipse.jetty.util.ssl.SslContextFactory.newSSLEngine
at org.eclipse.jetty.util.ssl.SslContextFactory.doStart(SslContextFactory.java:309)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start
at org.eclipse.jetty.util.component.ContainerLifeCycle.start
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart
at org.eclipse.jetty.client.HttpClient.doStart(HttpClient.java:229)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start
Affected code :
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import org.cometd.bayeux.Channel;
import org.cometd.bayeux.Message;
import org.cometd.bayeux.client.ClientSessionChannel;
import org.cometd.client.BayeuxClient;
import org.cometd.client.transport.ClientTransport;
import org.cometd.client.transport.LongPollingTransport;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import java.net.HttpCookie;
public class ConsoleChatClient extends Service {
private final IBinder mBinder = new LocalBinder();
BayeuxClient bayeuxClient = StaticRestTemplate.getClient();
HttpClient httpClient = new HttpClient(new SslContextFactory());
private void performConnection() {
try {
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setTrustAll(true);
HttpClient localClient = new HttpClient(sslContextFactory);
localClient.start();
ClientTransport clientTransport = new LongPollingTransport(null, localClient);
bayeuxClient = new BayeuxClient(defaultURL, clientTransport);
// Below for use with Spring-Security post-login.
bayeuxClient.putCookie(new HttpCookie("JSESSIONID", StaticRestTemplate.jsessionid));
bayeuxClient.getChannel(Channel.META_HANDSHAKE).addListener(new InitializerListener());
bayeuxClient.getChannel(Channel.META_CONNECT).addListener(new ConnectionListener());
bayeuxClient.handshake();
StaticRestTemplate.setClient(bayeuxClient);
StaticRestTemplate.setHttpClient(localClient);
httpClient = localClient;
boolean success = bayeuxClient.waitFor(4000, BayeuxClient.State.CONNECTED);
if (!success) {
System.err.printf("Could not handshake for ConsoleChatClient with server at %s%n", defaultURL);
} else {
System.err.printf("Handhskare ConsoleChatClient complete");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

Related

Java Function Timeout after 20 seconds

I'm getting started with a lambda function for java and I am working through the HelloWorldFunction that was generated by sam init
When running the sample I get only timeouts.
What should I check? What have I missed?
$ sam local invoke HelloWorldFunction --no-event
Invoking helloworld.App::handleRequest (java8)
2019-09-18 12:07:23 Found credentials in shared credentials file: ~/.aws/credentials
Fetching lambci/lambda:java8 Docker container image......
Mounting /Users/********/Documents/github/sam-app/.aws-sam/build/HelloWorldFunction as
/var/task:ro,delegated inside runtime container
START RequestId: 8a420a00-ef81-4921-9a9e-508111fc5c8a Version: $LATEST
Function 'HelloWorldFunction' timed out after 20 seconds
It's the sample that is generated with sam init.
package helloworld;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
/**
* Handler for requests to Lambda function.
*/
public class App implements RequestHandler<Object, Object> {
public Object handleRequest(final Object input, final Context context) {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put("X-Custom-Header", "application/json");
try {
final String pageContents = this.getPageContents("https://checkip.amazonaws.com");
String output = String.format("{ \"message\": \"hello world\", \"location\": \"%s\" }", pageContents);
return new GatewayResponse(output, headers, 200);
} catch (IOException e) {
return new GatewayResponse("{}", headers, 500);
}
}
private String getPageContents(String address) throws IOException{
URL url = new URL(address);
try(BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
return br.lines().collect(Collectors.joining(System.lineSeparator()));
}
}
}
I believe my issue is the proxy in my corporate environment.
How do I set the proxies in the java code?

Using proxy for specific HTTPS request in java

I have requirement to pass HTTPs calls of some specific URL via proxy and rest direct. I have written my own custom proxy implementation using ProxySelector of java.net. It is working fine for HTTP calls ( I can see in proxy access logs in that case) but in case of HTTPS calls it seems it is not using proxy).Am I missing something here.? Proxy server is configured properly and its access log is updating when some HTTPS calls passed from browser with proxy.
package com.blabla.proxy;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.vuclip.pubsub.logging.PubSubUtil;
import com.vuclip.pubsub.logging.client.GooglePubSubClient;
public class CustomProxySelector extends ProxySelector {
private static final Logger LOGGER = LogManager.getLogger(PubSubUtil.class);
private final ProxySelector def;
private final String PUB_SUB_URL = "pubsub.googleapis.com";
List<Proxy> proxyList = new ArrayList<Proxy>();
private Proxy proxy=null;
public CustomProxySelector(ProxySelector aDefault) {
this.def = aDefault;
}
#Override
public void connectFailed(URI arg0, SocketAddress soc, IOException ex) {
LOGGER.error("Error in connecting to proxcy "+soc +" for pubsub :"+ ex);
}
#Override
public List<Proxy> select(URI uri) {
if ("https".equalsIgnoreCase(uri.getScheme()) && uri.getHost().startsWith(PUB_SUB_URL)
&& GooglePubSubClient.isProxyEnabled()) {
synchronized (this) {
if (proxy == null) {
proxy = new Proxy(Proxy.Type.SOCKS,
new InetSocketAddress(GooglePubSubClient.getProxyHost(), GooglePubSubClient.getProxyPort()));
}
}
proxyList.add(proxy);
LOGGER.debug("ProxyList:" + proxyList);
return proxyList;
}
proxyList = def.select(uri);
LOGGER.debug("Default proxy list : " + proxyList);
return proxyList;
}
}
I changed Proxy.Type.SOCKS to Proxy.Type.HTTP and it worked for me.

ConnectionServer is not public in org.apache.xmlrpc.webserver; cannot be accessed from outside package

At two different places, Apache XML-RPC's documentation recommends to instanciate a org.apache.xmlrpc.webserver.ConnectionServer object: Custom Data Types and Introspection
However, when I try to do it:
import java.net.InetAddress;
import java.io.IOException;
import org.apache.xmlrpc.server.PropertyHandlerMapping;
import org.apache.xmlrpc.server.XmlRpcServer;
import org.apache.xmlrpc.server.XmlRpcServerConfigImpl;
import org.apache.xmlrpc.webserver.WebServer;
import org.apache.xmlrpc.webserver.ConnectionServer;
import org.apache.xmlrpc.XmlRpcException;
public class XMLRPCServer extends WebServer {
public XMLRPCServer(int port) throws XmlRpcException, IOException {
super(port);
XmlRpcServer xmlRpcServer = getXmlRpcServer();
PropertyHandlerMapping phm = new PropertyHandlerMapping();
phm.addHandler("MyHandler", MyXMLRPCService.class);
xmlRpcServer.setHandlerMapping(phm);
XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
}
protected XmlRpcStreamServer newXmlRpcStreamServer() {
XmlRpcStreamServer server = new ConnectionServer();
return server;
}
}
I get this error:
[javac] <path>/communication/xmlrpc/XMLRPCServer.java:8: error: ConnectionServer is not public in org.apache.xmlrpc.webserver; cannot be accessed from outside package
[javac] import org.apache.xmlrpc.webserver.ConnectionServer;
[javac] ^
Is there anything I am doing wrong? Or is it a bug in the doc/library?
I found a workaround:
protected XmlRpcStreamServer newXmlRpcStreamServer() {
XmlRpcStreamServer server = super.newXmlRpcStreamServer();
return server;
}

Using Selenium RemoteWebDriver behind corporate proxy

How can I connect to a selenium grid such as BrowserStack via RemoteWebDriver from behind a corporate proxy?
The application under test is outside the proxy and freely accessible from BrowserStack.
This Using Selenium RemoteWebDriver behind corporate proxy (Java) stackoverflow question asked the same question but I couldn't follow the accepted answer.
I managed to get something working based on the accepted answer in the linked stackoverflow question, here's my implementation in case anyone else is stuck on the same problem:
Example
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.openqa.selenium.remote.CommandInfo;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.http.HttpClient.Factory;
public class Example {
public RemoteWebDriver connectViaProxy(DesiredCapabilities caps) {
String proxyHost = "?";
int proxyPort = 8080;
String proxyUserDomain = "?";
String proxyUser = "?";
String proxyPassword = "?";
URL url;
try {
url = new URL("http://bsuser:bspassword#hub.browserstack.com/wd/hub");
} catch (MalformedURLException e) {
throw new RuntimeException(e.getMessage(), e);
}
HttpClientBuilder builder = HttpClientBuilder.create();
HttpHost proxy = new HttpHost(proxyHost, proxyPort);
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(proxyHost, proxyPort), new NTCredentials(proxyUser, proxyPassword, getWorkstation(), proxyUserDomain));
if (url.getUserInfo() != null && !url.getUserInfo().isEmpty()) {
credsProvider.setCredentials(new AuthScope(url.getHost(), (url.getPort() > 0 ? url.getPort() : url.getDefaultPort())), new UsernamePasswordCredentials(url.getUserInfo()));
}
builder.setProxy(proxy);
builder.setDefaultCredentialsProvider(credsProvider);
Factory factory = new MyHttpClientFactory(builder);
HttpCommandExecutor executor = new HttpCommandExecutor(new HashMap<String, CommandInfo>(), url, factory);
return new RemoteWebDriver(executor, caps);
}
private String getWorkstation() {
Map<String, String> env = System.getenv();
if (env.containsKey("COMPUTERNAME")) {
// Windows
return env.get("COMPUTERNAME");
} else if (env.containsKey("HOSTNAME")) {
// Unix/Linux/MacOS
return env.get("HOSTNAME");
} else {
// From DNS
try
{
return InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException ex)
{
return "Unknown";
}
}
}
}
MyHttpClientFactory
import java.net.URL;
import org.apache.http.impl.client.HttpClientBuilder;
import org.openqa.selenium.remote.internal.ApacheHttpClient;
public class MyHttpClientFactory implements org.openqa.selenium.remote.http.HttpClient.Factory {
final HttpClientBuilder builder;
public MyHttpClientFactory(HttpClientBuilder builder) {
this.builder = builder;
}
#Override
public org.openqa.selenium.remote.http.HttpClient createClient(URL url) {
return new ApacheHttpClient(builder.build(), url);
}
}
Adding to the answer above by Andrew, to make this work with Appium change the
HttpCommandExecutor executor = new HttpCommandExecutor(new HashMap<String, CommandInfo>(), url, factory);
to
HttpCommandExecutor executor = new HttpCommandExecutor(MobileCommand.commandRepository, url, factory);
I've reworked Andrew Sumner's solution slightly and taken some out in case someone like me wants to just quickly funnel their WebDriver traffic through Fiddler to see the traffic.
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import org.apache.http.HttpHost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.openqa.selenium.ie.InternetExplorerOptions;
import org.openqa.selenium.remote.CommandInfo;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpClient.Factory;
import org.openqa.selenium.remote.internal.ApacheHttpClient;
public class ProxiedRemoteExample {
private static final String PROXY_HOST = "localhost";
private static final int PROXY_PORT = 8888;
public ProxiedRemoteExample() throws MalformedURLException {
InternetExplorerOptions ieOptions = new InternetExplorerOptions();
RemoteWebDriver driver = new RemoteWebDriver(new HttpCommandExecutor(new HashMap<String, CommandInfo>(),
new URL("http://localhost:5555/"), new Factory() {
private HttpClientBuilder builder;
{
builder = HttpClientBuilder.create();
builder.setProxy(new HttpHost(PROXY_HOST, PROXY_PORT));
}
#Override
public HttpClient createClient(URL url) {
return new ApacheHttpClient(builder.build(), url);
}
}), ieOptions);
}
}
With
org.seleniumhq.selenium:selenium-java:4.0.0-beta-3 I had to apply proxy settings in the following way:
configure async http client to use proxy settings
create ahc.properties file under org/asynchttpclient/config folder
file content: org.asynchttpclient.useProxyProperties = true
configure JVM proxy properties
System.getProperties().setProperty("http.proxyHost", "yourProxyHost")
System.getProperties().setProperty("http.proxyPort", "yourProxyPort")

So when I deploy my code to CloudBees global.java won't run (Play Framework 2.1)

I'm just toying around with the google drive api (cloud storage) and figuring out how things work, I wrote some code in play framework where in global.java onStart access to the drive is gained and a test document is written to the drive. Locally this works fine but when I deploy my code to a new CloudBees app and visit the app I get this error in my log and I just can't figure out how to debug it:
Play server process ID is 7454
Oops, cannot start the server.
#6eonea90e: Cannot init the Global object
at play.api.WithDefaultGlobal$$anonfun$play$api$WithDefaultGlobal$$globalInstance$1.apply(Application.scala:57)
at play.api.WithDefaultGlobal$$anonfun$play$api$WithDefaultGlobal$$globalInstance$1.apply(Application.scala:51)
at play.utils.Threads$.withContextClassLoader(Threads.scala:18)
at play.api.WithDefaultGlobal$class.play$api$WithDefaultGlobal$$globalInstance(Application.scala:50)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$globalInstance$lzycompute(Application.scala:383)
at play.api.DefaultApplication.play$api$WithDefaultGlobal$$globalInstance(Application.scala:383)
at play.api.WithDefaultGlobal$class.global(Application.scala:66)
Link to complete CloudBees log
This is the code of Global.java:
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.Drive.Files;
import com.google.api.services.drive.model.FileList;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import play.*;
import play.Logger;
public class Global extends GlobalSettings {
private static String CLIENT_ID = "595172328396-l4kpto8ip9fpaea0k2987eeq8f42bged.apps.googleusercontent.com";
private static String CLIENT_SECRET = "EvTUvAodjGx2eW_d3k8oy8Fb";
private static String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
#Override
public void onStart(Application app) { try{
Logger.info("Application has started");
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.setJsonFactory(jsonFactory).setTransport(httpTransport).build()
.setRefreshToken("1/MZ4GTNA_HMbOcKDSqp6ymSd11dlkgxoMXxfWwhwMJRg").setAccessToken("ya29.AHES6ZQk7NDC-OCba7_yANc_uqWPLwDLl95TlT_DXgkLqrr6qmyLRw");;
//Create a new authorized API client
Drive service = new Drive.Builder(httpTransport, jsonFactory, credential).build();
//Insert a file
File body = new File();
body.setTitle("New Document");
body.setDescription("A test document");
body.setMimeType("text/plain");
java.io.File fileContent = new java.io.File("document.txt");
FileContent mediaContent = new FileContent("text/plain", fileContent);
File file = service.files().insert(body, mediaContent).execute();
Logger.info("List of stuff: " + service.children().toString());
Logger.info("File ID: " + file.getId()); }catch (IOException ex) {}
}
}
The google access token is only good for 1 hour. It does not seem as if you are actually requesting an access token with your refresh token... Instead it seems like you are setting one that was already issued.
You need to request an access token be fetched (using the refresh token)
The "fun" is that once you use the refresh token to generate a new access token, the old ones are invalidated... Or at least that is the experience I have found...

Categories

Resources