Add code challenge support

This commit is contained in:
2022-04-14 18:04:01 +02:00
parent 0b64c88fc6
commit 45f125a331
9 changed files with 117 additions and 11 deletions

View File

@ -12,6 +12,7 @@ use crate::constants::{AUTHORIZE_URI, CERT_URI, OPEN_ID_ACCESS_TOKEN_LEN, OPEN_I
use crate::controllers::base_controller::FatalErrorPage;
use crate::data::app_config::AppConfig;
use crate::data::client::{ClientID, ClientManager};
use crate::data::code_challenge::CodeChallenge;
use crate::data::current_user::CurrentUser;
use crate::data::id_token::IdToken;
use crate::data::jwt_signer::{JsonWebKey, JWTSigner};
@ -107,15 +108,16 @@ pub async fn authorize(user: CurrentUser, id: Identity, query: web::Query<Author
return error_redirect(&query, "invalid_request", "State is empty!");
}
let code_challenge = match (query.0.code_challenge.clone(), query.0.code_challenge_method.clone()) {
(Some(chal), Some(meth)) => {
if !meth.eq("S256") {
let code_challenge = match query.0.code_challenge.clone() {
Some(chal) => {
let meth = query.0.code_challenge_method.as_deref().unwrap_or("plain");
if !meth.eq("S256") && !meth.eq("plain") {
return error_redirect(&query, "invalid_request",
"Only S256 code challenge is supported!");
"Only S256 and plain code challenge methods are supported!");
}
Some((chal, meth))
Some(CodeChallenge { code_challenge: chal, code_challenge_method: meth.to_string() })
}
(_, _) => None
_ => None
};
// Check if user is authorized to access the application
@ -173,6 +175,7 @@ pub fn error_response<D: Debug>(query: &D, error: &str, description: &str) -> Ht
pub struct TokenAuthorizationCodeQuery {
redirect_uri: String,
code: String,
code_verifier: Option<String>,
}
#[derive(Debug, serde::Deserialize)]
@ -286,8 +289,22 @@ pub async fn token(req: HttpRequest,
return Ok(error_response(&query, "invalid_request", "Authorization code expired!"));
}
// Check code challenge, if needed
if let Some(chall) = &session.code_challenge {
let code_verifier = match &q.code_verifier {
None => {
return Ok(error_response(&query, "access_denied", "Code verifier missing"));
}
Some(s) => s
};
if !chall.verify_code(code_verifier) {
return Ok(error_response(&query, "invalid_grant", "Invalid code verifier"));
}
}
if session.authorization_code_used {
return Ok(error_response(&query, "invalid_request", "Authorization already used!"));
return Ok(error_response(&query, "invalid_request", "Authorization code already used!"));
}
// Mark session as used
@ -330,6 +347,10 @@ pub async fn token(req: HttpRequest,
return Ok(error_response(&query, "invalid_request", "Client mismatch!"));
}
if session.refresh_token_expire_at < time() {
return Ok(error_response(&query, "access_denied", "Refresh token has expired!"));
}
session.refresh_token = rand_str(OPEN_ID_REFRESH_TOKEN_LEN);
session.refresh_token_expire_at = OPEN_ID_REFRESH_TOKEN_TIMEOUT + time();
session.access_token = rand_str(OPEN_ID_ACCESS_TOKEN_LEN);