use thiserror::Error;
#[derive(Error, Debug)]
pub enum OidcRequirementsError {
#[error("Provider metadata does not contain a token endpoint")]
MissingTokenEndpoint,
}
#[derive(Error, Debug)]
pub enum EncodingDecodingErrors {
#[error("Encoding error: {0}")]
EncodingError(#[from] serde_json::Error),
#[error("JSON WebToken Decoding error: {0}")]
JsonWebTokenDecodingError(#[from] jsonwebtoken::errors::Error),
}
#[derive(Error, Debug)]
pub enum DeviceError {
#[error("Device related request error: {0}")]
TokenRequest(#[from] reqwest::Error),
#[error("Device related oidc requirements error: {0}")]
TokenRequestRequirements(#[from] OidcRequirementsError),
#[error("Invalid signature request response")]
InvalidSignatureResponse,
#[error("Invalid response: {0}")]
InvalidResponse(String),
#[error("Device encoding error: {0}")]
EncodingError(#[from] serde_json::Error),
#[error("Device reading config error: {0}")]
ConfigReadError(#[from] std::io::Error),
#[error("Device config parsing error: {0}")]
ConfigParseError(#[from] serde_yml::Error),
}
#[derive(Error, Debug)]
pub enum OidcError {
#[error("OIDC related request error: {0}")]
RequestError(#[from] reqwest::Error),
#[error("Request error: {status_code} - {error}: {error_description}")]
RequestErrorWithDetails {
status_code: u16,
error: String,
error_description: String,
},
#[error("JSON WebToken Decoding error: {0}")]
JsonWebTokenDecodingError(#[from] jsonwebtoken::errors::Error),
#[error("CIBA status check failed: {0}")]
CibaStatusCheckFailed(String),
#[error("CIBA status bad request: {0}")]
CibaStatusBadRequest(String),
#[error("CIBA authentication pending")]
CibaAuthenticationPending,
#[error("Token introspection failed: {0}")]
TokenIntrospectionFailed(String),
#[error("Token is not active")]
TokenNotActive,
#[error("Token identification failed: {0}")]
TokenIdentificationFailed(String),
#[error("OIDC requirements error: {0}")]
OIDCRequestRequirements(#[from] OidcRequirementsError),
#[error("OIDC Device error: {0}")]
DeviceError(#[from] DeviceError),
}
#[derive(Error, Debug)]
pub enum WellKnownApplicationsError {
#[error("Well known applications request error: {0}")]
RequestError(#[from] reqwest::Error),
#[error("Well known applications decoding error: {0}")]
DecodingError(#[from] serde_json::Error),
#[error("Well known application not found")]
NotFound,
}
impl actix_web::ResponseError for OidcError {
fn status_code(&self) -> actix_web::http::StatusCode {
match self {
OidcError::RequestErrorWithDetails { status_code, .. } => {
if *status_code > 0 {
actix_web::http::StatusCode::from_u16(*status_code)
.unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR)
} else {
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
}
},
OidcError::CibaAuthenticationPending => actix_web::http::StatusCode::BAD_REQUEST,
OidcError::CibaStatusBadRequest(_) => actix_web::http::StatusCode::BAD_REQUEST,
OidcError::CibaStatusCheckFailed(_) => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
OidcError::TokenIntrospectionFailed(_) => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
OidcError::TokenNotActive => actix_web::http::StatusCode::UNAUTHORIZED,
OidcError::TokenIdentificationFailed(_) => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
_ => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
}
}
fn error_response(&self) -> actix_web::HttpResponse {
match self {
OidcError::RequestErrorWithDetails { error, error_description, .. } => {
let error_body = serde_json::json!({
"error": error,
"error_description": error_description
});
actix_web::HttpResponse::build(self.status_code())
.content_type("application/json")
.body(error_body.to_string())
},
OidcError::CibaAuthenticationPending => {
let error_body = serde_json::json!({
"error": "authorization_pending",
"error_description": "Authorization request is still pending as the end-user hasn't yet completed the user interaction steps"
});
actix_web::HttpResponse::build(self.status_code())
.content_type("application/json")
.body(error_body.to_string())
},
_ => {
let error_body = serde_json::json!({
"error": "server_error",
"error_description": self.to_string()
});
actix_web::HttpResponse::build(self.status_code())
.content_type("application/json")
.body(error_body.to_string())
}
}
}
}