Add API tokens support (#9)
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			Make it possible to create token authorized to query predetermined set of routes. Reviewed-on: #9 Co-authored-by: Pierre HUBERT <pierre.git@communiquons.org> Co-committed-by: Pierre HUBERT <pierre.git@communiquons.org>
This commit is contained in:
		
							
								
								
									
										100
									
								
								virtweb_backend/src/controllers/api_tokens_controller.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								virtweb_backend/src/controllers/api_tokens_controller.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
//! # API tokens management
 | 
			
		||||
 | 
			
		||||
use crate::api_tokens;
 | 
			
		||||
use crate::api_tokens::{NewToken, TokenID, TokenRights};
 | 
			
		||||
use crate::controllers::api_tokens_controller::rest_token::RestToken;
 | 
			
		||||
use crate::controllers::HttpResult;
 | 
			
		||||
use actix_web::{web, HttpResponse};
 | 
			
		||||
use basic_jwt::JWTPrivateKey;
 | 
			
		||||
 | 
			
		||||
/// Create a special module for REST token to enforce usage of constructor function
 | 
			
		||||
mod rest_token {
 | 
			
		||||
    use crate::api_tokens::Token;
 | 
			
		||||
 | 
			
		||||
    #[derive(serde::Serialize)]
 | 
			
		||||
    pub struct RestToken {
 | 
			
		||||
        #[serde(flatten)]
 | 
			
		||||
        token: Token,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl RestToken {
 | 
			
		||||
        pub fn new(mut token: Token) -> Self {
 | 
			
		||||
            token.pub_key = None;
 | 
			
		||||
            Self { token }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize)]
 | 
			
		||||
struct CreateTokenResult {
 | 
			
		||||
    token: RestToken,
 | 
			
		||||
    priv_key: JWTPrivateKey,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a new API token
 | 
			
		||||
pub async fn create(new_token: web::Json<NewToken>) -> HttpResult {
 | 
			
		||||
    if let Some(err) = new_token.check_error() {
 | 
			
		||||
        log::error!("Failed to validate new API token information! {err}");
 | 
			
		||||
        return Ok(HttpResponse::BadRequest().json(format!(
 | 
			
		||||
            "Failed to validate new API token information! {err}"
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let (token, priv_key) = api_tokens::create(&new_token).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json(CreateTokenResult {
 | 
			
		||||
        token: RestToken::new(token),
 | 
			
		||||
        priv_key,
 | 
			
		||||
    }))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the list of API tokens
 | 
			
		||||
pub async fn list() -> HttpResult {
 | 
			
		||||
    let list = api_tokens::full_list()
 | 
			
		||||
        .await?
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(RestToken::new)
 | 
			
		||||
        .collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json(list))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct TokenIDInPath {
 | 
			
		||||
    uid: TokenID,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the information about a single token
 | 
			
		||||
pub async fn get_single(path: web::Path<TokenIDInPath>) -> HttpResult {
 | 
			
		||||
    let token = api_tokens::get_single(path.uid).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json(RestToken::new(token)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct UpdateTokenBody {
 | 
			
		||||
    rights: TokenRights,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Update a token
 | 
			
		||||
pub async fn update(
 | 
			
		||||
    path: web::Path<TokenIDInPath>,
 | 
			
		||||
    body: web::Json<UpdateTokenBody>,
 | 
			
		||||
) -> HttpResult {
 | 
			
		||||
    if let Some(err) = body.rights.check_error() {
 | 
			
		||||
        log::error!("Failed to validate updated API token information! {err}");
 | 
			
		||||
        return Ok(HttpResponse::BadRequest()
 | 
			
		||||
            .json(format!("Failed to validate API token information! {err}")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    api_tokens::update_rights(path.uid, body.0.rights).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Accepted().finish())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a token
 | 
			
		||||
pub async fn delete(path: web::Path<TokenIDInPath>) -> HttpResult {
 | 
			
		||||
    api_tokens::delete(path.uid).await?;
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Accepted().finish())
 | 
			
		||||
}
 | 
			
		||||
@@ -6,6 +6,7 @@ use std::error::Error;
 | 
			
		||||
use std::fmt::{Display, Formatter};
 | 
			
		||||
use std::io::ErrorKind;
 | 
			
		||||
 | 
			
		||||
pub mod api_tokens_controller;
 | 
			
		||||
pub mod auth_controller;
 | 
			
		||||
pub mod iso_controller;
 | 
			
		||||
pub mod network_controller;
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,9 @@ struct ServerConstraints {
 | 
			
		||||
    nwfilter_comment_size: LenConstraints,
 | 
			
		||||
    nwfilter_priority: SLenConstraints,
 | 
			
		||||
    nwfilter_selectors_count: LenConstraints,
 | 
			
		||||
    api_token_name_size: LenConstraints,
 | 
			
		||||
    api_token_description_size: LenConstraints,
 | 
			
		||||
    api_token_right_path_size: LenConstraints,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder {
 | 
			
		||||
@@ -98,6 +101,21 @@ pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder {
 | 
			
		||||
                max: 1000,
 | 
			
		||||
            },
 | 
			
		||||
            nwfilter_selectors_count: LenConstraints { min: 0, max: 1 },
 | 
			
		||||
 | 
			
		||||
            api_token_name_size: LenConstraints {
 | 
			
		||||
                min: constants::API_TOKEN_NAME_MIN_LENGTH,
 | 
			
		||||
                max: constants::API_TOKEN_NAME_MAX_LENGTH,
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            api_token_description_size: LenConstraints {
 | 
			
		||||
                min: constants::API_TOKEN_DESCRIPTION_MIN_LENGTH,
 | 
			
		||||
                max: constants::API_TOKEN_DESCRIPTION_MAX_LENGTH,
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            api_token_right_path_size: LenConstraints {
 | 
			
		||||
                min: 0,
 | 
			
		||||
                max: constants::API_TOKEN_RIGHT_PATH_MAX_LENGTH,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user