I am trying to add proxy settings to a Java Swing client app, which connects and gets data over https from an external server. However the ClientResource (restlet:2.4.0) ignores all efforts with parameters and connects directly to the url? If the syntax is correct, what are the correct parameters?
Further, how can I use system proxy settings?
private static ClientResource getClientResource(String url) {
ClientResource clientResource = null;
try {
// test
Client client = new Client(new Context(), Protocol.HTTPS);
client.getContext().getParameters().add("https.proxyHost", "PROXY_IP");
client.getContext().getParameters().add("https.proxyPort", "PROXY_PORT");
clientResource = new ClientResource(url);
// test
clientResource.setNext(client);
} catch (Exception e) {
e.printStackTrace();
}
return clientResource;
}
private static Response sendGetRequest(String url) {
ClientResource resource = getClientResource(BASE_URL + url);
try {
resource.get();
} catch (ResourceException e){
e.printStackStrace();
return null;
}
return getResponse();
}
EDIT added compiles:
compile 'org.restlet.jse:org.restlet:2.3.12'
compile 'org.restlet.jse:org.restlet.ext.jackson:2.3.12'
// switch to Apache Http Client, enable proxy'
compile 'org.restlet.jse:org.restlet.ext.httpclient:2.3.12'
// httpClient for Class Definitions
compile 'org.apache.httpcomponents:httpclient:4.3'
CURRENT EXCEPTION:
Starting the Apache HTTP client
An error occurred during the communication with the remote HTTP server.
org.apache.http.client.ClientProtocolException
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:867)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
at org.restlet.ext.httpclient.internal.HttpMethodCall.sendRequest(HttpMethodCall.java:339)
at org.restlet.engine.adapter.ClientAdapter.commit(ClientAdapter.java:105)
at org.restlet.engine.adapter.HttpClientHelper.handle(HttpClientHelper.java:119)
at org.restlet.Client.handle(Client.java:153)
I think this is only supported with the httpClient extension, that relies on the Apache HTTP client library (maven artifact id: org.restlet.ext.httpclient).
You can then either use the system environment properties: http.proxyHost and http.proxyPort, or set these parameters on the client instance (as you did, but names are distinct and documented here ).
Client client = new Client(new Context(), Protocol.HTTPS);
client.getContext().getParameters().add("proxyHost", "PROXY_IP");
client.getContext().getParameters().add("proxyPort", "PROXY_PORT");
Related
I want to create a servlet using 2 way ssl connector.
I created test2wayssl.jks and initiated SslSelectChannelConnector
When i send request from postman with client certificate, the response in postman is
There was an error connecting to 127.0.0.1:29226/2wayssl.
Here is my code below. But it does not work.
Server server = new Server(29226);
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("2-way-ssl-authentication/test2wayssl.jks");
sslContextFactory.setKeyStorePassword("123456");
sslContextFactory.setKeyManagerPassword("123456");
sslContextFactory.setTrustAll(true);
SslSelectChannelConnector sslConnector = new SslSelectChannelConnector(sslContextFactory);
sslConnector.setAllowRenegotiate(true);
sslConnector.setHost("localhost");
sslConnector.setServer(server);
server.addConnector(sslConnector);
ServletHandler handler = new ServletHandler();
handler.addServletWithMapping(HelloServlet.class, "/2wayssl");
server.setHandler(handler);
try {
server.start();
} catch (Exception e) {
e.printStackTrace(); // TODO impl
}
Below is my servlet class
#SuppressWarnings("serial")
public static class HelloServlet extends HttpServlet
{
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws IOException
{
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
response.getWriter().println("<h1>2 Way SSL Authentication</h1>");
}
}
Any help is appreciated.
SslSelectChannelConnector is from Jetty 8 and older which are now EOL/End of Life, and does not support client certificates, upgrade to supported and stable version of Jetty first.
How this is done with Jetty 9.4.27.v20200227 is by using the SslContextFactory.Server and one (or both) of the options
setWantClientAuth(true) which turns on JVM features on the SSL connection related to javax.net.ssl.SSLParameters.getWantClientAuth()
setNeedClientAuth(true) which turns on JVM features on the SSL connection related to javax.net.ssl.SSLParameters.getNeedClientAuth()
Example:
Server server = new Server();
int httpsPort = 8443;
// Setup HTTP Connector
HttpConfiguration httpConf = new HttpConfiguration();
httpConf.setSecurePort(httpsPort);
httpConf.setSecureScheme("https");
// Setup SSL
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStoreResource(findKeyStorePath());
sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
sslContextFactory.setWantClientAuth(true); // Option 1
sslContextFactory.setNeedClientAuth(true); // Option 2
// Setup HTTPS Configuration
HttpConfiguration httpsConf = new HttpConfiguration();
httpsConf.setSecureScheme("https");
httpsConf.setSecurePort(httpsPort);
httpsConf.addCustomizer(new SecureRequestCustomizer()); // adds ssl info to request object
// Establish the HTTPS ServerConnector
ServerConnector httpsConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,"http/1.1"),
new HttpConnectionFactory(httpsConf));
httpsConnector.setPort(httpsPort);
server.addConnector(httpsConnector);
// Add a Handlers for requests
HandlerList handlers = new HandlerList();
handlers.addHandler(new SecuredRedirectHandler());
handlers.addHandler(new HelloHandler("Hello Secure World"));
server.setHandler(handlers);
server.start();
server.join();
I tried to connect to a websocket server with SSL. But always failed on connection(...).
I am new to cpprestsdk, I can't find doc on how to set SSL information to websocket_client.
websocket_client_config config;
config.set_server_name("wss://host:port/v3/api");
websocket_client client(config);
auto fileStream = std::make_sharedconcurrency::streams::ostream();
pplx::task requestTask = fstream::open_ostream(U("results2.html"))
.then([&](ostream outFile)
{
*fileStream = outFile;
// Create http_client to send the request.
uri wsuri(U("wss://host:port/v3/api"));
client.connect(wsuri).wait();
websocket_outgoing_message msg;
msg.set_utf8_message(obj.serialize());
client.send(msg).wait();
printf("send success: %s\n", obj.serialize().c_str());
return client.receive().get();
})
it throws "Error exception:set_fail_handler: 8: TLS handshake failed".
Documentation for cpprestsdk can be found here
C++ REST SDK WebSocket client. Although this doesn't show all the necessary information related to cpprestsdk it will help you.
And also you can get an SSL test example here. I show a simple websocket client implemented using SSL or wss:// scheme
websocket_client client;
std::string body_str("hello");
try
{
client.connect(U("wss://echo.websocket.org/")).wait();
auto receive_task = client.receive().then([body_str](websocket_incoming_message ret_msg) {
VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length());
auto ret_str = ret_msg.extract_string().get();
VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0);
VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message);
});
websocket_outgoing_message msg;
msg.set_utf8_message(body_str);
client.send(msg).wait();
receive_task.wait();
client.close().wait();
}
catch (const websocket_exception& e)
{
if (is_timeout(e.what()))
{
// Since this test depends on an outside server sometimes it sporadically can fail due to timeouts
// especially on our build machines.
return;
}
throw;
}
And further examples here to guide you get it successfully is found here
https://github.com/microsoft/cpprestsdk/wiki/Web-Socket
I want to read certificate details (e.g. expiration date or CN) for security reasons.
Usually there are some properties in network classes available, that allow to check the certificate. This is missing in WP8 implementations.
Also I tried to create an SslStream but also there is no way to get any certificate detail like the RemoteCertificate on .net 4.5.
var sslStream = new SslStream(new NetworkStream(e.ConnectSocket));
The SslStream is missing everything relating security. So it looks like also BountyCastle and other libraries cannot be able to get the certificate, because the underlying framework doesn't support it.
So my questions are:
Can I read the CN or other Certificate details on WP8 using other approaches.?
If not, how can you create then seriously secure apps (line banking) on WP8 using techniques like SSL Pinning or client side certificate validation and is there any reason why this is not supported in WP8?
Regards
Holger
I issued a user voice request to Microsoft .NET team asking them to provide a solution for reading server SSL certificate details from portable class libraries (targeting also WP8). You can vote it here: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/4784983-support-server-ssl-certificate-chain-inspection-in
On Windows Phone 8.1 this can be done with HttpClient, as well as with StreamSocket (as Mike suggested).
Example for certificate validation with StreamSocket can be found here (Scenario5_Certificate in source code).
Certificate validation with HttpClient can be done by handling the ERROR_INTERNET_INVALID_CA exception, validating the server certificate using the HttpTransportInformation class, creating new instance of HttpBaseProtocolFilter class and specifying the errors to ignore.
Note that not all the errors are ignorable. You will receive an exception if you'll try to add Success, Revoked,
InvalidSignature, InvalidCertificateAuthorityPolicy, BasicConstraintsError, UnknownCriticalExtension or OtherErrors enum values.
I'm adding a sample code that bypasses certificate errors using HttpClient:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Security.Cryptography.Certificates;
using Windows.Web.Http;
using Windows.Web.Http.Filters;
namespace Example.App
{
public class HttpsHandler
{
private const int ERROR_INTERNET_INVALID_CA = -2147012851; // 0x80072f0d
public static async void HttpsWithCertificateValidation()
{
Uri resourceUri;
if (!Uri.TryCreate("https://www.pcwebshop.co.uk/", UriKind.Absolute, out resourceUri))
return;
IReadOnlyList<ChainValidationResult> serverErrors = await DoGet(null, resourceUri);
if (serverErrors != null)
{
HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
foreach (ChainValidationResult value in serverErrors)
{
try {
filter.IgnorableServerCertificateErrors.Add(value);
} catch (Exception ex) {
// Note: the following values can't be ignorable:
// Success Revoked InvalidSignature InvalidCertificateAuthorityPolicy
// BasicConstraintsError UnknownCriticalExtension OtherErrors
Debug.WriteLine(value + " can't be ignorable");
}
}
await DoGet(filter, resourceUri);
}
}
private static async Task<IReadOnlyList<ChainValidationResult>> DoGet(HttpBaseProtocolFilter filter, Uri resourceUri)
{
HttpClient httpClient;
if (filter != null)
httpClient = new HttpClient(filter);
else
httpClient = new HttpClient();
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, resourceUri);
bool hadCertificateException = false;
HttpResponseMessage response;
String responseBody;
try {
response = await httpClient.SendRequestAsync(requestMessage);
response.EnsureSuccessStatusCode();
responseBody = await response.Content.ReadAsStringAsync();
} catch (Exception ex) {
hadCertificateException = ex.HResult == ERROR_INTERNET_INVALID_CA;
}
return hadCertificateException ? requestMessage.TransportInformation.ServerCertificateErrors : null;
}
}
}
After trying open source libs like bouncyCastle, supersocket or webSocket4net I tested an evaluation of a commercial lib named ELDOS SecureBlackbox. This test was successfull. Here is a code snipped, that gets the X509Certificates with all details:
public void OpenSSL()
{
var c = new TElSimpleSSLClient();
c.OnCertificateValidate += new TSBCertificateValidateEvent(OnCertificateValidate);
c.Address = "myhostname.com";
c.Port = 443;
c.Open();
c.Close(false);
}
private void OnCertificateValidate(object sender, TElX509Certificate x509certificate, ref TSBBoolean validate)
{
validate = true;
}
The validation is getting all certificates... if validate is set to true, the next certificate will be shown. That means the callback is called forreach certificate there.
Regards
Holger
For WP8, you can use the StreamSocket class, which has an UpgradeToSslAsync() method that will do the TLS handshake for you as an async operation. Once that completes, you can use the .Information.ServerCertificate property to check that you got the server certificate you were expecting.
We have an issue in our environment when using Websphere to attempt to connect to an external system with HttpClient 4.x (current version is 4.2.1). Connecting to the external system is fine with their certificate being installed in Websphere with no additional configuration of HttpClient. However, when they enabled mutual authentication, it no longer works and we get a SSLPeerUnverifiedException exception:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated,
at com.ibm.jsse2.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:105),
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128),
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572),
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180),
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294),
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640),
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479),
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906),
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:1066),
I was provided the following code sample, and I was wondering if there's any way to configure HttpClient to use an explicit alias like this code sample does. I've tried to find good documentation on using SSL mutual authentication with HttpClient 4 and haven't been able to find much.
Here's the code sample:
private HttpURLConnection getConnection(String server, String machine,
String port) throws Exception {
URL u = new URL(server);
HttpsURLConnection connection = (HttpsURLConnection) u.openConnection();
String alias = "CellDefaultSSLSettings";
final HashMap connectionInfo = new HashMap();
connectionInfo.put(JSSEHelper.CONNECTION_INFO_DIRECTION,
JSSEHelper.DIRECTION_OUTBOUND);
connectionInfo.put(JSSEHelper.CONNECTION_INFO_REMOTE_HOST, machine);
connectionInfo.put(JSSEHelper.CONNECTION_INFO_REMOTE_PORT, port);
javax.net.ssl.SSLSocketFactory sslFact = JSSEHelper.getInstance()
.getSSLSocketFactory(alias, connectionInfo, null);
connection.setSSLSocketFactory(sslFact);
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
return connection;
}
Basically, how do I make HttpClient use "CellDefaultSSLSettings"?
Fundamentally this problem has nothing to do with HttpClient. HttpClient can be configured to establish HTTPS connections using any custom SSLContext or SSLSocketFactory instance. This is basically about how to use JSSE APIs to configure SSLContext in the right way. In your particular case JSSEHelper does all the hard work for you.
// JSSE socket factory
javax.net.ssl.SSLSocketFactory jssesf = JSSEHelper.getInstance().getSSLSocketFactory(alias, connectionInfo, null);
// HC socket factory
SSLSocketFactory hcsf = new SSLSocketFactory(jssesf, SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
This will give a connection socket factory that can be registered with the connection manager.
HttpClient 4.3 also comes with SSLContextBuilder class which can be used to assemble custom SSL configurations using fluid builder API.
https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLContextBuilder.java
oleg's answer helped me out.
What I did was extend the DefaultHttpClient, and each constructor takes a String argument for the destination URL and calls a method setupScheme:
private void setupScheme(final String url) throws Exception {
Scheme scheme = new Scheme("https", 443, retrieveWebsphereSSLConnectionFactory(url));
getConnectionManager().getSchemeRegistry().register(scheme);
}
The method retrieveWebsphereSSLConnectionFactory essentially combines the code from the sample with the code oleg provided:
private SchemeSocketFactory retrieveWebsphereSSLConnectionFactory(final String url)
throws SSLException, URISyntaxException {
final String alias = "CellDefaultSSLSettings";
final HashMap<String, String> connectionInfo = new HashMap<String, String>();
connectionInfo.put(JSSEHelper.CONNECTION_INFO_DIRECTION, JSSEHelper.DIRECTION_OUTBOUND);
connectionInfo.put(JSSEHelper.CONNECTION_INFO_REMOTE_HOST,
URIUtils.extractHost(new URI(url)).getHostName());
connectionInfo.put(JSSEHelper.CONNECTION_INFO_REMOTE_PORT, "443");
return new SSLSocketFactory(JSSEHelper.getInstance().getSSLSocketFactory(alias, connectionInfo, null),
SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
}
I have a locally hosted WCF service and a silverlight 5 app that communicates with it. By default silverlight tries to obtain the cross domain policy file over HTTP when making calls to the WCF service. I need to change this so that the policy file is served over net.tcp port 943 instead.
I have setup a local tcp listener that serves up the policy file over port 943 and i have followed this technique whereby i make a dummy socket connection in order to obtain the policy file over tcp as it is only retrieved once per application lifetime. The tcp server is being hit as expected and i am getting SocketError property value as Success (though i must note, the first time i hit the tcp server after starting the listener, the result is always access denied).
From what i can tell, the policy file is either invalid as the silverlight application as still unable to connect or the above mentioned technique does not work with silverlight 5.
What i would like to know is if what i am doing is possible & im doing it correctly, otherwise if there is an alternative means to have the policy file successfully downloaded over tcp and removing the need for retrieving it over HTTP.
Thanks
I wrote a long post about hosting silverlight in WPF - and using WCF with a http listener here:
How can I host a Silverlight 4 application in a WPF 4 application?
Now while not directly answering your question, it does show how to create a http version of the policy file.
I have also written something that serves up a policy listener over port 943, but I can't find where I posted the source - so I'll keep digging. As far as I remember though, silverlight does a cascade find of the policy file, if it doesn't get a connection on port 80, it'll then look on port 943.
I hope this is of some help somewhere.
Ok, here is the policy listener I had for net.TCP transport i.e. not HTTP based. I presume you have sorted this by now, sorry for the delay. It may well be of use to someone else now.
I was looking for the MS thing that said they cascade from HTTP to TCP, however, I can't, and therefore have to assume it was bunk and then changed.
Either way, if you call using a net.TCP service, and want a listener for it, this code should help:
#region "Policy Listener"
// This is a simple policy listener
// that provides the cross domain policy file for silverlight applications
// this provides them with a network access policy
public class SocketPolicyListener
{
private TcpListener listener = null;
private TcpClient Client = null;
byte[] Data;
private NetworkStream netStream = null;
private string listenaddress = "";
// This could be read from a file on the disk, but for now, this gives the silverlight application
// the ability to access any domain, and all the silverlight ports 4502-4534
string policyfile = "<?xml version='1.0' encoding='utf-8'?><access-policy><cross-domain-access><policy><allow-from><domain uri='*' /></allow-from><grant-to><socket-resource port='4502-4534' protocol='tcp' /></grant-to></policy></cross-domain-access></access-policy>";
// the request that we're expecting from the client
private string _policyRequestString = "<policy-file-request/>";
// Listen for our clients to connect
public void Listen(string ListenIPAddress)
{
listenaddress = ListenIPAddress;
if (listener == null)
{
listener = new TcpListener(IPAddress.Parse(ListenIPAddress), 943);
// Try and stop our clients from lingering, keeping the socket open:
LingerOption lo = new LingerOption(true, 1);
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger,lo);
}
listener.Start();
WaitForClientConnect();
}
private void WaitForClientConnect()
{
listener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), listener);
}
public void StopPolicyListener()
{
if (Client.Connected)
{
// Should never reach this point, as clients
// are closed if they request the policy
// only clients that open the connection and
// do not submit a policy request will remain unclosed
Client.Close();
}
listener.Stop();
}
public void RestartPolicyListener()
{
listener.Start();
}
// When a client connects:
private void OnClientConnected(IAsyncResult ar)
{
if (ar.IsCompleted)
{
// Get the listener that handles the client request.
TcpListener listener = (TcpListener)ar.AsyncState;
// End the operation and display the received data on
// the console.
Client = listener.EndAcceptTcpClient(ar);
// Try and stop our clients from lingering, keeping the socket open:
LingerOption lo = new LingerOption(true, 1);
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);
// Set our receive callback
Data = new byte[1024];
netStream = Client.GetStream();
netStream.BeginRead(Data, 0, 1024, ReceiveMessage, null);
}
WaitForClientConnect();
}
// Read from clients.
public void ReceiveMessage(IAsyncResult ar)
{
int bufferLength;
try
{
bufferLength = Client.GetStream().EndRead(ar);
// Receive the message from client side.
string messageReceived = Encoding.ASCII.GetString(Data, 0, bufferLength);
if (messageReceived == _policyRequestString)
{
// Send our policy file, as it's been requested
SendMessage(policyfile);
// Have to close the connection or the
// silverlight client will wait around.
Client.Close();
}
else
{
// Continue reading from client.
Client.GetStream().BeginRead(Data, 0, Data.Length, ReceiveMessage, null);
}
}
catch (Exception ex)
{
throw new Exception(Client.Client.RemoteEndPoint.ToString() + " is disconnected.");
}
}
// Send the message.
public void SendMessage(string message)
{
try
{
byte[] bytesToSend = System.Text.Encoding.ASCII.GetBytes(message);
//Client.Client.Send(bytesToSend,SocketFlags.None);
Client.GetStream().Write(bytesToSend,0, bytesToSend.Length);
Client.GetStream().Flush();
}
catch (Exception ex)
{
throw ex;
}
}
}
#endregion