Skip to content

Commit 6110de3

Browse files
committed
PoC authentication
Signed-off-by: Eloi DEMOLIS <eloi.demolis@clever-cloud.com>
1 parent 0722e78 commit 6110de3

File tree

10 files changed

+185
-111
lines changed

10 files changed

+185
-111
lines changed

bin/src/ctl/request_builder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ impl CommandManager {
250250
Some(tags) => tags,
251251
None => BTreeMap::new(),
252252
},
253+
required_auth: todo!(),
253254
redirect: todo!(),
254255
redirect_scheme: todo!(),
255256
redirect_template: todo!(),
@@ -304,6 +305,7 @@ impl CommandManager {
304305
Some(tags) => tags,
305306
None => BTreeMap::new(),
306307
},
308+
required_auth: todo!(),
307309
redirect: todo!(),
308310
redirect_scheme: todo!(),
309311
redirect_template: todo!(),

command/src/command.proto

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,8 @@ message ListenersList {
214214

215215
enum RedirectPolicy {
216216
FORWARD = 0;
217-
TEMPORARY = 1;
218-
PERMANENT = 2;
219-
UNAUTHORIZED = 3;
217+
PERMANENT = 1;
218+
UNAUTHORIZED = 2;
220219
}
221220

222221
enum RedirectScheme {
@@ -236,11 +235,12 @@ message RequestHttpFrontend {
236235
// custom tags to identify the frontend in the access logs
237236
map<string, string> tags = 7;
238237
optional RedirectPolicy redirect = 8;
239-
optional RedirectScheme redirect_scheme = 9;
240-
optional string redirect_template = 10;
241-
optional string rewrite_host = 11;
242-
optional string rewrite_path = 12;
243-
optional uint32 rewrite_port = 13;
238+
optional bool required_auth = 9;
239+
optional RedirectScheme redirect_scheme = 10;
240+
optional string redirect_template = 11;
241+
optional string rewrite_host = 12;
242+
optional string rewrite_path = 13;
243+
optional uint32 rewrite_port = 14;
244244
}
245245

246246
message RequestTcpFrontend {
@@ -371,6 +371,7 @@ message Cluster {
371371
optional LoadMetric load_metric = 7;
372372
optional uint32 https_redirect_port = 8;
373373
map<string, string> answers = 9;
374+
repeated uint64 authorized_hashes = 10;
374375
}
375376

376377
enum LoadBalancingAlgorithms {

command/src/config.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ pub struct FileClusterFrontendConfig {
625625
#[serde(default)]
626626
pub position: RulePosition,
627627
pub tags: Option<BTreeMap<String, String>>,
628+
pub required_auth: Option<bool>,
628629
pub redirect: Option<RedirectPolicy>,
629630
pub redirect_scheme: Option<RedirectScheme>,
630631
pub redirect_template: Option<String>,
@@ -716,6 +717,7 @@ impl FileClusterFrontendConfig {
716717
path,
717718
method: self.method.clone(),
718719
tags: self.tags.clone(),
720+
required_auth: self.required_auth.unwrap_or(false),
719721
redirect: self.redirect,
720722
redirect_scheme: self.redirect_scheme,
721723
redirect_template: self.redirect_template.clone(),
@@ -758,6 +760,8 @@ pub struct FileClusterConfig {
758760
pub load_metric: Option<LoadMetric>,
759761
#[serde(default)]
760762
pub answers: Option<BTreeMap<String, String>>,
763+
#[serde(default)]
764+
pub authorized_hashes: Vec<u64>,
761765
}
762766

763767
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
@@ -845,6 +849,7 @@ impl FileClusterConfig {
845849
load_balancing: self.load_balancing,
846850
load_metric: self.load_metric,
847851
answers: load_answers(self.answers.as_ref())?,
852+
authorized_hashes: self.authorized_hashes,
848853
}))
849854
}
850855
}
@@ -866,6 +871,7 @@ pub struct HttpFrontendConfig {
866871
#[serde(default)]
867872
pub position: RulePosition,
868873
pub tags: Option<BTreeMap<String, String>>,
874+
pub required_auth: bool,
869875
pub redirect: Option<RedirectPolicy>,
870876
pub redirect_scheme: Option<RedirectScheme>,
871877
pub redirect_template: Option<String>,
@@ -909,6 +915,7 @@ impl HttpFrontendConfig {
909915
method: self.method.clone(),
910916
position: self.position.into(),
911917
tags,
918+
required_auth: Some(self.required_auth),
912919
redirect: self.redirect.map(Into::into),
913920
redirect_scheme: self.redirect_scheme.map(Into::into),
914921
redirect_template: self.redirect_template.clone(),
@@ -929,6 +936,7 @@ impl HttpFrontendConfig {
929936
method: self.method.clone(),
930937
position: self.position.into(),
931938
tags,
939+
required_auth: Some(self.required_auth),
932940
redirect: self.redirect.map(Into::into),
933941
redirect_scheme: self.redirect_scheme.map(Into::into),
934942
redirect_template: self.redirect_template.clone(),
@@ -956,6 +964,7 @@ pub struct HttpClusterConfig {
956964
pub load_balancing: LoadBalancingAlgorithms,
957965
pub load_metric: Option<LoadMetric>,
958966
pub answers: BTreeMap<String, String>,
967+
pub authorized_hashes: Vec<u64>,
959968
}
960969

961970
impl HttpClusterConfig {
@@ -969,6 +978,7 @@ impl HttpClusterConfig {
969978
load_balancing: self.load_balancing as i32,
970979
load_metric: self.load_metric.map(|s| s as i32),
971980
answers: self.answers.clone(),
981+
authorized_hashes: self.authorized_hashes.clone(),
972982
})
973983
.into()];
974984

@@ -1029,6 +1039,7 @@ impl TcpClusterConfig {
10291039
load_balancing: self.load_balancing as i32,
10301040
load_metric: self.load_metric.map(|s| s as i32),
10311041
answers: Default::default(),
1042+
authorized_hashes: Default::default(),
10321043
})
10331044
.into()];
10341045

command/src/request.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ impl RequestHttpFrontend {
161161
pub fn to_frontend(self) -> Result<HttpFrontend, RequestError> {
162162
Ok(HttpFrontend {
163163
position: self.position(),
164+
required_auth: self.required_auth.unwrap_or(false),
164165
redirect: self.redirect(),
165166
redirect_scheme: self.redirect_scheme(),
166167
redirect_template: self.redirect_template,

command/src/response.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub struct HttpFrontend {
3939
#[serde(default)]
4040
pub position: RulePosition,
4141
pub tags: Option<BTreeMap<String, String>>,
42+
pub required_auth: bool,
4243
pub redirect: RedirectPolicy,
4344
pub redirect_scheme: RedirectScheme,
4445
#[serde(skip_serializing_if = "Option::is_none")]
@@ -61,6 +62,7 @@ impl From<HttpFrontend> for RequestHttpFrontend {
6162
method: val.method,
6263
position: val.position.into(),
6364
tags: val.tags.unwrap_or_default(),
65+
required_auth: Some(val.required_auth),
6466
redirect: Some(val.redirect.into()),
6567
redirect_scheme: Some(val.redirect_scheme.into()),
6668
redirect_template: val.redirect_template,

lib/src/http.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,7 @@ mod tests {
12841284
path: PathRule::prefix(uri1),
12851285
position: RulePosition::Tree,
12861286
cluster_id: Some(cluster_id1),
1287+
required_auth: false,
12871288
redirect: RedirectPolicy::Forward,
12881289
redirect_scheme: RedirectScheme::UseSame,
12891290
redirect_template: None,
@@ -1301,6 +1302,7 @@ mod tests {
13011302
path: PathRule::prefix(uri2),
13021303
position: RulePosition::Tree,
13031304
cluster_id: Some(cluster_id2),
1305+
required_auth: false,
13041306
redirect: RedirectPolicy::Forward,
13051307
redirect_scheme: RedirectScheme::UseSame,
13061308
redirect_template: None,
@@ -1318,6 +1320,7 @@ mod tests {
13181320
path: PathRule::prefix(uri3),
13191321
position: RulePosition::Tree,
13201322
cluster_id: Some(cluster_id3),
1323+
required_auth: false,
13211324
redirect: RedirectPolicy::Forward,
13221325
redirect_scheme: RedirectScheme::UseSame,
13231326
redirect_template: None,
@@ -1335,6 +1338,7 @@ mod tests {
13351338
path: PathRule::prefix("/test".to_owned()),
13361339
position: RulePosition::Tree,
13371340
cluster_id: Some("cluster_1".to_owned()),
1341+
required_auth: false,
13381342
redirect: RedirectPolicy::Forward,
13391343
redirect_scheme: RedirectScheme::UseSame,
13401344
redirect_template: None,
@@ -1369,19 +1373,19 @@ mod tests {
13691373
let frontend5 = listener.frontend_from_request("domain", "/", &Method::Get);
13701374
assert_eq!(
13711375
frontend1.expect("should find frontend"),
1372-
RouteResult::simple("cluster_1".to_string())
1376+
RouteResult::forward("cluster_1".to_string())
13731377
);
13741378
assert_eq!(
13751379
frontend2.expect("should find frontend"),
1376-
RouteResult::simple("cluster_1".to_string())
1380+
RouteResult::forward("cluster_1".to_string())
13771381
);
13781382
assert_eq!(
13791383
frontend3.expect("should find frontend"),
1380-
RouteResult::simple("cluster_2".to_string())
1384+
RouteResult::forward("cluster_2".to_string())
13811385
);
13821386
assert_eq!(
13831387
frontend4.expect("should find frontend"),
1384-
RouteResult::simple("cluster_3".to_string())
1388+
RouteResult::forward("cluster_3".to_string())
13851389
);
13861390
assert!(frontend5.is_err());
13871391
}

lib/src/https.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,25 +1504,25 @@ mod tests {
15041504
"lolcatho.st".as_bytes(),
15051505
&PathRule::Prefix(uri1),
15061506
&MethodRule::new(None),
1507-
&Route::simple(cluster_id1.clone())
1507+
&Route::forward(cluster_id1.clone())
15081508
));
15091509
assert!(fronts.add_tree_rule(
15101510
"lolcatho.st".as_bytes(),
15111511
&PathRule::Prefix(uri2),
15121512
&MethodRule::new(None),
1513-
&Route::simple(cluster_id2)
1513+
&Route::forward(cluster_id2)
15141514
));
15151515
assert!(fronts.add_tree_rule(
15161516
"lolcatho.st".as_bytes(),
15171517
&PathRule::Prefix(uri3),
15181518
&MethodRule::new(None),
1519-
&Route::simple(cluster_id3)
1519+
&Route::forward(cluster_id3)
15201520
));
15211521
assert!(fronts.add_tree_rule(
15221522
"other.domain".as_bytes(),
15231523
&PathRule::Prefix("test".to_string()),
15241524
&MethodRule::new(None),
1525-
&Route::simple(cluster_id1)
1525+
&Route::forward(cluster_id1)
15261526
));
15271527

15281528
let address = SocketAddress::new_v4(127, 0, 0, 1, 1032);
@@ -1561,25 +1561,25 @@ mod tests {
15611561
let frontend1 = listener.frontend_from_request("lolcatho.st", "/", &Method::Get);
15621562
assert_eq!(
15631563
frontend1.expect("should find a frontend"),
1564-
RouteResult::simple("cluster_1".to_string())
1564+
RouteResult::forward("cluster_1".to_string())
15651565
);
15661566
println!("TEST {}", line!());
15671567
let frontend2 = listener.frontend_from_request("lolcatho.st", "/test", &Method::Get);
15681568
assert_eq!(
15691569
frontend2.expect("should find a frontend"),
1570-
RouteResult::simple("cluster_1".to_string())
1570+
RouteResult::forward("cluster_1".to_string())
15711571
);
15721572
println!("TEST {}", line!());
15731573
let frontend3 = listener.frontend_from_request("lolcatho.st", "/yolo/test", &Method::Get);
15741574
assert_eq!(
15751575
frontend3.expect("should find a frontend"),
1576-
RouteResult::simple("cluster_2".to_string())
1576+
RouteResult::forward("cluster_2".to_string())
15771577
);
15781578
println!("TEST {}", line!());
15791579
let frontend4 = listener.frontend_from_request("lolcatho.st", "/yolo/swag", &Method::Get);
15801580
assert_eq!(
15811581
frontend4.expect("should find a frontend"),
1582-
RouteResult::simple("cluster_3".to_string())
1582+
RouteResult::forward("cluster_3".to_string())
15831583
);
15841584
println!("TEST {}", line!());
15851585
let frontend5 = listener.frontend_from_request("domain", "/", &Method::Get);

lib/src/protocol/kawa_h1/editor.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::{
2+
hash::{DefaultHasher, Hash, Hasher},
23
net::{IpAddr, SocketAddr},
34
str::{from_utf8, from_utf8_unchecked},
45
};
@@ -24,7 +25,7 @@ pub struct HttpContext {
2425
/// the value of the sticky session cookie in the request
2526
pub sticky_session_found: Option<String>,
2627
/// position of the last authentication header, only valid until prepare is called
27-
pub authentication_found: Option<usize>,
28+
pub authentication_found: Option<u64>,
2829
// ---------- Status Line
2930
/// the value of the method in the request line
3031
pub method: Option<Method>,
@@ -137,7 +138,7 @@ impl HttpContext {
137138
let mut has_x_port = false;
138139
let mut has_x_proto = false;
139140
let mut has_connection = false;
140-
for (i, block) in request.blocks.iter_mut().enumerate() {
141+
for block in &mut request.blocks {
141142
match block {
142143
kawa::Block::Header(header) if !header.is_elided() => {
143144
let key = header.key.data(buf);
@@ -185,7 +186,11 @@ impl HttpContext {
185186
.and_then(|data| from_utf8(data).ok())
186187
.map(ToOwned::to_owned);
187188
} else if compare_no_case(key, b"Proxy-Authenticate") {
188-
self.authentication_found = Some(i);
189+
self.authentication_found = header.val.data_opt(buf).map(|auth| {
190+
let mut h = DefaultHasher::new();
191+
auth.hash(&mut h);
192+
h.finish()
193+
});
189194
}
190195
}
191196
_ => {}

0 commit comments

Comments
 (0)