From 03796d64505b7c60f258b4b62b251297795b4624 Mon Sep 17 00:00:00 2001 From: Jan Romann Date: Mon, 4 Nov 2024 11:32:37 +0100 Subject: [PATCH] feat(binding_http): add possibility to define a custom SecurityContext --- lib/src/binding_http/http_client.dart | 27 +++++++++++++++++-- lib/src/binding_http/http_client_factory.dart | 7 ++++- lib/src/binding_http/http_config.dart | 18 +++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/lib/src/binding_http/http_client.dart b/lib/src/binding_http/http_client.dart index ce015589..76d368fc 100644 --- a/lib/src/binding_http/http_client.dart +++ b/lib/src/binding_http/http_client.dart @@ -6,9 +6,12 @@ import "dart:convert"; import "dart:io"; +import "dart:io" as io; import "package:http/http.dart"; +import "package:http/io_client.dart"; +import "../../binding_http.dart"; import "../../core.dart"; import "http_request_method.dart"; @@ -31,6 +34,8 @@ const _authorizationHeader = "Authorization"; /// /// The use of Proxies is not supported yet, while support for the digest /// security scheme has been temporarily removed. +/// Additional trusted certificates can be added via an (optional) +/// [HttpClientConfig]. /// /// [RFC 7617]: https://datatracker.ietf.org/doc/html/rfc7617 /// [RFC 7616]: https://datatracker.ietf.org/doc/html/rfc7616 @@ -40,12 +45,30 @@ final class HttpClient extends ProtocolClient with DirectDiscoverer, CoreLinkFormatDiscoverer { /// Creates a new [HttpClient]. HttpClient({ + HttpClientConfig? httpClientConfig, AsyncClientSecurityCallback? basicCredentialsCallback, AsyncClientSecurityCallback? bearerCredentialsCallback, }) : _basicCredentialsCallback = basicCredentialsCallback, - _bearerCredentialsCallback = bearerCredentialsCallback; + _bearerCredentialsCallback = bearerCredentialsCallback, + _client = + IOClient(io.HttpClient(context: _createContext(httpClientConfig))); - final _client = Client(); + static SecurityContext _createContext(HttpClientConfig? httpClientConfig) { + final context = SecurityContext(); + + final trustedCertificates = httpClientConfig?.trustedCertificates ?? []; + + for (final trustedCertificate in trustedCertificates) { + context.setTrustedCertificatesBytes( + trustedCertificate.certificate, + password: trustedCertificate.password, + ); + } + + return context; + } + + final IOClient _client; final AsyncClientSecurityCallback? _basicCredentialsCallback; diff --git a/lib/src/binding_http/http_client_factory.dart b/lib/src/binding_http/http_client_factory.dart index c35e72a0..779f4140 100644 --- a/lib/src/binding_http/http_client_factory.dart +++ b/lib/src/binding_http/http_client_factory.dart @@ -13,10 +13,14 @@ import "http_config.dart"; final class HttpClientFactory implements ProtocolClientFactory { /// Creates a new [HttpClientFactory] based on an optional [HttpConfig]. HttpClientFactory({ + HttpClientConfig? httpClientConfig, AsyncClientSecurityCallback? basicCredentialsCallback, AsyncClientSecurityCallback? bearerCredentialsCallback, }) : _basicCredentialsCallback = basicCredentialsCallback, - _bearerCredentialsCallback = bearerCredentialsCallback; + _bearerCredentialsCallback = bearerCredentialsCallback, + _httpClientConfig = httpClientConfig; + + final HttpClientConfig? _httpClientConfig; final AsyncClientSecurityCallback? _basicCredentialsCallback; @@ -34,6 +38,7 @@ final class HttpClientFactory implements ProtocolClientFactory { @override ProtocolClient createClient() => HttpClient( + httpClientConfig: _httpClientConfig, basicCredentialsCallback: _basicCredentialsCallback, bearerCredentialsCallback: _bearerCredentialsCallback, ); diff --git a/lib/src/binding_http/http_config.dart b/lib/src/binding_http/http_config.dart index 7bf2fd47..77963610 100644 --- a/lib/src/binding_http/http_config.dart +++ b/lib/src/binding_http/http_config.dart @@ -4,6 +4,8 @@ // // SPDX-License-Identifier: BSD-3-Clause +import "package:meta/meta.dart"; + /// Allows for configuring the behavior of HTTP clients and servers. class HttpConfig { /// Creates a new [HttpConfig] object. @@ -17,3 +19,19 @@ class HttpConfig { /// Indicates if the client or server should use HTTPS. bool? secure; } + +/// Configuration parameters specific to dart_wot's HTTP Client implementation. +@immutable +class HttpClientConfig { + /// Creates a new [HttpClientConfig] object. + const HttpClientConfig({ + this.trustedCertificates, + }); + + /// List of trusted certificates that will be added to the security contexts + /// of newly created HTTP clients. + /// + /// Certificates can either use the PEM or or the PKCS12 format, the latter of + /// which also supports the use of an optional password. + final List<({List certificate, String? password})>? trustedCertificates; +}