From 391f060744288d541ba4ac7b540ef9b8469445ee Mon Sep 17 00:00:00 2001 From: UnicodingUnicorn <7555ic@gmail.com> Date: Sat, 23 Mar 2019 19:42:16 +0800 Subject: [PATCH] Added capability for auth to read tokens from querystring. --- Cargo.toml | 1 + README.md | 6 +++++- src/main.rs | 24 +++++++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0166836..5f7fb69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,4 @@ router = "0.6.0" jsonwebtoken = "5" serde = { version = "1.0", features = [ "derive" ] } serde_json = "1.0" +urlencoded = "0.6.0" diff --git a/README.md b/README.md index f08950d..5737f02 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Beep backend auth proxy. At long last, something done properly in Rust. My ancestors are smiling at me, Imperial, can you say the same? -Is basically tailored just for traefik's Forward Authentication system. It takes a `GET`, `POST`, `PUT`, `PATCH` or `DELETE` request, reads a Bearer Auth JWT token if available. If it is not available or invalid, request fails with 4XX and traefik rejects the request. Otherwise, a success response is returned with a `X-User-Claim` header containing serialised user information. `OPTIONS` requests are allowed to pass through wholesale. +Is basically tailored just for traefik's Forward Authentication system. It takes a `GET`, `POST`, `PUT`, `PATCH` or `DELETE` request, reads a Bearer Auth JWT token if available. Alternatively, the token can be supplied in the querystring as `token`. Tokens in the Authorization header override tokens in the querystring. If it is not available or invalid, request fails with 4XX and traefik rejects the request. Otherwise, a success response is returned with a `X-User-Claim` header containing serialised user information. `OPTIONS` requests are allowed to pass through wholesale. ## Contents of `X-User-Claim` @@ -12,3 +12,7 @@ Is basically tailored just for traefik's Forward Authentication system. It takes "clientid": "" } ``` + +## Errors + +`auth` responses with `400` if there is no token supplied, or `401` if there is an error processing the token. diff --git a/src/main.rs b/src/main.rs index ff98395..8b02a29 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,12 +7,14 @@ extern crate dotenv; extern crate iron; extern crate router; extern crate jsonwebtoken as jwt; +extern crate urlencoded; use dotenv::dotenv; use iron::prelude::*; use iron::headers::{ Authorization, Bearer }; use iron::status::Status; use router::Router; +use urlencoded::UrlEncodedQuery; use std::env; #[derive(Debug, Serialize, Deserialize)] @@ -31,8 +33,28 @@ fn main() { } fn verify_jwt(req:&mut Request) -> IronResult { + let mut token = None; + + // Check token from querystring + match req.get_ref::() { + Ok(ref hashmap) => { + if let Some(token_vec) = hashmap.get("token") { + if !token_vec.is_empty() { + token = Some(token_vec[0].clone()); + } + } + }, + Err(_) => return Ok(Response::with((Status::BadRequest, "400 Bad Request"))), + }; + + // Check token from Authorization header if let Some(authorisation_header) = req.headers.get::>() { - match jwt::decode::(&authorisation_header.token, secret.as_ref(), &jwt::Validation{ validate_exp:false, ..Default::default()}) { // Don't validate expiry + token = Some(authorisation_header.token.clone()); + } + + // Process token + if let Some(token) = token { + match jwt::decode::(&token, secret.as_ref(), &jwt::Validation{ validate_exp:false, ..Default::default()}) { // Don't validate expiry // match jwt::decode::(&authorisation_header.token, secret.as_ref(), &jwt::Validation::default()) { // Production version Ok(decoded) => { let user_string = match serde_json::to_string(&decoded.claims) {