Normalize error responses

This commit is contained in:
Pierre HUBERT 2022-04-14 17:13:07 +02:00
parent 078a913f6a
commit 0b64c88fc6

View File

@ -1,3 +1,5 @@
use std::fmt::Debug;
use actix::Addr; use actix::Addr;
use actix_identity::Identity; use actix_identity::Identity;
use actix_web::{HttpRequest, HttpResponse, Responder, web}; use actix_web::{HttpRequest, HttpResponse, Responder, web};
@ -152,6 +154,21 @@ pub async fn authorize(user: CurrentUser, id: Identity, query: web::Query<Author
))).finish() ))).finish()
} }
#[derive(serde::Serialize)]
struct ErrorResponse {
error: String,
error_description: String,
}
pub fn error_response<D: Debug>(query: &D, error: &str, description: &str) -> HttpResponse {
log::warn!("request failed: {} - {} => '{:#?}'", error, description, query);
HttpResponse::BadRequest()
.json(ErrorResponse {
error: error.to_string(),
error_description: description.to_string(),
})
}
#[derive(Debug, serde::Deserialize)] #[derive(Debug, serde::Deserialize)]
pub struct TokenAuthorizationCodeQuery { pub struct TokenAuthorizationCodeQuery {
redirect_uri: String, redirect_uri: String,
@ -207,8 +224,11 @@ pub async fn token(req: HttpRequest,
(None, None, Some(v)) => { (None, None, Some(v)) => {
let token = match v.to_str().unwrap_or_default().strip_prefix("Basic ") { let token = match v.to_str().unwrap_or_default().strip_prefix("Basic ") {
None => { None => {
log::warn!("Token request failed: Authorization header does not start with 'Basic '! => got '{:#?}'", v); return Ok(error_response(
return Ok(HttpResponse::Unauthorized().body("Authorization header does not start with 'Basic '")); &query,
"invalid_request",
&format!("Authorization header does not start with 'Basic ', got '{:#?}'", v),
));
} }
Some(v) => v Some(v) => v
}; };
@ -216,8 +236,8 @@ pub async fn token(req: HttpRequest,
let decode = String::from_utf8_lossy(&match base64::decode(token) { let decode = String::from_utf8_lossy(&match base64::decode(token) {
Ok(d) => d, Ok(d) => d,
Err(e) => { Err(e) => {
log::warn!("Failed to decode authorization header! {:?}", e); log::error!("Failed to decode authorization header: {:?}", e);
return Ok(HttpResponse::InternalServerError().body("Failed to decode authorization header!")); return Ok(error_response(&query, "invalid_request", "Failed to decode authorization header!"));
} }
}).to_string(); }).to_string();
@ -228,8 +248,7 @@ pub async fn token(req: HttpRequest,
} }
_ => { _ => {
log::warn!("Token request failed: Unknown client authentication method! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Authentication method unknown!"));
return Ok(HttpResponse::BadRequest().body("Authentication method unknown!"));
} }
}; };
@ -238,8 +257,7 @@ pub async fn token(req: HttpRequest,
.ok_or_else(|| ErrorUnauthorized("Client not found"))?; .ok_or_else(|| ErrorUnauthorized("Client not found"))?;
if !client.secret.eq(&client_secret) { if !client.secret.eq(&client_secret) {
log::warn!("Token request failed: client secret is invalid! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Client secret is invalid!"));
return Ok(HttpResponse::Unauthorized().body("Client secret is invalid!"));
} }
let token_response = match (query.grant_type.as_str(), let token_response = match (query.grant_type.as_str(),
@ -251,30 +269,25 @@ pub async fn token(req: HttpRequest,
.await.unwrap() .await.unwrap()
{ {
None => { None => {
log::warn!("Token request failed: Session not found! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Session not found!"));
return Ok(HttpResponse::NotFound().body("Session not found!"));
} }
Some(s) => s, Some(s) => s,
}; };
if session.client != client.id { if session.client != client.id {
log::warn!("Token request failed: Client mismatch! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Client mismatch!"));
return Ok(HttpResponse::Unauthorized().body("Client mismatch!"));
} }
if session.redirect_uri != q.redirect_uri { if session.redirect_uri != q.redirect_uri {
log::warn!("Token request failed: Invalid redirect URI! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Invalid redirect URI!"));
return Ok(HttpResponse::Unauthorized().body("Invalid redirect URI!"));
} }
if session.authorization_code_expire_at < time() { if session.authorization_code_expire_at < time() {
log::warn!("Token request failed: Authorization code expired! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Authorization code expired!"));
return Ok(HttpResponse::Unauthorized().body("Authorization code expired!"));
} }
if session.authorization_code_used { if session.authorization_code_used {
log::warn!("Token request failed: Authorization already used! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Authorization already used!"));
return Ok(HttpResponse::Unauthorized().body("Authorization already used!"));
} }
// Mark session as used // Mark session as used
@ -308,15 +321,13 @@ pub async fn token(req: HttpRequest,
.await.unwrap() .await.unwrap()
{ {
None => { None => {
log::warn!("Token refresh failed: Session not found! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Session not found!"));
return Ok(HttpResponse::NotFound().body("Session not found!"));
} }
Some(s) => s, Some(s) => s,
}; };
if session.client != client.id { if session.client != client.id {
log::warn!("Token request failed: Client mismatch! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Client mismatch!"));
return Ok(HttpResponse::Unauthorized().body("Client mismatch!"));
} }
session.refresh_token = rand_str(OPEN_ID_REFRESH_TOKEN_LEN); session.refresh_token = rand_str(OPEN_ID_REFRESH_TOKEN_LEN);
@ -338,8 +349,7 @@ pub async fn token(req: HttpRequest,
} }
_ => { _ => {
log::warn!("Token request failed: Grant type unsupported or incomplete! {:#?}", query.0); return Ok(error_response(&query, "invalid_request", "Grant type unsupported!"));
return Ok(HttpResponse::BadRequest().body("Grant type unsupported!"));
} }
}; };