|
2 | 2 | //!
|
3 | 3 | //! - Documentation
|
4 | 4 |
|
5 |
| -use serde::Serialize; |
| 5 | +use serde::{de::DeserializeOwned, Serialize}; |
6 | 6 |
|
7 | 7 | use crate::{
|
8 | 8 | crypto::{
|
9 | 9 | hmac::{HmacSecret, Hs256, Hs384},
|
10 |
| - JwtSigner, |
| 10 | + JwtSigner, JwtVerifier, |
11 | 11 | },
|
12 |
| - errors::{new_error, Result}, |
13 |
| - serialization::{b64_encode, b64_encode_part}, |
14 |
| - Header, |
| 12 | + errors::{new_error, ErrorKind, Result}, |
| 13 | + serialization::{b64_encode, b64_encode_part, DecodedJwtPartClaims}, |
| 14 | + validation::validate, |
| 15 | + Header, TokenData, Validation, |
15 | 16 | };
|
16 | 17 |
|
17 | 18 | /// # Todo
|
@@ -44,13 +45,13 @@ impl JwtEncoder {
|
44 | 45 | /// # Todo
|
45 | 46 | ///
|
46 | 47 | /// - Test the the error checking works
|
47 |
| - pub fn with_header(mut self, header: Header) -> Result<Self> { |
| 48 | + pub fn with_header(mut self, header: &Header) -> Result<Self> { |
48 | 49 | // Check that the header makes use of the correct algorithm
|
49 | 50 | if header.alg != self.signing_provider.algorithm() {
|
50 | 51 | return Err(new_error(crate::errors::ErrorKind::InvalidAlgorithm));
|
51 | 52 | }
|
52 | 53 |
|
53 |
| - self.header = header; |
| 54 | + self.header = header.clone(); |
54 | 55 | Ok(self)
|
55 | 56 | }
|
56 | 57 |
|
@@ -84,6 +85,111 @@ impl JwtEncoder {
|
84 | 85 | }
|
85 | 86 | }
|
86 | 87 |
|
| 88 | +/// Takes the result of a rsplit and ensure we only get 2 parts |
| 89 | +/// Errors if we don't |
| 90 | +macro_rules! expect_two { |
| 91 | + ($iter:expr) => {{ |
| 92 | + let mut i = $iter; |
| 93 | + match (i.next(), i.next(), i.next()) { |
| 94 | + (Some(first), Some(second), None) => (first, second), |
| 95 | + _ => return Err(new_error(ErrorKind::InvalidToken)), |
| 96 | + } |
| 97 | + }}; |
| 98 | +} |
| 99 | + |
| 100 | +/// Todo |
| 101 | +pub struct JwtDecoder { |
| 102 | + verifying_provider: Box<dyn JwtVerifier>, |
| 103 | + validation: Validation, |
| 104 | +} |
| 105 | + |
| 106 | +impl JwtDecoder { |
| 107 | + /// Todo |
| 108 | + pub fn from_verifier<V: JwtVerifier + 'static>(verifying_provider: V) -> Self { |
| 109 | + Self::from_boxed_verifiyer(Box::new(verifying_provider)) |
| 110 | + } |
| 111 | + |
| 112 | + /// Todo |
| 113 | + pub fn from_boxed_verifiyer(verifying_provider: Box<dyn JwtVerifier>) -> Self { |
| 114 | + let validation = Validation::new(verifying_provider.algorithm()); |
| 115 | + |
| 116 | + Self { verifying_provider, validation } |
| 117 | + } |
| 118 | + |
| 119 | + /// Todo |
| 120 | + pub fn with_validation(mut self, validation: &Validation) -> Result<Self> { |
| 121 | + // Check that the validation contains the correct algorithm |
| 122 | + if !validation.algorithms.contains(&self.verifying_provider.algorithm()) { |
| 123 | + return Err(new_error(crate::errors::ErrorKind::InvalidAlgorithm)); |
| 124 | + } |
| 125 | + |
| 126 | + self.validation = validation.clone(); |
| 127 | + Ok(self) |
| 128 | + } |
| 129 | + |
| 130 | + /// Todo |
| 131 | + pub fn decode<T: DeserializeOwned>(&self, token: &str) -> Result<TokenData<T>> { |
| 132 | + let (header, claims) = self.verify_signature(token)?; |
| 133 | + |
| 134 | + let decoded_claims = DecodedJwtPartClaims::from_jwt_part_claims(claims)?; |
| 135 | + let claims = decoded_claims.deserialize()?; |
| 136 | + validate(decoded_claims.deserialize()?, &self.validation)?; |
| 137 | + |
| 138 | + Ok(TokenData { header, claims }) |
| 139 | + } |
| 140 | + |
| 141 | + /// Verify signature of a JWT, and return header object and raw payload |
| 142 | + /// |
| 143 | + /// If the token or its signature is invalid, it will return an error. |
| 144 | + fn verify_signature<'a>(&self, token: &'a str) -> Result<(Header, &'a str)> { |
| 145 | + if self.validation.validate_signature && self.validation.algorithms.is_empty() { |
| 146 | + return Err(new_error(ErrorKind::MissingAlgorithm)); |
| 147 | + } |
| 148 | + |
| 149 | + // Todo: This behaviour is currently not captured anywhere. |
| 150 | + // if validation.validate_signature { |
| 151 | + // for alg in &validation.algorithms { |
| 152 | + // if key.family != alg.family() { |
| 153 | + // return Err(new_error(ErrorKind::InvalidAlgorithm)); |
| 154 | + // } |
| 155 | + // } |
| 156 | + // } |
| 157 | + |
| 158 | + let (signature, message) = expect_two!(token.rsplitn(2, '.')); |
| 159 | + let (payload, header) = expect_two!(message.rsplitn(2, '.')); |
| 160 | + let header = Header::from_encoded(header)?; |
| 161 | + |
| 162 | + if self.validation.validate_signature && !self.validation.algorithms.contains(&header.alg) { |
| 163 | + return Err(new_error(ErrorKind::InvalidAlgorithm)); |
| 164 | + } |
| 165 | + |
| 166 | + if self.validation.validate_signature |
| 167 | + && self |
| 168 | + .verifying_provider |
| 169 | + .verify(message.as_bytes(), &signature.as_bytes().to_vec()) |
| 170 | + .is_err() |
| 171 | + { |
| 172 | + return Err(new_error(ErrorKind::InvalidSignature)); |
| 173 | + } |
| 174 | + |
| 175 | + Ok((header, payload)) |
| 176 | + } |
| 177 | + |
| 178 | + /// Create new [`JwtDecoder`] with the `HS256` algorithm. |
| 179 | + pub fn hs_256(secret: HmacSecret) -> Result<JwtDecoder> { |
| 180 | + let verifying_provider = Box::new(Hs256::new(secret)?); |
| 181 | + |
| 182 | + Ok(JwtDecoder::from_boxed_verifiyer(verifying_provider)) |
| 183 | + } |
| 184 | + |
| 185 | + /// Create new [`JwtDecoder`] with the `HS384` algorithm. |
| 186 | + pub fn hs_384(secret: HmacSecret) -> Result<JwtDecoder> { |
| 187 | + let verifying_provider = Box::new(Hs384::new(secret)?); |
| 188 | + |
| 189 | + Ok(JwtDecoder::from_boxed_verifiyer(verifying_provider)) |
| 190 | + } |
| 191 | +} |
| 192 | + |
87 | 193 | #[cfg(test)]
|
88 | 194 | mod builder_tests {
|
89 | 195 |
|
|
0 commit comments