Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Rust Sever] Upgrade to openssl 0.10 #5564

Merged
merged 2 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ client = [
"serde_urlencoded",
{{/usesUrlEncodedForm}}
{{#hasCallbacks}}
"tokio-tls", "regex", "percent-encoding", "lazy_static",
"regex", "percent-encoding", "lazy_static",
{{/hasCallbacks}}
"serde_json", "serde_ignored", "hyper", "hyper-tls", "native-tls", "openssl", "tokio", "url"
"serde_json", "serde_ignored", "hyper", "hyper-openssl", "native-tls", "openssl", "tokio", "url"
]
server = [
{{#apiUsesMultipart}}
Expand All @@ -37,16 +37,26 @@ server = [
{{#apiUsesMultipartRelated}}
"hyper_0_10", "mime_multipart",
{{/apiUsesMultipartRelated}}
{{#hasCallbacks}}
"native-tls", "hyper-openssl", "openssl",
{{/hasCallbacks}}
{{! Anything added to the list below, should probably be added to the callbacks list above }}
"serde_json", "serde_ignored", "hyper", "native-tls", "openssl", "tokio", "tokio-tls", "regex", "percent-encoding", "url", "lazy_static"
"serde_json", "serde_ignored", "hyper", "tokio", "regex", "percent-encoding", "url", "lazy_static"
]
conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"]

[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies]
native-tls = { version = "0.2", optional = true }

[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies]
hyper-openssl = { version = "0.7.1", optional = true }
openssl = {version = "0.10", optional = true }

[dependencies]
# Common
chrono = { version = "0.4", features = ["serde"] }
futures = "0.1"
swagger = "3.0"
swagger = "4.0"
log = "0.3.0"
mime = "0.3"

Expand All @@ -71,13 +81,10 @@ uuid = {version = "0.7", features = ["serde", "v4"]}

# Common between server and client features
hyper = {version = "0.12", optional = true}
hyper-tls = {version = "0.2.1", optional = true}
{{#apiUsesMultipartRelated}}
mime_multipart = {version = "0.5", optional = true}
hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true}
{{/apiUsesMultipartRelated}}
native-tls = {version = "0.1.4", optional = true}
openssl = {version = "0.9.14", optional = true}
serde_json = {version = "1.0", optional = true}
serde_ignored = {version = "0.0.4", optional = true}
tokio = {version = "0.1.17", optional = true}
Expand All @@ -92,7 +99,6 @@ serde_urlencoded = {version = "0.5.1", optional = true}
lazy_static = { version = "1.4", optional = true }
percent-encoding = {version = "1.0.0", optional = true}
regex = {version = "0.2", optional = true}
tokio-tls = {version = "0.1.3", optional = true}

# Conversion
frunk = { version = "0.3.0", optional = true }
Expand All @@ -109,6 +115,10 @@ env_logger = "0.6"
uuid = {version = "0.7", features = ["serde", "v4"]}
{{/apiUsesUuid}}

[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies]
tokio-openssl = "0.3"
openssl = "0.10"

[[example]]
name = "client"
required-features = ["client"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use hyper;
use hyper::client::HttpConnector;
use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE};
use hyper::{Body, Uri, Response};
use hyper_tls::HttpsConnector;
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
use hyper_openssl::HttpsConnector;
use serde_json;
use std::borrow::Cow;
#[allow(unused_imports)]
Expand All @@ -18,9 +19,7 @@ use std::str;
use std::str::FromStr;
use std::string::ToString;
use swagger;
use swagger::client::Service;
use swagger::connector;
use swagger::{ApiError, XSpanIdString, Has, AuthData};
use swagger::{ApiError, Connector, client::Service, XSpanIdString, Has, AuthData};
use url::form_urlencoded;
use url::percent_encoding::{utf8_percent_encode, PATH_SEGMENT_ENCODE_SET, QUERY_ENCODE_SET};
{{#apiUsesMultipartFormData}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ impl Client<hyper::client::ResponseFuture>
///
/// Intended for use with custom implementations of connect for e.g. protocol logging
/// or similar functionality which requires wrapping the transport layer. When wrapping a TCP connection,
/// this function should be used in conjunction with
/// `swagger::{http_connector, https_connector, https_mutual_connector}`.
/// this function should be used in conjunction with `swagger::Connector::builder()`.
///
/// For ordinary tcp connections, prefer the use of `try_new_http`, `try_new_https`
/// and `try_new_https_mutual`, to avoid introducing a dependency on the underlying transport layer.
Expand All @@ -69,18 +68,16 @@ impl Client<hyper::client::ResponseFuture>
///
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
/// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")`
/// * `connector_fn` - Function which returns an implementation of `hyper::client::Connect`
/// * `connector` - Implementation of `hyper::client::Connect` to use for the client
pub fn try_new_with_connector<C>(
base_path: &str,
protocol: Option<&'static str>,
connector_fn: Box<dyn Fn() -> C + Send + Sync>,
connector: C,
) -> Result<Self, ClientInitError> where
C: hyper::client::connect::Connect + 'static,
C::Transport: 'static,
C::Future: 'static,
{
let connector = connector_fn();

let client_service = Box::new(hyper::client::Client::builder().build(connector));

Ok(Client {
Expand All @@ -96,24 +93,42 @@ impl Client<hyper::client::ResponseFuture>
pub fn try_new_http(
base_path: &str,
) -> Result<Self, ClientInitError> {
let http_connector = connector::http_connector();
let http_connector = Connector::builder().build();

Self::try_new_with_connector(base_path, Some("http"), http_connector)
}

/// Create a client with a TLS connection to the server.
/// Create a client with a TLS connection to the server
///
/// # Arguments
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
pub fn try_new_https(base_path: &str) -> Result<Self, ClientInitError>
{
let https_connector = Connector::builder()
.https()
.build()
.map_err(|e| ClientInitError::SslError(e))?;
Self::try_new_with_connector(base_path, Some("https"), https_connector)
}

/// Create a client with a TLS connection to the server using a pinned certificate
///
/// # Arguments
/// * `base_path` - base path of the client API, i.e. "www.my-api-implementation.com"
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
pub fn try_new_https<CA>(
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
pub fn try_new_https_pinned<CA>(
base_path: &str,
ca_certificate: CA,
) -> Result<Self, ClientInitError>
where
CA: AsRef<Path>,
{
let https_connector = connector::https_connector(ca_certificate);
let https_connector = Connector::builder()
.https()
.pin_server_certificate(ca_certificate)
.build()
.map_err(|e| ClientInitError::SslError(e))?;
Self::try_new_with_connector(base_path, Some("https"), https_connector)
}

Expand All @@ -124,6 +139,7 @@ impl Client<hyper::client::ResponseFuture>
/// * `ca_certificate` - Path to CA certificate used to authenticate the server
/// * `client_key` - Path to the client private key
/// * `client_certificate` - Path to the client's public certificate associated with the private key
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
pub fn try_new_https_mutual<CA, K, D>(
base_path: &str,
ca_certificate: CA,
Expand All @@ -135,8 +151,12 @@ impl Client<hyper::client::ResponseFuture>
K: AsRef<Path>,
D: AsRef<Path>,
{
let https_connector =
connector::https_mutual_connector(ca_certificate, client_key, client_certificate);
let https_connector = Connector::builder()
.https()
.pin_server_certificate(ca_certificate)
.client_authentication(client_key, client_certificate)
.build()
.map_err(|e| ClientInitError::SslError(e))?;
Self::try_new_with_connector(base_path, Some("https"), https_connector)
}
}
Expand Down Expand Up @@ -170,7 +190,12 @@ pub enum ClientInitError {
MissingHost,

/// SSL Connection Error
SslError(openssl::error::ErrorStack)
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
SslError(native_tls::Error),

/// SSL Connection Error
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
SslError(openssl::error::ErrorStack),
}

impl From<hyper::http::uri::InvalidUri> for ClientInitError {
Expand All @@ -179,12 +204,6 @@ impl From<hyper::http::uri::InvalidUri> for ClientInitError {
}
}

impl From<openssl::error::ErrorStack> for ClientInitError {
fn from(err: openssl::error::ErrorStack) -> ClientInitError {
ClientInitError::SslError(err)
}
}

impl fmt::Display for ClientInitError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s: &dyn fmt::Debug = self;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ extern crate chrono;
#[macro_use]
extern crate error_chain;
extern crate hyper;
extern crate openssl;
extern crate native_tls;
extern crate tokio_tls;
{{#apiUsesUuid}}
extern crate uuid;
{{/apiUsesUuid}}

#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
extern crate openssl;
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
extern crate tokio_openssl;

mod server;
{{/hasCallbacks}}

Expand Down Expand Up @@ -79,9 +81,7 @@ fn main() {

let client = if matches.is_present("https") {
// Using Simple HTTPS
Client::try_new_https(
&base_url,
"examples/ca.pem")
Client::try_new_https(&base_url)
.expect("Failed to create HTTPS client")
} else {
// Using HTTP
Expand All @@ -99,7 +99,7 @@ fn main() {
{{#hasCallbacks}}

// We could do HTTPS here, but for simplicity we don't
rt.spawn(server::create("127.0.0.1:8081", None));
rt.spawn(server::create("127.0.0.1:8081", false));
{{/hasCallbacks}}

match matches.value_of("operation") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use chrono;
use futures::{future, Future, Stream};
use hyper::server::conn::Http;
use hyper::service::MakeService as _;
use native_tls;
use openssl::ssl::SslAcceptorBuilder;
use std::collections::HashMap;
use std::marker::PhantomData;
Expand All @@ -23,12 +22,18 @@ use swagger::{Has, XSpanIdString};
use swagger::auth::MakeAllowAllAuthenticator;
use swagger::EmptyContext;
use tokio::net::TcpListener;
use tokio_tls::TlsAcceptorExt;
{{#apiUsesUuid}}use uuid;{{/apiUsesUuid}}

#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
use tokio_openssl::SslAcceptorExt;
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};

use {{{externCrateName}}}::models;

pub fn create(addr: &str, https: Option<SslAcceptorBuilder>) -> Box<Future<Item = (), Error = ()> + Send> {
#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
/// Builds an SSL implementation for Simple HTTPS from some hard-coded file names
pub fn create(addr: &str, https: bool) -> Box<dyn Future<Item = (), Error = ()> + Send> {
let addr = addr.parse().expect("Failed to parse bind address");

let server = Server::new();
Expand All @@ -42,30 +47,44 @@ pub fn create(addr: &str, https: Option<SslAcceptorBuilder>) -> Box<Future<Item
service_fn
);

if let Some(ssl) = https {
let builder: native_tls::TlsAcceptorBuilder = native_tls::backend::openssl::TlsAcceptorBuilderExt::from_openssl(ssl);
let tls_acceptor = builder.build().expect("Failed to build TLS acceptor");
let service_fn = Arc::new(Mutex::new(service_fn));
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
let addr = tcp.peer_addr().expect("Unable to get remote address");
if https {
#[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))]
{
unimplemented!("SSL is not implemented for the examples on MacOS, Windows or iOS");
}

#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
{
let mut ssl = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).expect("Failed to create SSL Acceptor");

// Server authentication
ssl.set_private_key_file("examples/server-key.pem", SslFiletype::PEM).expect("Failed to set private key");
ssl.set_certificate_chain_file("examples/server-chain.pem").expect("Failed to set cerificate chain");
ssl.check_private_key().expect("Failed to check private key");

let tls_acceptor = ssl.build();
let service_fn = Arc::new(Mutex::new(service_fn));
let tls_listener = TcpListener::bind(&addr).unwrap().incoming().for_each(move |tcp| {
let addr = tcp.peer_addr().expect("Unable to get remote address");

let service_fn = service_fn.clone();
let service_fn = service_fn.clone();

hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
let ms = {
let mut service_fn = service_fn.lock().unwrap();
service_fn.make_service(&addr)
};
hyper::rt::spawn(tls_acceptor.accept_async(tcp).map_err(|_| ()).and_then(move |tls| {
let ms = {
let mut service_fn = service_fn.lock().unwrap();
service_fn.make_service(&addr)
};

ms.and_then(move |service| {
Http::new().serve_connection(tls, service)
}).map_err(|_| ())
}));
ms.and_then(move |service| {
Http::new().serve_connection(tls, service)
}).map_err(|_| ())
}));

Ok(())
}).map_err(|_| ());
Ok(())
}).map_err(|_| ());

Box::new(tls_listener)
Box::new(tls_listener)
}
} else {
// Using HTTP
Box::new(hyper::server::Server::bind(&addr).serve(service_fn).map_err(|e| panic!("{:?}", e)))
Expand Down
Loading