How to add Client Certificates ASP.NET 4.6 - asp.net

I'm trying to add this certificates into my code to make a HTTP Request on Asp.NET 4.6.
Anyone have any idea how to insert them on the request?
For now all I have in code is:
string privateKey = File.ReadAllText(#"C:\izio\clientid.key");
var certificate = new X509Certificate2(#"C:\izio\clientidwin.crt", #"");
HttpClientHandler handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(certificate);
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls12;
HttpClient client = new HttpClient(handler);
Thanks!!

Related

Is it possible in a .NET Core application to retrieve a certificate from AWS Certificate Manager and use it in a HttpClient post?

My .Net core application makes a post request to an external web service using HttpClient. The external web service requires a certificate to validate against.
The certificates are installed in AWS and I have an ARN that points to the certificate.
Is it possible to get the certificate programitically from AWS Certificate Manager and use this in my HtppClient, for example this is the code I would use normally to add a certificate but I need to get it from AWS.
private HttpClientHandler HttpClientHandler()
{
var handler = new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = SslProtocols.Tls12
};
handler.ClientCertificates.Add(new X509Certificate2("cert.crt")); //TODO: fetch from AWS.
return handler;
}
So, it's possible.
I installed AWSSDK.Core and AWSSDK.CertificateManager from NuGet.
Then, I created a credentials file for AWS, see instructions from Amazon
https://docs.aws.amazon.com/cli/latest/userguide/cli-config-files.html
Next, I used the AmazonCertificateManagerClient to get the certificate.
AmazonCertificateManagerClient client = new AmazonCertificateManagerClient();
var certificates = client.GetCertificateAsync(arn).Result;
I then converted the certificate from string to bytes and then add to the handler.
var handler = new HttpClientHandler{
ClientCertificateOptions = ClientCertificateOption.Manual,
SslProtocols = SslProtocols.Tls12
};
byte[] toBytes = Encoding.ASCII.GetBytes(certificates.Certificate);
var cert = new X509Certificate2(toBytes);
handler.ClientCertificates.Add(cert);
var httpClient = new HttpClient(handler);
Obviously, not production worthy code, hope it helps.
As mentioned by Zack the accepted answer does not work. It does retrieve a certificate out of ACM but it is not usable as a client certificate for HttpClient because it has no private key.
As far as I can tell there is no way to get the private key out of ACM so I ended up putting it in SecretsManager and doing something like:
var certManagerClient = new AmazonCertificateManagerClient();
var awsCert = certManagerClient.GetCertificateAsync(arn).Result;
byte[] awsBytes = Encoding.ASCII.GetBytes(awsCert.Certificate);
var cert = new X509Certificate2(awsBytes);
var secretsManagerClient = new AmazonSecretsManagerClient();
var privateKey = secretsManagerClient.GetSecretValueAsync(new GetSecretValueRequest { SecretId = secretId }).Result.SecretString;
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
var privateKey = RSA.Create();
privateKey.ImportRSAPrivateKey(new ReadOnlySpan<byte>(privateKeyBytes), out _);
var certWithPrivateKey = cert.CopyWithPrivateKey(privateKey);
And then using certWithPrivateKey in my HttpClientHandler:
var handler = new HttpClientHandler { ClientCertificateOptions = ClientCertificateOption.Manual };
handler.ClientCertificates.Add(certWithPrivateKey);
If you use the AWS SDK you can get certificates using the AmazonCertificateManagerClient. See the AWS SDK documentation for details. (select Amazon.CertificateManager > AmazonCertificateManagerClient)

.net core 2.0 proxy requests always result in http 407 (Proxy Authentication Required)

I'm trying to make HTTP requests via a WebProxy in a .net core 2.0 web application. The code I've got works fine in .net framework so I know (believe) its not an environmental issue. I've also tried to make the request using both HttpWebRequest and HttpClient but both mechanisms always result in 407 (Proxy Authentication Required) http error in .net core. Its as if in .net core the credentials I'm supplying are always being ignored.
Here is the code I've been using:
public void Test()
{
var cred = new NetworkCredential("xxxxx", "yyyyyy");
var proxyURI = new Uri("http://xxx.xxx.xxx.xxx:80");
var destinationURI = new Uri("http://www.bbc.co.uk");
WebProxy proxy = new WebProxy(proxyURI, false) { UseDefaultCredentials = false, Credentials = cred };
MakeProxyRequestViaHttpWebRequest(proxy, destinationURI);
MakeProxyRequestViaHttpClient(proxy, destinationURI);
}
private void MakeProxyRequestViaHttpClient(WebProxy proxy, Uri destination)
{
HttpClientHandler handler = new HttpClientHandler()
{
Proxy = proxy,
UseProxy = true,
PreAuthenticate = true,
UseDefaultCredentials = false
};
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = client.GetAsync(destination).Result;
if (response.IsSuccessStatusCode)
{
HttpContent content = response.Content;
string htmlData = content.ReadAsStringAsync().Result;
}
else
{
HttpStatusCode code = response.StatusCode;
}
}
private void MakeProxyRequestViaHttpWebRequest(WebProxy proxy, Uri destination)
{
HttpWebRequest req = HttpWebRequest.Create(destination) as HttpWebRequest;
req.UseDefaultCredentials = false;
req.Proxy = proxy;
req.PreAuthenticate = true;
using (WebResponse response = req.GetResponse())
{
using (StreamReader responseStream = new StreamReader(response.GetResponseStream()))
{
string htmlData = responseStream.ReadToEnd();
}
}
}
I've tried the following in .net core but the result is always 407:
Run the code in a console app
Implement IWebProxy and use that as the proxy
Set default values for other properties on WebProxy, HttpClient, etc. (removed on the example above because it works fine on .net standard)
I've run out of ideas and things to try. I have the following questions:
Does the code need to be different between .net core vs .net framework
Are there additional things that need to go into appsettings.json (ie. the config that would have gone into web.config)
Is there any additional configuration code required in Startup.cs
Should I be looking to use an external library
How would I trouble shoot what the issue is? Fiddler doesn't seem to be helping but then I haven't looked to hard at configuring it.

A connection attempt failed because the connected party did not properly -- Using HttpClient

I am receiving connection attempt failed to my web api service when I called the service from asp.net mvc application. If I call the service from a browser or from MVC application hosted on another server, it works.
It also works if I host the application in test server or development server.
It doesn't work only when I host the application on that server and call the service from the mvc app.
Any suggestion. Is something on the hosted server is blocking the connection.
using (var client = new HttpClient())
{
string baseUrlFromConfig = ConfigurationManager.AppSettings["webServiceUrl"];
client.BaseAddress = new Uri(baseUrlFromConfig);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Uri myUri = new Uri(baseUrlFromConfig + "api/account/ConfirmEmail?e=" + e + "&code=" + code, UriKind.Absolute);
var response = client.GetAsync(myUri).Result;
if (response.IsSuccessStatusCode)
{
string responseString = response.Content.ReadAsStringAsync().Result;
}
}

Authorization header with HttpGet with proxy

I am using HttpGet with a proxy setting. The call works for endpoints that don't need an authorization token. For services that need a token, I use setHeader(), but see an error saying auth token missing.
What am I missing ?
HttpGet get = new HttpGet(endPoint);
get.setHeader("Authorization", token);
HttpHost proxy = new HttpHost("exampleproxy.com",8080);
RequestConfig config = RequestConfig.custom() .setProxy(proxy).build();
get.setConfig(config);
CloseableHttpClient httpclient = HttpClients.custom().setDefaultCredentialsProvider(credsProvider).build();
CloseableHttpResponse response = httpclient.execute(get);
BufferedReader responseReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

calling a wcf webapi service with basic authentication from an asp.net 2.0 project

I'm working on a project that uses wcf webapi to expose all it's functionality as web services. I then consume these with various views (well two for now). One of these views is a legacy asp.net 2.0 project that will eventually be phased out once this new project has feature parity. I'm trying to consume these services by adding a service reference to the project but can't get it to work because the wcf api uses basic http auth and I can't configure that in the wizard. How do I manually add the service reference to my asp.net project?
Thanks!
When working with WCF Web API, you don't use service references but the new HttpClient instead e.g.:
var client = new HttpClient();
var byteArray = Encoding.ASCII.GetBytes(userName + ":" + password);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
var task = client.GetAsync("http://webapi/contact/1");
var contact = task.ContinueWith(
t => {
return t.Result.Content.ReadAsAsync<Contact>();
}).Unwrap().Result;
If you need to use .NET 2.0, you can use the HttpWebRequest (the HttpClient sample relies on .NET 4.0 as it is part of WCF Web API):
Uri myUri = new Uri("http://webapi/contact/1");
WebRequest myWebRequest = HttpWebRequest.Create(myUri);
HttpWebRequest myHttpWebRequest = (HttpWebRequest)myWebRequest;
NetworkCredential myNetworkCredential =
new NetworkCredential(username, password);
CredentialCache myCredentialCache = new CredentialCache();
myCredentialCache.Add(myUri, "Basic", myNetworkCredential);
myHttpWebRequest.PreAuthenticate = true;
myHttpWebRequest.Credentials = myCredentialCache;
WebResponse myWebResponse = myWebRequest.GetResponse();
Stream responseStream = myWebResponse.GetResponseStream();

Resources