summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-01-17 21:38:39 +0100
committermetamuffin <metamuffin@disroot.org>2025-01-17 21:38:39 +0100
commit49b615210cd1699daaf231508d59915c068dc7f8 (patch)
treef1a60b709a46047ef7616dba1fa02f7b1d31b592
parent455139ba2c73220da9e930838e876c59af6011f4 (diff)
downloadgnix-49b615210cd1699daaf231508d59915c068dc7f8.tar
gnix-49b615210cd1699daaf231508d59915c068dc7f8.tar.bz2
gnix-49b615210cd1699daaf231508d59915c068dc7f8.tar.zst
gnix-auth-no-redirect
-rw-r--r--readme.md5
-rw-r--r--src/modules/auth/cookie.rs47
2 files changed, 32 insertions, 20 deletions
diff --git a/readme.md b/readme.md
index 8ba9c1a..8a4fee1 100644
--- a/readme.md
+++ b/readme.md
@@ -167,8 +167,9 @@ themselves; in that case the request is passed on.
gnix and can therefore be used by applications. Alternatively a login may be
implemented by returning the `gnix-auth-success` header with a username as
the value from the `fail` handler, which is handled like a sucessful login
- for that user. This method can be useful for implementing custom login logic
- like OTP login or a CAPTCHA.
+ for that user. If `gnix-auth-no-redirect` is set the response of the `fail`
+ handler is passed instead of a redirect being sent. This method can be
+ useful for implementing custom login logic like OTP login or a CAPTCHA.
- `users`: list of valid logins (credentials)
- `expire`: seconds before logins expire; not setting this option keeps the
login valid forever on the server but cleared after the session on the
diff --git a/src/modules/auth/cookie.rs b/src/modules/auth/cookie.rs
index 091d41e..e078b6f 100644
--- a/src/modules/auth/cookie.rs
+++ b/src/modules/auth/cookie.rs
@@ -77,9 +77,7 @@ impl Node for CookieAuth {
debug!("login attempt for {username:?}");
if self.users.authentificate(username, password) {
debug!("login success via creds");
- Ok(apply_login_success_headers(
- context, &self, referrer, username,
- ))
+ Ok(login_success_response(context, &self, referrer, username))
} else {
debug!("login fail");
let mut r = Response::new(BoxBody::<_, ServiceError>::new(
@@ -134,12 +132,17 @@ impl Node for CookieAuth {
let mut r = self.fail.handle(context, request).await?;
if let Some(username) = r.headers_mut().remove("gnix-auth-success") {
debug!("login success via fail handler");
- Ok(apply_login_success_headers(
- context,
- &self,
- referrer,
- username.to_str()?,
- ))
+ if r.headers_mut().remove("gnix-auth-no-redirect").is_some() {
+ apply_login_success_headers(context, &self, username.to_str()?, &mut r);
+ Ok(r)
+ } else {
+ Ok(login_success_response(
+ context,
+ &self,
+ referrer,
+ username.to_str()?,
+ ))
+ }
} else {
debug!("unauthorized");
*r.status_mut() = StatusCode::UNAUTHORIZED;
@@ -153,9 +156,9 @@ impl Node for CookieAuth {
fn apply_login_success_headers(
context: &mut NodeContext,
node: &CookieAuth,
- referrer: Option<HeaderValue>,
username: &str,
-) -> Response<BoxBody<Bytes, ServiceError>> {
+ r: &mut Response<BoxBody<Bytes, ServiceError>>,
+) {
let nonce = [(); 12].map(|_| random::<u8>());
let plaintext = unix_seconds().to_be_bytes();
let mut ciphertext = context
@@ -169,7 +172,6 @@ fn apply_login_success_headers(
},
)
.unwrap();
-
ciphertext.extend(nonce);
let auth = base64::engine::general_purpose::URL_SAFE.encode(ciphertext);
@@ -181,12 +183,6 @@ fn apply_login_success_headers(
write!(cookie_opts, "; Secure").unwrap();
}
- let mut r = Response::new(BoxBody::<_, ServiceError>::new(
- String::new().clone().map_err(|_| unreachable!()),
- ));
- *r.status_mut() = StatusCode::FOUND;
- r.headers_mut()
- .append(LOCATION, referrer.unwrap_or(HeaderValue::from_static("/")));
r.headers_mut().append(
SET_COOKIE,
HeaderValue::from_str(&format!(
@@ -200,6 +196,21 @@ fn apply_login_success_headers(
SET_COOKIE,
HeaderValue::from_str(&format!("gnix_auth={}{}", auth, cookie_opts)).unwrap(),
);
+}
+
+fn login_success_response(
+ context: &mut NodeContext,
+ node: &CookieAuth,
+ referrer: Option<HeaderValue>,
+ username: &str,
+) -> Response<BoxBody<Bytes, ServiceError>> {
+ let mut r = Response::new(BoxBody::<_, ServiceError>::new(
+ String::new().clone().map_err(|_| unreachable!()),
+ ));
+ *r.status_mut() = StatusCode::FOUND;
+ r.headers_mut()
+ .append(LOCATION, referrer.unwrap_or(HeaderValue::from_static("/")));
+ apply_login_success_headers(context, node, username, &mut r);
r
}