summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYves Fischer <yvesf-git@xapek.org>2018-12-02 13:52:23 +0100
committerYves Fischer <yvesf-git@xapek.org>2018-12-02 13:52:23 +0100
commitf098fdc99de724f53f7f129b6a5bde50b73fd797 (patch)
treedab4645ee420a7d6373818c44c6a5f7439dc7726
parentcf40041946626b105102e3dab2515d2ef2fb0506 (diff)
downloadnginx-auth-totp-f098fdc99de724f53f7f129b6a5bde50b73fd797.tar.gz
nginx-auth-totp-f098fdc99de724f53f7f129b6a5bde50b73fd797.zip
request slowdown on login failureHEADmaster
-rw-r--r--src/main.rs6
-rw-r--r--src/request_handler/handler_login.rs25
-rw-r--r--src/request_handler/mod.rs4
-rw-r--r--src/request_handler/views.rs9
4 files changed, 38 insertions, 6 deletions
diff --git a/src/main.rs b/src/main.rs
index a025e69..6cdf77a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,4 @@
-#![feature(test)]
-#![feature(duration_as_u128)]
-
+#![feature(test,integer_atomics,duration_as_u128)]
use std::sync::Arc;
use std::thread;
use std::sync::atomic;
@@ -50,6 +48,7 @@ pub struct ApplicationState {
cookie_store: CookieStore,
cookie_max_age: Duration,
debug: bool,
+ request_slowdown: Arc<atomic::AtomicU64>,
}
#[derive(Debug, StructOpt)]
@@ -72,6 +71,7 @@ fn main() {
cookie_store: CookieStore::new(),
cookie_max_age: Duration::days(1),
debug: opt.debug,
+ request_slowdown: Arc::new(atomic::AtomicU64::new(0)),
};
let server_shutdown_condvar = Arc::new(atomic::AtomicBool::new(false));
diff --git a/src/request_handler/handler_login.rs b/src/request_handler/handler_login.rs
index aa93e96..ac0c37e 100644
--- a/src/request_handler/handler_login.rs
+++ b/src/request_handler/handler_login.rs
@@ -1,5 +1,9 @@
+use std::ops::Add;
use std::io;
use std::borrow::Cow;
+use std::time;
+use std::thread;
+use std::sync::atomic;
use tokio::prelude::*;
@@ -36,6 +40,18 @@ fn test_secrets(secrets: &Vec<&str>, token: &String) -> bool {
pub(in super) fn POST<'a>(header_infos: &HeaderExtract, state: &ApplicationState, req: &Request<Bytes>)
-> Response<String> {
+let wait_until = state.request_slowdown.load(atomic::Ordering::Acquire);
+ let now = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().as_secs();
+
+ let slept = if wait_until > now {
+ let time = wait_until - now;
+ warn!("Sleep {}s", time);
+ thread::sleep(time::Duration::from_secs(time));
+ time
+ } else {
+ 0
+ };
+
let mut token = None;
let mut redirect = None;
for (key, val) in form_urlencoded::parse(req.body()) {
@@ -67,6 +83,15 @@ pub(in super) fn POST<'a>(header_infos: &HeaderExtract, state: &ApplicationState
.header(SET_COOKIE, cookie.to_string())
.body(views::login_auth_success(&redirect)).unwrap()
} else {
+ let current_wait = state.request_slowdown.load(atomic::Ordering::Acquire);
+ let wait_until = time::SystemTime::now()
+ .add(time::Duration::from_secs(8))
+ .duration_since(time::UNIX_EPOCH).unwrap()
+ .as_secs();
+ // if this request was already delayed then we double-delay
+ let wait_until = wait_until.max(current_wait + 8 + slept);
+ state.request_slowdown.store(wait_until, atomic::Ordering::Release);
+
Response::builder()
.set_defaults()
.body(views::login_auth_fail()).unwrap()
diff --git a/src/request_handler/mod.rs b/src/request_handler/mod.rs
index 6812bb4..ec62ba3 100644
--- a/src/request_handler/mod.rs
+++ b/src/request_handler/mod.rs
@@ -1,5 +1,6 @@
#![allow(warnings)]
+use std::sync::atomic;
use std::cell::Cell;
use std::collections::HashMap;
use std::io;
@@ -121,7 +122,8 @@ fn info<'a>(request_handler: &RequestHandler, state: &super::ApplicationState,
let valid_cookies: Vec<(String, String)> = state.cookie_store.reader
.map_into(|k, v|
(k.to_string(), ftime(v[0] as i64)));
- views::info_debug(path_rest, valid_cookies)
+ views::info_debug(path_rest, valid_cookies,
+ state.request_slowdown.load(atomic::Ordering::Acquire))
} else {
views::info(path_rest)
};
diff --git a/src/request_handler/views.rs b/src/request_handler/views.rs
index bdd7999..d2de163 100644
--- a/src/request_handler/views.rs
+++ b/src/request_handler/views.rs
@@ -17,7 +17,7 @@ fn render_base_template(title: &'static str, page_body: Box<RenderBox>) -> Strin
}).into_string().unwrap()
}
-pub(in super) fn info_debug<'a>(path_rest: &'a str, cookies: Vec<(String, String)>) -> String {
+pub(in super) fn info_debug<'a>(path_rest: &'a str, cookies: Vec<(String, String)>, wait_until: u64) -> String {
let path = path_rest.to_string();
render_base_template("Info (debug)", box_html! {
h1(id = "heading") {
@@ -32,7 +32,7 @@ pub(in super) fn info_debug<'a>(path_rest: &'a str, cookies: Vec<(String, String
th: "Cookie value";
th: "Valid until";
}
- tbody {
+ tbody {
@ for (name, valid_until) in cookies {
tr {
td: name;
@@ -41,6 +41,11 @@ pub(in super) fn info_debug<'a>(path_rest: &'a str, cookies: Vec<(String, String
}
}
}
+ h2: "Request Slowdown";
+ p {
+ : "Until: ";
+ : wait_until;
+ }
})
}