Skip to content

Commit

Permalink
encrypting response when jarm is enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
bruno-ortiz committed Apr 30, 2024
1 parent e987db6 commit 7667cd1
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 115 deletions.
13 changes: 7 additions & 6 deletions core/src/response_mode/encoder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use indexmap::IndexMap;
use josekit::jwk::Jwk;
use url::Url;

use oidc_types::response_mode::ResponseMode;
Expand All @@ -9,9 +10,8 @@ use crate::response_mode::encoder::fragment::FragmentEncoder;
use crate::response_mode::encoder::jwt::JwtEncoder;
use crate::response_mode::encoder::query::QueryEncoder;
use crate::response_mode::error::Result;
use crate::services::keystore::KeystoreService;

use super::Authorisation;
use super::{AuthorisationResult, Error};

pub(crate) mod fragment;
pub(crate) mod jwt;
Expand All @@ -22,15 +22,16 @@ pub struct EncodingContext<'a> {
pub redirect_uri: &'a Url,
pub response_mode: ResponseMode,
pub provider: &'a OpenIDProviderConfiguration,
pub keystore_service: &'a KeystoreService,
pub signing_key: Option<Jwk>,
pub encryption_key: Option<Jwk>,
}

pub trait ResponseModeEncoder {
fn encode(
&self,
context: &EncodingContext,
parameters: IndexMap<String, String>,
) -> Result<Authorisation>;
) -> Result<AuthorisationResult>;
}

#[derive(Default, Copy, Clone)]
Expand All @@ -41,15 +42,15 @@ impl ResponseModeEncoder for DynamicResponseModeEncoder {
&self,
context: &EncodingContext,
parameters: IndexMap<String, String>,
) -> Result<Authorisation> {
) -> Result<AuthorisationResult> {
let response_mode = context.response_mode;

if !context
.provider
.response_modes_supported()
.contains(&response_mode)
{
todo!("Return error, unsupported responde mode")
return Err(Error::InvalidResponseMode(response_mode));
}

match response_mode {
Expand Down
6 changes: 3 additions & 3 deletions core/src/response_mode/encoder/fragment.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use form_urlencoded::Serializer;
use indexmap::IndexMap;

use crate::response_mode::encoder::{Authorisation, ResponseModeEncoder};
use crate::response_mode::encoder::{AuthorisationResult, ResponseModeEncoder};
use crate::response_mode::encoder::{EncodingContext, Result};

pub(crate) struct FragmentEncoder;
Expand All @@ -11,11 +11,11 @@ impl ResponseModeEncoder for FragmentEncoder {
&self,
context: &EncodingContext,
parameters: IndexMap<String, String>,
) -> Result<Authorisation> {
) -> Result<AuthorisationResult> {
let mut callback_uri = context.redirect_uri.clone();
let fragment = Self::encode_fragment(parameters);
callback_uri.set_fragment(Some(&fragment));
Ok(Authorisation::Redirect(callback_uri))
Ok(AuthorisationResult::Redirect(callback_uri))
}
}

Expand Down
29 changes: 14 additions & 15 deletions core/src/response_mode/encoder/jwt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use indexmap::IndexMap;
use josekit::jws::JwsHeader;
use josekit::jwt::JwtPayload;
use josekit::Value;
use oidc_types::jose::Algorithm;
use time::Duration;

use oidc_types::jose::jws::JwsHeaderExt;
Expand All @@ -11,11 +10,10 @@ use oidc_types::response_mode::ResponseMode;

use crate::configuration::clock::Clock;
use crate::configuration::OpenIDProviderConfiguration;
use crate::keystore::KeyUse;
use crate::response_mode::encoder::fragment::FragmentEncoder;
use crate::response_mode::encoder::query::QueryEncoder;
use crate::response_mode::encoder::EncodingContext;
use crate::response_mode::encoder::{Authorisation, ResponseModeEncoder};
use crate::response_mode::encoder::{AuthorisationResult, ResponseModeEncoder};
use crate::response_mode::error::{Error, Result};

const EXP_IN_MINUTES: i64 = 5i64;
Expand All @@ -27,24 +25,25 @@ impl ResponseModeEncoder for JwtEncoder {
&self,
context: &EncodingContext,
parameters: IndexMap<String, String>,
) -> Result<Authorisation> {
let alg = &context.client.metadata().authorization_signed_response_alg;
let keystore = context
.keystore_service
.server_keystore(context.client, alg);
let signing_key = keystore
.select(Some(KeyUse::Sig))
.alg(alg.name())
.first()
) -> Result<AuthorisationResult> {
let mut params = IndexMap::new();
let signing_key = context
.signing_key
.as_ref()
.ok_or(Error::MissingSigningKey)?;
let header = JwsHeader::from_key(signing_key);
let payload = self.build_payload(context.provider, context, parameters);
let jwt = SignedJWT::new(header, payload, signing_key).map_err(Error::JwtCreationError)?;
if let Some(enc_data) = context.client.metadata().authorization_encryption_data() {
todo!("how do I encrypt jwt here")
let encrption_key = context
.encryption_key
.as_ref()
.ok_or(Error::MissingEncryptionKey)?;
let enc_jwt = jwt.encrypt(encrption_key, enc_data.enc)?;
params.insert("response".to_owned(), enc_jwt.serialized_owned());
} else {
params.insert("response".to_owned(), jwt.serialized_owned());
}
let mut params = IndexMap::new();
params.insert("response".to_owned(), jwt.serialized_owned());

match context.response_mode {
ResponseMode::QueryJwt => QueryEncoder.encode(context, params),
Expand Down
6 changes: 3 additions & 3 deletions core/src/response_mode/encoder/query.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use indexmap::IndexMap;

use crate::response_mode::encoder::{Authorisation, ResponseModeEncoder};
use crate::response_mode::encoder::{AuthorisationResult, ResponseModeEncoder};
use crate::response_mode::encoder::{EncodingContext, Result};

pub(crate) struct QueryEncoder;
Expand All @@ -10,12 +10,12 @@ impl ResponseModeEncoder for QueryEncoder {
&self,
context: &EncodingContext,
parameters: IndexMap<String, String>,
) -> Result<Authorisation> {
) -> Result<AuthorisationResult> {
let mut callback_uri = context.redirect_uri.clone();
callback_uri
.query_pairs_mut()
.extend_pairs(parameters)
.finish();
Ok(Authorisation::Redirect(callback_uri))
Ok(AuthorisationResult::Redirect(callback_uri))
}
}
8 changes: 6 additions & 2 deletions core/src/response_mode/error.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
use thiserror::Error;

use oidc_types::jose::error::JWTError;
use oidc_types::{jose::error::JWTError, response_mode::ResponseMode};

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Error)]
pub enum Error {
#[error("Missing signing key configuration in jwks")]
MissingSigningKey,
#[error("Missing encryption key in client JWKs")]
MissingEncryptionKey,
#[error("Error creating JWT: {}", .0)]
JwtCreationError(JWTError),
JwtCreationError(#[from] JWTError),
#[error("Invalid response mode: {0:?}")]
InvalidResponseMode(ResponseMode),
#[error(transparent)]
InternalError(#[from] anyhow::Error),
}
11 changes: 7 additions & 4 deletions core/src/response_mode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ use std::collections::HashMap;
use url::Url;

#[derive(Debug, PartialEq, Eq)]
pub enum Authorisation {
pub enum AuthorisationResult {
Redirect(Url),
FormPost(Url, HashMap<String, String>),
}

impl Authorisation {
pub fn new<P: UrlEncodable>(context: EncodingContext, parameters: P) -> Result<Authorisation> {
impl AuthorisationResult {
pub fn new<P: UrlEncodable>(
context: EncodingContext,
parameters: P,
) -> Result<AuthorisationResult> {
let parameters = parameters.params();
let result = DynamicResponseModeEncoder
.encode(&context, parameters)
Expand All @@ -30,7 +33,7 @@ impl Authorisation {
}
}

fn encode_err(context: &EncodingContext, err: OpenIdError) -> Result<Authorisation> {
fn encode_err(context: &EncodingContext, err: OpenIdError) -> Result<AuthorisationResult> {
match context.response_mode {
ResponseMode::Fragment => FragmentEncoder.encode(context, err.params()),
ResponseMode::Query => QueryEncoder.encode(context, err.params()),
Expand Down
Loading

0 comments on commit 7667cd1

Please sign in to comment.