drogue_bazaar/actix/http/
bind.rs

1use crate::core::tls::TlsAuthConfig;
2use actix_http::{Request, Response};
3use actix_service::{IntoServiceFactory, ServiceFactory};
4use actix_web::{body::MessageBody, dev::AppConfig, Error, HttpServer};
5use std::{fmt, path::Path};
6use tokio::io;
7
8/// Bind HTTP server to HTTP or HTTPS port, using an enabled TLS implementation.
9pub fn bind_http<F, I, S, B, K, C>(
10    main: HttpServer<F, I, S, B>,
11    bind_addr: String,
12    tls_auth_config: Option<TlsAuthConfig>,
13    key_file: Option<K>,
14    cert_bundle_file: Option<C>,
15) -> io::Result<HttpServer<F, I, S, B>>
16where
17    F: Fn() -> I + Send + Clone + 'static,
18    I: IntoServiceFactory<S, Request>,
19    S: ServiceFactory<Request, Config = AppConfig> + 'static,
20    S::Error: Into<Error> + 'static,
21    S::InitError: fmt::Debug,
22    S::Response: Into<Response<B>> + 'static,
23    B: MessageBody + 'static,
24    K: AsRef<Path>,
25    C: AsRef<Path>,
26{
27    match (tls_auth_config, key_file, cert_bundle_file) {
28        #[allow(unused_variables)]
29        (Some(tls_auth_config), Some(key), Some(cert)) => {
30            #[cfg(feature = "openssl")]
31            if cfg!(feature = "openssl") {
32                return bind_http_openssl(main, tls_auth_config, bind_addr, key, cert);
33            }
34            panic!("TLS is required, but no TLS implementation enabled")
35        }
36        (None, None, None) => main.bind(bind_addr),
37        (Some(_), _, _) => {
38            panic!("Wrong TLS configuration: TLS enabled, but key or cert is missing")
39        }
40        (None, Some(_), _) | (None, _, Some(_)) => {
41            // the TLS configuration must be consistent, to prevent configuration errors.
42            panic!("Wrong TLS configuration: key or cert specified, but TLS is disabled")
43        }
44    }
45}
46
47#[cfg(feature = "openssl")]
48fn bind_http_openssl<F, I, S, B, K, C>(
49    main: HttpServer<F, I, S, B>,
50    tls_auth_config: TlsAuthConfig,
51    bind_addr: String,
52    key_file: K,
53    cert_bundle_file: C,
54) -> io::Result<HttpServer<F, I, S, B>>
55where
56    F: Fn() -> I + Send + Clone + 'static,
57    I: IntoServiceFactory<S, Request>,
58    S: ServiceFactory<Request, Config = AppConfig> + 'static,
59    S::Error: Into<Error> + 'static,
60    S::InitError: fmt::Debug,
61    S::Response: Into<Response<B>> + 'static,
62    B: MessageBody + 'static,
63    K: AsRef<Path>,
64    C: AsRef<Path>,
65{
66    use crate::core::tls::TlsMode;
67    use openssl::ssl;
68
69    let method = ssl::SslMethod::tls_server();
70    let mut builder = ssl::SslAcceptor::mozilla_intermediate_v5(method)?;
71    builder.set_private_key_file(key_file, ssl::SslFiletype::PEM)?;
72    builder.set_certificate_chain_file(cert_bundle_file)?;
73
74    if let TlsMode::Client = tls_auth_config.mode {
75        // we ask for client certificates, but don't enforce them
76        builder.set_verify_callback(ssl::SslVerifyMode::PEER, |_, ctx| {
77            log::debug!(
78                "Accepting client certificates: {:?}",
79                ctx.current_cert()
80                    .map(|cert| format!("{:?}", cert.subject_name()))
81                    .unwrap_or_else(|| "<unknown>".into())
82            );
83            true
84        });
85    }
86
87    if let Some(psk) = tls_auth_config.psk {
88        builder.set_psk_server_callback(move |ssl, identity, secret_mut| {
89            match psk(ssl, identity, secret_mut) {
90                Ok(len) => Ok(len),
91                Err(e) => {
92                    log::debug!("Error during TLS-PSK handshake: {:?}", e);
93                    Ok(0)
94                }
95            }
96        });
97    }
98
99    Ok(main
100        .bind_openssl(bind_addr, builder)?
101        .tls_handshake_timeout(std::time::Duration::from_secs(10)))
102}