Skip to content

Commit f3b12da

Browse files
authored
Merge pull request parallaxsecond#220 from joechrisellis/add_list_authenticators
Add implementation for ListAuthenticators operation
2 parents 5cb7685 + 058cd12 commit f3b12da

File tree

8 files changed

+121
-17
lines changed

8 files changed

+121
-17
lines changed

e2e_tests/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub use parsec_client::error;
1212
use log::error;
1313
use parsec_client::auth::AuthenticationData;
1414
use parsec_client::core::basic_client::BasicClient;
15+
use parsec_client::core::interface::operations::list_authenticators::AuthenticatorInfo;
1516
use parsec_client::core::interface::operations::list_providers::ProviderInfo;
1617
use parsec_client::core::interface::operations::psa_algorithm::{
1718
Aead, AeadWithDefaultLengthTag, Algorithm, AsymmetricEncryption, AsymmetricSignature, Hash,
@@ -688,6 +689,13 @@ impl TestClient {
688689
self.basic_client.list_providers().map_err(convert_error)
689690
}
690691

692+
/// Lists the authenticators available for the Parsec service.
693+
pub fn list_authenticators(&mut self) -> Result<Vec<AuthenticatorInfo>> {
694+
self.basic_client
695+
.list_authenticators()
696+
.map_err(convert_error)
697+
}
698+
691699
/// Lists the opcodes available for one provider to execute.
692700
pub fn list_opcodes(&mut self, provider_id: ProviderID) -> Result<HashSet<Opcode>> {
693701
self.basic_client

e2e_tests/tests/all_providers/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2019 Contributors to the Parsec project.
22
// SPDX-License-Identifier: Apache-2.0
33
use e2e_tests::TestClient;
4-
use parsec_client::core::interface::requests::{Opcode, ProviderID, Result};
4+
use parsec_client::core::interface::requests::{AuthType, Opcode, ProviderID, Result};
55
use std::collections::HashSet;
66
use uuid::Uuid;
77

@@ -21,6 +21,18 @@ fn list_providers() {
2121
assert!(uuids.contains(&Uuid::parse_str("1e4954a4-ff21-46d3-ab0c-661eeb667e1d").unwrap()));
2222
}
2323

24+
#[test]
25+
fn list_authenticators() {
26+
let mut client = TestClient::new();
27+
let authenticators = client
28+
.list_authenticators()
29+
.expect("list authenticators failed");
30+
assert_eq!(authenticators.len(), 1);
31+
let ids: HashSet<AuthType> = authenticators.iter().map(|p| p.id).collect();
32+
// Direct authenticator
33+
assert!(ids.contains(&AuthType::Direct));
34+
}
35+
2436
#[test]
2537
fn list_opcodes() {
2638
let mut client = TestClient::new();
@@ -48,6 +60,7 @@ fn list_opcodes() {
4860

4961
let _ = core_provider_opcodes.insert(Opcode::Ping);
5062
let _ = core_provider_opcodes.insert(Opcode::ListProviders);
63+
let _ = core_provider_opcodes.insert(Opcode::ListAuthenticators);
5164
let _ = core_provider_opcodes.insert(Opcode::ListOpcodes);
5265

5366
assert_eq!(

src/authenticators/direct_authenticator/mod.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use super::ApplicationName;
1212
use super::Authenticate;
1313
use crate::front::listener::ConnectionMetadata;
1414
use log::error;
15+
use parsec_interface::operations::list_authenticators;
1516
use parsec_interface::requests::request::RequestAuth;
17+
use parsec_interface::requests::AuthType;
1618
use parsec_interface::requests::{ResponseStatus, Result};
1719
use parsec_interface::secrecy::ExposeSecret;
1820
use std::str;
@@ -21,6 +23,19 @@ use std::str;
2123
pub struct DirectAuthenticator;
2224

2325
impl Authenticate for DirectAuthenticator {
26+
fn describe(&self) -> Result<list_authenticators::AuthenticatorInfo> {
27+
Ok(list_authenticators::AuthenticatorInfo {
28+
description: String::from(
29+
"Directly parses the authentication field as a UTF-8 string and uses that as the \
30+
application identity. Should be used for testing only.",
31+
),
32+
version_maj: 0,
33+
version_min: 1,
34+
version_rev: 0,
35+
id: AuthType::Direct,
36+
})
37+
}
38+
2439
fn authenticate(
2540
&self,
2641
auth: &RequestAuth,

src/authenticators/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
pub mod direct_authenticator;
1515

1616
use crate::front::listener::ConnectionMetadata;
17+
use parsec_interface::operations::list_authenticators;
1718
use parsec_interface::requests::request::RequestAuth;
1819
use parsec_interface::requests::Result;
1920

@@ -25,6 +26,12 @@ pub struct ApplicationName(String);
2526
///
2627
/// Interface that must be implemented for each authentication type available for the service.
2728
pub trait Authenticate {
29+
/// Return a description of the authenticator.
30+
///
31+
/// The descriptions are gathered in the Core Provider and returned for a ListAuthenticators
32+
/// operation.
33+
fn describe(&self) -> Result<list_authenticators::AuthenticatorInfo>;
34+
2835
/// Authenticates a `RequestAuth` payload and returns the `ApplicationName` if successful. A
2936
/// optional `ConnectionMetadata` object is passed in too, since it is sometimes possible to
3037
/// perform authentication based on the connection's metadata (i.e. as is the case for UNIX

src/back/backend_handler.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,12 @@ impl BackEndHandler {
204204
trace!("psa_aead_decrypt_egress");
205205
self.result_to_response(NativeResult::PsaAeadDecrypt(result), header)
206206
}
207-
NativeOperation::ListAuthenticators(_) => {
208-
panic!("Unsupported in this PR");
207+
NativeOperation::ListAuthenticators(op_list_authenticators) => {
208+
let result = unwrap_or_else_return!(self
209+
.provider
210+
.list_authenticators(op_list_authenticators));
211+
trace!("list_authenticators egress");
212+
self.result_to_response(NativeResult::ListAuthenticators(result), header)
209213
}
210214
NativeOperation::PsaHashCompute(op_hash_compute) => {
211215
let _app_name =

src/providers/core_provider/mod.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
use super::Provide;
99
use derivative::Derivative;
1010
use log::trace;
11-
use parsec_interface::operations::list_providers::ProviderInfo;
12-
use parsec_interface::operations::{list_opcodes, list_providers, ping};
11+
use parsec_interface::operations::{list_authenticators, list_opcodes, list_providers, ping};
12+
use parsec_interface::operations::{
13+
list_authenticators::AuthenticatorInfo, list_providers::ProviderInfo,
14+
};
1315
use parsec_interface::requests::{Opcode, ProviderID, ResponseStatus, Result};
1416
use std::collections::{HashMap, HashSet};
1517
use std::io::{Error, ErrorKind};
@@ -18,7 +20,12 @@ use std::sync::Arc;
1820
use uuid::Uuid;
1921
use version::{version, Version};
2022

21-
const SUPPORTED_OPCODES: [Opcode; 3] = [Opcode::ListProviders, Opcode::ListOpcodes, Opcode::Ping];
23+
const SUPPORTED_OPCODES: [Opcode; 4] = [
24+
Opcode::ListProviders,
25+
Opcode::ListOpcodes,
26+
Opcode::Ping,
27+
Opcode::ListAuthenticators,
28+
];
2229

2330
/// Service information provider
2431
///
@@ -32,6 +39,7 @@ pub struct CoreProvider {
3239
wire_protocol_version_maj: u8,
3340
provider_info: Vec<ProviderInfo>,
3441
provider_opcodes: HashMap<ProviderID, HashSet<Opcode>>,
42+
authenticator_info: Vec<AuthenticatorInfo>,
3543
#[derivative(Debug = "ignore")]
3644
prov_list: Vec<Arc<dyn Provide + Send + Sync>>,
3745
}
@@ -55,6 +63,16 @@ impl Provide for CoreProvider {
5563
})
5664
}
5765

66+
fn list_authenticators(
67+
&self,
68+
_op: list_authenticators::Operation,
69+
) -> Result<list_authenticators::Result> {
70+
trace!("list_authenticators ingress");
71+
Ok(list_authenticators::Result {
72+
authenticators: self.authenticator_info.clone(),
73+
})
74+
}
75+
5876
fn ping(&self, _op: ping::Operation) -> Result<ping::Result> {
5977
trace!("ping ingress");
6078
let result = ping::Result {
@@ -74,6 +92,8 @@ pub struct CoreProviderBuilder {
7492
version_min: Option<u8>,
7593
#[derivative(Debug = "ignore")]
7694
prov_list: Vec<Arc<dyn Provide + Send + Sync>>,
95+
#[derivative(Debug = "ignore")]
96+
authenticator_info: Vec<AuthenticatorInfo>,
7797
}
7898

7999
impl CoreProviderBuilder {
@@ -82,6 +102,7 @@ impl CoreProviderBuilder {
82102
version_maj: None,
83103
version_min: None,
84104
prov_list: Vec::new(),
105+
authenticator_info: Vec::new(),
85106
}
86107
}
87108

@@ -98,6 +119,12 @@ impl CoreProviderBuilder {
98119
self
99120
}
100121

122+
pub fn with_authenticator_info(mut self, authenticator_info: AuthenticatorInfo) -> Self {
123+
self.authenticator_info.push(authenticator_info);
124+
125+
self
126+
}
127+
101128
pub fn build(self) -> std::io::Result<CoreProvider> {
102129
let mut provider_opcodes = HashMap::new();
103130
let _ = provider_opcodes.insert(
@@ -144,6 +171,7 @@ impl CoreProviderBuilder {
144171
.ok_or_else(|| Error::new(ErrorKind::InvalidData, "version min is missing"))?,
145172
provider_opcodes,
146173
provider_info: provider_info_vec,
174+
authenticator_info: self.authenticator_info,
147175
prov_list: self.prov_list,
148176
};
149177

@@ -161,6 +189,7 @@ mod tests {
161189
wire_protocol_version_min: 8,
162190
wire_protocol_version_maj: 10,
163191
provider_info: Vec::new(),
192+
authenticator_info: Vec::new(),
164193
provider_opcodes: HashMap::new(),
165194
prov_list: Vec::new(),
166195
};

src/providers/mod.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ impl ProviderConfig {
7575

7676
use crate::authenticators::ApplicationName;
7777
use parsec_interface::operations::{
78-
list_opcodes, list_providers, ping, psa_aead_decrypt, psa_aead_encrypt, psa_asymmetric_decrypt,
79-
psa_asymmetric_encrypt, psa_destroy_key, psa_export_key, psa_export_public_key,
80-
psa_generate_key, psa_hash_compare, psa_hash_compute, psa_import_key, psa_raw_key_agreement,
81-
psa_sign_hash, psa_verify_hash,
78+
list_authenticators, list_opcodes, list_providers, ping, psa_aead_decrypt, psa_aead_encrypt,
79+
psa_asymmetric_decrypt, psa_asymmetric_encrypt, psa_destroy_key, psa_export_key,
80+
psa_export_public_key, psa_generate_key, psa_hash_compare, psa_hash_compute, psa_import_key,
81+
psa_raw_key_agreement, psa_sign_hash, psa_verify_hash,
8282
};
8383
use parsec_interface::requests::{ResponseStatus, Result};
8484

@@ -107,6 +107,15 @@ pub trait Provide {
107107
Err(ResponseStatus::PsaErrorNotSupported)
108108
}
109109

110+
/// List the authenticators supported by the given provider.
111+
fn list_authenticators(
112+
&self,
113+
_op: list_authenticators::Operation,
114+
) -> Result<list_authenticators::Result> {
115+
trace!("list_authenticators ingress");
116+
Err(ResponseStatus::PsaErrorNotSupported)
117+
}
118+
110119
/// Execute a Ping operation to get the wire protocol version major and minor information.
111120
///
112121
/// # Errors

src/utils/service_builder.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! provided configuration.
77
use super::global_config::GlobalConfigBuilder;
88
use crate::authenticators::direct_authenticator::DirectAuthenticator;
9+
use crate::authenticators::Authenticate;
910
use crate::back::{
1011
backend_handler::{BackEndHandler, BackEndHandlerBuilder},
1112
dispatcher::DispatcherBuilder,
@@ -54,6 +55,7 @@ const DEFAULT_BODY_LEN_LIMIT: usize = 1 << 19;
5455

5556
type KeyInfoManager = Arc<RwLock<dyn ManageKeyInfo + Send + Sync>>;
5657
type Provider = Arc<dyn Provide + Send + Sync>;
58+
type Authenticator = Box<dyn Authenticate + Send + Sync>;
5759

5860
#[derive(Copy, Clone, Deserialize, Debug)]
5961
pub struct CoreSettings {
@@ -109,24 +111,33 @@ impl ServiceBuilder {
109111
return Err(Error::new(ErrorKind::InvalidData, "need one provider"));
110112
}
111113

112-
let backend_handlers = build_backend_handlers(providers)?;
114+
// The authenticators supported by the Parsec service.
115+
// NOTE: order here is important. The order in which the elements are added here is the
116+
// order in which they will be returned to any client requesting them!
117+
let mut authenticators: Vec<(AuthType, Authenticator)> = Vec::new();
118+
authenticators.push((AuthType::Direct, Box::from(DirectAuthenticator {})));
119+
120+
let backend_handlers = build_backend_handlers(providers, &authenticators)?;
113121

114122
let dispatcher = DispatcherBuilder::new()
115123
.with_backends(backend_handlers)
116124
.build()?;
117125

118-
let direct_authenticator = Box::from(DirectAuthenticator {});
119-
120-
Ok(FrontEndHandlerBuilder::new()
126+
let mut front_end_handler_builder = FrontEndHandlerBuilder::new();
127+
for (auth_type, authenticator) in authenticators {
128+
front_end_handler_builder =
129+
front_end_handler_builder.with_authenticator(auth_type, authenticator);
130+
}
131+
front_end_handler_builder = front_end_handler_builder
121132
.with_dispatcher(dispatcher)
122-
.with_authenticator(AuthType::Direct, direct_authenticator)
123133
.with_body_len_limit(
124134
config
125135
.core_settings
126136
.body_len_limit
127137
.unwrap_or(DEFAULT_BODY_LEN_LIMIT),
128-
)
129-
.build()?)
138+
);
139+
140+
Ok(front_end_handler_builder.build()?)
130141
}
131142

132143
/// Construct the service IPC front component and return ownership to it.
@@ -152,12 +163,20 @@ impl ServiceBuilder {
152163

153164
fn build_backend_handlers(
154165
mut providers: Vec<(ProviderID, Provider)>,
166+
authenticators: &[(AuthType, Authenticator)],
155167
) -> Result<HashMap<ProviderID, BackEndHandler>> {
156168
let mut map = HashMap::new();
157169

158170
let mut core_provider_builder = CoreProviderBuilder::new()
159171
.with_wire_protocol_version(WIRE_PROTOCOL_VERSION_MINOR, WIRE_PROTOCOL_VERSION_MAJOR);
160172

173+
for (_auth_type, authenticator) in authenticators {
174+
let authenticator_info = authenticator
175+
.describe()
176+
.map_err(|_| Error::new(ErrorKind::Other, "Failed to describe authenticator"))?;
177+
core_provider_builder = core_provider_builder.with_authenticator_info(authenticator_info);
178+
}
179+
161180
for (provider_id, provider) in providers.drain(..) {
162181
core_provider_builder = core_provider_builder.with_provider(provider.clone());
163182

0 commit comments

Comments
 (0)