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
							
								
									226a899dfe
								
							
						
					
					
						commit
						8957d950fd
					
				@ -4,11 +4,11 @@ use crate::{
 | 
			
		||||
        opaque_handler::OpaqueHandler,
 | 
			
		||||
    },
 | 
			
		||||
    infra::{
 | 
			
		||||
        tcp_api::{error_to_api_response, ApiResult},
 | 
			
		||||
        tcp_backend_handler::*,
 | 
			
		||||
        tcp_server::{error_to_http_response, AppState},
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
use lldap_model::{JWTClaims, BindRequest};
 | 
			
		||||
use actix_web::{
 | 
			
		||||
    cookie::{Cookie, SameSite},
 | 
			
		||||
    dev::{Service, ServiceRequest, ServiceResponse, Transform},
 | 
			
		||||
@ -22,6 +22,7 @@ use futures::future::{ok, Ready};
 | 
			
		||||
use futures_util::{FutureExt, TryFutureExt};
 | 
			
		||||
use hmac::Hmac;
 | 
			
		||||
use jwt::{SignWithKey, VerifyWithKey};
 | 
			
		||||
use lldap_model::{login, registration, BindRequest, JWTClaims};
 | 
			
		||||
use log::*;
 | 
			
		||||
use sha2::Sha512;
 | 
			
		||||
use std::collections::{hash_map::DefaultHasher, HashSet};
 | 
			
		||||
@ -165,30 +166,35 @@ where
 | 
			
		||||
        .finish()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn post_authorize<Backend>(
 | 
			
		||||
async fn opaque_login_start<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
 | 
			
		||||
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
 | 
			
		||||
    // token.
 | 
			
		||||
    data.backend_handler
 | 
			
		||||
        .bind(req)
 | 
			
		||||
        // If the authentication was successful, we need to fetch the groups to create the JWT
 | 
			
		||||
        // token.
 | 
			
		||||
        .and_then(|_| data.backend_handler.get_user_groups(request.name.clone()))
 | 
			
		||||
        .and_then(|g| async {
 | 
			
		||||
            Ok((
 | 
			
		||||
                g,
 | 
			
		||||
                data.backend_handler
 | 
			
		||||
                    .create_refresh_token(&request.name)
 | 
			
		||||
                    .await?,
 | 
			
		||||
            ))
 | 
			
		||||
        })
 | 
			
		||||
        .get_user_groups(name.to_string())
 | 
			
		||||
        .and_then(|g| async { Ok((g, data.backend_handler.create_refresh_token(&name).await?)) })
 | 
			
		||||
        .await
 | 
			
		||||
        .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()
 | 
			
		||||
                .cookie(
 | 
			
		||||
                    Cookie::build("token", token.as_str())
 | 
			
		||||
@ -199,7 +205,7 @@ where
 | 
			
		||||
                        .finish(),
 | 
			
		||||
                )
 | 
			
		||||
                .cookie(
 | 
			
		||||
                    Cookie::build("refresh_token", refresh_token + "+" + &request.name)
 | 
			
		||||
                    Cookie::build("refresh_token", refresh_token + "+" + &name)
 | 
			
		||||
                        .max_age(max_age.num_days().days())
 | 
			
		||||
                        .path("/auth")
 | 
			
		||||
                        .http_only(true)
 | 
			
		||||
@ -211,6 +217,64 @@ where
 | 
			
		||||
        .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;
 | 
			
		||||
 | 
			
		||||
impl<S> Transform<S, ServiceRequest> for CookieToHeaderTranslatorFactory
 | 
			
		||||
@ -306,6 +370,22 @@ where
 | 
			
		||||
    Backend: TcpBackendHandler + LoginHandler + OpaqueHandler + BackendHandler + 'static,
 | 
			
		||||
{
 | 
			
		||||
    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("/logout").route(web::post().to(post_logout::<Backend>)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,11 +7,11 @@ use crate::{
 | 
			
		||||
};
 | 
			
		||||
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))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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>(
 | 
			
		||||
    data: web::Data<AppState<Backend>>,
 | 
			
		||||
 | 
			
		||||
@ -73,10 +73,7 @@ fn http_config<Backend>(
 | 
			
		||||
    .service(web::scope("/").route("/.*", web::get().to(index)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) struct AppState<Backend>
 | 
			
		||||
where
 | 
			
		||||
    Backend: TcpBackendHandler + BackendHandler + 'static,
 | 
			
		||||
{
 | 
			
		||||
pub(crate) struct AppState<Backend> {
 | 
			
		||||
    pub backend_handler: Backend,
 | 
			
		||||
    pub jwt_key: Hmac<Sha512>,
 | 
			
		||||
    pub jwt_blacklist: RwLock<HashSet<u64>>,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user