Skip to content

Commit

Permalink
Address feedback in #12
Browse files Browse the repository at this point in the history
- Implement From for SigningKey to convert JWKs to SigningKey Structs
- Use serde(tag) to map to the correct enum variant of the JWKs Response

Signed-off-by: Anton Engelhardt <[email protected]>
  • Loading branch information
antonengelhardt committed Nov 3, 2023
1 parent 7209964 commit 83d6312
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 35 deletions.
40 changes: 10 additions & 30 deletions src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::sync::Mutex;
use url::Url;

// base64
use base64::{engine::general_purpose::URL_SAFE_NO_PAD as base64engine_urlsafe, engine::general_purpose::STANDARD_NO_PAD as base64engine, Engine as _};
use base64::{engine::general_purpose::STANDARD_NO_PAD as base64engine, Engine as _};

// duration
use std::time::Duration;
Expand All @@ -25,7 +25,7 @@ use aes_gcm::{Aes256Gcm, KeyInit};
// crate
use crate::{OpenIdConfig, ConfiguredOidc, PauseRequests};
use crate::config::PluginConfiguration;
use crate::responses::{JWKsResponse, OidcDiscoveryResponse, JsonWebKey, SigningKey};
use crate::responses::{JWKsResponse, OidcDiscoveryResponse, SigningKey};

// This is the initial entry point of the plugin.
proxy_wasm::main! {{
Expand Down Expand Up @@ -60,7 +60,7 @@ pub struct OidcDiscovery {
pub state: OidcRootState,
/// Queue of waiting requests which are waiting for the configuration to be loaded
waiting: Mutex<Vec<u32>>,
/// Tokenid of the HttpCalls to verify the call is correct
/// token_id of the HttpCalls to verify the call is correct
token_id: Option<u32>,
/// AES256 key used to encrypt the session data
cipher: Option<Aes256Gcm>,
Expand Down Expand Up @@ -388,35 +388,15 @@ impl Context for OidcDiscovery {
return;
}

// For all keys, check if it is a key of any of the supported types.
// For all keys, create a signing key if possible
let mut keys : Vec<SigningKey> = vec![];
for key in jwks_response.keys {
match key {
// Build the public key from the components and add it to the list of keys.
JsonWebKey::RS256{kty, alg, n, e} => {

// Check if the key is of type RSA
if kty != "RSA" && alg != "RS256" {
warn!("key is not of type RSA or alg is not RS256, skipping");
continue;
}

// Extract public key components
let public_key_comp_n = &n;
let public_key_comp_e = &e;

// Decode and parse the public key
let n_dec = base64engine_urlsafe.decode(public_key_comp_n).unwrap();
let e_dec = base64engine_urlsafe.decode(public_key_comp_e).unwrap();

let public_key = SigningKey::RS256PublicKey(
jwt_simple::algorithms::RS256PublicKey::from_components(&n_dec, &e_dec)
.unwrap());

keys.push(public_key);
}
// Possibility to add more algorithms here
}

// Create the signing key from the JWK
let signing_key = SigningKey::from(key);

// Add the signing key to the list of keys
keys.push(signing_key);
}

// Now that we have loaded all the configuration, we can set the tick period
Expand Down
48 changes: 43 additions & 5 deletions src/responses.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
// serde
use serde::Deserialize;

// log
use log::{debug, info};

// base64
use {base64::engine::general_purpose::URL_SAFE_NO_PAD as base64engine_urlsafe, base64::Engine as _};

// jwt_simple
use jwt_simple::{self, prelude::{RSAPublicKeyLike, VerificationOptions, JWTClaims}, Error, claims::NoCustomClaims};

Expand All @@ -27,14 +33,12 @@ pub struct JWKsResponse {
/// [JWK](https://tools.ietf.org/html/rfc7517)
/// Define the structure of each key type that are retrieved from the jwks uri
#[derive(Deserialize, Debug)]
#[serde(untagged)]
#[serde(tag = "alg")]
pub enum JsonWebKey {
/// A RSA Key of 256 bits
RS256 {
/// The key type
kty: String,
/// The key algorithm
alg: String,
/// The Public Keys Component n, the modulus
n: String,
/// The Public Keys Component e, the exponent
Expand All @@ -48,7 +52,9 @@ pub enum JsonWebKey {
/// the `verify_token` function
#[derive(Clone, Debug)]
pub enum SigningKey {
RS256PublicKey(jwt_simple::algorithms::RS256PublicKey)
/// A RSA Key of 256 bits
RS256PublicKey(jwt_simple::algorithms::RS256PublicKey),
// Add more key types here
}

/// A public key that can be used for the validation of the ID Token
Expand All @@ -59,7 +65,39 @@ impl SigningKey {

match self {
// RSA Key of 256 bits
SigningKey::RS256PublicKey(key) => key.verify_token(token, Some(options))
SigningKey::RS256PublicKey(key) => key.verify_token(token, Some(options)),
// Add more key types here
}
}
}

/// Implementation of the `From` trait for the `SigningKey` enum to convert the `JsonWebKey` into
/// the `SigningKey` enum
impl From<JsonWebKey> for SigningKey {
fn from(key: JsonWebKey) -> Self {
match key {
// RSA Key of 256 bits
JsonWebKey::RS256 { kty, n, e, .. } => {

// Check if the key is of type RSA
if kty != "RSA" {
debug!("key is not of type RSA although alg is RS256");
}

// Extract public key components
let public_key_comp_n = &n;
let public_key_comp_e = &e;

// Decode and parse the public key
let n_dec = base64engine_urlsafe.decode(public_key_comp_n).unwrap();
let e_dec = base64engine_urlsafe.decode(public_key_comp_e).unwrap();

info!("loaded rs256 public key");

return SigningKey::RS256PublicKey(
jwt_simple::algorithms::RS256PublicKey::from_components(&n_dec, &e_dec)
.unwrap());
},
// Add more key types here
}
}
Expand Down

0 comments on commit 83d6312

Please sign in to comment.