Add code challenge support
This commit is contained in:
@ -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);
|
||||
|
Reference in New Issue
Block a user