Refactor code to prepare support of implicit flow
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This commit is contained in:
Pierre HUBERT 2024-03-28 18:58:51 +01:00
parent 719416eea9
commit 24c7072c0c
2 changed files with 63 additions and 46 deletions

View File

@ -16,7 +16,7 @@ use crate::constants::*;
use crate::controllers::base_controller::{build_fatal_error_page, redirect_user}; use crate::controllers::base_controller::{build_fatal_error_page, redirect_user};
use crate::data::action_logger::{Action, ActionLogger}; use crate::data::action_logger::{Action, ActionLogger};
use crate::data::app_config::AppConfig; use crate::data::app_config::AppConfig;
use crate::data::client::{ClientID, ClientManager}; use crate::data::client::{AuthenticationFlow, ClientID, ClientManager};
use crate::data::code_challenge::CodeChallenge; use crate::data::code_challenge::CodeChallenge;
use crate::data::current_user::CurrentUser; use crate::data::current_user::CurrentUser;
use crate::data::id_token::IdToken; use crate::data::id_token::IdToken;
@ -162,14 +162,6 @@ pub async fn authorize(
return error_redirect(&query, "invalid_request", "openid scope missing!"); return error_redirect(&query, "invalid_request", "openid scope missing!");
} }
if !query.response_type.eq("code") {
return error_redirect(
&query,
"invalid_request",
"Only code response type is supported!",
);
}
if query.state.as_ref().map(String::is_empty).unwrap_or(false) { if query.state.as_ref().map(String::is_empty).unwrap_or(false) {
return error_redirect(&query, "invalid_request", "State is specified but empty!"); return error_redirect(&query, "invalid_request", "State is specified but empty!");
} }
@ -201,45 +193,69 @@ pub async fn authorize(
); );
} }
// Save all authentication information in memory // Check that requested authorization flow is supported
let session = Session { if query.response_type != "code" && query.response_type != "id_token" {
session_id: SessionID(rand_str(OPEN_ID_SESSION_LEN)), return error_redirect(&query, "invalid_request", "Unsupported authorization flow!");
client: client.id.clone(), }
user: user.uid.clone(),
auth_time: SessionIdentity(Some(&id)).auth_time(),
redirect_uri,
authorization_code: rand_str(OPEN_ID_AUTHORIZATION_CODE_LEN),
authorization_code_expire_at: time() + OPEN_ID_AUTHORIZATION_CODE_TIMEOUT,
access_token: None,
access_token_expire_at: time() + OPEN_ID_ACCESS_TOKEN_TIMEOUT,
refresh_token: "".to_string(),
refresh_token_expire_at: 0,
nonce: query.0.nonce,
code_challenge,
};
sessions
.send(openid_sessions_actor::PushNewSession(session.clone()))
.await
.unwrap();
log::trace!("New OpenID session: {:#?}", session); match (client.auth_flow(), query.response_type.as_str()) {
logger.log(Action::NewOpenIDSession { client: &client }); (AuthenticationFlow::AuthorizationCode, "code") => {
// Save all authentication information in memory
let session = Session {
session_id: SessionID(rand_str(OPEN_ID_SESSION_LEN)),
client: client.id.clone(),
user: user.uid.clone(),
auth_time: SessionIdentity(Some(&id)).auth_time(),
redirect_uri,
authorization_code: rand_str(OPEN_ID_AUTHORIZATION_CODE_LEN),
authorization_code_expire_at: time() + OPEN_ID_AUTHORIZATION_CODE_TIMEOUT,
access_token: None,
access_token_expire_at: time() + OPEN_ID_ACCESS_TOKEN_TIMEOUT,
refresh_token: "".to_string(),
refresh_token_expire_at: 0,
nonce: query.0.nonce,
code_challenge,
};
sessions
.send(openid_sessions_actor::PushNewSession(session.clone()))
.await
.unwrap();
HttpResponse::Found() log::trace!("New OpenID session: {:#?}", session);
.append_header(( logger.log(Action::NewOpenIDSession { client: &client });
"Location",
format!( HttpResponse::Found()
"{}?{}session_state={}&code={}", .append_header((
session.redirect_uri, "Location",
match &query.0.state { format!(
Some(state) => format!("state={}&", urlencoding::encode(state)), "{}?{}session_state={}&code={}",
None => "".to_string(), session.redirect_uri,
}, match &query.0.state {
urlencoding::encode(&session.session_id.0), Some(state) => format!("state={}&", urlencoding::encode(state)),
urlencoding::encode(&session.authorization_code) None => "".to_string(),
), },
)) urlencoding::encode(&session.session_id.0),
.finish() urlencoding::encode(&session.authorization_code)
),
))
.finish()
}
//(AuthenticationFlow::Implicit, "id_token") => {}
(flow, code) => {
log::warn!(
"For client {:?}, configured with flow {:?}, made request with code {}",
client.id,
flow,
code
);
error_redirect(
&query,
"invalid_request",
"Requested authentication flow is unsupported / not configured for this client!",
)
}
}
} }
#[derive(serde::Serialize)] #[derive(serde::Serialize)]

View File

@ -4,6 +4,7 @@ use crate::utils::string_utils::apply_env_vars;
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)] #[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
pub struct ClientID(pub String); pub struct ClientID(pub String);
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AuthenticationFlow { pub enum AuthenticationFlow {
AuthorizationCode, AuthorizationCode,
Implicit, Implicit,