Skip to main content

sspi/kerberos/
config.rs

1use std::fmt::Debug;
2use std::str::FromStr;
3
4use url::Url;
5
6use crate::kdc::detect_kdc_url;
7use crate::kerberos::ServerProperties;
8use crate::negotiate::{NegotiatedProtocol, ProtocolConfig};
9use crate::{Kerberos, Result};
10
11/// Kerberos client configuration.
12#[derive(Clone, Debug)]
13pub struct KerberosConfig {
14    /// KDC URL
15    ///
16    /// Depending on the scheme it is expected to be either:
17    /// - a (Kerberos) KDC address (e.g.: tcp://domain:88, udp://domain:88), or
18    /// - a KDC _Proxy_ URL (e.g.: <https://gateway.devolutions.net/jet/KdcProxy?token=…>)
19    ///
20    /// That is, when the scheme is `http` or `https`, the KDC Proxy Protocol ([KKDCP]) will be
21    /// used on top of the Kerberos protocol, wrapping the messages.
22    /// Otherwise, the scheme must be either `tcp` or `udp`, and the KDC protocol will be used
23    /// in order to communicate with the KDC server directly.
24    ///
25    /// [KKDCP]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kkdcp/5bcebb8d-b747-4ee5-9453-428aec1c5c38
26    pub kdc_url: Option<Url>,
27    /// Computer name, or "workstation name", of the client machine performing the authentication attempt
28    ///
29    /// This is also referred to as the "Source Workstation", i.e.: the name of the computer attempting to logon.
30    pub client_computer_name: String,
31}
32
33impl ProtocolConfig for KerberosConfig {
34    fn new_instance(&self) -> Result<NegotiatedProtocol> {
35        Ok(NegotiatedProtocol::Kerberos(Kerberos::new_client_from_config(
36            self.clone(),
37        )?))
38    }
39
40    fn box_clone(&self) -> Box<dyn ProtocolConfig> {
41        Box::new(self.clone())
42    }
43}
44
45pub fn parse_kdc_url(kdc_url: &str) -> Option<Url> {
46    if !kdc_url.contains("://") {
47        Url::from_str(&format!("tcp://{kdc_url}")).ok()
48    } else {
49        Url::from_str(kdc_url).ok()
50    }
51}
52
53impl KerberosConfig {
54    pub fn new(kdc_url: &str, client_computer_name: String) -> Self {
55        let kdc_url = parse_kdc_url(kdc_url);
56
57        Self {
58            kdc_url,
59            client_computer_name,
60        }
61    }
62
63    pub fn get_kdc_url(self, domain: &str) -> Option<Url> {
64        if let Some(kdc_url) = self.kdc_url {
65            Some(kdc_url)
66        } else {
67            detect_kdc_url(domain)
68        }
69    }
70}
71
72/// Kerberos server configuration.
73#[derive(Clone, Debug)]
74pub struct KerberosServerConfig {
75    /// General Kerberos configuration.
76    pub kerberos_config: KerberosConfig,
77    /// Kerberos server specific parameters.
78    pub server_properties: ServerProperties,
79}
80
81impl ProtocolConfig for KerberosServerConfig {
82    fn new_instance(&self) -> Result<NegotiatedProtocol> {
83        Ok(NegotiatedProtocol::Kerberos(Kerberos::new_server_from_config(
84            self.kerberos_config.clone(),
85            self.server_properties.clone(),
86        )?))
87    }
88
89    fn box_clone(&self) -> Box<dyn ProtocolConfig> {
90        Box::new(self.clone())
91    }
92}