Skip to content

Commit 1bb0349

Browse files
authored
Update server TLS example to showcase how to extract connection information (#3023)
Showcase how to pass TLS derived information to server operation handlers, like the certificate chain presented by the client. To test, run `RUST_LOG=pokemon_service_tls=DEBUG cargo run` and `curl -v --insecure https://localhost:13734/do-nothing`. Alternatively, run the tests using `RUST_LOG=pokemon_service_tls=DEBUG cargo test`, which have been updated to hit the operation that logs the TLS connection derived information. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
1 parent 42cc7cf commit 1bb0349

File tree

5 files changed

+67
-18
lines changed

5 files changed

+67
-18
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,17 +202,19 @@ jobs:
202202
popd &>/dev/null
203203
done
204204
205-
# We make sure that Smithy-rs can be compiled on platforms that are not natively supported by GitHub actions.
206-
# We run as many tests we can on those platforms because they require a more complicated setup involving architecture
207-
# emulation.
205+
# We make sure that smithy-rs can be compiled on platforms that are not
206+
# natively supported by GitHub actions. We run as many tests as we can on
207+
# those platforms, but not all of them, because they require a more
208+
# complicated setup involving architecture emulation.
208209
test-exotic-platform-support:
209210
name: Exotic platform support
210211
runs-on: ubuntu-latest
211212
strategy:
212213
fail-fast: false
213214
matrix:
214215
include:
215-
# We always exclude aws-smithy-http-server-python since the Python framework is experimental.
216+
# We always exclude `aws-smithy-http-server-python` and
217+
# `aws-smithy-http-server-typescript` since they are experimental.
216218
- target: i686-unknown-linux-gnu
217219
build_smithy_rs_features: --all-features
218220
build_aws_exclude: ''

examples/pokemon-service-tls/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ description = "A smithy Rust service to retrieve information about Pokémon."
1010
clap = { version = "4.1.11", features = ["derive"] }
1111
hyper = { version = "0.14.26", features = ["server"] }
1212
tokio = "1.26.0"
13+
tracing = "0.1"
1314

1415
# These dependencies are only required for the `pokemon-service-tls` program.
1516
tls-listener = { version = "0.7.0", features = ["rustls", "hyper-h2"] }

examples/pokemon-service-tls/src/main.rs

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424

2525
use std::{fs::File, future, io::BufReader, net::SocketAddr, sync::Arc};
2626

27-
use aws_smithy_http_server::AddExtensionLayer;
27+
use aws_smithy_http_server::{
28+
request::connect_info::ConnectInfo, routing::Connected, AddExtensionLayer,
29+
};
2830
use clap::Parser;
2931
use futures_util::stream::StreamExt;
3032
use tokio_rustls::{
@@ -33,10 +35,10 @@ use tokio_rustls::{
3335
};
3436

3537
use pokemon_service_common::{
36-
capture_pokemon, check_health, do_nothing, get_pokemon_species, get_server_statistics,
37-
get_storage, setup_tracing, stream_pokemon_radio, State,
38+
capture_pokemon, check_health, get_pokemon_species, get_server_statistics, get_storage,
39+
setup_tracing, stream_pokemon_radio, State,
3840
};
39-
use pokemon_service_server_sdk::{PokemonService, PokemonServiceConfig};
41+
use pokemon_service_server_sdk::{input, output, PokemonService, PokemonServiceConfig};
4042
use pokemon_service_tls::{DEFAULT_ADDRESS, DEFAULT_PORT, DEFAULT_TEST_CERT, DEFAULT_TEST_KEY};
4143

4244
#[derive(Parser, Debug)]
@@ -56,6 +58,46 @@ struct Args {
5658
tls_key_path: String,
5759
}
5860

61+
/// Information derived from the TLS connection.
62+
#[derive(Debug, Clone)]
63+
pub struct TlsConnectInfo {
64+
/// The remote peer address of this connection.
65+
pub socket_addr: SocketAddr,
66+
67+
/// The set of TLS certificates presented by the peer in this connection.
68+
pub certs: Option<Arc<Vec<Certificate>>>,
69+
}
70+
71+
impl Connected<&tokio_rustls::server::TlsStream<hyper::server::conn::AddrStream>>
72+
for TlsConnectInfo
73+
{
74+
fn connect_info(
75+
target: &tokio_rustls::server::TlsStream<hyper::server::conn::AddrStream>,
76+
) -> Self {
77+
let (addr_stream, session) = target.get_ref();
78+
let socket_addr = addr_stream.remote_addr();
79+
80+
let certs = session
81+
.peer_certificates()
82+
.map(|certs| Arc::new(certs.to_vec()));
83+
84+
TlsConnectInfo { socket_addr, certs }
85+
}
86+
}
87+
88+
/// Empty operation used to showcase how we can get access to information derived from the TLS
89+
/// connection in.
90+
pub async fn do_nothing_with_tls_connect_info(
91+
_input: input::DoNothingInput,
92+
ConnectInfo(tls_connect_info): ConnectInfo<TlsConnectInfo>,
93+
) -> output::DoNothingOutput {
94+
// Logging these might pose a security concern! You probably don't want to do this in
95+
// production.
96+
tracing::debug!(?tls_connect_info.certs, "peer TLS certificates");
97+
98+
output::DoNothingOutput {}
99+
}
100+
59101
#[tokio::main]
60102
pub async fn main() {
61103
let args = Args::parse();
@@ -73,7 +115,7 @@ pub async fn main() {
73115
.get_storage(get_storage)
74116
.get_server_statistics(get_server_statistics)
75117
.capture_pokemon(capture_pokemon)
76-
.do_nothing(do_nothing)
118+
.do_nothing(do_nothing_with_tls_connect_info)
77119
.check_health(check_health)
78120
.stream_pokemon_radio(stream_pokemon_radio)
79121
.build()
@@ -96,8 +138,11 @@ pub async fn main() {
96138
future::ready(true)
97139
}
98140
});
99-
let server = hyper::Server::builder(hyper::server::accept::from_stream(listener))
100-
.serve(app.into_make_service());
141+
// Using `into_make_service_with_connect_info`, rather than `into_make_service`, to adjoin the `TlsConnectInfo`
142+
// connection info.
143+
let make_app = app.into_make_service_with_connect_info::<TlsConnectInfo>();
144+
let server =
145+
hyper::Server::builder(hyper::server::accept::from_stream(listener)).serve(make_app);
101146
if let Err(err) = server.await {
102147
eprintln!("server error: {}", err);
103148
}

examples/pokemon-service-tls/tests/custom_connectors.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,23 @@ pub mod common;
77

88
use serial_test::serial;
99

10-
#[tokio::test]
11-
#[serial]
1210
// This test invokes an operation with a client that can only send HTTP2 requests and whose TLS
1311
// implementation is backed by `rustls`.
14-
async fn test_check_health_http2_rustls_connector() {
12+
#[tokio::test]
13+
#[serial]
14+
async fn test_do_nothing_http2_rustls_connector() {
1515
let _child = common::run_server().await;
1616
let client = common::client_http2_only();
1717

18-
let _check_health = client.check_health().send().await.unwrap();
18+
let _check_health = client.do_nothing().send().await.unwrap();
1919
}
2020

21+
// This test invokes an operation with a client whose TLS implementation is backed by `native_tls`.
2122
#[tokio::test]
2223
#[serial]
23-
// This test invokes an operation with a client whose TLS implementation is backed by `native_tls`.
24-
async fn test_check_health_native_tls_connector() {
24+
async fn test_do_nothing_native_tls_connector() {
2525
let _child = common::run_server().await;
2626
let client = common::native_tls_client();
2727

28-
let _check_health = client.check_health().send().await.unwrap();
28+
let _check_health = client.do_nothing().send().await.unwrap();
2929
}

rust-runtime/aws-smithy-http-server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ regex = "1.5.5"
3838
serde_urlencoded = "0.7"
3939
thiserror = "1.0.40"
4040
tokio = { version = "1.23.1", features = ["full"] }
41+
tokio-rustls = "0.24"
4142
tower = { version = "0.4.11", features = ["util", "make"], default-features = false }
4243
tower-http = { version = "0.3", features = ["add-extension", "map-response-body"] }
4344
tracing = "0.1.35"

0 commit comments

Comments
 (0)