Directly check a domain's SSL certificate without a callback in C# - c#

I'm attempting to directly retrieve the SSL certificate for a given domain, so that I can access its fields (such as Issuer, Expiration date, Errors, etc).
All the non-deprecated examples I can find, including from Microsoft, make use of the ServerCertificateCustomValidationCallback method, such as in the example here: https://learn.microsoft.com/en-us/dotnet/api/System.Net.Http.HttpClientHandler.ServerCertificateCustomValidationCallback?view=net-7.0
The issue is that I want to sequentially execute my code as follows, without relying on any callback function in a separate thread. What I want is for example the following:
...
var cert = await httpClient.SomehowRequestCertificateFromUrl("https://someUrl.com"/);
Console.WriteLine($"The issuer is: {cert.issuer}");
Essentially I want to maintain the same scope at the point I make the request and receive the response, awaiting for the operation to complete. Using the callback method that's typically used, I lose the scope. I don't wish to store the certificate anywhere, I merely want to examine the certificate response from a request within the same scope.
Is there any way to achieve what I want?
For reference, I'm creating a .Net Core console application, not using Asp.Net, so I have no need for a callback, and a callback goes against what I want to do.

Related

.Net core HttpClientFactory how to dynamically add certificates

When registering with HttpclientFactory, can only do certificate injection in startUp. Is there any way to do dynamic injection?
services.AddHttpClient().ConfigurePrimaryHttpMessageHandler(() => {
var certificate = new X509Certificate2("", "", X509KeyStorageFlags.MachineKeySet);
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(certificate);
return handler;
});
For any future users who stumble across this question, I had a very similar need and was frustrated with this limitation of the default HttpClientFactory implementation; I had a very robust HttpClient pipeline with Polly and delegating handlers all chained up, but the underlying certificate that needed to be used might be different based on the specific endpoint URL, and I didn't necessarily want to register four or five versions of the same pipeline for different typed clients nor did I want to have to have the certificates available at the composition root. I wrote a library to extend DefaultHttpClientFactory to add support for contextually applied handlers while retaining the pooling, expiry, and typed client pipelines that DefaultHttpClientFactory provides.
https://github.com/agertenbach/Ringleader
https://www.nuget.org/packages/Ringleader
The DefaultHttpClientFactory uses the named client's name or typed client's type name to uniquely distinguish and track both the pipeline and options you attach at startup, as well as the name that the resultant primary handler will have in the managed pool; for example, a typed client "MyTypedClient" will have primary handlers in the pool named "MyTypedClient" that will get reused and renewed as needed.
By decorating the HttpClientFactoryOptions IOptionsMonitor that DefaultHttpClientFactory uses and hooking in an IHttpMessageHandlerBuilderFilter during the handler management processes, it's possible to keep all the pipeline stuff working, but create and resolve more granular handlers in the pool, i.e. "MyTypedClient-contextA", "MyTypedClient-contextB", that have different contextual settings, such as a different certificate. The library just requires you implement a couple interfaces to distinguish those contexts and then return a well-formed primary handler for that context when a new one must be created.
This still is not ideal if your certificates are going to be different on every request or very infrequently reused (as you're losing all the benefits of the pooling anyways), but if you have a well-developed typed client pipeline that has a different cert for URL A vs URL B (or user A vs user B, etc.) and you're connecting to them all fairly frequently, this might save you some headaches. Happy for any feedback or comments if this helps you out.
The delegate you are passing in for ConfigurePrimaryHttpMessageHandler is called depending on its lifetime (two minutes by default). So in that delegate you can actually make a dynamic list of certificates (and it will called every two minutes -when you create the HttpClient instance-).
You can choose the lifetime of the handler using SetHandlerLifeTime (on the builder on AddHttpClient()) and choose a shorter time span if it needs be... however if you need a different handler for the same client many times, that defies the whole purpose of using the HttpClientFactory.
So I see three options:
If you have sets of different certificates, use named or typed clients and assign a different handler for each name/type.
If, instead, your http client "generally" uses the same certificates and they just change at some point in time... then set a reasonable lifespan (with SetHandlerLifetime) depending on your application needs.
If you actually need the certificates to be defined per-request (or per-instance)... then don't use the HttpClientFactory or any other client pooling method because you do not want to have the clients pooled at all and you want a different one (with its own handler) per request.

Appropriate request method to send tokens

What is the correct method to consume a resource passing a token after i am correctly authenticated? For example, is it right to do a GET with a Bearer Authorization to get an array of JSON objects or should i make a POST request?
According to Wikipedia
GET requests a representation of the specified resource. Note that GET
should not be used for operations that cause side-effects, such as
using it for taking actions in web applications. One reason for this
is that GET may be used arbitrarily by robots or crawlers, which
should not need to consider the side effects that a request should
cause.
and
POST submits data to be processed (e.g., from an HTML form) to the
identified resource. The data is included in the body of the request.
This may result in the creation of a new resource or the updates of
existing resources or both.
So, it does not depend on passing a token. It depends whether your request just retrieves the resource or it creates/updates an existing resource.
For just retrieving a resource use GET.
For creating a new resource/updating a new resource use POST.

Global variables in WCF REST services

My applciation works as follows
[user]----username/password/domain----->[WCF service]
then i access the domain server to see to which actual DB the user is associated,
after getting that, i validate the user in his actual DB(DB is per domain)
the problem is that i need a place to store the domain name for the following requests against the db.
for example,if the users calls a WCF service operation:
Test()
first the validation procedure is called, (WCF UserNamePasswordValidator) which validates the user password(which is sent as part of the header for REST or as part of the SOAP), and the next function to be called is the Test, but by then i cant tell the domain of the user(to actually serve the request agains that domain..)
I dont want to change the signature of each domain to
Test(string domain)
I cant simply access the headers since i expose the same methods both as REST and as SOAP and the authentication is different for each of them..(one is with headers as with Amazon S3 and the later is using the SOAP standard)
so basically i'm looking for a global, per call storage.(i want to avoid the Per-Call initiation method)
thanks.
EDIT:
Maybe i should use the ThreadStaticAttribute? will that work?
This will not work. You can't store anything in UserNamePasswordValidator. It even doesn't have access to OperationContext because it runs on different thread.
The way to do this is create custom message inspector and extract the information from custom message header to custom operation context extension as Frank mentioned.
WCF knows a Current OperationContext. You can write your own extensions for it. Unrelated to this issue, I used the same mechanics in this NHibernate Session management here, which may work in its concept for you as well. It accesses the InstanceContext, but the concepts are similar.

When should I use OperationContextScope inside of a WCF service?

I'm currently working on a WCF service that reaches out to another service to submit information in a few of its operations. The proxy for the second service is generated through the strongly typed ProxyFactory<T> class. I haven't experienced any issues but have heard I should do something like the following when making the call:
using (new OperationContextScope((IContextChannel)_service))
_service.Send(message);
So my question is: when is creating this new OperationContextScope appropriate, and why?
Thanks!
If you are using callbacks or if you want to modify the message or headers then you need to use OperationContextScope. Your service might need to modify outgoing headers while calling that another service.
When you establish OperationContextScope then you can:
Access and modify incoming and outgoing message headers and other properties.
Access the runtime, including dispatchers, the host, channel, and extensions.
Access other types of contexts, such as security, instance, and request contexts.
Access the channel associated with the OperationContext object or (if the channel implements System.ServiceModel.Channels.ISession) the associated channel's session identifier.
The other service which you call, is it a session-based service? Probably you need to look at its sample client code or documentation if available.

ICerfiticatePolicy and ServicePoint

So I'm using the PayPal API. They require bigger companies to send an X509Certificate along with each SOAP API request. I've never heard of using a cert, it's always been just send the API signature along with an API request.
So I first created a class called Cerficate that implements the .NET ICerfiticatePolicy. One of the member methods, really the only one you have to implement is:
System.Net.ICertificatePolicy.CheckValidationResult(System.Net.ServicePoint, System.Security.Cryptography.X509Certificates.X509Certificate, System.Net.WebRequest, int)
So far I'm having trouble really understanding what to pass to this method. I guess the method simply validates that the Cerfiticate is valid. So I'm not sure what ServicePoint is and what to pass into it. I assumed it was my web service reference and a proxy class within such as the PayPalAPIAAInterfaceClient
I also see a very old example using ServicePointManager.S for something but I don't understand it, even after looking at MSDN. So I guess you are to use ServicePointManager.ServerCertificateValidationCallback and I suppose set the callback to the CheckValidationResult? If so, when do you do this? It's just very confusing to me.
Also, So I guess I create an instance of my Certificate class and set the certificate properties by reading the P12 certificate from my disk and then pass in that to this method to check if it's valid? I guess that's right.
I'm still trying to figure out this whole thing and I'm really stuck on the ServicePoint as well as WebRequest because really I'm using a proxy class in PayPal which does the under the hood sending of the request. So I don't see how I can even pass in type WebRequest because I'm using a proxy method for that anyway. So what would I even pass for the WebRequest param? I'm using a SOAP API WSDL, not NVP here so I'm not for example creating an HttpWebRequest variable like you do with REST services in order to send the API request over Http.
so far here's what I've tried:
PayPalAPIAAInterfaceClient client = new PayPalAPIAAInterfaceClient();
Certificate x509Certificate = new Certificate();
ServicePointManager.ServerCertificateValidationCallback = x509Certificate.CheckValidationResult();
client.ClientCredentials.ClientCertificate.Certificate = x509Certificate;
the problem is, what do I pass in for the ServicePiont and the rest of the params for CheckValidationResult?? I don't even know if I'm calling this right.
It's certainly not unheard of and in fact fairly common to secure SOAP services with X.509 certificates using the WS-Security spec - in fact, we do this for all of our internal and external web services. All web service frameworks including WCF are specifically designed to make this as easy as possible.
You should never have to use the ServicePointManager or ICertificatePolicy with a SOAP service using WS-Security. Unless there's something truly bizarre about PayPal's API, I think you're on the wrong track with that. All you have to do in WCF is this:
var client = new PayPalAPIInterfaceClient();
X509Certificate2 certificate = (...);
client.ClientCredentials.ClientCertificate.Certificate = certificate;
client.AddressVerify(...); // or whatever method you want to call
You don't even really need to write this code; if you have the certificate installed in the server's certificate store then you just edit the binding and behavior elements of the app.config - or use the WCF Service Configuration Editor, which is a lot easier.
Of course, in order to do this you have to have an X.509 certificate, and PayPal has to know about it. You can't just write new X509Certificate2(). You need to have a .pfx or .p12 file somewhere or, as mentioned above, have the certificate physically installed (this is the easiest way and the most secure because you're not hard-coding a password). And you need to upload the public key to PayPal.
You might be able to use OpenSSL to create a cert. PayPal's EWP page suggests that they'll accept these and gives instructions on how to create them, although it's not entirely clear whether or not the same process can be used for their SOAP API. It could be that they require a "real" certificate from Verisign, Thawte, etc. - I would try OpenSSL first and see, or just ask them.
There's a pretty comprehensive guide to the whole process here - you'll probably want to skip the sections on generating the certificate unless you have a Microsoft CA somewhere. Again, for that part, you'll probably want to try using the OpenSSL utility instead and follow PayPal's instructions, then install the cert on your server and skip to step 7 of that guide.

Categories

Resources