parsec_service/authenticators/
mod.rs

1// Copyright 2019 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! Request authentication
4//!
5//! [Authenticators](https://parallaxsecond.github.io/parsec-book/parsec_service/authenticators.html)
6//! provide functionality to the service for verifying the authenticity of requests.
7//! The result of an authentication is an `Application` which is parsed by the authenticator and
8//! used throughout the service for identifying the request initiator. The input to an authentication
9//! is the `RequestAuth` field of a request, which is parsed by the authenticator specified in the header.
10//! The authentication functionality is abstracted through an `Authenticate` trait.
11
12#[cfg(not(any(
13    feature = "direct-authenticator",
14    feature = "unix-peer-credentials-authenticator",
15    feature = "jwt-svid-authenticator",
16)))]
17compile_error!("Please provide in at least one authenticator");
18
19#[cfg(feature = "direct-authenticator")]
20pub mod direct_authenticator;
21
22#[cfg(feature = "unix-peer-credentials-authenticator")]
23pub mod unix_peer_credentials_authenticator;
24
25#[cfg(feature = "jwt-svid-authenticator")]
26pub mod jwt_svid_authenticator;
27
28use crate::front::listener::ConnectionMetadata;
29use crate::utils::config::Admin;
30use parsec_interface::operations::list_authenticators;
31use parsec_interface::requests::request::RequestAuth;
32use parsec_interface::requests::{AuthType, Result};
33use std::fmt;
34use std::ops::Deref;
35
36/// A unique identifier for an application.
37#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38pub struct ApplicationIdentity {
39    /// The name of the application.
40    name: String,
41    /// The id of the authenticator used to authenticate the application name.
42    auth: Auth,
43}
44
45/// Application Name any ApplicationIdentity generated by calling `new_internal()`
46pub const INTERNAL_APP_NAME: &str = "parsec";
47
48impl fmt::Display for ApplicationIdentity {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        write!(
51            f,
52            "ApplicationIdentity: [name=\"{}\", auth=\"{}\"]",
53            self.name, self.auth
54        )
55    }
56}
57
58impl ApplicationIdentity {
59    /// Creates a new instance of ApplicationIdentity using the client-facing authenticator type.
60    /// Note that for creating internal keys, new_internal should be used instead
61    pub fn new(name: String, authenticator_id: AuthType) -> ApplicationIdentity {
62        ApplicationIdentity {
63            name,
64            auth: authenticator_id.into(),
65        }
66    }
67
68    /// Creates a new instance of ApplicationIdentity using the authenticator type.
69    /// Note that for creating internal keys, new_internal should be used instead
70    pub fn new_with_auth(name: String, auth: Auth) -> ApplicationIdentity {
71        ApplicationIdentity { name, auth }
72    }
73
74    /// Creates a new instance of ApplicationIdentity using the internal authenticator
75    /// An `INTERNAL_APP_NAME` as its application name
76    pub fn new_internal() -> ApplicationIdentity {
77        ApplicationIdentity {
78            name: INTERNAL_APP_NAME.to_string(),
79            auth: Auth::Internal,
80        }
81    }
82
83    /// Get the identity of the application
84    pub fn name(&self) -> &String {
85        &self.name
86    }
87
88    /// Get the numeric ID of the authenticator
89    pub fn authenticator_id(&self) -> u8 {
90        self.auth.authenticator_id()
91    }
92
93    /// Get the authenticator type of the application
94    pub fn auth(&self) -> &Auth {
95        &self.auth
96    }
97
98    /// Check if the application identity is of type internal
99    pub fn is_internal(&self) -> bool {
100        self.auth == Auth::Internal
101    }
102}
103
104/// Authentication type covering both internal and external sources
105#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
106pub enum Auth {
107    /// An authentication origination from a client request
108    Client(AuthType),
109    /// An authentication origination from within the service
110    Internal,
111}
112
113/// Authenticatior id for the Auth::Internal enum.
114pub const INTERNAL_AUTH_ID: i64 = 255;
115
116impl Auth {
117    /// Get the numeric ID of the authenticator
118    pub fn authenticator_id(&self) -> u8 {
119        match self {
120            Auth::Client(auth) => *auth as u8,
121            Auth::Internal => INTERNAL_AUTH_ID as u8,
122        }
123    }
124}
125
126impl From<AuthType> for Auth {
127    fn from(auth: AuthType) -> Self {
128        Auth::Client(auth)
129    }
130}
131
132impl fmt::Display for Auth {
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        match self {
135            Auth::Client(auth) => {
136                write!(f, "Client authenticator ({})", auth)
137            }
138            Auth::Internal => {
139                write!(f, "Internal service authenticator")
140            }
141        }
142    }
143}
144
145/// Wrapper for a Parsec application
146#[derive(Debug, Clone)]
147pub struct Application {
148    /// The identity of the Application
149    identity: ApplicationIdentity,
150    /// Whether the application has administrator rights
151    is_admin: bool,
152}
153
154impl fmt::Display for Application {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        write!(
157            f,
158            "Application {{identity: {}, is_admin: {}}}",
159            self.identity, self.is_admin
160        )
161    }
162}
163
164impl Application {
165    /// Creates a new instance of ProviderIdentity.
166    pub fn new(identity: ApplicationIdentity, is_admin: bool) -> Application {
167        Application { identity, is_admin }
168    }
169
170    /// Get the identity of the application
171    pub fn identity(&self) -> &ApplicationIdentity {
172        &self.identity
173    }
174
175    /// Get whether the application has administrator rights
176    pub fn is_admin(&self) -> &bool {
177        &self.is_admin
178    }
179}
180
181/// Authentication interface
182///
183/// Interface that must be implemented for each authentication type available for the service.
184pub trait Authenticate {
185    /// Return a description of the authenticator.
186    ///
187    /// The descriptions are gathered in the Core Provider and returned for a ListAuthenticators
188    /// operation.
189    fn describe(&self) -> Result<list_authenticators::AuthenticatorInfo>;
190
191    /// Authenticates a `RequestAuth` payload and returns the `Application` if successful. A
192    /// optional `ConnectionMetadata` object is passed in too, since it is sometimes possible to
193    /// perform authentication based on the connection's metadata (i.e. as is the case for UNIX
194    /// domain sockets with Unix peer credentials).
195    ///
196    /// # Errors
197    ///
198    /// If the authentification fails, returns a `ResponseStatus::AuthenticationError`.
199    fn authenticate(
200        &self,
201        auth: &RequestAuth,
202        meta: Option<ConnectionMetadata>,
203    ) -> Result<Application>;
204}
205
206#[derive(Debug, Clone, Default)]
207struct AdminList(Vec<Admin>);
208
209impl AdminList {
210    fn is_admin(&self, app_name: &str) -> bool {
211        self.iter().any(|admin| admin.name() == app_name)
212    }
213}
214
215impl Deref for AdminList {
216    type Target = Vec<Admin>;
217
218    fn deref(&self) -> &Self::Target {
219        &self.0
220    }
221}
222
223impl From<Vec<Admin>> for AdminList {
224    fn from(admin_list: Vec<Admin>) -> Self {
225        AdminList(admin_list)
226    }
227}