diff options
Diffstat (limited to 'src/auth.rs')
| -rw-r--r-- | src/auth.rs | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/src/auth.rs b/src/auth.rs new file mode 100644 index 0000000..e22262c --- /dev/null +++ b/src/auth.rs | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | use crate::error::Error; | ||
| 2 | use crate::schema::{Db, Transaction}; | ||
| 3 | use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; | ||
| 4 | use serde::{Deserialize, Serialize}; | ||
| 5 | use warp::header::headers_cloned; | ||
| 6 | use warp::http::header::{HeaderMap, HeaderValue, AUTHORIZATION}; | ||
| 7 | use warp::{reject, Filter, Rejection}; | ||
| 8 | use thiserror::Error; | ||
| 9 | use anyhow::*; | ||
| 10 | |||
| 11 | const BEARER: &str = "Bearer "; | ||
| 12 | const PUBLIC_KEY_PEM: &str = "-----BEGIN PUBLIC KEY----- | ||
| 13 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4nU0G4WjkmcQUx0hq6LQ | ||
| 14 | uV5Q+ACmUFL/OjoYMDwC/O/6pCd1UZgCfgHN2xEffDPznzcTn8OiFRxr4oWyBiny | ||
| 15 | rUpnY4mhy0SQUwoeCw7YkcHAyhCjNT74aR/ohX0MCj0qRRdbt5ZQXM/GC3HJuXE1 | ||
| 16 | ptSuhFgQxziItamn8maoJ6JUSVEXVO1NOrrjoM3r7Q+BK2B+sX4/bLZ+VG5g1q2n | ||
| 17 | EbFdTHS6pHqtZNHQndTmEKwRfh0RYtzEzOXuO6e1gQY42Tujkof40dhGCIU7TeIG | ||
| 18 | GHwdFxy1niLkXwtHNjV7lnIOkTbx6+sSPamRfQAlZqUWM2Lf5o+7h3qWP3ENB138 | ||
| 19 | sQIDAQAB | ||
| 20 | -----END PUBLIC KEY-----"; | ||
| 21 | |||
| 22 | // const private_key_pem: &str = "-----BEGIN RSA PRIVATE KEY----- | ||
| 23 | // MIIEpAIBAAKCAQEA4nU0G4WjkmcQUx0hq6LQuV5Q+ACmUFL/OjoYMDwC/O/6pCd1 | ||
| 24 | // UZgCfgHN2xEffDPznzcTn8OiFRxr4oWyBinyrUpnY4mhy0SQUwoeCw7YkcHAyhCj | ||
| 25 | // NT74aR/ohX0MCj0qRRdbt5ZQXM/GC3HJuXE1ptSuhFgQxziItamn8maoJ6JUSVEX | ||
| 26 | // VO1NOrrjoM3r7Q+BK2B+sX4/bLZ+VG5g1q2nEbFdTHS6pHqtZNHQndTmEKwRfh0R | ||
| 27 | // YtzEzOXuO6e1gQY42Tujkof40dhGCIU7TeIGGHwdFxy1niLkXwtHNjV7lnIOkTbx | ||
| 28 | // 6+sSPamRfQAlZqUWM2Lf5o+7h3qWP3ENB138sQIDAQABAoIBAD23nYTmrganag6M | ||
| 29 | // wPFrBSGP79c3Lhx0EjUHQjJbGKFgsdltG48qM3ut+DF9ACy0Z+/7bbC7+39vaIOq | ||
| 30 | // 1jLR2d6aiYTaLKseO4s2FawD1sgamvU3BZPsXn0gAhnnU5Gyy8Nas1dccvhoc9wI | ||
| 31 | // neaZUPrvucQ90AzLfo6r9yacDbYHB1lOyomApUvpJxOgHISGEtc9qGPDrdH19aF0 | ||
| 32 | // 8fCv2bbQRh+TChgN3IB0o5w0wXaI7YAyAouAv/AzHCoEMpt7OGjFTkjh/ujlPL9O | ||
| 33 | // +FLuJNsQRHDN0gJo2pcvwGwDCsioMixQ9bZ7ZrUu2BNpEQygyeSbj9ZI1iRvhosO | ||
| 34 | // JU3rwEECgYEA9MppTYA6A9WQbCCwPH1QMpUAmPNVSWVhUVag4lGOEhdCDRcz9ook | ||
| 35 | // DohQMKctiEB1luKuvDokxo0uMOfMO9/YwjsRB7qjQip7Th1zMJIjD+A+juLzHK4r | ||
| 36 | // /RiRtWYGAnF8mptDvE+93JsPb3C/lQLvIhio5GQYWBqPJu6SpeosIskCgYEA7NPi | ||
| 37 | // Gbffzr2UQhW8BNKmctEEh8yFRVojFo3wwwWxSNUVXGSmSm31CL+Q8h817R+2OkPV | ||
| 38 | // 1ZMUOBU4UJiqFt28kIvTDFqbAJlJQGCpY2mY7OLQiD2A+TVLcFrHmoCaPfCAK1Qd | ||
| 39 | // hQ0PmFK7Mf8qClpA3E5chop/WfKQfiu46sZv1qkCgYAhGdXPcw1lQ1W6KVlrdI6J | ||
| 40 | // qHhiNlVMDXdxZkNvFxQdAiQeXQrbxaZGiMw/J/wSNpUwCAsUzM/4QVMDrfSCDCzl | ||
| 41 | // ZtNQtj4pTlFKKNVQthIjrXEIJUw2jp7IJLBfVSJu5iWxSlmId0f3MsiNizN81N69 | ||
| 42 | // P5Rm/doE3+KHoy8VXGsHcQKBgQCkNh62enqjHWypjex6450qS6f6iWN3PRLLVsw0 | ||
| 43 | // TcQpniZblCaBwVCAKmRUnjOEIdL2/4ZLutnwMTaFG/YEOOfAylMiY8jKV38lNmD9 | ||
| 44 | // X4D78CFr9klxgvS2CRwSE03f2NzmLkLxuKaxldvaxPTfjMkgeO1LFMlNExYBhkuH | ||
| 45 | // 7uQpUQKBgQCKX6qMNh2gSdgG7qyxfTFZ4y5EGOBoKe/dE+IcVF3Vnh6DZVbCAbBL | ||
| 46 | // 5EdFWZSrCnDjA4xiKW55mwp95Ud9EZsZAb13L8V9t82eK+UDBoWlb7VRNYpda/x1 | ||
| 47 | // 5/i4qQJ28x2UNJDStpYFpnp4Ba1lvXjKngIbDPkjU+hbBJ+BNGAIeg== | ||
| 48 | // -----END RSA PRIVATE KEY-----"; | ||
| 49 | |||
| 50 | /// sub: Subject, user identifier | ||
| 51 | /// exp: Expiration date, Unix Time, epoch | ||
| 52 | /// puk: Public Key? Not 100% on this | ||
| 53 | #[derive(Debug, Serialize, Deserialize)] | ||
| 54 | struct Claims { | ||
| 55 | sub: String, | ||
| 56 | exp: usize, | ||
| 57 | puk: String, | ||
| 58 | } | ||
| 59 | |||
| 60 | // #[derive(Error, Debug)] | ||
| 61 | // pub enum Nope { | ||
| 62 | // #[error("Invalid header")] | ||
| 63 | // InvalidHeader { | ||
| 64 | // expected: String, | ||
| 65 | // found: String, | ||
| 66 | // }, | ||
| 67 | // } | ||
| 68 | |||
| 69 | pub fn with_auth( | ||
| 70 | db: Db, | ||
| 71 | t: Transaction, | ||
| 72 | ) -> impl Filter<Extract = (String,), Error = Rejection> + Clone { | ||
| 73 | headers_cloned() | ||
| 74 | .map(move |headers: HeaderMap<HeaderValue>| (db.clone(), headers)) | ||
| 75 | .and_then(authorize) | ||
| 76 | } | ||
| 77 | |||
| 78 | impl warp::reject::Reject for Nope {} | ||
| 79 | |||
| 80 | async fn authorize((db, headers): (Db, HeaderMap<HeaderValue>)) -> Result<String, Error> { | ||
| 81 | match jwt_from_header(&headers) { | ||
| 82 | Ok(jwt) => { | ||
| 83 | let decoded = decode::<Claims>( | ||
| 84 | &jwt, | ||
| 85 | // TODO: what key are we using here? pass db/pw store here to get the claimant's | ||
| 86 | // public key <10-04-21, yigit> // | ||
| 87 | &DecodingKey::from_rsa_pem(PUBLIC_KEY_PEM.as_bytes()).unwrap(), | ||
| 88 | &Validation::new(Algorithm::HS512), | ||
| 89 | ) | ||
| 90 | .map_err(|_| reject::custom(Error::JWTTokenError)) | ||
| 91 | .unwrap(); | ||
| 92 | |||
| 93 | Ok(decoded.claims.puk) | ||
| 94 | } | ||
| 95 | Err(e) => return Err(anyhow!("missing!")); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | fn jwt_from_header(headers: &HeaderMap<HeaderValue>) -> Result<String, Error> { | ||
| 100 | let header = match headers.get(AUTHORIZATION) { | ||
| 101 | Some(v) => v, | ||
| 102 | None => return Err(Error::NoAuthHeaderError), | ||
| 103 | }; | ||
| 104 | let auth_header = match std::str::from_utf8(header.as_bytes()) { | ||
| 105 | Ok(v) => v, | ||
| 106 | Err(_) => return Err(Error::NoAuthHeaderError), | ||
| 107 | }; | ||
| 108 | if !auth_header.starts_with(BEARER) { | ||
| 109 | return Err(Error::InvalidAuthHeaderError); | ||
| 110 | } | ||
| 111 | Ok(auth_header.trim_start_matches(BEARER).to_owned()) | ||
| 112 | } | ||
