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 | } | ||