From 8d3651d6fc388b48456228462ccab6b6c345153a Mon Sep 17 00:00:00 2001 From: landrigun Date: Sat, 19 Nov 2022 15:53:31 +0000 Subject: [PATCH] add http method validation on each route + add pubkey tests --- README.md | 6 ++++++ src/http/request.rs | 4 ++++ src/http/router.rs | 25 +++++++++++++++++++------ tests/bash/curling.bash | 15 +++++++++++++-- tests/python/test_requests.py | 21 +++++++++++++++++++++ 5 files changed, 63 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b8bc60f..e58d5c2 100644 --- a/README.md +++ b/README.md @@ -45,13 +45,19 @@ expiration_time = 2 # in hours ```bash ./simple-auth +# get a JWT curl http://:/get/ -d '{"username":"", "password":""}' # should returned {"token":"
.."} +# validate a JWT curl http://:/validate/ -d '{"token":"
.."}' # should returned (if valid) {"valid":"true"} + +# get the public key for local validation +curl http://:/pubkey/ +{"pubkey":""} ``` ## Test diff --git a/src/http/request.rs b/src/http/request.rs index 1dccfb5..c4c7bc2 100644 --- a/src/http/request.rs +++ b/src/http/request.rs @@ -217,6 +217,10 @@ impl HTTPRequest { } } + pub fn get_method(&self) -> String { + self.start_line.method.clone() + } + #[allow(dead_code)] pub fn is_valid(&self) -> bool { return self.start_line.is_valid(); diff --git a/src/http/router.rs b/src/http/router.rs index 57b0070..f12b677 100644 --- a/src/http/router.rs +++ b/src/http/router.rs @@ -14,7 +14,11 @@ const GET_ROUTE: &'static str = "/get/"; const VALIDATE_ROUTE: &'static str = "/validate/"; const PUBKEY_ROUTE: &'static str = "/pubkey/"; -async fn handle_get(request: HTTPRequest, config: Config) -> HTTPResponse { +async fn handle_get(request: HTTPRequest, config: Config, method: &str) -> HTTPResponse { + if method.trim().to_lowercase() != "post" { + return HTTPResponse::as_400(); + } + let mut store = FileStore::new(config.filestore_path.clone()); match &request.body { Some(ref b) => { @@ -48,7 +52,11 @@ async fn handle_get(request: HTTPRequest, config: Config) -> HTTPResponse { /// validates the token by checking: /// * expiration time /// * signature -async fn handle_validate(request: HTTPRequest, config: Config) -> HTTPResponse { +async fn handle_validate(request: HTTPRequest, config: Config, method: &str) -> HTTPResponse { + if request.get_method().trim().to_lowercase() != method { + return HTTPResponse::as_400(); + } + let token = { match request.get_body_value("token") { Some(t) => t, @@ -90,7 +98,11 @@ async fn handle_validate(request: HTTPRequest, config: Config) -> HTTPResponse { } /// returns the JWT public key in base64 encoded -async fn handle_public_key(_request: HTTPRequest, config: Config) -> HTTPResponse { +async fn handle_public_key(request: HTTPRequest, config: Config, method: &str) -> HTTPResponse { + if request.get_method().trim().to_lowercase() != method { + return HTTPResponse::as_400(); + } + let jwt_signer = { match JWTSigner::new(config).await { Ok(s) => s, @@ -114,6 +126,7 @@ async fn handle_public_key(_request: HTTPRequest, config: Config) -> HTTPRespons pub struct Router; impl Router { + /// routes the request to the corresponding handling method pub async fn route(&self, request_str: &str, addr: String, config: Config) -> HTTPResponse { let mut request = HTTPRequest::from(request_str); request.set_addr(addr); @@ -121,9 +134,9 @@ impl Router { let target = request.start_line.get_target(); match target.as_str() { - GET_ROUTE => handle_get(request, config).await, - VALIDATE_ROUTE => handle_validate(request, config).await, - PUBKEY_ROUTE => handle_public_key(request, config).await, + GET_ROUTE => handle_get(request, config, "post").await, + VALIDATE_ROUTE => handle_validate(request, config, "post").await, + PUBKEY_ROUTE => handle_public_key(request, config, "get").await, _ => HTTPResponse::as_404(), } } diff --git a/tests/bash/curling.bash b/tests/bash/curling.bash index 4c9813d..5bd0be3 100755 --- a/tests/bash/curling.bash +++ b/tests/bash/curling.bash @@ -9,8 +9,8 @@ URL=${SIMPLE_AUTH_URL} if [ -z ${URL} ] then - echo "[WARN]: SIMPLE_AUTH_URL is empty, set to http://localhost:9001" - URL="http://localhost:9001" + echo "[WARN]: SIMPLE_AUTH_URL is empty, set to http://localhost:5555" + URL="http://localhost:5555" fi for i in {0..10} @@ -39,3 +39,14 @@ do exit 1 fi done + + +for i in {0..10} +do + http_response=$(curl -s -o response.txt -w "%{http_code}" ${URL}/pubkey/) + if [ $http_response != "200" ] + then + echo "bad http status code : ${http_response}, expect 400" + exit 1 + fi +done diff --git a/tests/python/test_requests.py b/tests/python/test_requests.py index bc28b5a..9247873 100644 --- a/tests/python/test_requests.py +++ b/tests/python/test_requests.py @@ -1,3 +1,4 @@ +import base64 import jwt import os import requests @@ -113,3 +114,23 @@ class TestResponse(TestCase): "the url requested does not exist", "invalid error message returned", ) + + def test_get_pubkey(self): + resp = requests.get(URL + "/pubkey/") + self.assertEqual(resp.status_code, 200, "bad status code returned") + self.assertIsNotNone(resp.json(), "response data must not be empty") + self.assertIsNotNone(resp.json()["pubkey"], "invalid error message returned") + + b64_pubkey = base64.b64decode(resp.json()["pubkey"]) + self.assertIsNotNone(b64_pubkey, "public key b64 decoded can't be empty") + self.assertIn("-BEGIN PUBLIC KEY-", b64_pubkey.decode()) + + def test_get_pubkey_bad_method(self): + resp = requests.post(URL + "/pubkey/", json={"tutu": "toto"}) + self.assertEqual(resp.status_code, 400, "bad status code returned") + self.assertIsNotNone(resp.json(), "response data must not be empty") + self.assertEqual( + resp.json()["error"], + "the incoming request is not valid", + "invalid error message returned", + )