use std::convert::Infallible;
use std::sync::Arc;
use http::StatusCode;
use serde::Serialize;
use warp::Filter;
use crate::OAuthConfig;
use crate::error::OAuthError;
use crate::grants::{self, TokenRequest};
pub fn oauth_filter(
config: Arc<OAuthConfig>,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
let config_filter = warp::any().map(move || Arc::clone(&config));
warp::path!("oauth" / "token")
.and(warp::post())
.and(warp::body::json())
.and(config_filter)
.and_then(handle_request)
}
async fn handle_request(
request: TokenRequest,
config: Arc<OAuthConfig>,
) -> Result<impl warp::Reply, Infallible> {
let response = grants::issue_token(&config, request);
let reply = match response {
Ok(token) => {
let body = warp::reply::json(&token);
warp::reply::with_status(body, StatusCode::OK)
}
Err(err) => {
let body = warp::reply::json(&ErrorBody::from(&err));
warp::reply::with_status(body, err.status_code())
}
};
Ok(reply)
}
#[derive(Serialize)]
struct ErrorBody {
error: String,
#[serde(skip_serializing_if = "Option::is_none")]
error_description: Option<String>,
}
impl From<&OAuthError> for ErrorBody {
fn from(err: &OAuthError) -> Self {
let error = match err {
OAuthError::InvalidClient => "invalid_client",
OAuthError::UnsupportedGrant(_) | OAuthError::NotImplemented(_) => {
"unsupported_grant_type"
}
OAuthError::InvalidGrant(_) => "invalid_grant",
OAuthError::InvalidScope(_) => "invalid_scope",
OAuthError::Config(_) | OAuthError::TokenStore(_) | OAuthError::Internal(_) => {
"server_error"
}
}
.to_string();
let error_description = match err {
OAuthError::UnsupportedGrant(message)
| OAuthError::InvalidGrant(message)
| OAuthError::InvalidScope(message)
| OAuthError::Internal(message) => Some(message.clone()),
OAuthError::NotImplemented(message) => Some((*message).into()),
_ => None,
};
Self {
error,
error_description,
}
}
}