blob: 47d3519f62f9dcd28aea2d4d67e2a0a16e9d066a [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use failure::Error;
use fidl::endpoints::ServerEnd;
use fidl_fuchsia_auth::{AuthProviderConfig, AuthProviderMarker};
use fidl_fuchsia_auth_account::Status;
use fidl_fuchsia_auth_account_internal::{
AccountHandlerContextRequest, AccountHandlerContextRequestStream,
};
use futures::prelude::*;
use std::collections::HashMap;
use token_manager::AuthProviderConnection;
/// A type that can respond to`AccountHandlerContext` requests from the AccountHandler components
/// that we launch. These requests provide contextual and service information to the
/// AccountHandlers, such as connections to components implementing the `AuthProviderFactory`
/// interface.
pub struct AccountHandlerContext {
/// A map from auth_provider_type to an `AuthProviderConnection` used to launch the associated
/// component.
auth_provider_connections: HashMap<String, AuthProviderConnection>,
}
impl AccountHandlerContext {
/// Creates a new `AccountHandlerContext` from the supplied vector of `AuthProviderConfig`
/// objects.
pub fn new(auth_provider_configs: &[AuthProviderConfig]) -> AccountHandlerContext {
AccountHandlerContext {
auth_provider_connections: auth_provider_configs
.iter()
.map(|apc| {
(
apc.auth_provider_type.clone(),
AuthProviderConnection::from_config_ref(apc),
)
})
.collect(),
}
}
/// Asynchronously handles the supplied stream of `AccountHandlerContextRequest` messages.
pub async fn handle_requests_from_stream(
&self, mut stream: AccountHandlerContextRequestStream,
) -> Result<(), Error> {
while let Some(req) = await!(stream.try_next())? {
await!(self.handle_request(req))?;
}
Ok(())
}
/// Asynchronously handles a single `AccountHandlerContextRequest`.
async fn handle_request(&self, req: AccountHandlerContextRequest) -> Result<(), fidl::Error> {
match req {
AccountHandlerContextRequest::GetAuthProvider {
auth_provider_type,
auth_provider,
responder,
} => responder.send(await!(
self.get_auth_provider(&auth_provider_type, auth_provider)
)),
}
}
async fn get_auth_provider<'a>(
&'a self, auth_provider_type: &'a str, auth_provider: ServerEnd<AuthProviderMarker>,
) -> Status {
match self.auth_provider_connections.get(auth_provider_type) {
Some(apc) => match await!(apc.connect(auth_provider)) {
Ok(()) => Status::Ok,
Err(_) => Status::UnknownError,
},
None => Status::NotFound,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
/// Note: Most AccountHandlerContext methods launch instances of an AuthProvider. Since its
/// currently not convenient to mock out this component launching in Rust, we rely on the
/// hermetic component test to provide coverage for these areas and only cover the in-process
/// behavior with this unit-test.
#[test]
fn test_new() {
let dummy_configs = vec![
AuthProviderConfig {
auth_provider_type: "dummy_1".to_string(),
url: "fuchsia-pkg://fuchsia.com/dummy_ap_1#meta/ap.cmx".to_string(),
params: Some(vec!["test_arg_1".to_string()]),
},
AuthProviderConfig {
auth_provider_type: "dummy_2".to_string(),
url: "fuchsia-pkg://fuchsia.com/dummy_ap_2#meta/ap.cmx".to_string(),
params: None,
},
];
let dummy_config_1 = &dummy_configs[0];
let dummy_config_2 = &dummy_configs[1];
let test_object = AccountHandlerContext::new(&dummy_configs);
let test_connection_1 = test_object
.auth_provider_connections
.get(&dummy_config_1.auth_provider_type)
.unwrap();
let test_connection_2 = test_object
.auth_provider_connections
.get(&dummy_config_2.auth_provider_type)
.unwrap();
assert_eq!(test_connection_1.component_url(), dummy_config_1.url);
assert_eq!(test_connection_2.component_url(), dummy_config_2.url);
assert!(test_object
.auth_provider_connections
.get("bad url")
.is_none());
}
}