nacos_sdk/api/plugin/auth/
mod.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
#[cfg(feature = "auth-by-http")]
mod auth_by_http;
#[cfg(feature = "auth-by-http")]
pub use auth_by_http::*;

#[cfg(feature = "auth-by-aliyun")]
mod auth_by_aliyun_ram;
#[cfg(feature = "auth-by-aliyun")]
pub use auth_by_aliyun_ram::*;

use std::{collections::HashMap, sync::Arc, thread, time::Duration};
use tokio::{sync::oneshot, time::sleep};
use tracing::{debug, debug_span, info, Instrument};

use crate::common::executor;

/// Auth plugin in Client.
/// This api may change in the future, please forgive me if you customize the implementation.
#[async_trait::async_trait]
pub trait AuthPlugin: Send + Sync {
    /// Login with [`AuthContext`], Note that this method will be scheduled continuously.
    async fn login(&self, server_list: Vec<String>, auth_context: AuthContext);

    /// Get the [`LoginIdentityContext`].
    fn get_login_identity(&self, resource: RequestResource) -> LoginIdentityContext;
}

#[derive(Clone, Default)]
pub struct AuthContext {
    pub(crate) params: HashMap<String, String>,
}

impl AuthContext {
    /// Add the param.
    pub fn add_param(mut self, key: impl Into<String>, val: impl Into<String>) -> Self {
        self.params.insert(key.into(), val.into());
        self
    }

    /// Add the params.
    pub fn add_params(mut self, map: HashMap<String, String>) -> Self {
        self.params.extend(map);
        self
    }
}

#[derive(Clone, Default)]
pub struct LoginIdentityContext {
    pub(crate) contexts: HashMap<String, String>,
}

impl LoginIdentityContext {
    /// Add the context.
    pub fn add_context(mut self, key: impl Into<String>, val: impl Into<String>) -> Self {
        self.contexts.insert(key.into(), val.into());
        self
    }

    /// Add the contexts.
    pub fn add_contexts(mut self, map: HashMap<String, String>) -> Self {
        self.contexts.extend(map);
        self
    }
}

/// Noop AuthPlugin.
#[derive(Default)]
pub(crate) struct NoopAuthPlugin {
    login_identity: LoginIdentityContext,
}

#[async_trait::async_trait]
impl AuthPlugin for NoopAuthPlugin {
    #[allow(unused_variables)]
    async fn login(&self, server_list: Vec<String>, auth_context: AuthContext) {
        // noop
    }

    fn get_login_identity(&self, _: RequestResource) -> LoginIdentityContext {
        // noop
        self.login_identity.clone()
    }
}

pub fn init_auth_plugin(
    auth_plugin: Arc<dyn AuthPlugin>,
    server_list: Vec<String>,
    auth_params: HashMap<String, String>,
    id: String,
) {
    let (tx, rx) = oneshot::channel::<()>();
    executor::spawn(
        async move {
            info!("init auth task");
            let auth_context = AuthContext::default().add_params(auth_params);
            auth_plugin
                .login(server_list.clone(), auth_context.clone())
                .in_current_span()
                .await;
            info!("init auth finish");
            let _ = tx.send(());

            info!("auth plugin task start.");
            loop {
                auth_plugin
                    .login(server_list.clone(), auth_context.clone())
                    .in_current_span()
                    .await;
                debug!("auth_plugin schedule at fixed delay");
                sleep(Duration::from_secs(30)).await;
            }
        }
        .instrument(debug_span!("auth_task", id = id)),
    );

    let wait_ret = thread::spawn(move || rx.blocking_recv());

    let _ = wait_ret.join().unwrap();
}

#[derive(Debug)]
pub struct RequestResource {
    pub request_type: String,
    pub namespace: Option<String>,
    pub group: Option<String>,
    pub resource: Option<String>,
}

impl RequestResource {
    fn default() -> Self {
        Self {
            request_type: "".to_string(),
            namespace: None,
            group: None,
            resource: None,
        }
    }
}