Skip to content

Commit b32e0a3

Browse files
authored
deserialization support for some missing algorithms (#324)
* Only deserialization support for missing Algorithm (Keycloak) * linting fixes * linting change leftover fix * KeyAlgorithm moved to mod jwk, typo fixes * Moved pub method to Jwk private * Removed test
1 parent e7bb952 commit b32e0a3

File tree

3 files changed

+112
-11
lines changed

3 files changed

+112
-11
lines changed

examples/auth0.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/// Example for the backend to backend implementation
22
use std::collections::HashMap;
3+
use std::str::FromStr;
34

45
use jsonwebtoken::jwk::AlgorithmParameters;
5-
use jsonwebtoken::{decode, decode_header, jwk, DecodingKey, Validation};
6+
use jsonwebtoken::{decode, decode_header, jwk, Algorithm, DecodingKey, Validation};
67

78
const TOKEN: &str = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjFaNTdkX2k3VEU2S1RZNTdwS3pEeSJ9.eyJpc3MiOiJodHRwczovL2Rldi1kdXp5YXlrNC5ldS5hdXRoMC5jb20vIiwic3ViIjoiNDNxbW44c281R3VFU0U1N0Fkb3BhN09jYTZXeVNidmRAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZGV2LWR1enlheWs0LmV1LmF1dGgwLmNvbS9hcGkvdjIvIiwiaWF0IjoxNjIzNTg1MzAxLCJleHAiOjE2MjM2NzE3MDEsImF6cCI6IjQzcW1uOHNvNUd1RVNFNTdBZG9wYTdPY2E2V3lTYnZkIiwic2NvcGUiOiJyZWFkOnVzZXJzIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.0MpewU1GgvRqn4F8fK_-Eu70cUgWA5JJrdbJhkCPCxXP-8WwfI-qx1ZQg2a7nbjXICYAEl-Z6z4opgy-H5fn35wGP0wywDqZpqL35IPqx6d0wRvpPMjJM75zVXuIjk7cEhDr2kaf1LOY9auWUwGzPiDB_wM-R0uvUMeRPMfrHaVN73xhAuQWVjCRBHvNscYS5-i6qBQKDMsql87dwR72DgHzMlaC8NnaGREBC-xiSamesqhKPVyGzSkFSaF3ZKpGrSDapqmHkNW9RDBE3GQ9OHM33vzUdVKOjU1g9Leb9PDt0o1U4p3NQoGJPShQ6zgWSUEaqvUZTfkbpD_DoYDRxA";
89
const JWKS_REPLY: &str = r#"
@@ -21,7 +22,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
2122
match &j.algorithm {
2223
AlgorithmParameters::RSA(rsa) => {
2324
let decoding_key = DecodingKey::from_rsa_components(&rsa.n, &rsa.e).unwrap();
24-
let mut validation = Validation::new(j.common.algorithm.unwrap());
25+
26+
let mut validation = Validation::new(
27+
Algorithm::from_str(j.common.key_algorithm.unwrap().to_string().as_str())
28+
.unwrap(),
29+
);
2530
validation.validate_exp = false;
2631
let decoded_token =
2732
decode::<HashMap<String, serde_json::Value>>(TOKEN, &decoding_key, &validation)

src/algorithms.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ impl Algorithm {
8484

8585
#[cfg(test)]
8686
mod tests {
87+
use crate::jwk::KeyAlgorithm;
88+
8789
use super::*;
8890

8991
#[test]

src/jwk.rs

Lines changed: 103 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
#![allow(missing_docs)]
2-
//! This crate contains types only for working JWK and JWK Sets
3-
//! This is only meant to be used to deal with public JWK, not generate ones.
4-
//! Most of the code in this file is taken from https://github.com/lawliet89/biscuit but
5-
//! tweaked to remove the private bits as it's not the goal for this crate currently.
6-
use crate::Algorithm;
2+
///! This crate contains types only for working JWK and JWK Sets
3+
///! This is only meant to be used to deal with public JWK, not generate ones.
4+
///! Most of the code in this file is taken from https://github.com/lawliet89/biscuit but
5+
/// tweaked to remove the private bits as it's not the goal for this crate currently.
6+
///!
7+
use crate::{
8+
errors::{self, Error, ErrorKind},
9+
Algorithm,
10+
};
711
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
8-
use std::fmt;
12+
use std::{fmt, str::FromStr};
913

1014
/// The intended usage of the public `KeyType`. This enum is serialized `untagged`
1115
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
@@ -141,6 +145,87 @@ impl<'de> Deserialize<'de> for KeyOperations {
141145
}
142146
}
143147

148+
/// The algorithms of the keys
149+
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
150+
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize)]
151+
pub enum KeyAlgorithm {
152+
/// HMAC using SHA-256
153+
HS256,
154+
/// HMAC using SHA-384
155+
HS384,
156+
/// HMAC using SHA-512
157+
HS512,
158+
159+
/// ECDSA using SHA-256
160+
ES256,
161+
/// ECDSA using SHA-384
162+
ES384,
163+
164+
/// RSASSA-PKCS1-v1_5 using SHA-256
165+
RS256,
166+
/// RSASSA-PKCS1-v1_5 using SHA-384
167+
RS384,
168+
/// RSASSA-PKCS1-v1_5 using SHA-512
169+
RS512,
170+
171+
/// RSASSA-PSS using SHA-256
172+
PS256,
173+
/// RSASSA-PSS using SHA-384
174+
PS384,
175+
/// RSASSA-PSS using SHA-512
176+
PS512,
177+
178+
/// Edwards-curve Digital Signature Algorithm (EdDSA)
179+
EdDSA,
180+
181+
/// RSAES-PKCS1-V1_5
182+
RSA1_5,
183+
184+
/// RSAES-OAEP using SHA-1
185+
#[serde(rename = "RSA-OAEP")]
186+
RSA_OAEP,
187+
188+
/// RSAES-OAEP-256 using SHA-2
189+
#[serde(rename = "RSA-OAEP-256")]
190+
RSA_OAEP_256,
191+
}
192+
193+
impl FromStr for KeyAlgorithm {
194+
type Err = Error;
195+
fn from_str(s: &str) -> errors::Result<Self> {
196+
match s {
197+
"HS256" => Ok(KeyAlgorithm::HS256),
198+
"HS384" => Ok(KeyAlgorithm::HS384),
199+
"HS512" => Ok(KeyAlgorithm::HS512),
200+
"ES256" => Ok(KeyAlgorithm::ES256),
201+
"ES384" => Ok(KeyAlgorithm::ES384),
202+
"RS256" => Ok(KeyAlgorithm::RS256),
203+
"RS384" => Ok(KeyAlgorithm::RS384),
204+
"PS256" => Ok(KeyAlgorithm::PS256),
205+
"PS384" => Ok(KeyAlgorithm::PS384),
206+
"PS512" => Ok(KeyAlgorithm::PS512),
207+
"RS512" => Ok(KeyAlgorithm::RS512),
208+
"EdDSA" => Ok(KeyAlgorithm::EdDSA),
209+
"RSA1_5" => Ok(KeyAlgorithm::RSA1_5),
210+
"RSA-OAEP" => Ok(KeyAlgorithm::RSA_OAEP),
211+
"RSA-OAEP-256" => Ok(KeyAlgorithm::RSA_OAEP_256),
212+
_ => Err(ErrorKind::InvalidAlgorithmName.into()),
213+
}
214+
}
215+
}
216+
217+
impl fmt::Display for KeyAlgorithm {
218+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
219+
write!(f, "{:?}", self)
220+
}
221+
}
222+
223+
impl KeyAlgorithm {
224+
fn to_algorithm(self) -> errors::Result<Algorithm> {
225+
Algorithm::from_str(self.to_string().as_str())
226+
}
227+
}
228+
144229
/// Common JWK parameters
145230
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Default, Hash)]
146231
pub struct CommonParameters {
@@ -158,9 +243,9 @@ pub struct CommonParameters {
158243
#[serde(rename = "key_ops", skip_serializing_if = "Option::is_none", default)]
159244
pub key_operations: Option<Vec<KeyOperations>>,
160245

161-
/// The algorithm intended for use with the key
246+
/// The algorithm keys intended for use with the key.
162247
#[serde(rename = "alg", skip_serializing_if = "Option::is_none", default)]
163-
pub algorithm: Option<Algorithm>,
248+
pub key_algorithm: Option<KeyAlgorithm>,
164249

165250
/// The case sensitive Key ID for the key
166251
#[serde(rename = "kid", skip_serializing_if = "Option::is_none", default)]
@@ -326,6 +411,13 @@ pub struct Jwk {
326411
pub algorithm: AlgorithmParameters,
327412
}
328413

414+
impl Jwk {
415+
/// Find whether the Algorithm is implmented and supported
416+
pub fn is_supported(&self) -> bool {
417+
self.common.key_algorithm.unwrap().to_algorithm().is_ok()
418+
}
419+
}
420+
329421
/// A JWK set
330422
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
331423
pub struct JwkSet {
@@ -366,7 +458,9 @@ mod tests {
366458
assert_eq!(set.keys.len(), 1);
367459
let key = &set.keys[0];
368460
assert_eq!(key.common.key_id, Some("abc123".to_string()));
369-
assert_eq!(key.common.algorithm, Some(Algorithm::HS256));
461+
let algorithm = key.common.key_algorithm.unwrap().to_algorithm().unwrap();
462+
assert_eq!(algorithm, Algorithm::HS256);
463+
370464
match &key.algorithm {
371465
AlgorithmParameters::OctetKey(key) => {
372466
assert_eq!(key.key_type, OctetKeyType::Octet);

0 commit comments

Comments
 (0)