Setting up ssl for http: ^0.12.0 package - http

I wonder how can I setup ssl for http(http: ^0.12.0) package in Flutter,
without migrating to dart:io.
Currently I'm using:
http.Client httpClient = http.Client();
and I do not see any options there to setup ssl.
Do I have to use
final SecurityContext context = SecurityContext.defaultContext;
HttpClient client = HttpClient(context);
from dart:io?

You can create a HttpOverride to make the Client ignore bad certificates as mentioned on this GitHub issue ticket. This is only recommended to be used in development builds.
class DevHttpOverrides extends HttpOverrides {
#override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
}
}
Then initialize the HttpOverride to be used.
HttpOverrides.global = DevHttpOverrides();

Related

How to view HTTP commands sent by Cosmos DB SDK V3

We are using OData on top of SQL SDK V3 and we want to view generated queries sent to CosmosDB. I have changed connection mode to Gateway so HTTPS connection is used and I can view dependencies in Application Insights ... but I can only see the URL and it is not clear whether it is GET or POST and no other details.
I have tried Rhino Profiler but it says SDK version is not supported.
I am sure there should be a way to view queries.
I would expect App Insights to also track the verb but the other alternative is to add the logging yourself. You can inject a handler on the pipeline and access the RequestMessage.Method property (full solution https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos.Samples/Usage/Handlers/).
class LoggingHandler : RequestHandler
{
private readonly TelemetryClient telemetryClient;
public LoggingHandler()
{
this.telemetryClient = new TelemetryClient();
}
public override async Task<ResponseMessage> SendAsync(
RequestMessage request,
CancellationToken cancellationToken)
{
using (Microsoft.ApplicationInsights.Extensibility.IOperationHolder<RequestTelemetry> operation = this.telemetryClient.StartOperation<RequestTelemetry>("CosmosDBRequest"))
{
this.telemetryClient.TrackTrace($"{request.Method.Method} - {request.RequestUri.ToString()}");
ResponseMessage response = await base.SendAsync(request, cancellationToken);
operation.Telemetry.ResponseCode = ((int)response.StatusCode).ToString();
operation.Telemetry.Success = response.IsSuccessStatusCode;
this.telemetryClient.StopOperation(operation);
return response;
}
}
}

Client certificate not included by HttpClientHandler in .net core

I'm having difficulties sending a certificate using HttpClientHandler because the certificate simply won't appear on Server's request. The certificate has the proper EKU for server and client authentication, and Key Usage of "Digital Signature". #davidsh regarded the issue 26531 for the lack of logging that HttpClient had but running my project in Visual Studio (with logs set to Trace and using dotnet 3.1.401) no output error came out. I'm not very familiar at all with logman but I ran it when the issue supposed to happen as I executed my code and nothing from the log stood out indicating what the problem could be. Running out of options to test the code I attempted to add a certificate without the private key on the client request to see if the httpClientHandler.ClientCertificates.Add ... would throw any error saying something like "You need a certificate with private key to sign your request", shouldn't it say anything?
On client:
services.AddHttpClient<ILetterManClient, LetterManClient.LetterManClient>()
.ConfigureHttpClient(client =>
{
client.BaseAddress = new Uri(configuration.GetValue<string>("Microservices:LetterManAPI"));
})
.ConfigurePrimaryHttpMessageHandler(() =>
{
HttpClientHandler httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = ValidateServiceCertficate;
httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
clientCertificate = new X509Certificate2("client_cert.pfx", "developer");
httpClientHandler.ClientCertificates.Add(clientCertificate);
return httpClientHandler;
});
On server:
public class ValidateClientCertificates : TypeFilterAttribute
{
public ValidateClientCertificates() : base(typeof(ValidateClientCertificatesImpl))
{
}
private class ValidateClientCertificatesImpl : IAsyncAuthorizationFilter
{
X509Certificate2 clientCertificate;
public ValidateClientCertificatesImpl(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
{
clientCertificate = new X509Certificate2("client_cert.crt");
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var certificate = await context.HttpContext.Connection.GetClientCertificateAsync();
if ((certificate == null) || (!certificate.Thumbprint.Equals(clientCertificate.Thumbprint)))
{
context.Result = new UnauthorizedObjectResult("");
return;
}
}
}
}
Side note:
I've been also trying to debug my project using code compiled from corefx repo to see what's going but Visual Studio insists reference the code from local installed sdk instead of the project from corefx that it's referencing it but this is another issue.
I've created this project that simulates the issue. It creates the certificates and it has two projects with one service and another client implemented.
Any help will be very welcomed.
These are the guidelines for Kestrel to require Client certificate but it assumes that the CA is installed in the machine otherwise you have to specify the client certificate directly when configuring Kestrel server as follows:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(o => {
o.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
o.ClientCertificateValidation = ValidateClientCertficate;
});
});
});
public static Func<X509Certificate, X509Chain, SslPolicyErrors, bool> ValidateClientCertficate =
delegate (X509Certificate serviceCertificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
X509Certificate2 clientCertificate;
clientCertificate = new X509Certificate2("client.crt");
if (serviceCertificate.GetCertHashString().Equals(clientCertificate.Thumbprint))
{
return true;
}
return false;
};
Unfortunately, you can't require Client certificates for a specific route as I intended.

Can you run a asp.net core 3.0 gRPC CLIENT in IIS? (possibly on Azure?)

I've read a lot of conflicting information about this and it seems people are not 100% clear on what is possible and what is not. I am certain that you cannot host a gRPC server app in IIS due to the HTTP/2 limitations. The documentation is pretty clear. However, I want to use IIS as a reverse proxy, with the internal side communicating using gRPC. So the client would be in IIS, not the server. I assumed that since the communication at this point (i.e. the back end) was not funneled through IIS, there would be no issue with this. However, I keep seeing mixed answers.
I have created a dumb webapp that is hosted in IIS Express and can successfully post to my service running on Kestrel with gRPC.
Client code sample below. The SubmitButton is just a form post on the razor page.
public async void OnPostSubmitButton()
{
// The port number(5001) must match the port of the gRPC server.
using var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(
new HelloRequest { Name = "GreeterClient" });
Console.WriteLine("Greeting: " + reply.Message);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
Server code is the boilerplate template for gRPC but looks like this:
namespace grpcGreeter
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
namespace grpcGreeter
{
public class GreeterService : Greeter.GreeterBase
{
private readonly ILogger<GreeterService> _logger;
public GreeterService(ILogger<GreeterService> logger)
{
_logger = logger;
}
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply
{
Message = "Hello " + request.Name
});
}
}
}
This works. But, because I keep seeing mixed information saying it that it won't, I am not certain that once I go to deploy the client code (i.e. the reverse proxy), if I will run into problems. I would like to use a host like Azure...but don't know if it's possible or not.
Any clarity on the subject would be greatly appreciated.
As far as I know, we could use asp.net core mvc or razor page application as the client to call the grpc server.
But gRPC client requires the service to have a trusted certificate when you hosted the application on remote server IIS.
If you don't have the permission to install the certificate, you should uses HttpClientHandler.ServerCertificateCustomValidationCallback to allow calls without a trusted certificate.
Notice: this will make the call not security.
Additional configuration is required to call insecure gRPC services with the .NET Core client. The gRPC client must set the System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport switch to true and use http in the server address.
Code as below:
AppContext.SetSwitch(
"System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
var httpClientHandler = new HttpClientHandler();
// Return `true` to allow certificates that are untrusted/invalid
httpClientHandler.ServerCertificateCustomValidationCallback =
HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var httpClient = new HttpClient(httpClientHandler);
var channel = GrpcChannel.ForAddress("https://localhost:5001",
new GrpcChannelOptions { HttpClient = httpClient });
var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = "World" });

How to define a custom port for the WebDAV server using sardine?

In Sardine how do I change the port number to something different from port 80 (for HTTP) and 443 (for HTTPS)?
The User guide states that I have to "override SardineImpl#createDefaultSchemeRegistry() or provide your own configured HTTP client instance by instantiating SardineImpl#SardineImpl(org.apache.http.impl.client.HttpClientBuilder)" but I can't find how to define the port.
When I instantiate SardineImpl using:
HttpClientBuilder builder = HttpClientBuilder.create();
SardineImpl sardine = new SardineImpl(builder, "user", "password");
byte[] data;
data = FileUtils.readFileToByteArray(new File("test.txt"));
sardine.put("http://webdav-server:8095/projects/", data);
I obtain:
org.apache.http.NoHttpResponseException: webdav-server:8095 failed to respond
The server is accessible via browser so the problem must be with the definition of the port and I could not find an example on how to do this.
Can someone help me on this? Thanks in advance.
This is what I figured out after racking my brain trying to find a solution. Hopefully it helps someone else:
HttpClientBuilder builder = new HttpClientBuilder(){
#Override
public CloseableHttpClient build() {
SchemePortResolver spr = new SchemePortResolver() {
#Override
public int resolve(HttpHost httpHost) throws UnsupportedSchemeException {
return 8443; // SSL port to use
}
};
CloseableHttpClient httpclient = HttpClients.custom()
.useSystemProperties()
.setSchemePortResolver(spr)
.build();
return httpclient;
}
};
Sardine sardine = new SardineImpl(builder, "user", "passwd");
List<DavResource> resources = null;
resources = sardine.list("https://ftp-site.com/path/");
resources.forEach(resource -> {
System.out.println(resource.getName());
}
Hope that helps somebody.

Turn SSL verification off for JGit clone command

I am trying to a clone of a Git Repository via the CloneCommand.
With this piece of code
`Git.cloneRepository().setDirectory(new File(path)).setURI(url).call();`
The remote repository is on a GitBlit Instance which uses self signed certificates.
Because of these self signed certificates I get the below exception when the Fetch Part of the Clone is executing:
Caused by: java.security.cert.CertificateException: No name matching <hostName> found
at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:221)
at sun.security.util.HostnameChecker.match(HostnameChecker.java:95)
While I could create a new TrustManager, register a dummy HostnameVerifier and create and init a SSLContext that uses this dummy TrustManager.
And after the clone is done revert all of this.
However this would mean that any other SSL connection that is initiated during the same time would expose them to unsecured connections.
On a already cloned repo you can set the http.sslVerify to false and JGit works perfectly fine.
Is there a cleaner way in which I could tell JGit to set this http.sslVerify to false for Clone action, like I can do for a already cloned repo.
With version 4.9, JGit will handle SSL verification more gracefully. If the SSL
handshake was unsuccessful, JGit will ask the CredentialsProvider whether SSL verification should be skipped or not.
In this process, the CredentialsProvider is given an InformationalMessage describing the issue textually and up to three YesNoType CredentialItems to decide whether to skip SSL verification for this operation, for the current repository, and/or always.
It seems that the change was made with an interactive UI in mind and it might be hard to answer these 'credential requests' programmatically. The commit message of this change describes the behavior in more detail.
If you are certain that SSL verification is the only InformationalMessage that will be sent, you can apply the technique used in this test that accompanies the change and blindly answer 'yes' to all such questions.
For earlier versions of JGit, or if the CredentialsProvider model does not fit your needs, there are two workarounds described below.
To work around this limitation, you can execute the specific clone steps manually as suggested in the comments below:
init a repository using the InitCommand
set ssl verify to false
StoredConfig config = git.getRepository().getConfig();
config.setBoolean( "http", null, "sslVerify", false );
config.save();
fetch (see FetchCommand)
checkout (see CheckoutCommand)
Another way to work around the issue is to provide an HttpConnectionFactory that returns HttpConnections with dummy host name and certificate verifiers. For example:
class InsecureHttpConnectionFactory implements HttpConnectionFactory {
#Override
public HttpConnection create( URL url ) throws IOException {
return create( url, null );
}
#Override
public HttpConnection create( URL url, Proxy proxy ) throws IOException {
HttpConnection connection = new JDKHttpConnectionFactory().create( url, proxy );
HttpSupport.disableSslVerify( connection );
return connection;
}
}
HttpConnection is in package org.eclipse.jgit.transport.http and is a JGit abstraction for HTTP connections. While the example uses the default implementation (backed by JDK http code), you are free to use your own implementation or the one provided by the org.eclipse.jgit.transport.http.apache package that uses Apache http components.
The currently used connection factory can be changed with HttpTransport::setConnectionFactory():
HttpConnectionFactory preservedConnectionFactory = HttpTransport.getConnectionFactory();
HttpTransport.setConnectionFactory( new InsecureHttpConnectionFactory() );
// clone repository
HttpTransport.setConnectionFactory( preservedConnectionFactory );
Unfortunately, the connection factory is a singleton so that this trick needs extra work (e.g. a thread local variable to control if sslVerify is on or off) when JGit commands are executed concurrently.
Another workaround is to create a .gitconfig file in the home of the current user before calling Git.cloneRepository():
File file = new File(System.getProperty("user.home")+"/.gitconfig");
if(!file.exists()) {
PrintWriter writer = new PrintWriter(file);
writer.println("[http]");
writer.println("sslverify = false");
writer.close();
}
This will make JGit skip SSL certificate verification.
I have inferred from all answers above for the snippet below;
private void disableSSLVerify(URI gitServer) throws Exception {
if (gitServer.getScheme().equals("https")) {
FileBasedConfig config = SystemReader.getInstance().openUserConfig(null, FS.DETECTED);
synchronized (config) {
config.load();
config.setBoolean(
"http",
"https://" + gitServer.getHost() + ':' + (gitServer.getPort() == -1 ? 443 : gitServer.getPort()),
"sslVerify", false);
config.save();
}
}
}
This option is safer because it allows sslVerify to false for the gitServer alone.
Please take a look at this link which shares other options.
I have come across with the same problem and I used ChainingCredentialsProvider class to create a credential provider, I did my implementation as bellow,
Please note that this is an implementation of a previously given answer.
CredentialsProvider token = new UsernamePasswordCredentialsProvider("PRIVATE-TOKEN", token);
CredentialsProvider ssl = new CredentialsProvider() {
#Override
public boolean supports(CredentialItem... items) {
for ( CredentialItem item : items ) {
if ( (item instanceof CredentialItem.YesNoType) ) {
return true;
}
}
return false;
}
#Override
public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {
for ( CredentialItem item : items ) {
if ( item instanceof CredentialItem.YesNoType ) {
(( CredentialItem.YesNoType ) item).setValue(true);
return true;
}
}
return false;
}
#Override
public boolean isInteractive() {
return false;
}
};
CredentialsProvider cp = new ChainingCredentialsProvider(ssl, token);
Git result = Git.cloneRepository()
.setURI(gitProjectUrl)
.setDirectory(localPath)
.setCredentialsProvider(cp)
.call();

Resources