cataclysm_jwt/jwt_session/
hs256_session.rs1use crate::{Error, error::{JWTError,ConstructionError}, sign_algorithms::HS256, jwt_session::JWTSession, JWT};
2
3use chrono::{DateTime, Utc};
4use std::collections::HashMap;
5use cataclysm::{session::{SessionCreator, Session}, http::Request};
6
7#[derive(Clone)]
8pub struct JWTHS256Session {
10 pub aud: String,
11 pub iss: String,
12 pub verification_key: HS256,
13 #[cfg(feature = "delta-start")]
14 pub delta_start: Option<i64>,
15}
16
17impl JWTHS256Session {
18
19 pub fn builder() -> JWTHS256Builder {
21 JWTHS256Builder::default()
22 }
23
24}
25
26impl SessionCreator for JWTHS256Session {
27
28 fn apply(&self, _values: &HashMap<String, String>, res: cataclysm::http::Response) -> cataclysm::http::Response {
29 res
30 }
31
32 fn create(&self, req: &cataclysm::http::Request) -> Result<cataclysm::session::Session, cataclysm::Error> {
33 match self.build_from_req(req) {
34 Ok(payload) => {
35 return Ok(Session::new_with_values(self.clone(),payload))
36 },
37 Err(_) => {
38 return Err(cataclysm::Error::Custom(format!("Unable to create session!!")));
39 }
40 }
41 }
42
43}
44
45impl JWTSession for JWTHS256Session {
46
47 fn build_from_req(&self, req: &Request) -> Result<HashMap<String,String>, Error> {
48
49 let jwt = Self::obtain_token_from_req(req)?;
50
51 self.initial_validation(&jwt)?;
52
53 return Ok(jwt.payload)
54
55
56 }
57
58 fn initial_validation(&self, jwt: &JWT) -> Result<(),Error> {
59
60 match jwt.header.get("alg") {
62 Some(a) => {
63 if a.to_lowercase().as_str() != self.verification_key.to_string() {
64 return Err(Error::JWT(JWTError::WrongAlgorithm));
65 }
66 },
67 None => {
68 return Err(Error::JWT(JWTError::NoAlgorithm));
69 }
70 };
71
72 #[cfg(not(feature = "lax-security"))]
73 {
74 match jwt.payload.get("aud") {
76 Some(a) => {
77 if a.as_str() != &self.aud {
78 return Err(Error::JWT(JWTError::WrongAudience));
79 }
80 },
81 None => {
82 return Err(Error::JWT(JWTError::NoAudience))
83 }
84 }
85
86 match jwt.payload.get("iss") {
88 Some(i) => {
89 if i.as_str() != &self.iss {
90 return Err(Error::JWT(JWTError::WrongIss));
91 }
92 },
93 None => {
94 return Err(Error::JWT(JWTError::NoIss))
95 }
96 }
97
98 match jwt.payload.get("exp") {
100 Some(e) => {
101
102 let num_e = str::parse::<i64>(e)?;
103 let date_utc = DateTime::from_timestamp(num_e,0).ok_or(Error::ParseTimestamp)?;
104 let now = Utc::now();
105
106 if date_utc < now {
107 return Err(Error::JWT(JWTError::Expired));
108 }
109
110 },
111 None => {
112 return Err(Error::JWT(JWTError::NoExp))
113 }
114 }
115
116 match jwt.payload.get("iat") {
118 Some(ia) => {
119 let num_ia = str::parse::<i64>(ia)?;
120 let now = Utc::now();
121
122 #[cfg(not(feature = "delta-start"))] {
123 let date_utc = DateTime::from_timestamp(num_ia,0).ok_or(Error::ParseTimestamp)?;
124 if date_utc > now {
125 return Err(Error::JWT(JWTError::ToBeValid));
126 }
127 }
128
129 #[cfg(feature = "delta-start")] {
130 let delta = match self.delta_start {
131 Some(d) => d,
132 None => 0
133 };
134 let date_utc = DateTime::from_timestamp(num_ia - delta,0).ok_or(Error::ParseTimestamp)?;
135 if date_utc > now {
136 return Err(Error::JWT(JWTError::Expired));
137 }
138 }
139 },
140 None => {
141 return Err(Error::JWT(JWTError::NoIat))
142 }
143 }
144
145 match jwt.payload.get("nbf") {
146 Some(nb) => {
147 let num_nb = str::parse::<i64>(nb)?;
148 let now = Utc::now();
149
150 #[cfg(not(feature = "delta-start"))] {
151 let date_utc = DateTime::from_timestamp(num_nb,0).ok_or(Error::ParseTimestamp)?;
152 if date_utc > now {
153 return Err(Error::JWT(JWTError::ToBeValid));
154 }
155 }
156
157 #[cfg(feature = "delta-start")] {
158 let delta = match self.delta_start {
159 Some(d) => d,
160 None => 0
161 };
162 let date_utc = DateTime::from_timestamp(num_nb - delta,0).ok_or(Error::ParseTimestamp)?;
163 if date_utc > now {
164 return Err(Error::JWT(JWTError::Expired));
165 }
166 }
167 },
168 None => {
169 return Err(Error::JWT(JWTError::NoNbf))
170 }
171 }
172
173 }
174
175 self.verification_key.verify_jwt(&jwt.raw_jwt)
176
177 }
178
179}
180
181#[derive(Default)]
182pub struct JWTHS256Builder {
184 aud: Option<String>,
185 iss: Option<String>,
186 verification_key: Option<HS256>,
187 #[cfg(feature = "delta-start")]
188 delta_start: Option<i64>,
189}
190
191impl JWTHS256Builder {
192
193 pub fn aud<A: AsRef<str>>(self, aud: A) -> Self {
195 Self {
196 aud: Some(aud.as_ref().to_string()),
197 ..self
198 }
199 }
200
201 pub fn iss<A: AsRef<str>>(self, iss: A) -> Self {
203 Self {
204 iss: Some(iss.as_ref().to_string()),
205 ..self
206 }
207 }
208
209 pub fn add_from_secret<A: AsRef<str>>(self, secret: A) -> Self {
211
212 let verification_key = HS256::new(secret);
213
214 Self {
215 verification_key: Some(verification_key),
216 ..self
217 }
218
219 }
220
221 #[cfg(feature = "delta-expiration")]
225 pub fn delta_start(self, delta_exipration: i64) -> Self {
226
227 Self {
228 delta_start: Some(delta_start),
229 ..self
230 }
231
232 }
233
234 pub fn build(self) -> Result<JWTHS256Session, Error> {
236
237 let aud = match self.aud {
238 Some(a) => a,
239 None => {
240 return Err(Error::Construction(ConstructionError::Aud));
241 }
242 };
243
244 let iss = match self.iss {
245 Some(i) => i,
246 None => {
247 return Err(Error::Construction(ConstructionError::Iss));
248 }
249 };
250
251 let verification_key = match self.verification_key {
252 Some(k) => k,
253 None => {
254 return Err(Error::Construction(ConstructionError::Keys))
255 }
256 };
257
258 Ok(JWTHS256Session {
259 aud,
260 iss,
261 verification_key,
262 #[cfg(feature = "delta-start")]
263 delta_start: self.delta_start
264 })
265 }
266}