Am trying to query an odata web.api hosted on IIS7. The site requires a client cert. How do I attach the certificate to the query? Using web.api 2, framework 4.5, mvc5
string certPath = #"E:\ClientCertificate.cer";
Uri uri = new Uri("https://server/odata/");
var container = new CourseService.Container(uri);
container.ClientCertificate = new X509Certificate(certPath);
The extension to the container class was achieved by reading this:
http://bartwullems.blogspot.co.uk/2013/03/odata-attach-client-certificate-through.htm
You could attach the certificate to request in SendRequest2 event yourself:
context.SendingRequest2 += (sender, eventArgs) =>
{
// We can safely cast RequestMessage to HttpWebRequestMessage if this is not in batch.
if (!eventArgs.IsBatchPart)
{
((HttpWebRequestMessage)eventArgs.RequestMessage).HttpWebRequest.ClientCertificates.Add(theCertificate);
}
};
Related
I have an API Gateway that uses IAM authorization. I have a C# application that I'm hoping to call the API with. I started with a GetMethodRequest but I don't see anyway to set the PathPart parameter.
var userId = _remoteCredentials.UserId;
var key = _remoteCredentials.Key;
var client = new AmazonAPIGatewayClient(userId, key, Amazon.RegionEndpoint.USEast2);
GetMethodRequest getMethodRequest = new GetMethodRequest();
getMethodRequest.HttpMethod = HttpMethod.Get.ToString();
getMethodRequest.ResourceId = "4abcde";
getMethodRequest.RestApiId = "aasfasdfs";
var task = Task.Run(async () => await client.GetMethodAsync(getMethodRequest).ConfigureAwait(false));
I was expecting something like the Test-AGInvokeMethod in the Powershell SDK which allows me to set the query string and the path.
$response = Test-AGInvokeMethod
-RestApiId aasfasdfs
-ResourceId 4abcde
-HttpMethod GET
-PathWithQueryString '/etl/upload_url'
Any help is greatly appreciated.
EDIT Below is something of a solution that I ended up using the AWS4RequestSigner is a library that I found on Github
var signer = new AWS4RequestSigner(userId, key);
var destinationUrl = string.Format("https://ad9vxabc123.execute-api.us-east-2.amazonaws.com/dev/etl/summary/latest?tms_id={0}&model_id={1}", _tmsId, _modelId);
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(destinationUrl),
};
var signed = Task.Run(async () => await signer.Sign(request, "execute-api", "us-east-2").ConfigureAwait(false));
var signedResult = signed.Result;
The AmazonAPIGatewayClient is for managing your API Gateway e.g. adding new stages or deleting API keys.
You're looking to invoke a method on your API Gateway, like Test-AGInvokeMethod does.
To invoke your API gateway, you need to call the deployed API endpoint using a HTTP client.
.NET's in-built HttpClient is a good start.
I have a solution like this :
-MySolution
|--MyWCFWrapper
|--MyaspnetcoreWebApp
|--ConsoleTestApp
MyWCFWrapper is a .NET Standard library consumes the WCF service added as a WCF reference using the Visual Studio import wizard.
The MyaspnetcoreWebApp application provides controllers for a front end to consume. In this controller, I am instantiating and making calls to MyWCFWrapper library.
The ConsoleTestApp is a console application that also makes calls to MyWCFWrapper library for testing.
I get an error:
System.ServiceModel.Security.SecurityNegotiationException: 'Could not establish trust relationship for the SSL/TLS secure channel with authority 'exampleabc.com'
when I make WCF service calls.
The reason for this error is my WCF service at exampleablc.com is a test server and has a self signed certificate (name different to the webservice) and is also expired.
Workaround that works in ConsoleTestApp :
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) =>
{
return true;
};
MyWCFWrapperClass api = new MyWCFWrapperClass(..);
api.SendNewInfo("NewInfo");
This is not recommended, but this is ok for me for now because it's a test server.
The same workaround does not work in the MyaspnetcoreWebApp controller. What I have tried to make it work :.
In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient("SeitaCertificate").ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = (request, certificate, certificateChain, policy) =>
{
return true;
}
};
});
services.AddControllersWithViews();
----
}
Added the certificate to Trusted Root Certificate Authorities on my local PC. This fails probably because the certificate has expired.
The certificate error is raised in the WCF call library and I have not been able to find a way to ignore the cert error.
What I can do is at least have the certificate updated so that it is not expired. (I have started this process and it is likely to take some time)
I would like to learn a way how to capture and ignore these certificate errors selectively and appropriately for calling a WCF library in a asp .net core 3.1 web application. How can I do that?
You can refer to the following code to bypass certificate verification:
BasicHttpsBinding binding = new BasicHttpsBinding();
binding.Security.Mode = BasicHttpsSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, new EndpointAddress(uri));
factory.Credentials.ServiceCertificate.SslCertificateAuthentication = new System.ServiceModel.Security.X509ServiceCertificateAuthentication()
{
CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None,
RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck
};
You can resolve this issue by overriding the certificate validation method X509CertificateValidator
class Program
{
static void Main(string[] args)
{
var client = new YourServiceReference.Cient();
// Bypass certificate verification
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication
{
CertificateValidationMode = X509CertificateValidationMode.Custom,
CustomCertificateValidator = new CustomCertificateValidator()
};
// --------
}
internal class CustomCertificateValidator : X509CertificateValidator
{
// Override certificate validation
public override void Validate(X509Certificate2 certificate) { }
}
}
I'm working on several Dotnet Core APIs hosted on a Kubernettes cluster and some of the APIs do call other APIs, and that's when the exception in title is thrown.
It doesn't matter whether I edit the appsettings.json and replace all https by http -in fact people at devops team suggested me to do that- as the same exception is thrown.
This is the little piece of code I use for the http call:
int idCity = Convert.ToInt32(Utils.GetConfig().GetSection("Settings")["idCity"]);
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(Utils.GetConfig().GetSection("xxx")["xxxx"]);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string queryString = "?startDate=" + startDate + "&endDate=" + endDate + "&idCity=" + idCity;
HttpResponseMessage response = client.GetAsync(queryString).GetAwaiter().GetResult();
if (response.IsSuccessStatusCode)
{
var resultHolidays = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
return JsonConvert.DeserializeObject<JSONGeneric<HolidayDTO>>(resultHolidays);
}
else
{
return null;
}
}
I have a copy of the certificate in .crt format and also tried:
string certPath = Path.Combine(_env.ContentRootPath, _configuration.GetSection("Certificate")["certificatePath"]);
string pwd = _configuration.GetSection("Certificate")["certificatePwd"];
HttpClientHandler requestHandler = new HttpClientHandler();
requestHandler.ClientCertificates.Add(new X509Certificate2(certPath, pwd,
X509KeyStorageFlags.MachineKeySet));
using (HttpClient client = new HttpClient(requestHandler))
{
...
}
To no avail, as the same exception is thrown.
I'm not an expert on working with certificates, but I truly need to make this to work, to be able to make on api in a pod call other api, so any help will be much appreciated.
Update 1: The "weird" thing is that if I just copy the url to be requested -no matter if you use http or https- and paste it into a browser with the certificate installed it does work. If you copy and paste the http version of the url n the browser, Kubernettes (or whoever it is) does a redirection to the https version but in the end you get results. Not from .Net
I would start by disabling certificate validation in the client and see what is the behavior. You can do it like this:
var httpHandler = new HttpClientHandler {
ServerCertificateCustomValidationCallback = (m, crt, chn, e) => true
};
using var httpClient = new HttpClient(httpHandler);
// rest of the code
If the call succeeds, the next step is to adapt the certificate validation callback to check the server's certificate.
Note: in your example you're configuring a client certificate, which is useful if you host a service and want to authorize your clients based on their certificates, as described here. From the problem description I understand that what you need is the opposite: validate the server certificate in your client.
var srvCrt = new X509Certificate2(certPath, pwd);
var httpHandler = new HttpClientHandler {
ServerCertificateCustomValidationCallback = (m, crt, chn, e) => {
return crt.Thumbprint == srvCrt.Thumbprint;
}
};
using var httpClient = new HttpClient(httpHandler);
// rest of the code
I am trying to connect from a client to the service. The service is configurated to use a self signed Ssl certificate and I am trying to configurate the client with the client certificate. I am using this code:
string cacert = System.IO.File.ReadAllText("certificados/ca.crt");
string cert = System.IO.File.ReadAllText("certificados/client.crt");
string key = System.IO.File.ReadAllText("certificados/client.key");
KeyCertificatePair keypair = new KeyCertificatePair(cert, key);
SslCredentials sslCreds = new SslCredentials(cacert, keypair);
var channel = GrpcChannel.ForAddress("https://x.x.x.x:5001", new GrpcChannelOptions { Credentials = sslCreds });
var client = new Gestor.GestorClient(channel);
But I am getting the following error: using SslCredentials with non-null arguments is not supported by GrpcChannel.
I don't understand very good the message error. SslCredentials is ChannelCredentials? type, and SslCreds is Grpc.Core.SslCredentials. It can be compiled, so the type I guess it is correct.
What I would like to know it is how I can configure the client to use the self signed certificate that I have created.
Thanks.
The SslCredentials support in only available grpc-dotnet is to provide some level of compatibility with Grpc.Core in the most common use case, it doesn't expose all the functionality though. In grpc-dotnet, only SslCredentials() (parameterless which uses the default roots) is supported. If you want to provide your self-signed creds, you can certainly do that, you'll need to use a different API for configuring GrpcChannel:
See example here (creating a GrpcChannel with custom credentials).
https://github.com/grpc/grpc-dotnet/blob/dd72d6a38ab2984fd224aa8ed53686dc0153b9da/testassets/InteropTestsClient/InteropClient.cs#L170
I spend a fair bit of time googling around for solutions to this problem, and didn't find a concise answer. Here is ultimately how I was able to configure a dotnet client to use mutual SSL authentication:
MyService.MyServiceClient GetClient(){
var httpClientHandler = new HttpClientHandler();
// Validate the server certificate with the root CA
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, _) => {
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(new X509Certificate2("ca.crt"));
return chain.Build(cert);
};
// Pass the client certificate so the server can authenticate the client
var clientCert = X509Certificate2.CreateFromPemFile("client.crt", "client.key");
httpClientHandler.ClientCertificates.Add(clientCert);
// Create a GRPC Channel
var httpClient = new HttpClient(httpClientHandler);
var channel = GrpcChannel.ForAddress("https://localhost:8080", new GrpcChannelOptions{
HttpClient = httpClient,
});
return new MyService.MyServiceClient(channel);
}
I want to test my Web API service using in-memory HttpServer.
The current setup looks the following:
var httpConfig = CreateTestHttpConfiguration();
var server = new HttpServer(httpConfig);
var handler = new WebRequestHandler();
var cert = new X509Certificate2("filename", "password");
handler.ClientCertificates.Add(cert);
var client = HttpClientFactory.Create(handler, server);
I can make requests to the server using these client and everything works except that certificate is not added to the request.
As I understand that happens since server executes before handler (I can't rearrange them since they implement different interfaces) and since server immediately responses handler is not even executed (I've tested this assumption using HttpClientHandler subclass instead of handler).
So my question is: How can I add the client certificate for in-memory testing?
This approach will do it:
var server = new HttpServer(configuration);
var invoker = new HttpMessageInvoker(server);
var certificate = GetCertificate();
var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/YourPath");
request.Properties[HttpPropertyKeys.ClientCertificateKey] = certificate;
var result = await invoker.SendAsync(request, CancellationToken.None);