Owin self host SSL connection reset - ssl

I got an issue when setting up HTTPs for a self host Owin console application. The browser always shows a connection reset error.
I've tried creating certificates manually according to this link http://chavli.com/how-to-configure-owin-self-hosted-website-with-ssl/ but I still get the connection reset issue on that port.
And I've checked the windows event log and there's no error messages.
The application will create X509 certificate by itself and run netsh command automatically.
Without Ssl, the application can display the web page correctly.
Can any one run my code below and see whether it can work on your computer?
Thanks in advance.
Need to add COM reference CertEnroll 1.0 Type Library to compile the code below (vs2015 already contains this COM reference in Type Libraries)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using CERTENROLLLib;
using Microsoft.Owin.Hosting;
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
namespace Owin.Startup
{
class Program
{
static void Main(string[] args)
{
int port = 8888;
string url = $"https://localhost:{port}";
var cert = GetCert("localhost", TimeSpan.FromDays(3650), "devpwd", AppDomain.CurrentDomain.BaseDirectory + "cert.dat");
ActivateCert(cert, port, GetAppId());
using (WebApp.Start<Startup>(url))
{
Console.WriteLine($"Hosted: {url}");
Console.ReadLine();
}
}
static private string GetAppId()
{
Assembly assembly = Assembly.GetExecutingAssembly();
//The following line (part of the original answer) is misleading.
//**Do not** use it unless you want to return the System.Reflection.Assembly type's GUID.
//Console.WriteLine(assembly.GetType().GUID.ToString());
// The following is the correct code.
var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
var id = attribute.Value;
return id;
}
static public X509Certificate2 GetCert(string cn, TimeSpan expirationLength, string pwd = "", string filename = null)
{
// http://stackoverflow.com/questions/18339706/how-to-create-self-signed-certificate-programmatically-for-wcf-service
// http://stackoverflow.com/questions/21629395/http-listener-with-https-support-coded-in-c-sharp
// https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.storename(v=vs.110).aspx
// create DN for subject and issuer
var base64encoded = string.Empty;
if (filename != null && File.Exists(filename))
{
base64encoded = File.ReadAllText(filename);
}
else
{
base64encoded = CreateCertContent(cn, expirationLength, pwd);
if (filename != null)
{
File.WriteAllText(filename, base64encoded);
}
}
// instantiate the target class with the PKCS#12 data (and the empty password)
var rlt = new System.Security.Cryptography.X509Certificates.X509Certificate2(
System.Convert.FromBase64String(base64encoded), pwd,
// mark the private key as exportable (this is usually what you want to do)
// mark private key to go into the Machine store instead of the current users store
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
);
return rlt;
}
private static string CreateCertContent(string cn, TimeSpan expirationLength, string pwd)
{
string base64encoded = string.Empty;
var dn = new CX500DistinguishedName();
dn.Encode("CN=" + cn, X500NameFlags.XCN_CERT_NAME_STR_NONE);
CX509PrivateKey privateKey = new CX509PrivateKey();
privateKey.ProviderName = "Microsoft Strong Cryptographic Provider";
privateKey.Length = 2048;
privateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
privateKey.KeyUsage = X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_DECRYPT_FLAG |
X509PrivateKeyUsageFlags.XCN_NCRYPT_ALLOW_KEY_AGREEMENT_FLAG;
privateKey.MachineContext = true;
privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
privateKey.Create();
// Use the stronger SHA512 hashing algorithm
var hashobj = new CObjectId();
hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID,
ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
AlgorithmFlags.AlgorithmFlagsNone, "SHA512");
// Create the self signing request
var cert = new CX509CertificateRequestCertificate();
cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, "");
cert.Subject = dn;
cert.Issuer = dn; // the issuer and the subject are the same
cert.NotBefore = DateTime.Now.Date;
// this cert expires immediately. Change to whatever makes sense for you
cert.NotAfter = cert.NotBefore + expirationLength;
cert.HashAlgorithm = hashobj; // Specify the hashing algorithm
cert.Encode(); // encode the certificate
// Do the final enrollment process
var enroll = new CX509Enrollment();
enroll.InitializeFromRequest(cert); // load the certificate
enroll.CertificateFriendlyName = cn; // Optional: add a friendly name
string csr = enroll.CreateRequest(); // Output the request in base64
// and install it back as the response
enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate,
csr, EncodingType.XCN_CRYPT_STRING_BASE64, pwd); // no password
// output a base64 encoded PKCS#12 so we can import it back to the .Net security classes
base64encoded = enroll.CreatePFX(pwd, // no password, this is for internal consumption
PFXExportOptions.PFXExportChainWithRoot);
return base64encoded;
}
private static void ActivateCert(X509Certificate2 rlt, int port, string appId)
{
X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
if (!store.Certificates.Contains(rlt))
{
store.Add(rlt);
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "netsh";
psi.Arguments = $"http delete sslcert ipport=0.0.0.0:{port}";
Process procDel = Process.Start(psi);
procDel.WaitForExit();
psi.Arguments = $"http add sslcert ipport=0.0.0.0:{port} certhash={rlt.Thumbprint} appid={{{appId}}}";
Process proc = Process.Start(psi);
proc.WaitForExit();
psi.Arguments = $"http delete sslcert ipport=[::]:{port}";
Process procDelV6 = Process.Start(psi);
procDelV6.WaitForExit();
psi.Arguments = $"http add sslcert ipport=[::]:{port} certhash={rlt.Thumbprint} appid={{{appId}}}";
Process procV6 = Process.Start(psi);
procV6.WaitForExit();
psi.Arguments = $"http add urlacl url=https://+:{port}/ user={Environment.UserDomainName}\\{Environment.UserName}";
Process procAcl = Process.Start(psi);
procAcl.WaitForExit();
}
store.Close();
}
}
public class Startup
{
private IAppBuilder app;
public void Configuration(IAppBuilder app)
{
#if DEBUG
app.UseErrorPage();
#endif
app.Use(new Func<AppFunc, AppFunc>(next => (async env =>
{
Console.WriteLine("Begin Request");
foreach (var i in env.Keys)
{
Console.WriteLine($"{i}\t={(env[i] == null ? "null" : env[i].ToString())}\t#\t{(env[i] == null ? "null" : env[i].GetType().FullName)}");
}
if (next != null)
{
await next.Invoke(env);
}
else
{
Console.WriteLine("Process Complete");
}
Console.WriteLine("End Request");
})));
app.UseWelcomePage("/");
this.app = app;
}
}
}

You should not create certificate with the base64 content which loaded from the cert.dat. Try using cert.Export(X509ContentType.Pfx, pwd) and load it with new X509Certificate2(filename, pwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

Related

HttpClient POST request with Client Certificate

I'm trying to make a call to a third-party API which requires a client certificate. I generated the client certificate using the SSL tool and
uploaded this to the third party site. I have generated a successful POST request through Postman, providing the client certificate through
their dialogs.
The Headers are:
X-application = (MyApplicationName)
Content-Type = application/x-www-form-urlencoded
Accept = application/json
Body (x-www-form-urlencoded)
UserName = (username)
Password = (password)
When I perform a similar request through .NET I am receiving an error code indicating the certificate is not present. I have added the certificate to my personal certificate store and verified
the certificate has been added to the webhandler through debugging.
Can anyone suggest what the error might be or how I could diagnose the issue?
static async void LaunchRawHttpClient()
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback +=
ValidateServerCertificate;
string page = "https://<URL>";
var handler = new WebRequestHandler();
X509Certificate2 cert = GetMyCert();
if (cert!= null)
{
handler.ClientCertificates.Add(cert);
}
else
{
Console.WriteLine("Cert not found");
Console.ReadLine();
return;
}
// ... Use HttpClient.
using (HttpClient client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Add("X-Application", "<applicationname>");
client.DefaultRequestHeaders.Add("Accept", "application/json");
var nvc = new List<KeyValuePair<string, string>>();
nvc.Add(new KeyValuePair<string, string>("username", "<username>"));
nvc.Add(new KeyValuePair<string, string>("password", "<password>"));
FormUrlEncodedContent reqContent = new FormUrlEncodedContent(nvc);
reqContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.PostAsync(page, reqContent))
using (HttpContent content = response.Content)
{
// ... Read the string.
string result = await content.ReadAsStringAsync();
// ... Display the result.
if (result != null)
{
Console.WriteLine(result);
}
}
}
}
static X509Certificate2 GetMyCert()
{
string certThumbprint = "<thumbprint>";
X509Certificate2 cert = null;
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = store.Certificates.Find
(X509FindType.FindByThumbprint, certThumbprint, false);
if (certCollection.Count > 0)
cert = certCollection[0];
store.Close();
return cert;
}
public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
{
Console.WriteLine("No SSL Errors");
return true;
}
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
Console.ReadLine();
return false;
}
I receive "No SSL Errors" message x2, followed by the missing certificate status code.
Thanks in advance
Jim
Finally found the answer on this - the problem was the private key file was not being loaded. Postman sent requests successfully, as did Curl. Curl asks for the key file explicity and this was a clue.
In .NET Core - there's a function on the X509Certificate2 object which allows you to copy it to another object combined with the key file. My project is in .NET framework and Core wasn't available.
The option I went for was using openssl to combine the cer and the key file into a pfx, which I loaded into the X509Certificate2 object. The Http Post then succeeded.

NSUrlSession: Challenge NSURLAuthenticationMethodServerTrust fails only when client certificate is also needed

we want to connect our app to our IIS webservice. We use self signed certificates and also a client certificate for authentication.
When the webservice doesn't require client certificate authentication, everything works fine, NSURLAuthenticationMethodServerTrust gets called and the request continues.
But when I activate client certificate authentication on our server, after DidReceiveChallenge with NSURLAuthenticationMethodServerTrust as the challenge, DidCompleteWithError gets called. Error message is: "The certificate for this server is invalid. You might be connecting to a server that is pretending to be "192.168.221.118" which could put your confidential information at risk.
Note: "NSURLAuthenticationMethodClientCertificate" never gets called, the app crashes before that.
The client certificate is signed by the intermediate certificate, so I don't understand why the ServerTrust Challenge fails.
Also: in my opinion it should not be necessary, but I also tried adding the client certificate to the collection of AnchorCertificates of the Sectrust.
Thanks in advance for your help.
Here is my code:
private class SessionDelegate : NSUrlSessionDataDelegate, INSUrlSessionDelegate
{
private Action<bool, string> completed_callback;
private string antwortCache;
private int status_code;
public SessionDelegate(Action<bool, string> completed)
{
completed_callback = completed;
antwortCache = "";
}
public override void DidReceiveChallenge(NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
if (challenge.PreviousFailureCount == 0)
{
if (challenge.ProtectionSpace.AuthenticationMethod.Equals("NSURLAuthenticationMethodServerTrust"))
{
// GetParent is correct, because I'm too lazy to copy the certs into to the correct folders...
var path = Directory.GetParent(GlobaleObjekte.SSLZertifikatePath);
var caPath = Path.Combine(path.FullName, "ca.cert.der");
var caByteArray = File.ReadAllBytes(caPath);
var caCert = new X509Certificate2(caByteArray);
var interPath = Path.Combine(path.FullName, "intermediate.cert.der");
var interByteArray = File.ReadAllBytes(interPath);
var interCert = new X509Certificate2(interByteArray);
var secTrust = challenge.ProtectionSpace.ServerSecTrust;
var certCollection = new X509CertificateCollection();
certCollection.Add(caCert);
certCollection.Add(interCert);
secTrust.SetAnchorCertificates(certCollection);
var credential = new NSUrlCredential(secTrust);
completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);
return;
}
if (challenge.ProtectionSpace.AuthenticationMethod.Equals("NSURLAuthenticationMethodClientCertificate"))
{
var path = Directory.GetParent(GlobaleObjekte.SSLZertifikatePath);
var certPath = Path.Combine(path.FullName, "client.pfx");
var certByteArray = File.ReadAllBytes(certPath);
var cert = new X509Certificate2(certByteArray, Settings.WSClientCertPasswort);
var ident = SecIdentity.Import(certByteArray, Settings.WSClientCertPasswort);
var credential = new NSUrlCredential(ident, new SecCertificate[] { new SecCertificate(cert) }, NSUrlCredentialPersistence.ForSession);
completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);
return;
}
if (challenge.ProtectionSpace.AuthenticationMethod.Equals("NSURLAuthenticationMethodHTTPBasic"))
{
var credential = new NSUrlCredential(Settings.WebserviceBenutzer, Settings.WebservicePasswort, NSUrlCredentialPersistence.ForSession);
completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);
return;
}
completed_callback(false, "Unbekannte Authentifizierungsanfrage: " + challenge?.ProtectionSpace?.AuthenticationMethod);
}
else
{
completed_callback(false, "Authentifizierung fehlgeschlagen: " + challenge?.ProtectionSpace?.AuthenticationMethod);
}
}
}
I finally found a solution. I had to create the credential object in a different way. Instead of adding the certificates to the SecTrust and create the credential with the SecTrust as a parameter, I had to create a identity from the client certificate and then create the credential with the identity and the other certificates as parameters:
if (challenge.ProtectionSpace.AuthenticationMethod.Equals("NSURLAuthenticationMethodServerTrust"))
{
var path = Directory.GetParent(GlobaleObjekte.SSLZertifikatePath);
var caPath = Path.Combine(path.FullName, "ca.cert.der");
var caByteArray = File.ReadAllBytes(caPath);
var caCert = new SecCertificate(caByteArray);
var interPath = Path.Combine(path.FullName, "intermediate.cert.der");
var interByteArray = File.ReadAllBytes(interPath);
var interCert = new SecCertificate(interByteArray);
var clientPath = Path.Combine(path.FullName, "client.pfx");
var clientByteArray = File.ReadAllBytes(clientPath);
var clientCert = new X509Certificate2(clientByteArray, Settings.WSClientCertPasswort);
//var secTrust = challenge.ProtectionSpace.ServerSecTrust;
//var certCollection = new X509CertificateCollection();
//certCollection.Add(caCert);
//certCollection.Add(interCert);
//certCollection.Add(cert);
//secTrust.SetAnchorCertificates(certCollection);
//var credential = new NSUrlCredential(secTrust);
var identity = SecIdentity.Import(clientCert);
var credential = new NSUrlCredential(identity, new SecCertificate[] { caCert, interCert }, NSUrlCredentialPersistence.ForSession);
completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, credential);
return;
}

How to pass client certificate using AutoRest client

We are using AutoRest for generating client code based on API Swagger files.
I'm trying to pass client certificate to the API. But noticed that generated client code doesn't accept WebRequestHandler.
Generated code looks like below:
public MyTestApiV1(Uri baseUri, params DelegatingHandler[] handlers) : this(handlers)
{
if (baseUri == null)
{
throw new ArgumentNullException("baseUri");
}
this.BaseUri = baseUri;
}
I feel like I'm missing something here. Has anyone managed to send client certificate using AutoRest?
Tried this but webRequestHandler is always null:
var webRequestHandler = client.HttpMessageHandlers.First() as WebRequestHandler;
if (webRequestHandler != null)
{
var secretRetrieved = keyVault.GetSecretAsync("my-cert");
var pfxBytes = Convert.FromBase64String(secretRetrieved.Result);
// or recreate the certificate directly
var certificate = new X509Certificate2(pfxBytes);
webRequestHandler.ClientCertificates.Add(certificate);
}
You can use another overloaded constructor:
/// <summary>
/// Initializes ServiceClient using base HttpClientHandler and list of handlers.
/// </summary>
/// <param name="rootHandler">Base HttpClientHandler.</param>
/// <param name="handlers">List of handlers from top to bottom (outer handler is the first in the list)</param>
protected ServiceClient(HttpClientHandler rootHandler, params DelegatingHandler[] handlers)
ServiceClient is the base class for generated clients. Therefore, code might look like:
var secretRetrieved = keyVault.GetSecretAsync("my-cert");
var pfxBytes = Convert.FromBase64String(secretRetrieved.Result);
// or recreate the certificate directly
var certificate = new X509Certificate2(pfxBytes);
WebRequestHandler webRequestHandler = new WebRequestHandler();
webRequestHandler.ClientCertificates.Add(certificate);
var client = new MyTestApiV1(webRequestHandler);
client.BaseUri = baseUri;
.net Core version
Ivan R's answer led me on the right path but it's a little different for .net core (2.2 at this point in time) as WebRequestHandler is not available in core.
I had to use a pfx file and password in my case. GetNumberPassedIn isn't in the generic Petstore Swagger template but was what I was testing with.
Program.cs:
using System;
using System.Net.Http;
namespace SimpleApi2.Console
{
class Program
{
static void Main(string[] args)
{
var certificate = new CertInfo().GetCertFromPfx(Const.PfxPath, Const.PfxPassword);
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
var client = new HttpClient(handler);
var petStore = new SwaggerPetstore(client, true);
petStore.BaseUri = new Uri(Const.PublicUrl);
var result = petStore.GetNumberPassedIn(135, Const.ApiKey);
System.Console.WriteLine(result.ToString());
System.Console.ReadKey();
}
}
}
CertInfo.cs:
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Security;
namespace SimpleApi2.Console
{
class CertInfo
{
internal static byte[] ReadFile(string fileName)
{
FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read);
int size = (int)f.Length;
byte[] data = new byte[size];
f.Read(data, 0, size);
f.Close();
return data;
}
public CertInfo() { }
public X509Certificate2 GetCertFromPfx(string pfxFilePath, string password)
{
try
{
byte[] rawData = ReadFile(pfxFilePath);
var passwordAsChars = password.ToCharArray();
var securePassword = new SecureString();
foreach (char c in password)
securePassword.AppendChar(c);
securePassword.MakeReadOnly();
X509Certificate2 x509 = new X509Certificate2(pfxFilePath, password,
X509KeyStorageFlags.UserKeySet);
WriteCertInfo(x509);
return x509;
}
catch (DirectoryNotFoundException)
{
System.Console.WriteLine("Error: The directory specified could not be found.");
throw;
}
catch (IOException)
{
System.Console.WriteLine("Error: A file in the directory could not be accessed.");
throw;
}
catch (NullReferenceException)
{
System.Console.WriteLine("File must be a .cer file. Program does not have access to that type of file.");
throw;
}
}
private static void WriteCertInfo(X509Certificate2 x509)
{
//Print to console information contained in the certificate.
System.Console.WriteLine("{0}Subject: {1}{0}", Environment.NewLine, x509.Subject);
System.Console.WriteLine("{0}Issuer: {1}{0}", Environment.NewLine, x509.Issuer);
System.Console.WriteLine("{0}Version: {1}{0}", Environment.NewLine, x509.Version);
System.Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, x509.NotBefore);
System.Console.WriteLine("{0}Expiry Date: {1}{0}", Environment.NewLine, x509.NotAfter);
System.Console.WriteLine("{0}Thumbprint: {1}{0}", Environment.NewLine, x509.Thumbprint);
System.Console.WriteLine("{0}Serial Number: {1}{0}", Environment.NewLine, x509.SerialNumber);
System.Console.WriteLine("{0}Friendly Name: {1}{0}", Environment.NewLine, x509.PublicKey.Oid.FriendlyName);
System.Console.WriteLine("{0}Public Key Format: {1}{0}", Environment.NewLine, x509.PublicKey.EncodedKeyValue.Format(true));
System.Console.WriteLine("{0}Raw Data Length: {1}{0}", Environment.NewLine, x509.RawData.Length);
System.Console.WriteLine("{0}Certificate to string: {1}{0}", Environment.NewLine, x509.ToString(true));
}
}
}

TwitterSettings.OAuthVersion

i don't understand that : GetRequestToken is not working in TweetSharp on Windows Phone
My code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using PhoneApp2.Resources;
using TweetSharp;
namespace PhoneApp2
{
public partial class MainPage : PhoneApplicationPage
{
private const string consumerKey = "zvBvaKjEQRwGqu9ECaNfop0pr";
private const string consumerSecret = "SgEqsMRcIrEYNrtXhvtYdnx7qBA9EITzswneyjf8wRorDvSAvn";
private TwitterService myclient;
private OAuthRequestToken requestToken;
private bool userAuthenticated = false;
// Constructeur
public MainPage()
{
InitializeComponent();
myclient = new TwitterService(consumerKey, consumerSecret);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//If user is already logged in, just send the tweet, otherwise get the RequestToken
if (userAuthenticated)
//send the Tweet, this is just a placeholder, we will add the actual code later
Dispatcher.BeginInvoke(() => { MessageBox.Show("Placeholder for tweet sending"); });
else
myclient.GetRequestToken(processRequestToken);
}
private void processRequestToken(OAuthRequestToken token, TwitterResponse response)
{
if (token == null)
Dispatcher.BeginInvoke(() => { MessageBox.Show("Error getting request token"); });
else
{
requestToken = token;
Dispatcher.BeginInvoke(() =>
{
Browser.Visibility = System.Windows.Visibility.Visible;
Browser.Navigate(myclient.GetAuthorizationUri(requestToken));
});
}
}
}
}
and visual studio 2013 create an error on myclient.GetRequestToken(processRequestToken); ...
how can incorporate your solution with hammock on my code?
I had this identical error last week (doing this app) The solution was to implement the Hammock Library instead of tweet sharp. Also in the post tweet example change the version from 1 to 1.1
This is the Nokia Developer Documentation I followed to implement logging in
This is the Nokia Developer Documentation I followed to implement posting a tweet
REMEMBER CHANGE THE VERSION TO 1.1 LIKE THIS
From this
var credentials = new OAuthCredentials
{
Type = OAuthType.ProtectedResource,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
ConsumerKey = AppSettings.consumerKey,
ConsumerSecret = AppSettings.consumerKeySecret,
Token = this.accessToken,
TokenSecret = this.accessTokenSecret,
Version = "1.0"
};
var restClient = new RestClient
{
Authority = "http://api.twitter.com",
HasElevatedPermissions = true
};
var restRequest = new RestRequest
{
Credentials = credentials,
Path = "/1/statuses/update.json",
Method = WebMethod.Post
};
restRequest.AddParameter("status", txtTweetContent.Text);
restClient.BeginRequest(restRequest, new RestCallback(PostTweetRequestCallback));
To This
var credentials = new OAuthCredentials
{
Type = OAuthType.ProtectedResource,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader,
ConsumerKey = AppSettings.consumerKey,
ConsumerSecret = AppSettings.consumerKeySecret,
Token = this.accessToken,
TokenSecret = this.accessTokenSecret,
Version = "1.0"
};
var restClient = new RestClient
{
Authority = "http://api.twitter.com",
HasElevatedPermissions = true
};
var restRequest = new RestRequest
{
Credentials = credentials,
Path = "/1.1/statuses/update.json",
Method = WebMethod.Post
};
restRequest.AddParameter("status", txtTweetContent.Text);
restClient.BeginRequest(restRequest, new RestCallback(PostTweetRequestCallback));

httpcomponents's ssl connection results in socket is closed

I am trying to get some data from webserver which works fine with http.
But when I try https(ssl connection), I get the exceptions like below.
I get the http status code 200 and response content length 2230 which is correct.
java.net.SocketException: Socket is closed
at sun.security.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.java:1483)
at sun.security.ssl.AppInputStream.read(AppInputStream.java:92)
at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:166)
at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:90)
at org.apache.http.impl.io.AbstractSessionInputBuffer.read(AbstractSessionInputBuffer.java:183)
at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:144)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:121)
My code is like below with apache httpcomponents httpclient(4.2.5) library.
try {
HttpPost httppost = new HttpPost(uri);
HttpHost targetHost = new HttpHost(HOST_NAME, HOST_PORT, PROTOCOL);
InputStreamEntity reqEntity = new InputStreamEntity(new ByteArrayInputStream(request), -1);
String contentType = TSPConstants.CONST_TSA_CONTENT_TYPE_TSREQUEST;
reqEntity.setContentType(contentType);
reqEntity.setChunked(true);
// It may be more appropriate to use FileEntity class in this particular
// instance but we are using a more generic InputStreamEntity to demonstrate
// the capability to stream out data from any arbitrary source
//
// FileEntity entity = new FileEntity(file, "binary/octet-stream");
httppost.setEntity(reqEntity);
//Authentication
httpclient.getCredentialsProvider().setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new UsernamePasswordCredentials(id, password));
// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local
// auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
// Add AuthCache to the execution context
BasicHttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(ClientContext.AUTH_CACHE, authCache);
httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
//SSL
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme sch = new Scheme("https", HOST_PORT, ssf);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
System.out.println("executing request " + httppost.getRequestLine());
httpclient.execute(httppost, httpContext);
HttpResponse response = send(request);
HttpEntity resEntity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (resEntity != null) {
System.out.println("Response content length: " + resEntity.getContentLength());
System.out.println("Chunked?: " + resEntity.isChunked());
}
EntityUtils.consume(resEntity);
resEntity.getContent()
} finally {
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
Basically the answer gave #Avner in the comment.
The problem (for me) was, that the response was closed before the entity was read.
I did something like this, which was wrong:
HttpEntity entity = null;
try (CloseableHttpResponse response = client.execute(request)) {
entity = response.getEntity();
}
read(entity);
The following worked:
try (CloseableHttpResponse response = client.execute(request)) {
HttpEntity entity = response.getEntity();
read(entity);
}
The maybe not so obvious part: The try-with-resources block in the first example closed the stream, before it was read.