mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
infra: Remove the TCP API
Deprecated in favor of GraphQL
This commit is contained in:
parent
651adbe3c8
commit
08a3845cbe
@ -5,7 +5,6 @@ use crate::{
|
||||
opaque_handler::OpaqueHandler,
|
||||
},
|
||||
infra::{
|
||||
tcp_api::{error_to_api_response, ApiResult},
|
||||
tcp_backend_handler::*,
|
||||
tcp_server::{error_to_http_response, AppState},
|
||||
},
|
||||
@ -16,7 +15,6 @@ use actix_web::{
|
||||
error::{ErrorBadRequest, ErrorUnauthorized},
|
||||
web, HttpRequest, HttpResponse,
|
||||
};
|
||||
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||
use anyhow::Result;
|
||||
use chrono::prelude::*;
|
||||
use futures::future::{ok, Ready};
|
||||
@ -24,7 +22,6 @@ use futures_util::{FutureExt, TryFutureExt};
|
||||
use hmac::Hmac;
|
||||
use jwt::{SignWithKey, VerifyWithKey};
|
||||
use lldap_model::{login, registration, JWTClaims};
|
||||
use log::*;
|
||||
use sha2::Sha512;
|
||||
use std::collections::{hash_map::DefaultHasher, HashSet};
|
||||
use std::hash::{Hash, Hasher};
|
||||
@ -167,6 +164,12 @@ where
|
||||
.finish()
|
||||
}
|
||||
|
||||
pub(crate) fn error_to_api_response<T>(error: DomainError) -> ApiResult<T> {
|
||||
ApiResult::Right(error_to_http_response(error))
|
||||
}
|
||||
|
||||
pub type ApiResult<M> = actix_web::Either<web::Json<M>, HttpResponse>;
|
||||
|
||||
async fn opaque_login_start<Backend>(
|
||||
data: web::Data<AppState<Backend>>,
|
||||
request: web::Json<login::ClientLoginStartRequest>,
|
||||
@ -386,48 +389,6 @@ pub(crate) fn check_if_token_is_valid<Backend>(
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn token_validator<Backend>(
|
||||
req: ServiceRequest,
|
||||
credentials: BearerAuth,
|
||||
admin_required: bool,
|
||||
) -> Result<ServiceRequest, actix_web::Error>
|
||||
where
|
||||
Backend: TcpBackendHandler + BackendHandler + 'static,
|
||||
{
|
||||
let state = req
|
||||
.app_data::<web::Data<AppState<Backend>>>()
|
||||
.expect("Invalid app config");
|
||||
let ValidationResults { user, is_admin } = check_if_token_is_valid(state, credentials.token())?;
|
||||
if is_admin || (!admin_required && req.match_info().get("user_id") == Some(&user)) {
|
||||
debug!("Got authorized token for user {}", &user);
|
||||
Ok(req)
|
||||
} else {
|
||||
Err(ErrorUnauthorized(
|
||||
"JWT error: User is not authorized to access this resource",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn admin_token_validator<Backend>(
|
||||
req: ServiceRequest,
|
||||
credentials: BearerAuth,
|
||||
) -> Result<ServiceRequest, actix_web::Error>
|
||||
where
|
||||
Backend: TcpBackendHandler + BackendHandler + 'static,
|
||||
{
|
||||
token_validator::<Backend>(req, credentials, true).await
|
||||
}
|
||||
|
||||
pub async fn user_token_validator<Backend>(
|
||||
req: ServiceRequest,
|
||||
credentials: BearerAuth,
|
||||
) -> Result<ServiceRequest, actix_web::Error>
|
||||
where
|
||||
Backend: TcpBackendHandler + BackendHandler + 'static,
|
||||
{
|
||||
token_validator::<Backend>(req, credentials, false).await
|
||||
}
|
||||
|
||||
pub fn configure_server<Backend>(cfg: &mut web::ServiceConfig)
|
||||
where
|
||||
Backend: TcpBackendHandler + LoginHandler + OpaqueHandler + BackendHandler + 'static,
|
||||
|
@ -77,6 +77,19 @@ pub fn configure_endpoint<Backend>(cfg: &mut web::ServiceConfig)
|
||||
where
|
||||
Backend: BackendHandler + Sync + 'static,
|
||||
{
|
||||
let json_config = web::JsonConfig::default()
|
||||
.limit(4096)
|
||||
.error_handler(|err, _req| {
|
||||
// create custom error response
|
||||
log::error!("API error: {}", err);
|
||||
let msg = err.to_string();
|
||||
actix_web::error::InternalError::from_response(
|
||||
err,
|
||||
HttpResponse::BadRequest().body(msg),
|
||||
)
|
||||
.into()
|
||||
});
|
||||
cfg.app_data(json_config);
|
||||
cfg.service(
|
||||
web::resource("/graphql")
|
||||
.route(web::post().to(graphql_route::<Backend>))
|
||||
|
@ -8,6 +8,5 @@ pub mod ldap_handler;
|
||||
pub mod ldap_server;
|
||||
pub mod logging;
|
||||
pub mod sql_backend_handler;
|
||||
pub mod tcp_api;
|
||||
pub mod tcp_backend_handler;
|
||||
pub mod tcp_server;
|
||||
|
@ -1,149 +0,0 @@
|
||||
use crate::{
|
||||
domain::{error::DomainError, handler::*},
|
||||
infra::{
|
||||
auth_service,
|
||||
tcp_backend_handler::*,
|
||||
tcp_server::{error_to_http_response, AppState},
|
||||
},
|
||||
};
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
use actix_web_httpauth::middleware::HttpAuthentication;
|
||||
|
||||
pub(crate) fn error_to_api_response<T>(error: DomainError) -> ApiResult<T> {
|
||||
ApiResult::Right(error_to_http_response(error))
|
||||
}
|
||||
|
||||
pub type ApiResult<M> = actix_web::Either<web::Json<M>, HttpResponse>;
|
||||
|
||||
async fn user_list_handler<Backend>(
|
||||
data: web::Data<AppState<Backend>>,
|
||||
info: web::Json<ListUsersRequest>,
|
||||
) -> ApiResult<Vec<User>>
|
||||
where
|
||||
Backend: TcpBackendHandler + BackendHandler + 'static,
|
||||
{
|
||||
data.backend_handler
|
||||
.list_users(info.into_inner())
|
||||
.await
|
||||
.map(|res| ApiResult::Left(web::Json(res)))
|
||||
.unwrap_or_else(error_to_api_response)
|
||||
}
|
||||
|
||||
async fn user_details_handler<Backend>(
|
||||
data: web::Data<AppState<Backend>>,
|
||||
request: HttpRequest,
|
||||
) -> ApiResult<User>
|
||||
where
|
||||
Backend: TcpBackendHandler + BackendHandler + 'static,
|
||||
{
|
||||
let request = UserDetailsRequest {
|
||||
user_id: request.match_info().get("user_id").unwrap().to_string(),
|
||||
};
|
||||
data.backend_handler
|
||||
.get_user_details(request)
|
||||
.await
|
||||
.map(|res| ApiResult::Left(web::Json(res)))
|
||||
.unwrap_or_else(error_to_api_response)
|
||||
}
|
||||
|
||||
async fn create_user_handler<Backend>(
|
||||
data: web::Data<AppState<Backend>>,
|
||||
info: web::Json<CreateUserRequest>,
|
||||
) -> ApiResult<()>
|
||||
where
|
||||
Backend: TcpBackendHandler + BackendHandler + 'static,
|
||||
{
|
||||
data.backend_handler
|
||||
.create_user(info.into_inner())
|
||||
.await
|
||||
.map(|res| ApiResult::Left(web::Json(res)))
|
||||
.unwrap_or_else(error_to_api_response)
|
||||
}
|
||||
|
||||
pub fn api_config<Backend>(cfg: &mut web::ServiceConfig)
|
||||
where
|
||||
Backend: TcpBackendHandler + BackendHandler + Sync + 'static,
|
||||
{
|
||||
let json_config = web::JsonConfig::default()
|
||||
.limit(4096)
|
||||
.error_handler(|err, _req| {
|
||||
// create custom error response
|
||||
log::error!("API error: {}", err);
|
||||
let msg = err.to_string();
|
||||
actix_web::error::InternalError::from_response(
|
||||
err,
|
||||
HttpResponse::BadRequest().body(msg),
|
||||
)
|
||||
.into()
|
||||
});
|
||||
cfg.app_data(json_config);
|
||||
super::graphql::api::configure_endpoint::<Backend>(cfg);
|
||||
cfg.service(
|
||||
web::resource("/user/{user_id}")
|
||||
.route(web::get().to(user_details_handler::<Backend>))
|
||||
.wrap(HttpAuthentication::bearer(
|
||||
auth_service::user_token_validator::<Backend>,
|
||||
)),
|
||||
);
|
||||
cfg.service(
|
||||
web::scope("/users")
|
||||
.wrap(HttpAuthentication::bearer(
|
||||
auth_service::admin_token_validator::<Backend>,
|
||||
))
|
||||
.guard(actix_web::guard::Header("content-type", "application/json"))
|
||||
.service(web::resource("").route(web::post().to(user_list_handler::<Backend>)))
|
||||
.service(
|
||||
web::resource("/create").route(web::post().to(create_user_handler::<Backend>)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use hmac::{Hmac, NewMac};
|
||||
use std::collections::HashSet;
|
||||
use std::sync::RwLock;
|
||||
|
||||
fn get_data(
|
||||
handler: MockTestTcpBackendHandler,
|
||||
) -> web::Data<AppState<MockTestTcpBackendHandler>> {
|
||||
let app_state = AppState::<MockTestTcpBackendHandler> {
|
||||
backend_handler: handler,
|
||||
jwt_key: Hmac::new_varkey(b"jwt_secret").unwrap(),
|
||||
jwt_blacklist: RwLock::new(HashSet::new()),
|
||||
};
|
||||
web::Data::<AppState<MockTestTcpBackendHandler>>::new(app_state)
|
||||
}
|
||||
|
||||
fn expect_json<T: std::fmt::Debug>(result: ApiResult<T>) -> T {
|
||||
if let ApiResult::Left(res) = result {
|
||||
res.0
|
||||
} else {
|
||||
panic!("Expected Json result, got: {:?}", result);
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_user_list_ok() {
|
||||
let mut backend_handler = MockTestTcpBackendHandler::new();
|
||||
backend_handler
|
||||
.expect_list_users()
|
||||
.times(1)
|
||||
.return_once(|_| {
|
||||
Ok(vec![User {
|
||||
user_id: "bob".to_string(),
|
||||
..Default::default()
|
||||
}])
|
||||
});
|
||||
let json = web::Json(ListUsersRequest { filters: None });
|
||||
let resp = user_list_handler(get_data(backend_handler), json).await;
|
||||
assert_eq!(
|
||||
expect_json(resp),
|
||||
vec![User {
|
||||
user_id: "bob".to_string(),
|
||||
..Default::default()
|
||||
}]
|
||||
);
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ use crate::{
|
||||
handler::{BackendHandler, LoginHandler},
|
||||
opaque_handler::OpaqueHandler,
|
||||
},
|
||||
infra::{auth_service, configuration::Configuration, tcp_api, tcp_backend_handler::*},
|
||||
infra::{auth_service, configuration::Configuration, tcp_backend_handler::*},
|
||||
};
|
||||
use actix_files::{Files, NamedFile};
|
||||
use actix_http::HttpServiceBuilder;
|
||||
@ -64,7 +64,7 @@ fn http_config<Backend>(
|
||||
.service(
|
||||
web::scope("/api")
|
||||
.wrap(auth_service::CookieToHeaderTranslatorFactory)
|
||||
.configure(tcp_api::api_config::<Backend>),
|
||||
.configure(super::graphql::api::configure_endpoint::<Backend>),
|
||||
)
|
||||
// Serve the /pkg path with the compiled WASM app.
|
||||
.service(Files::new("/pkg", "./app/pkg"))
|
||||
|
Loading…
Reference in New Issue
Block a user