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

feat: allow cli option to disable ssl verification #157

Merged
merged 2 commits into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
33 changes: 33 additions & 0 deletions examples/server.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFnzCCA4cCFCUGGh4r5q0rSDgWacZfimC2/HoMMA0GCSqGSIb3DQEBCwUAMIGL
MQswCQYDVQQGEwJaQTEMMAoGA1UECAwDS1pOMQ8wDQYDVQQHDAZQbGFjZXMxEDAO
BgNVBAoMB1VubGVhc2gxFDASBgNVBAsMC2RldmVsb3BtZW50MRIwEAYDVQQDDAls
b2NhbGhvc3QxITAfBgkqhkiG9w0BCQEWEnRlYW1AZ2V0dW5sZWFzaC5pbzAeFw0y
MzA0MTcxMDUyMThaFw00MzA0MTIxMDUyMThaMIGLMQswCQYDVQQGEwJaQTEMMAoG
A1UECAwDS1pOMQ8wDQYDVQQHDAZQbGFjZXMxEDAOBgNVBAoMB1VubGVhc2gxFDAS
BgNVBAsMC2RldmVsb3BtZW50MRIwEAYDVQQDDAlsb2NhbGhvc3QxITAfBgkqhkiG
9w0BCQEWEnRlYW1AZ2V0dW5sZWFzaC5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBALujqEdzGN/M5RhUbkdnOhIo4oJ3lzDX2Pkn2hkWAitBsr4FIUA+
12O1H00J9QP9kNydF+xDu0aAiAjN2rm9pzNQ+0KkzjWR2E7CPTo8ZMqR4u31EWG5
2dPqEQdmvRvp/kPv71ldz8JlrFn9MqSWY6KrKhEiFiz208OlKg0VN/FWLx6fkqMX
D2dLy+6t5k7yhNU2hgZ2fImYYD9l7KaD8rM8TLzwqcSM2M2OwrRfDMI4eaMwD9jl
I/qIpa+sgZlSxnABwet02PugpZ1eVbJKrezSWx1qNI2KeWywVizhdTlckVoa14nW
hk9qdblY2gH+IENjeRKog7Nr7VcGSakwzuDqGS1QqsadL8n/czzUxRTEBX/wRAPZ
ND/obLxSHNMYKsnKn0xMa3cBbbyu2zj+cdwWaE3/7q4UZ8X2VCVStl+6IjmgaStV
xNmHvkNRD4SL0UliKtNPFUTSGZxMeGbqLjPbRL7rgCfcxpLxj+5d09yYLZesy2zG
/fMxxUVKFvPaBd8QDf6DoDlAReB6ebNa1AKozBQEz2l50lIB9BneZfY+S55ovfpI
EHwRGTQbWy/q24ZM/UXMLa6O9OBeAN82v03zkrtd2/DAGHvFZYacoCnZEGmX+RsH
sqf//iMKJ1tpN3Gi4krmtiE2nm+XREgmgCP+KmGlFeA2bDLtpdZFr5JtAgMBAAEw
DQYJKoZIhvcNAQELBQADggIBADEKJnMpbsUA4NuM9MtpCykmo2ZPCcYjHKo8Ymjj
WOkoHQ078CiK7QUQQgIBWGtqZ0Z323qPpGddr7xYX0D3PzON2qM6i6Y4CKhSWIo1
dRdmeLfkLsUwY6pEClF6h53d6G87k2raLAc77+W+rEiS7PS4pm7AdEjyfqeUhcnC
JbFwDC8kVjR/3+0/4MGYaYSKbUwe+20O927UIiShVaoruiJJ9JaH1YnIDCNOzekj
4/Gd/mnlqitJuyRSuVSAI6S+YkfaLeAXyrYIJsNrQpoShblXEYMc/C39rCHvNU2C
V/xBABkXOmOX48DeMaZ26I1q8xmIDewAs2iCtJtaN3nX5ioY7C09UDYH57wCdxF6
oL78p2IQxL4FJhn7bmtKUWWXDct1Bbiikhrmyckz2VwvoVWrh+gaekPRXGvAtC7c
YRBLbQGthAR/uZrsYdFTYkQc1Y0Ntxrs+jbqljce2yQprcne6JKjqIeAfxN8Cvt6
ZUkV6MECckgMVbt9Aw9fiM0CNWKb1mj7myHMOXf6zr2HzHKC4J9pY0Pv7al9p4Fq
aztOQBJAj9DkA6UqrCYFh4HnhV7QDzkzp4/h8VylrQ+cii0wpwz1kkCTGvYeKwdc
dZieoT+78V+PRtmb8Ch4Wh/7oHxm5uYNU3be/gjwNnSoHO3FYTO3P0e2H1mhhPGJ
eZFS
-----END CERTIFICATE-----
52 changes: 52 additions & 0 deletions examples/server.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
RfVjCJn+jnI3UV8MzyE+ii2n5dNTvOY3
-----END PRIVATE KEY-----
2 changes: 1 addition & 1 deletion server/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ async fn build_edge(args: &EdgeArgs) -> EdgeResult<EdgeInfo> {
let persistence = get_data_source(args).await;

let unleash_client = Url::parse(&args.upstream_url.clone())
.map(UnleashClient::from_url)
.map(|url| UnleashClient::from_url(url, args.skip_ssl_verification))
.map(|c| c.with_custom_client_headers(args.custom_client_headers.clone()))
.map(Arc::new)
.map_err(|_| EdgeError::InvalidServerUrl(args.upstream_url.clone()))?;
Expand Down
4 changes: 4 additions & 0 deletions server/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ pub struct EdgeArgs {
/// for instance `-H X-Api-Key: mysecretapikey`
#[clap(short = 'H', long, env, value_delimiter = ',', value_parser = string_to_header_tuple)]
pub custom_client_headers: Vec<(String, String)>,

/// If set to true, we will skip SSL verification when connecting to the upstream Unleash server
#[clap(short, long, env, default_value_t = false)]
pub skip_ssl_verification: bool,
}

pub fn string_to_header_tuple(s: &str) -> Result<(String, String), String> {
Expand Down
2 changes: 1 addition & 1 deletion server/src/client_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub async fn get_features(
}
#[utoipa::path(
context_path = "/api",
params(("feature_name" = String, Path,)),
params(("feature_name" = String, Path,)),
responses(
(status = 200, description = "Return feature toggles for this token", body = ClientFeature),
(status = 403, description = "Was not allowed to access feature"),
Expand Down
21 changes: 14 additions & 7 deletions server/src/http/feature_refresher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,8 @@ mod tests {

#[tokio::test]
pub async fn registering_token_for_refresh_works() {
let unleash_client = UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap());
let unleash_client =
UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap(), false);
let features_cache = Arc::new(DashMap::default());
let engines_cache = Arc::new(DashMap::default());

Expand All @@ -349,7 +350,8 @@ mod tests {

#[tokio::test]
pub async fn registering_multiple_non_overlapping_tokens_will_keep_all() {
let unleash_client = UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap());
let unleash_client =
UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap(), false);
let features_cache = Arc::new(DashMap::default());
let engines_cache = Arc::new(DashMap::default());
let duration = Duration::seconds(5);
Expand Down Expand Up @@ -384,7 +386,8 @@ mod tests {

#[tokio::test]
pub async fn registering_wildcard_project_token_only_keeps_the_wildcard() {
let unleash_client = UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap());
let unleash_client =
UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap(), false);
let features_cache = Arc::new(DashMap::default());
let engines_cache = Arc::new(DashMap::default());
let duration = Duration::seconds(5);
Expand Down Expand Up @@ -428,7 +431,8 @@ mod tests {

#[tokio::test]
pub async fn registering_tokens_with_multiple_projects_overwrites_single_tokens() {
let unleash_client = UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap());
let unleash_client =
UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap(), false);
let features_cache = Arc::new(DashMap::default());
let engines_cache = Arc::new(DashMap::default());
let duration = Duration::seconds(5);
Expand Down Expand Up @@ -476,7 +480,8 @@ mod tests {

#[tokio::test]
pub async fn registering_a_token_that_is_already_subsumed_does_nothing() {
let unleash_client = UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap());
let unleash_client =
UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap(), false);
let features_cache = Arc::new(DashMap::default());
let engines_cache = Arc::new(DashMap::default());

Expand Down Expand Up @@ -509,7 +514,8 @@ mod tests {

#[tokio::test]
pub async fn simplification_only_happens_in_same_environment() {
let unleash_client = UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap());
let unleash_client =
UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap(), false);
let features_cache = Arc::new(DashMap::default());
let engines_cache = Arc::new(DashMap::default());

Expand Down Expand Up @@ -537,7 +543,8 @@ mod tests {

#[tokio::test]
pub async fn is_able_to_only_fetch_for_tokens_due_to_refresh() {
let unleash_client = UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap());
let unleash_client =
UnleashClient::from_url(Url::parse("http://localhost:4242").unwrap(), false);
let features_cache = Arc::new(DashMap::default());
let engines_cache = Arc::new(DashMap::default());

Expand Down
89 changes: 82 additions & 7 deletions server/src/http/unleash_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::str::FromStr;
use std::time::Duration;
use ulid::Ulid;
use unleash_types::client_features::ClientFeatures;

use crate::metrics::client_metrics::MetricsBatch;
Expand Down Expand Up @@ -60,7 +59,7 @@ pub struct UnleashClient {
custom_headers: HashMap<String, String>,
}

fn new_reqwest_client(instance_id: String) -> Client {
fn new_reqwest_client(instance_id: String, skip_ssl_verification: bool) -> Client {
let mut header_map = HeaderMap::new();
header_map.insert(
UNLEASH_APPNAME_HEADER,
Expand All @@ -77,6 +76,7 @@ fn new_reqwest_client(instance_id: String) -> Client {
Client::builder()
.user_agent(format!("unleash-edge-{}", crate::types::build::PKG_VERSION))
.default_headers(header_map)
.danger_accept_invalid_certs(skip_ssl_verification)
.timeout(Duration::from_secs(5))
.build()
.unwrap()
Expand All @@ -87,19 +87,33 @@ pub struct EdgeTokens {
}

impl UnleashClient {
pub fn from_url(server_url: Url) -> Self {
pub fn from_url(server_url: Url, skip_ssl_verification: bool) -> Self {
Self {
urls: UnleashUrls::from_base_url(server_url),
backing_client: new_reqwest_client("unleash_edge".into()),
backing_client: new_reqwest_client("unleash_edge".into(), skip_ssl_verification),
custom_headers: Default::default(),
}
}

#[cfg(test)]
pub fn new(server_url: &str, instance_id_opt: Option<String>) -> Result<Self, EdgeError> {
use ulid::Ulid;

let instance_id = instance_id_opt.unwrap_or_else(|| Ulid::new().to_string());
Ok(Self {
urls: UnleashUrls::from_str(server_url)?,
backing_client: new_reqwest_client(instance_id),
backing_client: new_reqwest_client(instance_id, false),
custom_headers: Default::default(),
})
}

#[cfg(test)]
pub fn new_insecure(server_url: &str) -> Result<Self, EdgeError> {
use ulid::Ulid;

Ok(Self {
urls: UnleashUrls::from_str(server_url)?,
backing_client: new_reqwest_client(Ulid::new().to_string(), true),
custom_headers: Default::default(),
})
}
Expand Down Expand Up @@ -258,13 +272,15 @@ impl UnleashClient {
#[cfg(test)]
mod tests {
use crate::{
cli::TlsOptions,
middleware::as_async_middleware::as_async_middleware,
tls,
types::{
ClientFeaturesRequest, ClientFeaturesResponse, EdgeToken, TokenValidationStatus,
ValidateTokensRequest,
},
};
use actix_http::{body::MessageBody, HttpService};
use actix_http::{body::MessageBody, HttpService, TlsAcceptorConfig};
use actix_http_test::{test_server, TestServer};
use actix_middleware_etag::Etag;
use actix_service::map_config;
Expand All @@ -273,7 +289,7 @@ mod tests {
http::header::EntityTag,
web, App, HttpResponse,
};
use std::str::FromStr;
use std::{str::FromStr, time::Duration};
use unleash_types::client_features::{ClientFeature, ClientFeatures};

use super::{EdgeTokens, UnleashClient};
Expand Down Expand Up @@ -333,6 +349,35 @@ mod tests {
.await
}

async fn test_features_server_with_untrusted_ssl() -> TestServer {
test_server(move || {
let tls_options = TlsOptions {
tls_server_cert: Some("../examples/server.crt".into()),
tls_enable: true,
tls_server_key: Some("../examples/server.key".into()),
tls_server_port: 443,
};
let server_config = tls::config(tls_options).unwrap();
let tls_acceptor_config =
TlsAcceptorConfig::default().handshake_timeout(Duration::from_secs(5));
HttpService::new(map_config(
App::new()
.wrap(Etag::default())
.service(
web::resource("/api/client/features")
.route(web::get().to(return_client_features)),
)
.service(
web::resource("/edge/validate")
.route(web::post().to(return_validate_tokens)),
),
|_| AppConfig::default(),
))
.rustls_with_config(server_config, tls_acceptor_config)
})
.await
}

async fn validate_api_key_middleware(
req: ServiceRequest,
srv: crate::middleware::as_async_middleware::Next<impl MessageBody + 'static>,
Expand Down Expand Up @@ -478,4 +523,34 @@ mod tests {
.await;
assert!(authed_res.is_ok());
}

#[actix_web::test]
pub async fn disabling_ssl_verification_allows_communicating_with_upstream_unleash_with_self_signed_cert(
) {
let srv = test_features_server_with_untrusted_ssl().await;
let client = UnleashClient::new_insecure(srv.surl("/").as_str()).unwrap();

let validate_result = client
.validate_tokens(ValidateTokensRequest {
tokens: vec![TEST_TOKEN.to_string()],
})
.await;

validate_result.unwrap();
sighphyre marked this conversation as resolved.
Show resolved Hide resolved
}

#[actix_web::test]
pub async fn not_disabling_ssl_verification_fails_communicating_with_upstream_unleash_with_self_signed_cert(
) {
let srv = test_features_server_with_untrusted_ssl().await;
let client = UnleashClient::new(srv.surl("/").as_str(), None).unwrap();

let validate_result = client
.validate_tokens(ValidateTokensRequest {
tokens: vec![TEST_TOKEN.to_string()],
})
.await;

assert!(validate_result.is_err());
}
}