Initial commit
parent
e185b09d17
commit
3879bbb3e6
|
@ -1,14 +1,4 @@
|
||||||
# ---> Go
|
# ---> Rust
|
||||||
# Binaries for programs and plugins
|
/target
|
||||||
*.exe
|
Cargo.lock
|
||||||
*.exe~
|
**/*.rs.bk
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Test binary, build with `go test -c`
|
|
||||||
*.test
|
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
|
||||||
*.out
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "backend-auth"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["UnicodingUnicorn <7555ic@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dotenv = "0.13.0"
|
||||||
|
lazy_static = "1.2.0"
|
||||||
|
iron = "0.6.0"
|
||||||
|
router = "0.6.0"
|
||||||
|
jsonwebtoken = "5"
|
||||||
|
serde = { version = "1.0", features = [ "derive" ] }
|
||||||
|
serde_json = "1.0"
|
13
README.md
13
README.md
|
@ -1,3 +1,14 @@
|
||||||
# backend-auth
|
# backend-auth
|
||||||
|
|
||||||
Beep backend auth proxy
|
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.
|
||||||
|
|
||||||
|
## Contents of `X-User-Claim`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"userid": "<userid>",
|
||||||
|
"clientid": "<clientid>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde;
|
||||||
|
extern crate serde_json;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
extern crate dotenv;
|
||||||
|
extern crate iron;
|
||||||
|
extern crate router;
|
||||||
|
extern crate jsonwebtoken as jwt;
|
||||||
|
|
||||||
|
use dotenv::dotenv;
|
||||||
|
use iron::prelude::*;
|
||||||
|
use iron::headers::{ Authorization, Bearer };
|
||||||
|
use iron::status::Status;
|
||||||
|
use router::Router;
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct UserClaims {
|
||||||
|
userid: String,
|
||||||
|
clientid: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dotenv().ok();
|
||||||
|
|
||||||
|
let listen = env::var("LISTEN").unwrap();
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref secret:String = env::var("SECRET").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_jwt(req:&mut Request) -> IronResult<Response> {
|
||||||
|
if let Some(authorisation_header) = req.headers.get::<Authorization<Bearer>>() {
|
||||||
|
match jwt::decode::<UserClaims>(&authorisation_header.token, secret.as_ref(), &jwt::Validation{ validate_exp:false, ..Default::default()}) { // Don't validate expiry
|
||||||
|
// match jwt::decode::<UserClaims>(&authorisation_header.token, secret.as_ref(), &jwt::Validation::default()) { // Production version
|
||||||
|
Ok(decoded) => {
|
||||||
|
let user_string = match serde_json::to_string(&decoded.claims) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => return Ok(Response::with((Status::Unauthorized, "401 Unauthorised"))),
|
||||||
|
};
|
||||||
|
let mut res = Response::with((Status::Ok, "200 Ok"));
|
||||||
|
res.headers.set_raw("X-User-Claim", vec![user_string.as_bytes().to_vec()]);
|
||||||
|
Ok(res)
|
||||||
|
},
|
||||||
|
Err(_) => Ok(Response::with((Status::Unauthorized, "401 Unauthorised")))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(Response::with((Status::BadRequest, "400 Bad Request")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut router = Router::new();
|
||||||
|
// Let OPTIONS through
|
||||||
|
router.options("/auth", success, "auth_options");
|
||||||
|
// Auth GET, POST, PUT, PATCH, DELETE
|
||||||
|
router.get("/auth", verify_jwt, "auth_get");
|
||||||
|
router.post("/auth", verify_jwt, "auth_post");
|
||||||
|
router.put("/auth", verify_jwt, "auth_put");
|
||||||
|
router.patch("/auth", verify_jwt, "auth_patch");
|
||||||
|
router.delete("/auth", verify_jwt, "auth_delete");
|
||||||
|
|
||||||
|
match Iron::new(router).http(&listen) {
|
||||||
|
Ok(_) => println!("Listening on {}", &listen),
|
||||||
|
Err(e) => println!("Error: {:?}", e),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn success(_:&mut Request) -> IronResult<Response> {
|
||||||
|
Ok(Response::with((Status::Ok, "")))
|
||||||
|
}
|
Loading…
Reference in New Issue