rocket/mtls/
name.rs

1use std::fmt;
2use std::ops::Deref;
3
4use ref_cast::RefCast;
5
6use crate::mtls::x509::X509Name;
7use crate::mtls::oid;
8
9/// An X.509 Distinguished Name (DN) found in a
10/// [`Certificate`](crate::mtls::Certificate).
11///
12/// This type is a wrapper over [`X509Name`] with convenient methods and
13/// complete documentation. Should the data exposed by the inherent methods not
14/// suffice, this type derefs to [`X509Name`].
15#[repr(transparent)]
16#[derive(Debug, PartialEq, RefCast)]
17pub struct Name<'a>(X509Name<'a>);
18
19impl<'a> Name<'a> {
20    /// Returns the _first_ UTF-8 _string_ common name, if any.
21    ///
22    /// Note that common names need not be UTF-8 strings, or strings at all.
23    /// This method returns the first common name attribute that is.
24    ///
25    /// # Example
26    ///
27    /// ```rust
28    /// # #[macro_use] extern crate rocket;
29    /// use rocket::mtls::Certificate;
30    ///
31    /// #[get("/auth")]
32    /// fn auth(cert: Certificate<'_>) {
33    ///     if let Some(name) = cert.subject().common_name() {
34    ///         println!("Hello, {}!", name);
35    ///     }
36    /// }
37    /// ```
38    pub fn common_name(&self) -> Option<&'a str> {
39        self.common_names().next()
40    }
41
42    /// Returns an iterator over all of the UTF-8 _string_ common names in
43    /// `self`.
44    ///
45    /// Note that common names need not be UTF-8 strings, or strings at all.
46    /// This method filters the common names in `self` to those that are. Use
47    /// the raw [`iter_common_name()`](#method.iter_common_name) to iterate over
48    /// all value types.
49    ///
50    /// # Example
51    ///
52    /// ```rust
53    /// # #[macro_use] extern crate rocket;
54    /// use rocket::mtls::Certificate;
55    ///
56    /// #[get("/auth")]
57    /// fn auth(cert: Certificate<'_>) {
58    ///     for name in cert.issuer().common_names() {
59    ///         println!("Issued by {}.", name);
60    ///     }
61    /// }
62    /// ```
63    pub fn common_names(&self) -> impl Iterator<Item = &'a str> + '_ {
64        self.iter_by_oid(&oid::OID_X509_COMMON_NAME).filter_map(|n| n.as_str().ok())
65    }
66
67    /// Returns the _first_ UTF-8 _string_ email address, if any.
68    ///
69    /// Note that email addresses need not be UTF-8 strings, or strings at all.
70    /// This method returns the first email address attribute that is.
71    ///
72    /// # Example
73    ///
74    /// ```rust
75    /// # #[macro_use] extern crate rocket;
76    /// use rocket::mtls::Certificate;
77    ///
78    /// #[get("/auth")]
79    /// fn auth(cert: Certificate<'_>) {
80    ///     if let Some(email) = cert.subject().email() {
81    ///         println!("Hello, {}!", email);
82    ///     }
83    /// }
84    /// ```
85    pub fn email(&self) -> Option<&'a str> {
86        self.emails().next()
87    }
88
89    /// Returns an iterator over all of the UTF-8 _string_ email addresses in
90    /// `self`.
91    ///
92    /// Note that email addresses need not be UTF-8 strings, or strings at all.
93    /// This method filters the email address in `self` to those that are. Use
94    /// the raw [`iter_email()`](#method.iter_email) to iterate over all value
95    /// types.
96    ///
97    /// # Example
98    ///
99    /// ```rust
100    /// # #[macro_use] extern crate rocket;
101    /// use rocket::mtls::Certificate;
102    ///
103    /// #[get("/auth")]
104    /// fn auth(cert: Certificate<'_>) {
105    ///     for email in cert.subject().emails() {
106    ///         println!("Reach me at: {}", email);
107    ///     }
108    /// }
109    /// ```
110    pub fn emails(&self) -> impl Iterator<Item = &'a str> + '_ {
111        self.iter_by_oid(&oid::OID_PKCS9_EMAIL_ADDRESS).filter_map(|n| n.as_str().ok())
112    }
113
114    /// Returns `true` if `self` has no data.
115    ///
116    /// When this is the case for a `subject()`, the subject data can be found
117    /// in the `subjectAlt` [`extension`].
118    ///
119    /// [`extension`]: crate::mtls::Certificate::extensions()
120    ///
121    /// # Example
122    ///
123    /// ```rust
124    /// # #[macro_use] extern crate rocket;
125    /// use rocket::mtls::Certificate;
126    ///
127    /// #[get("/auth")]
128    /// fn auth(cert: Certificate<'_>) {
129    ///     let no_data = cert.subject().is_empty();
130    /// }
131    /// ```
132    pub fn is_empty(&self) -> bool {
133        self.0.as_raw().is_empty()
134    }
135}
136
137impl<'a> Deref for Name<'a> {
138    type Target = X509Name<'a>;
139
140    fn deref(&self) -> &Self::Target {
141        &self.0
142    }
143}
144
145impl fmt::Display for Name<'_> {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        self.0.fmt(f)
148    }
149}