rsiot/components/cmp_auth/
fn_process.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use std::time::Duration;

use tokio::time::sleep;
use tracing::{info, warn};

use hmac::{Hmac, Mac};
use jwt::{SignWithKey, VerifyWithKey};
use sha2::Sha256;

use crate::{
    executor::CmpInOut,
    message::{system_messages::*, *},
};

use super::{token_payload::TokenPayload, Config, ConfigStore, ConfigStoreLocalItem, Error};

pub async fn fn_process<TMsg, TService>(
    config: Config,
    in_out: CmpInOut<TMsg, TService>,
) -> super::Result<()>
where
    TMsg: MsgDataBound + 'static,
    TService: ServiceBound,
{
    loop {
        let result = task_main(config.clone(), in_out.clone()).await;
        warn!("Component error: {:?}", result);
        info!("Restart");
        sleep(Duration::from_secs(2)).await;
    }
}

async fn task_main<TMsg, TService>(
    config: Config,
    mut in_out: CmpInOut<TMsg, TService>,
) -> super::Result<()>
where
    TMsg: MsgDataBound + 'static,
    TService: ServiceBound,
{
    while let Ok(msg) = in_out.recv_input().await {
        let msg_response = match msg.data {
            MsgData::System(data) => match data {
                System::AuthRequestByLogin(value) => {
                    process_request_by_login(value, &config, msg.trace.clone()).await
                }
                System::AuthRequestByToken(value) => {
                    process_request_by_token(value, &config, msg.trace.clone()).await
                }
                _ => continue,
            },
            _ => continue,
        };
        let msg = match msg_response {
            Ok(msg) => {
                info!("Success login: {:?}", msg);
                msg
            }
            Err(err) => {
                warn!("Wrong login attempt: {}", err);
                let trace_ids = msg.trace.get_ids();
                let value = AuthResponseErr {
                    error: err.to_string(),
                    trace_ids,
                };
                message_new!("System-AuthResponseErr::value")
            }
        };
        in_out.send_output(msg).await.map_err(Error::CmpOutput)?;
    }
    Ok(())
}

/// Обработка запроса по токену
async fn process_request_by_token<TMsg>(
    request_by_login: AuthRequestByToken,
    config: &Config,
    msg_trace: MsgTrace,
) -> super::Result<Message<TMsg>>
where
    TMsg: MsgDataBound,
{
    let key: Hmac<Sha256> = Hmac::new_from_slice(config.secret_key.as_bytes())?;
    let claims: TokenPayload = request_by_login.token.verify_with_key(&key)?;

    let trace_ids = msg_trace.get_ids();
    let value = AuthResponseOk {
        token: request_by_login.token,
        perm: claims.role,
        trace_ids,
        login: claims.login,
    };
    let msg = message_new!("System-AuthResponseOk::value");
    Ok(msg)
}

/// Обработка запроса по логину-паролю
async fn process_request_by_login<TMsg>(
    request_by_login: AuthRequestByLogin,
    config: &Config,
    msg_trace: MsgTrace,
) -> super::Result<Message<TMsg>>
where
    TMsg: MsgDataBound,
{
    info!("Request: {request_by_login:?}");
    let valid_password = get_credentials(&request_by_login.login, config).await?;

    // Пользователь не найден
    let valid_password = valid_password.ok_or(Error::ProcessRequest("Unknown user".into()))?;

    // Пароль не подходит
    if valid_password.password != request_by_login.password {
        return Err(Error::ProcessRequest("Wrong password".into()));
    }

    // Генерируем jwt
    let key: Hmac<Sha256> = Hmac::new_from_slice(config.secret_key.as_bytes())?;
    let claims = TokenPayload {
        login: request_by_login.login.clone(),
        role: valid_password.role,
    };
    let token = claims.sign_with_key(&key)?;

    let trace_ids = msg_trace.get_ids();

    let value = AuthResponseOk {
        token,
        perm: valid_password.role,
        trace_ids,
        login: request_by_login.login,
    };
    let msg = message_new!("System-AuthResponseOk::value");
    Ok(msg)
}

async fn get_credentials(
    login: &str,
    config: &Config,
) -> super::Result<Option<ConfigStoreLocalItem>> {
    match &config.store {
        ConfigStore::Local(local) => {
            let item = local.iter().find(|e| e.login == login).cloned();
            Ok(item)
        }

        ConfigStore::Surrealdb => todo!(),
    }
}