mirror of
https://github.com/NLnetLabs/krill.git
synced 2026-09-23 18:04:54 +02:00
Fixes: * Just use the token we have if we would ideally refresh before expiration but don't have a refresh token. * Don't hide useful OpenID Connect error details (such as self-signed cert rejected instead of just request failed). (fixes #427) * Lagosta fixes from branch issue-379-handle-connection-issues commit 58f5ccc7 (relates to #442). Functional improvements: * Return or log less in some error scenarios (#419). * Upgrade to Oso 0.11.2 to get a MUCH better error report when a ?= query in a .polar file fails, plus the Mutex around Oso is no longer needed. * Log when OIDC discovery completes successfully. * Be cautious, just log connection issues to the OpenID Connect provider for now, don't retry discovery. * Use a lower timeout for the OpenID Connect HTTP client than the normal Krill HTTP client. * Log more cause chains where available. Code quality improvements: * Apply review feddback: unwrap locks and crash out via panic to be consistent with the rest of Krill. * Factor out the repeated RAII guard handling. * Split login() out into helper methods. * Removed TODO comment. Testing improvements: * Removed left-behind debug screenshot. * Add a test to show a bug whereby access is wrongly denied if a token is pending expiration and has no refresh token. * Add a test to make sure Krill handles timeout of requests to the OIDC provider correctly. Also adds support for a lower timeout in test mode ala how it's done elsewhere in Krill, and more faithfully replicates the normal Krill HTTP client configuration when configuring the OIDC HTTP client. Also factored the OIDC HTTP client code out as it is getting too large to live in provider.rs. * Extend the OpenID Connect provider not available test to show that Krill copes with the provider being unavailable and coming back to life again. * Re-worked the test/mock relationship so that the mock no longer has hard-coded users and username based behaviour activation but rather now the test sets the desired behaviour and is thus easier to understand and more flexible. * Extended the OpenID Connect mock so that its endpoints can be disabled and enabled during tests, and be disabled before Krill even does initial discovery. * Use example.com based bad ACR ID token. * Remove support for the NoResponse mock failure mode as it blocks the tiny http server thread indefinitely also preventing a test using it from exiting, and adds little no perceived benefit over the SlowResponse failure mode (which does at least stop blocking within the expected test run time). * The mock OpenID Connect provider must be shutdown before the UI test result is asserted, otherwise the test process never terminates. * Use the expected OpenID Connect provider timeout when in test mode. * Extend the openid connect test to test the 'hybrid' user attributes case. * Give the login more time to complete before expiring the access token. (#466). * Wait for the right backend status BEFORE clicking the ROAs tab. (#465) Other: * OpenID Connect log message consistency tweaks. * Sync with updated correspoinding Lagosta branch commit d2a92fe1 with latest Lagosta master merged in and a yarn build empty catch block fix. * Sync with commit b9a2f5b3 in the corresponding PR branch in Lagosta to get a testbed REST API client fix. Co-authored-by: Tim Bruijnzeels <tim@nlnetlabs.nl>
169 lines
5.5 KiB
Rust
169 lines
5.5 KiB
Rust
#[cfg(feature = "multi-user")]
|
|
mod openid_connect_mock;
|
|
|
|
use OpenIDConnectMockMode::NotStarted;
|
|
use tokio::task;
|
|
|
|
use std::{env, process::ExitStatus};
|
|
use std::process::Command;
|
|
|
|
use krill::daemon::config::Config;
|
|
use krill::test::*;
|
|
|
|
#[allow(dead_code)]
|
|
#[derive(Copy, Clone)]
|
|
pub enum OpenIDConnectMockMode {
|
|
NotStarted,
|
|
WithRPInitiatedLogout,
|
|
WithOAuth2Revocation,
|
|
WithNoLogoutEndpoints,
|
|
}
|
|
|
|
pub struct OpenIDConnectMockConfig {
|
|
mode: OpenIDConnectMockMode,
|
|
enabled_on_startup: bool,
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
impl OpenIDConnectMockConfig {
|
|
/// Don't start the OpenID Connect mock.
|
|
pub fn do_not_start() -> OpenIDConnectMockConfig {
|
|
Self { mode: NotStarted, enabled_on_startup: false }
|
|
}
|
|
|
|
/// Start the OpenID Mock and enable it ready for use.
|
|
pub fn enabled(mode: OpenIDConnectMockMode) -> OpenIDConnectMockConfig {
|
|
Self { mode, enabled_on_startup: true }
|
|
}
|
|
|
|
/// Start the OpenID Mock initially disabled. This can be useful to prevent initial OpenID Connect Discovery
|
|
/// succeeding before the first test runs.
|
|
pub fn disabled(mode: OpenIDConnectMockMode) -> OpenIDConnectMockConfig {
|
|
Self { mode, enabled_on_startup: false }
|
|
}
|
|
|
|
pub fn mode(&self) -> OpenIDConnectMockMode {
|
|
self.mode
|
|
}
|
|
|
|
pub fn enabled_on_startup(&self) -> bool {
|
|
self.enabled_on_startup
|
|
}
|
|
}
|
|
|
|
#[cfg(not(feature = "multi-user"))]
|
|
pub async fn run_krill_ui_test(
|
|
test_name: &str,
|
|
_: OpenIDConnectMockConfig,
|
|
) {
|
|
assert!(do_run_krill_ui_test(test_name).await);
|
|
}
|
|
|
|
#[cfg(feature = "multi-user")]
|
|
pub async fn run_krill_ui_test(
|
|
test_name: &str,
|
|
openid_connect_mock_config: OpenIDConnectMockConfig,
|
|
) {
|
|
let op_handle = match openid_connect_mock_config.mode() {
|
|
NotStarted => None,
|
|
_ => Some(openid_connect_mock::start(openid_connect_mock_config, 1).await),
|
|
};
|
|
|
|
let test_result = do_run_krill_ui_test(test_name).await;
|
|
|
|
if let Some(handle) = op_handle {
|
|
openid_connect_mock::stop(handle).await;
|
|
}
|
|
|
|
assert!(test_result);
|
|
}
|
|
|
|
struct CypressRunner {
|
|
status: ExitStatus
|
|
}
|
|
impl CypressRunner {
|
|
pub async fn run(test_name: &str) -> Self {
|
|
let test_name = test_name.to_string();
|
|
|
|
ctrlc::set_handler(move || {
|
|
// If `cargo test` is stopped with CTRL-C the background Cypress Docker container continues to run. This
|
|
// prevents the next run of `cargo test` from working as the container unexpectedly already exists. Tell
|
|
// Docker to kill it to avoid leaving it lying around.
|
|
Command::new("docker").arg("kill").arg("cypress").spawn().expect("Failed to kill Cypress Docker container");
|
|
}).expect("Error setting Ctrl-C handler");
|
|
|
|
let task = task::spawn_blocking(move || {
|
|
// NOTE: the directory mentioned here must be the same as the directory
|
|
// mentioned in the tests/ui/cypress/plugins/index.js file in the
|
|
// "integrationFolder" property otherwise Cypress mysteriously complains
|
|
// that it cannot find the spec file.
|
|
let cypress_spec_path = format!("tests/ui/cypress/specs/{}.js", test_name);
|
|
|
|
let mut cmd = Command::new("docker");
|
|
|
|
cmd
|
|
.arg("run")
|
|
.arg("--name").arg("cypress")
|
|
.arg("--rm")
|
|
.arg("--net=host")
|
|
.arg("--ipc=host")
|
|
.arg("-v").arg(format!("{}:/e2e", env::current_dir().unwrap().display()))
|
|
.arg("-w").arg("/e2e");
|
|
|
|
if let Ok(debug_level) = std::env::var("CYPRESS_DEBUG") {
|
|
// Example values:
|
|
// - To get LOTS of Cypress logging: CYPRESS_DEBUG=cypress:*
|
|
// - To get logging relating to HTTP requests: CYPRESS_DEBUG=cypress:proxy:http:*
|
|
cmd
|
|
.arg("-e").arg(format!("DEBUG={}", debug_level));
|
|
}
|
|
|
|
if std::env::var("CYPRESS_INTERACTIVE").is_ok() {
|
|
// After running `cargo test` a Chrome browser should open from the Cypress Docker container on your local
|
|
// X server. For this to work you might need to run this command in your shell prior to `cargo test`:
|
|
// xhost +
|
|
cmd
|
|
.arg("-v").arg(format!("/tmp/.X11-unix:/tmp/.X11-unix"))
|
|
.arg("-e").arg("DISPLAY")
|
|
.arg("--entrypoint").arg("cypress");
|
|
}
|
|
|
|
cmd.arg("cypress/included:6.8.0");
|
|
|
|
if std::env::var("CYPRESS_INTERACTIVE").is_ok() {
|
|
cmd
|
|
.arg("open")
|
|
.arg("--project").arg(".");
|
|
} else {
|
|
cmd
|
|
.arg("--spec").arg(cypress_spec_path);
|
|
}
|
|
|
|
cmd
|
|
.arg("--browser").arg("chrome")
|
|
.status()
|
|
.expect("Failed to run Cypress Docker UI test suite")
|
|
}).await;
|
|
|
|
Self {
|
|
status: task.unwrap()
|
|
}
|
|
}
|
|
|
|
pub fn success(self) -> bool {
|
|
self.status.success()
|
|
}
|
|
}
|
|
|
|
async fn do_run_krill_ui_test(test_name: &str) -> bool {
|
|
krill::constants::enable_test_mode();
|
|
let config_path = &format!("test-resources/ui/{}.conf", test_name);
|
|
let config = Config::read_config(&config_path).unwrap();
|
|
|
|
// Start Krill as a Tokio task in the background and wait just until we can tell that it has started.
|
|
start_krill_with_custom_config(config).await;
|
|
|
|
// Run the specified Cypress UI test suite and wait for it to finish
|
|
CypressRunner::run(test_name).await.success()
|
|
}
|