redis_enterprise/
ldap_mappings.rs

1//! LDAP integration and role mapping
2//!
3//! ## Overview
4//! - Configure LDAP mappings
5//! - Map LDAP groups to roles
6//! - Query mapping status
7
8use crate::client::RestClient;
9use crate::error::Result;
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use typed_builder::TypedBuilder;
13
14/// LDAP mapping information
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct LdapMapping {
17    /// LDAP-mapping's unique uid
18    pub uid: u32,
19    /// Role's name
20    pub name: String,
21    /// An LDAP group's distinguished name
22    pub dn: String,
23    /// Role identifier (deprecated, use role_uids instead)
24    pub role: String,
25    /// Email address that (if set) is used for alerts
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub email: Option<String>,
28    /// List of role uids associated with the LDAP group
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub role_uids: Option<Vec<u32>>,
31
32    #[serde(flatten)]
33    pub extra: Value,
34}
35
36/// Create or update LDAP mapping request
37#[derive(Debug, Serialize, Deserialize, TypedBuilder)]
38pub struct CreateLdapMappingRequest {
39    /// Role's name for the LDAP mapping
40    #[builder(setter(into))]
41    pub name: String,
42    /// LDAP group's distinguished name to map
43    #[builder(setter(into))]
44    pub dn: String,
45    /// Role identifier (deprecated, use role_uids instead)
46    #[builder(setter(into))]
47    pub role: String,
48    /// Email address for alert notifications
49    #[serde(skip_serializing_if = "Option::is_none")]
50    #[builder(default, setter(into, strip_option))]
51    pub email: Option<String>,
52    /// List of role UIDs to associate with this LDAP group
53    #[serde(skip_serializing_if = "Option::is_none")]
54    #[builder(default, setter(strip_option))]
55    pub role_uids: Option<Vec<u32>>,
56}
57
58/// LDAP configuration
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct LdapConfig {
61    /// Whether LDAP authentication is enabled
62    pub enabled: bool,
63    /// List of LDAP servers to connect to
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub servers: Option<Vec<LdapServer>>,
66    /// Cache refresh interval in seconds for LDAP data
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub cache_refresh_interval: Option<u32>,
69    /// LDAP query suffix for authentication
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub authentication_query_suffix: Option<String>,
72    /// LDAP query suffix for authorization
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub authorization_query_suffix: Option<String>,
75    /// Distinguished name for LDAP binding
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub bind_dn: Option<String>,
78    /// Password for LDAP binding
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub bind_pass: Option<String>,
81
82    #[serde(flatten)]
83    pub extra: Value,
84}
85
86/// LDAP server configuration
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct LdapServer {
89    /// LDAP server hostname or IP address
90    pub host: String,
91    /// LDAP server port number (typically 389 for plain, 636 for SSL)
92    pub port: u16,
93    /// Whether to use TLS encryption for the LDAP connection
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub use_tls: Option<bool>,
96    /// Whether to use STARTTLS for upgrading the connection to TLS
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub starttls: Option<bool>,
99}
100
101/// LDAP mapping handler
102pub struct LdapMappingHandler {
103    client: RestClient,
104}
105
106impl LdapMappingHandler {
107    pub fn new(client: RestClient) -> Self {
108        LdapMappingHandler { client }
109    }
110
111    /// List all LDAP mappings
112    pub async fn list(&self) -> Result<Vec<LdapMapping>> {
113        self.client.get("/v1/ldap_mappings").await
114    }
115
116    /// Get specific LDAP mapping
117    pub async fn get(&self, uid: u32) -> Result<LdapMapping> {
118        self.client.get(&format!("/v1/ldap_mappings/{}", uid)).await
119    }
120
121    /// Create a new LDAP mapping
122    pub async fn create(&self, request: CreateLdapMappingRequest) -> Result<LdapMapping> {
123        self.client.post("/v1/ldap_mappings", &request).await
124    }
125
126    /// Update an existing LDAP mapping
127    pub async fn update(&self, uid: u32, request: CreateLdapMappingRequest) -> Result<LdapMapping> {
128        self.client
129            .put(&format!("/v1/ldap_mappings/{}", uid), &request)
130            .await
131    }
132
133    /// Delete an LDAP mapping
134    pub async fn delete(&self, uid: u32) -> Result<()> {
135        self.client
136            .delete(&format!("/v1/ldap_mappings/{}", uid))
137            .await
138    }
139
140    /// Get LDAP configuration
141    pub async fn get_config(&self) -> Result<LdapConfig> {
142        self.client.get("/v1/cluster/ldap").await
143    }
144
145    /// Update LDAP configuration
146    pub async fn update_config(&self, config: LdapConfig) -> Result<LdapConfig> {
147        self.client.put("/v1/cluster/ldap", &config).await
148    }
149}