i am going to present my problem:
My web application submit a form by https to a server that it needs client certificate for set the communication. It works fine, when i submit the form, the https server asks me for a certificate, i select my certificate and the server response me. But now, i want to post to https server from a servlet with HttpClient because i want to manage the response from https server, and here i have problems...
My code to send a post with HttpClient is:
DefaultHttpClient client = new DefaultHttpClient();
// in the truststore i have the https server certificates for establish connection
// from my client to https server
FileInputStream instream = new FileInputStream(new File(TRUESTORE_PATH));
KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
truststore.load(instream, KEY_TRUESTORE_PASS.toCharArray());
// in the keystore i have the client certificate but without private key because,
// in theory, i shouldn't know it
FileInputStream otherinstream = new FileInputStream(new File(KEYSTORE_PATH));
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(otherinstream,KEY_STORE_PASS.toCharArray());
SSLSocketFactory socketFactory = new SocketFactory(keystore,KEY_STORE_PASS,truststore);
Scheme sch = new Scheme("https", 443, socketFactory);
client.getConnectionManager().getSchemeRegistry().register(sch);
HttpGet httpget = new HttpGet("https://remote_server_with_client_authentication");
HttpResponse response = client.execute(httpget);
When i execute this code, in an unit test for example, i have response from https server, but it tells me that i am not authorized. I suspect that i can't authenticate with the https server because the keystore has the client certificate but whitout private key, then i am not authorized.
Then, Is there some way to establish communication with the https server with a client certificate selected by the user?
Thanks!
Related
How can i get server certificate information when using IWinHttpRequest (or its IServerXMLHTTPRequest wrapper)?
WinHttp example
IWinHttpRequest http = new WinHttpRequest();
http.Open("GET", "https://example.com", false);
http.send(null);
MSXML example
//IServerXmlHttpRequest internally is a wrapper around WinHttp
IServerXmlHttpRequest http = new ServerXmlHttp60();
http.open("GET", "https://example.com/", false);
http.send(null);
Now that i've sent the request, how can i get information about the server certificate?
Specifically:
i need it's thumbprint (e.g., 43c930419a3adf8ae1e9a635e078ae62e2c7ab4b)
i would like it's subject (e.g., CN = *.silkroad.onion)
i would like it's issuerer (e.g., CN = DigiCert SHA2 Secure Server CA)
It goes without saying that this is not using the flat C WinHttp API, but is using the COM object.
Bonus Reading
InternetQueryOption function
INTERNET_OPTION_SECURITY_CERTIFICATE / INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT
INTERNET_CERTIFICATE_INFO structure
Before applying ssl(I take from cloudflare) my website is loaded over http and my socket connection is made over ws
and it's working fine and connection was made successfully.
conn = new WebSocket('ws://myDomain:8090');
But after applying ssl when my website loads over https the I use wss (otherwise it give error)
conn = new WebSocket('wss://myDomain:8090');
Now it gives me the error
WebSocket connection to 'wss://myDomain:8090/' failed: Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT
The websocket server is started over 8090 port I also change the port to 9991 but to no avail.
Here is the code for websocket server
public function handle()
{
$server = IoServer::factory(
new HttpServer(
new WsServer(
new WebSocketController()
)
),
8090
);
$server->run();
}
I don't configure apache to to run a websocket server to accept secure connection request. May be due to this I am getting an error. It means that I am sending a secure connection request to an insecure websocket server. If I am right can you tell me how I configure my websocket server so that it can accept secure connection request.
I am again telling you that I am using the SSL from cloud flare. I tell me my domain and they provide me nameservers to replace it with my existing nameservers.
I requested you to give a clear solution to solve this. I am not using nginx, I am using apache on Lampp.
Someone solved my problem. So I am posting the solution here to help others. I was making two mistakes.
I am using SSL from cloudflare, which causes some issues. So I buy a paid SSL certificate.
I don't configure my websocket server for wss
So here is the code to configure your websocket server for wss in Laravel with Ratchet
public function handle()
{
$loop = Factory::create();
$webSock = new SecureServer(
new Server('0.0.0.0:8090', $loop),
$loop,
array(
'local_cert' => '', // path to your cert
'local_pk' => '', // path to your server private key
'allow_self_signed' => TRUE, // Allow self signed certs (should be false
in production)
'verify_peer' => FALSE
)
);
// Ratchet magic
$webServer = new IoServer(
new HttpServer(
new WsServer(
new WebSocketController()
)
),
$webSock
);
$loop->run();
}
Cloudflare doesn't work with port 8090, here is the list of the ports that are supported by cloudflare.
Also try http://sitemeer.com/#https://yourDomain:8090 to see if your server + domain is serving ssl
I have a uwp app which access web api link (which returns a json array) using HttpClient. It was working well with local host and remote host. But now when tries to access the webapi which is in remote host shows an exception "A connection with the server could not be established". User can able to browse that API through device where the app has been installed and can see the json files. But cant access the link within the app.
I have got same issue before in local host. And it is resolved by enabling local loopback for uwp
checknetisolation loopbackexempt -a -n=packagefamilyname
But how can I resolve it in remote host?
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://###/***/");//web api link is here
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response1 = await client.GetAsync("api/details");
response1.EnsureSuccessStatusCode(); // Throw if not a success code.
}
I use HttpClient to talk to my WebAPI service. For SSL authentication, I set up the client certificates on the HttpClient using WebRequestHandler -
private static WebRequestHandler CreateWebRequestHandler(List<X509Certificate2> clientCertificates)
{
WebRequestHandler handler = new WebRequestHandler();
if (clientCertificates != null && clientCertificates.Any())
{
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
clientCertificates.ForEach(cert => handler.ClientCertificates.Add(cert));
}
return handler;
}
On the Service, I have a custom DelegatingHandler to validate the client certificates using thumbprint -
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
X509Certificate2 certificate = request.GetClientCertificate();
// Code to validate certificate's Thumbprint with white listed thumbprints
}
From the HttpRequest, I can get only one client certificate.
My question: Why does WebRequestHandler allow a collection of ClientCertificates to be set? Does it present all the client certificates to the server? If yes, then how do I get the list of client certificates in the DelegatingHandler?
Actually, only one certificate is send to server by a client during TLS\SSL handshake which you are obtain on the Server. The process of choosing this certificate is well described here.
Briefly explanation is - the client will choose the best suitable certificate from X509CertificateCollection looking for a match between the list of certificate issuers provided by the server and the client certificate issuer name. The first certificate that matches is sent to the server. If no certificate matches or the certificate collection is empty, then an anonymous credential is sent to the server. The deeper mechanism of TLS\SSL work described in a good manner here
I am trying to connect to service which is accesssible over https and need authentication.
The error I get is:
Test method
TestProject1.UnitTest1.TestReharB2B
threw exception:
System.ServiceModel.Security.MessageSecurityException:
The HTTP request is unauthorized with
client authentication scheme
'Anonymous'. The authentication header
received from the server was 'Basic
realm="Application"'. --->
System.Net.WebException: The remote
server returned an error: (401)
Unauthorized..
It seems to me like that username and password is not sent to service. What am I missing?
The code:
EndpointAddress address = new EndpointAddress(
new Uri("https://84.52.158.151:8443/JavaStore/services/B2BService"),
EndpointIdentity.CreateDnsIdentity("JavaStore"),
new AddressHeaderCollection()
);
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
var client = new ReharB2BService.B2BServicePortTypeClient(binding, address);
client.ChannelFactory.Credentials.UserName.UserName = "dotNet";
client.ChannelFactory.Credentials.UserName.Password = "dotnetpwd";
client.Open();
client.getAllItems();
Your service returns error because there is some misconfiguration between server and client. Your client uses transport security with UserName message credentials. That means that HTTPS is used and message contains SOAP header with user name and password. But your service returns exception because it (probably IIS) expects transport security with Basic credentials. That means HTTPS and HTTP Basic authentication (HTTP header).