mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
Add TCP handlers for opaque protocol
This commit is contained in:
parent
7be0e420d4
commit
4d68a2a015
@ -4,11 +4,11 @@ use crate::{
|
|||||||
opaque_handler::OpaqueHandler,
|
opaque_handler::OpaqueHandler,
|
||||||
},
|
},
|
||||||
infra::{
|
infra::{
|
||||||
|
tcp_api::{error_to_api_response, ApiResult},
|
||||||
tcp_backend_handler::*,
|
tcp_backend_handler::*,
|
||||||
tcp_server::{error_to_http_response, AppState},
|
tcp_server::{error_to_http_response, AppState},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lldap_model::{JWTClaims, BindRequest};
|
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
cookie::{Cookie, SameSite},
|
cookie::{Cookie, SameSite},
|
||||||
dev::{Service, ServiceRequest, ServiceResponse, Transform},
|
dev::{Service, ServiceRequest, ServiceResponse, Transform},
|
||||||
@ -22,6 +22,7 @@ use futures::future::{ok, Ready};
|
|||||||
use futures_util::{FutureExt, TryFutureExt};
|
use futures_util::{FutureExt, TryFutureExt};
|
||||||
use hmac::Hmac;
|
use hmac::Hmac;
|
||||||
use jwt::{SignWithKey, VerifyWithKey};
|
use jwt::{SignWithKey, VerifyWithKey};
|
||||||
|
use lldap_model::{login, registration, BindRequest, JWTClaims};
|
||||||
use log::*;
|
use log::*;
|
||||||
use sha2::Sha512;
|
use sha2::Sha512;
|
||||||
use std::collections::{hash_map::DefaultHasher, HashSet};
|
use std::collections::{hash_map::DefaultHasher, HashSet};
|
||||||
@ -165,30 +166,35 @@ where
|
|||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn post_authorize<Backend>(
|
async fn opaque_login_start<Backend>(
|
||||||
data: web::Data<AppState<Backend>>,
|
data: web::Data<AppState<Backend>>,
|
||||||
request: web::Json<BindRequest>,
|
request: web::Json<login::ClientLoginStartRequest>,
|
||||||
|
) -> ApiResult<login::ServerLoginStartResponse>
|
||||||
|
where
|
||||||
|
Backend: OpaqueHandler + 'static,
|
||||||
|
{
|
||||||
|
data.backend_handler
|
||||||
|
.login_start(request.clone())
|
||||||
|
.await
|
||||||
|
.map(|res| ApiResult::Left(web::Json(res)))
|
||||||
|
.unwrap_or_else(error_to_api_response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_login_successful_response<Backend>(
|
||||||
|
data: &web::Data<AppState<Backend>>,
|
||||||
|
name: &str,
|
||||||
) -> HttpResponse
|
) -> HttpResponse
|
||||||
where
|
where
|
||||||
Backend: TcpBackendHandler + BackendHandler + LoginHandler + 'static,
|
Backend: TcpBackendHandler + BackendHandler,
|
||||||
{
|
{
|
||||||
let req: BindRequest = request.clone();
|
// The authentication was successful, we need to fetch the groups to create the JWT
|
||||||
data.backend_handler
|
|
||||||
.bind(req)
|
|
||||||
// If the authentication was successful, we need to fetch the groups to create the JWT
|
|
||||||
// token.
|
// token.
|
||||||
.and_then(|_| data.backend_handler.get_user_groups(request.name.clone()))
|
|
||||||
.and_then(|g| async {
|
|
||||||
Ok((
|
|
||||||
g,
|
|
||||||
data.backend_handler
|
data.backend_handler
|
||||||
.create_refresh_token(&request.name)
|
.get_user_groups(name.to_string())
|
||||||
.await?,
|
.and_then(|g| async { Ok((g, data.backend_handler.create_refresh_token(&name).await?)) })
|
||||||
))
|
|
||||||
})
|
|
||||||
.await
|
.await
|
||||||
.map(|(groups, (refresh_token, max_age))| {
|
.map(|(groups, (refresh_token, max_age))| {
|
||||||
let token = create_jwt(&data.jwt_key, request.name.clone(), groups);
|
let token = create_jwt(&data.jwt_key, name.to_string(), groups);
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.cookie(
|
.cookie(
|
||||||
Cookie::build("token", token.as_str())
|
Cookie::build("token", token.as_str())
|
||||||
@ -199,7 +205,7 @@ where
|
|||||||
.finish(),
|
.finish(),
|
||||||
)
|
)
|
||||||
.cookie(
|
.cookie(
|
||||||
Cookie::build("refresh_token", refresh_token + "+" + &request.name)
|
Cookie::build("refresh_token", refresh_token + "+" + &name)
|
||||||
.max_age(max_age.num_days().days())
|
.max_age(max_age.num_days().days())
|
||||||
.path("/auth")
|
.path("/auth")
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
@ -211,6 +217,64 @@ where
|
|||||||
.unwrap_or_else(error_to_http_response)
|
.unwrap_or_else(error_to_http_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn opaque_login_finish<Backend>(
|
||||||
|
data: web::Data<AppState<Backend>>,
|
||||||
|
request: web::Json<login::ClientLoginFinishRequest>,
|
||||||
|
) -> HttpResponse
|
||||||
|
where
|
||||||
|
Backend: TcpBackendHandler + BackendHandler + OpaqueHandler + 'static,
|
||||||
|
{
|
||||||
|
let name = match data.backend_handler.login_finish(request.clone()).await {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(e) => return error_to_http_response(e),
|
||||||
|
};
|
||||||
|
get_login_successful_response(&data, &name).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn post_authorize<Backend>(
|
||||||
|
data: web::Data<AppState<Backend>>,
|
||||||
|
request: web::Json<BindRequest>,
|
||||||
|
) -> HttpResponse
|
||||||
|
where
|
||||||
|
Backend: TcpBackendHandler + BackendHandler + LoginHandler + 'static,
|
||||||
|
{
|
||||||
|
if let Err(e) = data.backend_handler.bind(request.clone()).await {
|
||||||
|
return error_to_http_response(e);
|
||||||
|
}
|
||||||
|
get_login_successful_response(&data, &request.name).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn opaque_register_start<Backend>(
|
||||||
|
data: web::Data<AppState<Backend>>,
|
||||||
|
request: web::Json<registration::ClientRegistrationStartRequest>,
|
||||||
|
) -> ApiResult<registration::ServerRegistrationStartResponse>
|
||||||
|
where
|
||||||
|
Backend: OpaqueHandler + 'static,
|
||||||
|
{
|
||||||
|
data.backend_handler
|
||||||
|
.registration_start(request.clone())
|
||||||
|
.await
|
||||||
|
.map(|res| ApiResult::Left(web::Json(res)))
|
||||||
|
.unwrap_or_else(error_to_api_response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn opaque_register_finish<Backend>(
|
||||||
|
data: web::Data<AppState<Backend>>,
|
||||||
|
request: web::Json<registration::ClientRegistrationFinishRequest>,
|
||||||
|
) -> HttpResponse
|
||||||
|
where
|
||||||
|
Backend: TcpBackendHandler + BackendHandler + OpaqueHandler + 'static,
|
||||||
|
{
|
||||||
|
if let Err(e) = data
|
||||||
|
.backend_handler
|
||||||
|
.registration_finish(request.clone())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return error_to_http_response(e);
|
||||||
|
}
|
||||||
|
HttpResponse::Ok().finish()
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CookieToHeaderTranslatorFactory;
|
pub struct CookieToHeaderTranslatorFactory;
|
||||||
|
|
||||||
impl<S> Transform<S, ServiceRequest> for CookieToHeaderTranslatorFactory
|
impl<S> Transform<S, ServiceRequest> for CookieToHeaderTranslatorFactory
|
||||||
@ -306,6 +370,22 @@ where
|
|||||||
Backend: TcpBackendHandler + LoginHandler + OpaqueHandler + BackendHandler + 'static,
|
Backend: TcpBackendHandler + LoginHandler + OpaqueHandler + BackendHandler + 'static,
|
||||||
{
|
{
|
||||||
cfg.service(web::resource("").route(web::post().to(post_authorize::<Backend>)))
|
cfg.service(web::resource("").route(web::post().to(post_authorize::<Backend>)))
|
||||||
|
.service(
|
||||||
|
web::resource("/opaque/login/start")
|
||||||
|
.route(web::post().to(opaque_login_start::<Backend>)),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::resource("/opaque/login/finish")
|
||||||
|
.route(web::post().to(opaque_login_finish::<Backend>)),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::resource("/opaque/register/start")
|
||||||
|
.route(web::post().to(opaque_register_start::<Backend>)),
|
||||||
|
)
|
||||||
|
.service(
|
||||||
|
web::resource("/opaque/register/finish")
|
||||||
|
.route(web::post().to(opaque_register_finish::<Backend>)),
|
||||||
|
)
|
||||||
.service(web::resource("/refresh").route(web::get().to(get_refresh::<Backend>)))
|
.service(web::resource("/refresh").route(web::get().to(get_refresh::<Backend>)))
|
||||||
.service(web::resource("/logout").route(web::post().to(post_logout::<Backend>)));
|
.service(web::resource("/logout").route(web::post().to(post_logout::<Backend>)));
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,11 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{web, HttpResponse};
|
||||||
|
|
||||||
fn error_to_api_response<T>(error: DomainError) -> ApiResult<T> {
|
pub(crate) fn error_to_api_response<T>(error: DomainError) -> ApiResult<T> {
|
||||||
ApiResult::Right(error_to_http_response(error))
|
ApiResult::Right(error_to_http_response(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApiResult<M> = actix_web::Either<web::Json<M>, HttpResponse>;
|
pub type ApiResult<M> = actix_web::Either<web::Json<M>, HttpResponse>;
|
||||||
|
|
||||||
async fn user_list_handler<Backend>(
|
async fn user_list_handler<Backend>(
|
||||||
data: web::Data<AppState<Backend>>,
|
data: web::Data<AppState<Backend>>,
|
||||||
|
@ -73,10 +73,7 @@ fn http_config<Backend>(
|
|||||||
.service(web::scope("/").route("/.*", web::get().to(index)));
|
.service(web::scope("/").route("/.*", web::get().to(index)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct AppState<Backend>
|
pub(crate) struct AppState<Backend> {
|
||||||
where
|
|
||||||
Backend: TcpBackendHandler + BackendHandler + 'static,
|
|
||||||
{
|
|
||||||
pub backend_handler: Backend,
|
pub backend_handler: Backend,
|
||||||
pub jwt_key: Hmac<Sha512>,
|
pub jwt_key: Hmac<Sha512>,
|
||||||
pub jwt_blacklist: RwLock<HashSet<u64>>,
|
pub jwt_blacklist: RwLock<HashSet<u64>>,
|
||||||
|
Loading…
Reference in New Issue
Block a user