parsec_client/
auth.rs

1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! Client app authentication data
4use crate::error::{Error, Result};
5use parsec_interface::requests::{request::RequestAuth, AuthType};
6use std::convert::TryFrom;
7
8/// Authentication data used in Parsec requests
9#[derive(Clone, Debug)]
10pub enum Authentication {
11    /// Used in cases where no authentication is desired or required
12    None,
13    /// Data used for direct, identity-based authentication
14    ///
15    /// Warning: Systems using direct authentication require extra measures
16    /// to be as secure as deployments with other authentication mechanisms.
17    /// Please check the
18    /// [Parsec Threat Model](https://parallaxsecond.github.io/parsec-book/parsec_security/parsec_threat_model/threat_model.html)
19    /// for more information.
20    Direct(String),
21    /// Used for authentication via Peer Credentials provided by Unix
22    /// operating systems for Domain Socket connections.
23    UnixPeerCredentials,
24    /// Authentication using JWT SVID tokens. The will fetch its JWT-SVID and pass it in the
25    /// Authentication field. The socket endpoint is found through the SPIFFE_ENDPOINT_SOCKET
26    /// environment variable.
27    #[cfg(feature = "spiffe-auth")]
28    JwtSvid,
29}
30
31impl Authentication {
32    /// Get the Parsec authentication type based on the data type
33    pub fn auth_type(&self) -> AuthType {
34        match self {
35            Authentication::None => AuthType::NoAuth,
36            Authentication::Direct(_) => AuthType::Direct,
37            Authentication::UnixPeerCredentials => AuthType::UnixPeerCredentials,
38            #[cfg(feature = "spiffe-auth")]
39            Authentication::JwtSvid => AuthType::JwtSvid,
40        }
41    }
42}
43
44impl TryFrom<&Authentication> for RequestAuth {
45    type Error = Error;
46
47    fn try_from(data: &Authentication) -> Result<Self> {
48        match data {
49            Authentication::None => Ok(RequestAuth::new(Vec::new())),
50            Authentication::Direct(name) => Ok(RequestAuth::new(name.bytes().collect())),
51            Authentication::UnixPeerCredentials => {
52                let current_uid: libc::uid_t = unsafe { libc::getuid() };
53                Ok(RequestAuth::new(current_uid.to_le_bytes().to_vec()))
54            }
55            #[cfg(feature = "spiffe-auth")]
56            Authentication::JwtSvid => {
57                use crate::error::ClientErrorKind;
58                use log::error;
59                use spiffe::workload_api::client::WorkloadApiClient;
60
61                let client = WorkloadApiClient::default().unwrap();
62                let token = client.fetch_jwt_token(&["parsec"], None).map_err(|e| {
63                    error!("Error while fetching the JWT-SVID ({}).", e);
64                    Error::Client(ClientErrorKind::Spiffe(e))
65                })?;
66
67                Ok(RequestAuth::new(token.as_bytes().into()))
68            }
69        }
70    }
71}
72
73impl PartialEq for Authentication {
74    fn eq(&self, other: &Self) -> bool {
75        match (self, other) {
76            (Authentication::None, Authentication::None) => true,
77            (Authentication::UnixPeerCredentials, Authentication::UnixPeerCredentials) => true,
78            (Authentication::Direct(app_name), Authentication::Direct(other_app_name)) => {
79                app_name == other_app_name
80            }
81            #[cfg(feature = "spiffe-auth")]
82            (Authentication::JwtSvid, Authentication::JwtSvid) => true,
83            _ => false,
84        }
85    }
86}