rusty_vault 0.2.1

RustyVault is a powerful identity-based secrets management software, providing features such as cryptographic key management, encryption as a service, public key cryptography, certificates management, identity credentials management and so forth. RustyVault's RESTful API is designed to be fully compatible with Hashicorp Vault.
Documentation
use std::{collections::HashMap, sync::Arc};

use super::{UserPassBackend, UserPassBackendInner};
use crate::{
    context::Context,
    errors::RvError,
    logical::{Auth, Backend, Field, FieldType, Lease, Operation, Path, PathOperation, Request, Response},
    new_fields, new_fields_internal, new_path, new_path_internal,
};

impl UserPassBackend {
    pub fn login_path(&self) -> Path {
        let userpass_backend_ref = Arc::clone(&self.inner);

        let path = new_path!({
            pattern: r"login/(?P<username>\w[\w-]+\w)",
            fields: {
                "username": {
                    field_type: FieldType::Str,
                    required: true,
                    description: "Username of the user."
                },
                "password": {
                    field_type: FieldType::SecretStr,
                    required: true,
                    description: "Password for this user."
                }
            },
            operations: [
                {op: Operation::Write, handler: userpass_backend_ref.login}
            ],
            help: r#"This endpoint authenticates using a username and password."#
        });

        path
    }
}

impl UserPassBackendInner {
    pub fn login(&self, _backend: &dyn Backend, req: &mut Request) -> Result<Option<Response>, RvError> {
        let err_info = "invalid username or password";
        let username_value = req.get_data("username")?;
        let username = username_value.as_str().unwrap().to_lowercase();
        let password_value = req.get_data("password")?;
        let password = password_value.as_str().unwrap();

        let user = self.get_user(req, &username)?;
        if user.is_none() {
            log::error!("{}", err_info);
            let resp = Response::error_response(&err_info);
            return Ok(Some(resp));
        }

        let user = user.unwrap();

        let check = self.verify_password_hash(password, &user.password_hash)?;
        if !check {
            log::error!("{}", err_info);
            let resp = Response::error_response(&err_info);
            return Ok(Some(resp));
        }

        let mut auth = Auth {
            lease: Lease {
                ttl: user.ttl,
                max_ttl: user.max_ttl,
                renewable: user.ttl.as_secs() > 0,
                ..Default::default()
            },
            display_name: username.to_string(),
            policies: user.policies.clone(),
            ..Default::default()
        };
        auth.metadata.insert("username".to_string(), username.to_string());

        user.populate_token_auth(&mut auth);

        let resp = Response { auth: Some(auth), ..Response::default() };

        Ok(Some(resp))
    }
}