Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions credentialsd-common/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ pub enum Operation {

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Type)]
pub struct PortalBackendOptions {
/// A token that can be used to activate the UI window.
pub activation_token: Optional<String>,

/// Top-level origin of the request if different from the origin.
pub top_origin: Optional<String>,

Expand Down
58 changes: 40 additions & 18 deletions credentialsd/src/dbus/flow_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,44 @@ use crate::{
dbus::ui_control::UiController,
model::{CredentialRequest, CredentialResponse},
};
pub struct UiRequestContext {
request: CredentialRequest,
app: RequestingApplication,
/// Client window handle
window_handle: Option<WindowHandle>,
activation_token: Option<String>,
response_channel: oneshot::Sender<Result<CredentialResponse, CredentialServiceError>>,
}

pub async fn start_flow_control_service<M: ManageDevice + Debug + Send + Sync + 'static>(
conn: Connection,
mut listener: Receiver<(
CredentialRequest,
RequestingApplication,
Option<WindowHandle>, // Client window handle
oneshot::Sender<Result<CredentialResponse, CredentialServiceError>>,
)>,
mut listener: Receiver<UiRequestContext>,
device_manager: M,
) -> zbus::Result<AbortHandle> {
let svc = Arc::new(AsyncMutex::new(device_manager));
let svc2 = svc.clone();

let task = tokio::spawn(async move {
while let Some((msg, requesting_app, window_handle, tx)) = listener.recv().await {
while let Some(ui_request_ctx) = listener.recv().await {
let svc = svc2.clone();
let ui_control_client = UiControlServiceClient::new(conn.clone());
if let Err(_) =
tx.send(handle(svc, ui_control_client, msg, requesting_app, window_handle).await)
{
let UiRequestContext {
request,
app,
window_handle,
activation_token,
response_channel,
} = ui_request_ctx;
let response = handle(
svc,
ui_control_client,
request,
app,
window_handle,
activation_token,
)
.await;
if let Err(_) = response_channel.send(response) {
tracing::error!(
"Received response to credential request, but failed to forward it to gateway"
);
Expand All @@ -61,6 +78,7 @@ async fn handle<M: ManageDevice + Debug + Send + Sync + 'static, UC: UiControlle
msg: CredentialRequest,
requesting_app: RequestingApplication,
window_handle: Option<WindowHandle>,
activation_token: Option<String>,
) -> Result<CredentialResponse, CredentialServiceError> {
let (request_tx, request_rx) = oneshot::channel();
let request_id = svc.lock().await.init_request(&msg, request_tx).await?;
Expand Down Expand Up @@ -112,6 +130,7 @@ async fn handle<M: ManageDevice + Debug + Send + Sync + 'static, UC: UiControlle
// TODO: Make path and app ID separate.
path_or_app_id,
PortalBackendOptions {
activation_token: activation_token.into(),
top_origin: top_origin.into(),
rp_id: Some(rp_id).into(),
},
Expand Down Expand Up @@ -235,29 +254,32 @@ pub trait CredentialRequestController {
requesting_app: RequestingApplication,
request: CredentialRequest,
window_handle: Option<WindowHandle>,
activation_token: Option<String>,
) -> Result<CredentialResponse, WebAuthnError>;
}

pub struct CredentialRequestControllerClient {
pub initiator: Sender<(
CredentialRequest,
RequestingApplication, // Application name sending the request
Option<WindowHandle>, // Client window handle,
oneshot::Sender<Result<CredentialResponse, CredentialServiceError>>,
)>,
pub initiator: Sender<UiRequestContext>,
}

#[async_trait]
impl CredentialRequestController for CredentialRequestControllerClient {
async fn request_credential(
&self,
requesting_app: RequestingApplication,
app: RequestingApplication,
request: CredentialRequest,
window_handle: Option<WindowHandle>,
activation_token: Option<String>,
) -> Result<CredentialResponse, WebAuthnError> {
let (tx, rx) = oneshot::channel();
self.initiator
.send((request, requesting_app, window_handle, tx))
.send(UiRequestContext {
request,
app,
window_handle,
activation_token,
response_channel: tx,
})
.await
.unwrap();
let response = rx.await.map_err(|_| {
Expand Down
18 changes: 14 additions & 4 deletions credentialsd/src/gateway/dbus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl CredentialPortalGateway {
claimed_app_display_name: Optional<String>,
) -> PortalResult<CreateCredentialResponse, Error> {
let CreateCredentialPortalOptions {
activation_token: _,
activation_token,
top_origin,
public_key,
} = options;
Expand Down Expand Up @@ -114,7 +114,12 @@ impl CredentialPortalGateway {
.gateway_service
.lock()
.await
.handle_create_credential(request, context, parent_window.into())
.handle_create_credential(
request,
context,
parent_window.into(),
activation_token.into(),
)
.await
.map_err(Error::from);

Expand All @@ -133,7 +138,7 @@ impl CredentialPortalGateway {
claimed_app_display_name: Optional<String>,
) -> PortalResult<GetCredentialResponse, Error> {
let GetCredentialPortalOptions {
activation_token: _,
activation_token,
top_origin,
public_key,
} = options;
Expand Down Expand Up @@ -174,7 +179,12 @@ impl CredentialPortalGateway {
.gateway_service
.lock()
.await
.handle_get_credential(request, context, parent_window.into())
.handle_get_credential(
request,
context,
parent_window.into(),
activation_token.into(),
)
.await
.map_err(Error::from);
response.into()
Expand Down
16 changes: 14 additions & 2 deletions credentialsd/src/gateway/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl GatewayService {
request: CreateCredentialRequest,
context: RequestContext,
parent_window: Option<WindowHandle>,
activation_token: Option<String>,
) -> Result<CreateCredentialResponse, WebAuthnError> {
let request_environment = validate_request(&context)?;

Expand All @@ -110,7 +111,12 @@ impl GatewayService {

let response = self
.request_controller
.request_credential(context.into(), cred_request, parent_window)
.request_credential(
context.into(),
cred_request,
parent_window,
activation_token,
)
.await?;

if let CredentialResponse::CreatePublicKeyCredentialResponse(cred_response) = response {
Expand Down Expand Up @@ -142,6 +148,7 @@ impl GatewayService {
request: GetCredentialRequest,
context: RequestContext,
parent_window: Option<WindowHandle>,
activation_token: Option<String>,
) -> Result<GetCredentialResponse, WebAuthnError> {
let request_environment = validate_request(&context)?;

Expand All @@ -166,7 +173,12 @@ impl GatewayService {

let response = self
.request_controller
.request_credential(context.into(), cred_request, parent_window)
.request_credential(
context.into(),
cred_request,
parent_window,
activation_token,
)
.await?;

if let CredentialResponse::GetPublicKeyCredentialResponse(cred_response) = response {
Expand Down
Loading