diff --git a/Cargo.lock b/Cargo.lock index a2b0e899973..94527100bdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -884,6 +884,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -1691,7 +1701,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "base64 0.20.0", + "base64 0.21.0", "omicron-sled-agent", "omicron-test-utils", "oxide-client", @@ -2461,6 +2471,19 @@ dependencies = [ "tokio-rustls", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.53" @@ -3077,6 +3100,24 @@ dependencies = [ "syn", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nb" version = "0.1.3" @@ -3237,7 +3278,7 @@ version = "0.1.0" dependencies = [ "anyhow", "api_identity", - "base64 0.20.0", + "base64 0.21.0", "chrono", "nexus-passwords", "omicron-common", @@ -3497,7 +3538,7 @@ dependencies = [ "async-bb8-diesel", "async-trait", "authz-macros", - "base64 0.20.0", + "base64 0.21.0", "bb8", "chrono", "clap 4.0.32", @@ -3886,7 +3927,7 @@ dependencies = [ name = "oxide-client" version = "0.1.0" dependencies = [ - "base64 0.20.0", + "base64 0.21.0", "chrono", "futures", "progenitor", @@ -4561,7 +4602,7 @@ dependencies = [ [[package]] name = "progenitor" version = "0.2.1-dev" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#634bf98b053cc494191365e2072b3580f4b03df6" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#1ef131a244cf30b9c4213fdb31674fe071cb0043" dependencies = [ "anyhow", "clap 4.0.32", @@ -4571,12 +4612,13 @@ dependencies = [ "progenitor-macro", "serde", "serde_json", + "serde_yaml", ] [[package]] name = "progenitor-client" version = "0.2.1-dev" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#634bf98b053cc494191365e2072b3580f4b03df6" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#1ef131a244cf30b9c4213fdb31674fe071cb0043" dependencies = [ "bytes", "futures-core", @@ -4590,7 +4632,7 @@ dependencies = [ [[package]] name = "progenitor-impl" version = "0.2.1-dev" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#634bf98b053cc494191365e2072b3580f4b03df6" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#1ef131a244cf30b9c4213fdb31674fe071cb0043" dependencies = [ "getopts", "heck", @@ -4612,7 +4654,7 @@ dependencies = [ [[package]] name = "progenitor-macro" version = "0.2.1-dev" -source = "git+https://github.com/oxidecomputer/progenitor?branch=main#634bf98b053cc494191365e2072b3580f4b03df6" +source = "git+https://github.com/oxidecomputer/progenitor?branch=main#1ef131a244cf30b9c4213fdb31674fe071cb0043" dependencies = [ "openapiv3", "proc-macro2", @@ -4622,15 +4664,16 @@ dependencies = [ "serde", "serde_json", "serde_tokenstream", + "serde_yaml", "syn", ] [[package]] name = "propolis-client" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/propolis?rev=666ded451b13bba0895485c0b34515c0e59c2c6e#666ded451b13bba0895485c0b34515c0e59c2c6e" +source = "git+https://github.com/oxidecomputer/propolis?rev=92508d573529a1ee50a9422fbca045a5e980a2b5#92508d573529a1ee50a9422fbca045a5e980a2b5" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", "crucible-client-types", "progenitor", "propolis_types", @@ -4649,7 +4692,7 @@ dependencies = [ [[package]] name = "propolis_types" version = "0.0.0" -source = "git+https://github.com/oxidecomputer/propolis?rev=666ded451b13bba0895485c0b34515c0e59c2c6e#666ded451b13bba0895485c0b34515c0e59c2c6e" +source = "git+https://github.com/oxidecomputer/propolis?rev=92508d573529a1ee50a9422fbca045a5e980a2b5#92508d573529a1ee50a9422fbca045a5e980a2b5" dependencies = [ "schemars", "serde", @@ -4969,10 +5012,12 @@ dependencies = [ "http-body", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -4982,6 +5027,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-rustls", "tokio-util", "tower-service", @@ -5307,6 +5353,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys", +] + [[package]] name = "scheduled-thread-pool" version = "0.2.6" @@ -5365,6 +5420,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.1.20" @@ -5554,6 +5632,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_yaml" +version = "0.9.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serial_test" version = "0.10.0" @@ -6410,6 +6501,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-postgres" version = "0.7.7" @@ -6832,6 +6933,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2" + [[package]] name = "untrusted" version = "0.7.1" diff --git a/Cargo.toml b/Cargo.toml index 98882ce81a5..39a4a403d14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,7 +93,7 @@ async-bb8-diesel = { git = "https://github.com/oxidecomputer/async-bb8-diesel", async-trait = "0.1.60" authz-macros = { path = "nexus/authz-macros" } backoff = { version = "0.4.0", features = [ "tokio" ] } -base64 = "0.20.0" +base64 = "0.21.0" bb8 = "0.8.0" bcs = "0.1.4" bincode = "1.3.3" @@ -185,7 +185,7 @@ pretty-hex = "0.3.0" proc-macro2 = "1.0" progenitor = { git = "https://github.com/oxidecomputer/progenitor", branch = "main" } progenitor-client = { git = "https://github.com/oxidecomputer/progenitor", branch = "main" } -propolis-client = { git = "https://github.com/oxidecomputer/propolis", rev = "666ded451b13bba0895485c0b34515c0e59c2c6e", features = [ "generated-migration" ] } +propolis-client = { git = "https://github.com/oxidecomputer/propolis", rev = "92508d573529a1ee50a9422fbca045a5e980a2b5", features = [ "generated-migration" ] } proptest = "1.0.0" quote = "1.0" rand = "0.8.5" diff --git a/end-to-end-tests/src/instance_launch.rs b/end-to-end-tests/src/instance_launch.rs index aa95907f7d0..d347efa42c5 100644 --- a/end-to-end-tests/src/instance_launch.rs +++ b/end-to-end-tests/src/instance_launch.rs @@ -156,8 +156,13 @@ async fn instance_launch() -> Result<()> { .and_then(|line| line.split_whitespace().nth(1)) .context("failed to get SSH host key from serial console")?; eprintln!("host key: ssh-ed25519 {}", host_key); - let host_key = - PublicKey::parse(b"ssh-ed25519", &base64::decode(host_key)?)?; + let host_key = PublicKey::parse( + b"ssh-ed25519", + &base64::Engine::decode( + &base64::engine::general_purpose::STANDARD, + host_key, + )?, + )?; eprintln!("connecting ssh"); let mut session = russh::client::connect( diff --git a/nexus/src/app/instance.rs b/nexus/src/app/instance.rs index 44bb4b9f9be..787a8de58e9 100644 --- a/nexus/src/app/instance.rs +++ b/nexus/src/app/instance.rs @@ -612,7 +612,8 @@ impl super::Nexus { external_ips, firewall_rules, disks: disk_reqs, - cloud_init_bytes: Some(base64::encode( + cloud_init_bytes: Some(base64::Engine::encode( + &base64::engine::general_purpose::STANDARD, db_instance.generate_cidata(&public_keys)?, )), }; diff --git a/nexus/src/app/sagas/disk_create.rs b/nexus/src/app/sagas/disk_create.rs index 9a678ec5f75..bcd5044caaf 100644 --- a/nexus/src/app/sagas/disk_create.rs +++ b/nexus/src/app/sagas/disk_create.rs @@ -400,14 +400,17 @@ async fn sdc_regions_ensure( flush_timeout: None, // all downstairs will expect encrypted blocks - key: Some(base64::encode({ - // TODO the current encryption key - // requirement is 32 bytes, what if that - // changes? - let mut random_bytes: [u8; 32] = [0; 32]; - rng.fill_bytes(&mut random_bytes); - random_bytes - })), + key: Some(base64::Engine::encode( + &base64::engine::general_purpose::STANDARD, + { + // TODO the current encryption key + // requirement is 32 bytes, what if that + // changes? + let mut random_bytes: [u8; 32] = [0; 32]; + rng.fill_bytes(&mut random_bytes); + random_bytes + }, + )), // TODO TLS, which requires sending X509 stuff during // downstairs region allocation too. diff --git a/nexus/src/app/sagas/snapshot_create.rs b/nexus/src/app/sagas/snapshot_create.rs index 68783ccf33d..f2d7feb555a 100644 --- a/nexus/src/app/sagas/snapshot_create.rs +++ b/nexus/src/app/sagas/snapshot_create.rs @@ -331,14 +331,17 @@ async fn ssc_regions_ensure( flush_timeout: None, // all downstairs will expect encrypted blocks - key: Some(base64::encode({ - // TODO the current encryption key - // requirement is 32 bytes, what if that - // changes? - let mut random_bytes: [u8; 32] = [0; 32]; - rng.fill_bytes(&mut random_bytes); - random_bytes - })), + key: Some(base64::Engine::encode( + &base64::engine::general_purpose::STANDARD, + { + // TODO the current encryption key + // requirement is 32 bytes, what if that + // changes? + let mut random_bytes: [u8; 32] = [0; 32]; + rng.fill_bytes(&mut random_bytes); + random_bytes + }, + )), // TODO TLS, which requires sending X509 stuff during // downstairs region allocation too. diff --git a/nexus/src/app/silo.rs b/nexus/src/app/silo.rs index d06c4f123e4..e2217ad8c43 100644 --- a/nexus/src/app/silo.rs +++ b/nexus/src/app/silo.rs @@ -746,14 +746,17 @@ impl super::Nexus { } params::IdpMetadataSource::Base64EncodedXml { data } => { - let bytes = - base64::decode(data).map_err(|e| Error::InvalidValue { - label: String::from("data"), - message: format!( - "error getting decoding base64 data: {}", - e - ), - })?; + let bytes = base64::Engine::decode( + &base64::engine::general_purpose::STANDARD, + data, + ) + .map_err(|e| Error::InvalidValue { + label: String::from("data"), + message: format!( + "error getting decoding base64 data: {}", + e + ), + })?; String::from_utf8_lossy(&bytes).into_owned() } }; diff --git a/nexus/src/authn/silos.rs b/nexus/src/authn/silos.rs index 337e82e1dfb..ff1ae711334 100644 --- a/nexus/src/authn/silos.rs +++ b/nexus/src/authn/silos.rs @@ -11,6 +11,8 @@ use crate::db::{model, DataStore}; use omicron_common::api::external::LookupResult; use anyhow::{anyhow, Result}; +use base64::Engine; +use dropshot::HttpError; use samael::metadata::ContactPerson; use samael::metadata::ContactType; use samael::metadata::EntityDescriptor; @@ -19,8 +21,6 @@ use samael::metadata::HTTP_REDIRECT_BINDING; use samael::schema::Response as SAMLResponse; use samael::service_provider::ServiceProvider; use samael::service_provider::ServiceProviderBuilder; - -use dropshot::HttpError; use serde::{Deserialize, Serialize}; #[derive(Deserialize)] @@ -209,7 +209,10 @@ impl SamlIdentityProvider { fn public_cert_bytes(&self) -> Result>> { if let Some(cert) = &self.public_cert { - Ok(Some(base64::decode(cert.as_bytes())?)) + Ok(Some( + base64::engine::general_purpose::STANDARD + .decode(cert.as_bytes())?, + )) } else { Ok(None) } @@ -217,7 +220,10 @@ impl SamlIdentityProvider { fn private_key_bytes(&self) -> Result>> { if let Some(key) = &self.private_key { - Ok(Some(base64::decode(key.as_bytes())?)) + Ok(Some( + base64::engine::general_purpose::STANDARD + .decode(key.as_bytes())?, + )) } else { Ok(None) } @@ -240,15 +246,14 @@ impl SamlIdentityProvider { ) })?; - let raw_response_bytes = base64::decode( - saml_post.saml_response.as_bytes(), - ) - .map_err(|e| { - HttpError::for_bad_request( - None, - format!("error base64 decoding SAMLResponse! {}", e), - ) - })?; + let raw_response_bytes = base64::engine::general_purpose::STANDARD + .decode(saml_post.saml_response.as_bytes()) + .map_err(|e| { + HttpError::for_bad_request( + None, + format!("error base64 decoding SAMLResponse! {}", e), + ) + })?; // This base64 decoded string is the SAMLResponse XML. Be aware that // parsing unauthenticated arbitrary XML is garbage and a source of diff --git a/nexus/src/external_api/console_api.rs b/nexus/src/external_api/console_api.rs index bb9a0897e29..34bfc75680e 100644 --- a/nexus/src/external_api/console_api.rs +++ b/nexus/src/external_api/console_api.rs @@ -227,7 +227,8 @@ pub struct RelayState { impl RelayState { pub fn to_encoded(&self) -> Result { - Ok(base64::encode( + Ok(base64::Engine::encode( + &base64::engine::general_purpose::STANDARD, serde_json::to_string(&self).context("encoding relay state")?, )) } @@ -235,8 +236,11 @@ impl RelayState { pub fn from_encoded(encoded: String) -> Result { serde_json::from_str( &String::from_utf8( - base64::decode(encoded) - .context("base64 decoding relay state")?, + base64::Engine::decode( + &base64::engine::general_purpose::STANDARD, + encoded, + ) + .context("base64 decoding relay state")?, ) .context("creating relay state string")?, ) diff --git a/nexus/tests/integration_tests/saml.rs b/nexus/tests/integration_tests/saml.rs index 2e85c615081..a5b396ab2b2 100644 --- a/nexus/tests/integration_tests/saml.rs +++ b/nexus/tests/integration_tests/saml.rs @@ -5,6 +5,8 @@ use std::fmt::Debug; use nexus_test_utils::http_testing::{AuthnMode, NexusRequest, RequestBuilder}; +use nexus_test_utils::resource_helpers::{create_silo, object_create}; +use nexus_test_utils_macros::nexus_test; use omicron_common::api::external::IdentityMetadataCreateParams; use omicron_nexus::authn::silos::{ IdentityProviderType, SamlIdentityProvider, SamlLoginPost, @@ -14,13 +16,10 @@ use omicron_nexus::external_api::views::{self, Silo}; use omicron_nexus::external_api::{params, shared}; use omicron_nexus::TestInterfaces; +use base64::Engine; +use dropshot::ResultsPage; use http::method::Method; use http::StatusCode; -use nexus_test_utils::resource_helpers::{create_silo, object_create}; - -use nexus_test_utils_macros::nexus_test; - -use dropshot::ResultsPage; use httptest::{matchers::*, responders::*, Expectation, Server}; use uuid::Uuid; @@ -488,12 +487,14 @@ async fn test_saml_idp_reject_keypair(cptestctx: &ControlPlaneTestContext) { // Reject signing keypair if the certificate or key is base64 encoded // but not valid params::DerEncodedKeyPair { - public_cert: base64::encode("not a cert"), + public_cert: base64::engine::general_purpose::STANDARD + .encode("not a cert"), private_key: RSA_KEY_1_PRIVATE.to_string(), }, params::DerEncodedKeyPair { public_cert: RSA_KEY_1_PUBLIC.to_string(), - private_key: base64::encode("not a cert"), + private_key: base64::engine::general_purpose::STANDARD + .encode("not a cert"), }, // Reject signing keypair if cert and key are swapped params::DerEncodedKeyPair { @@ -644,7 +645,8 @@ fn test_correct_saml_response() { }; let body_bytes = serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(&SAML_RESPONSE), + saml_response: base64::engine::general_purpose::STANDARD + .encode(&SAML_RESPONSE), relay_state: None, }) .unwrap(); @@ -690,7 +692,8 @@ fn test_correct_saml_response_ecdsa_sha256() { }; let body_bytes = serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(&SAML_RESPONSE_SIGNED_WITH_ECDSA_SHA256), + saml_response: base64::engine::general_purpose::STANDARD + .encode(&SAML_RESPONSE_SIGNED_WITH_ECDSA_SHA256), relay_state: None, }) .unwrap(); @@ -735,7 +738,8 @@ fn test_accept_saml_response_only_assertion_signed() { }; let body_bytes = serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(&SAML_RESPONSE_ONLY_ASSERTION_SIGNED), + saml_response: base64::engine::general_purpose::STANDARD + .encode(&SAML_RESPONSE_ONLY_ASSERTION_SIGNED), relay_state: None, }) .unwrap(); @@ -774,7 +778,8 @@ fn test_reject_unsigned_saml_response() { }; let body_bytes = serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(&SAML_RESPONSE_UNSIGNED), + saml_response: base64::engine::general_purpose::STANDARD + .encode(&SAML_RESPONSE_UNSIGNED), relay_state: None, }) .unwrap(); @@ -816,7 +821,8 @@ fn test_reject_saml_response_with_xml_comment() { }; let body_bytes = serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(&SAML_RESPONSE_WITH_COMMENT), + saml_response: base64::engine::general_purpose::STANDARD + .encode(&SAML_RESPONSE_WITH_COMMENT), relay_state: None, }) .unwrap(); @@ -855,7 +861,8 @@ fn test_correct_saml_response_with_group_attributes() { }; let body_bytes = serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(&SAML_RESPONSE_WITH_GROUPS), + saml_response: base64::engine::general_purpose::STANDARD + .encode(&SAML_RESPONSE_WITH_GROUPS), relay_state: None, }) .unwrap(); @@ -905,7 +912,8 @@ fn test_correct_saml_response_with_group_attributes_wrong_attribute_name() { }; let body_bytes = serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(&SAML_RESPONSE_WITH_GROUPS), + saml_response: base64::engine::general_purpose::STANDARD + .encode(&SAML_RESPONSE_WITH_GROUPS), relay_state: None, }) .unwrap(); @@ -954,7 +962,8 @@ async fn test_post_saml_response(cptestctx: &ControlPlaneTestContext) { }, idp_metadata_source: params::IdpMetadataSource::Base64EncodedXml { - data: base64::encode(SAML_RESPONSE_IDP_DESCRIPTOR), + data: base64::engine::general_purpose::STANDARD + .encode(SAML_RESPONSE_IDP_DESCRIPTOR), }, idp_entity_id: "https://some.idp.test/oxide_rack/".to_string(), @@ -990,7 +999,8 @@ async fn test_post_saml_response(cptestctx: &ControlPlaneTestContext) { ) .raw_body(Some( serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(SAML_RESPONSE_WITH_GROUPS), + saml_response: base64::engine::general_purpose::STANDARD + .encode(SAML_RESPONSE_WITH_GROUPS), relay_state: None, }) .unwrap(), @@ -1094,7 +1104,8 @@ async fn test_post_saml_response_with_relay_state( }, idp_metadata_source: params::IdpMetadataSource::Base64EncodedXml { - data: base64::encode(SAML_RESPONSE_IDP_DESCRIPTOR), + data: base64::engine::general_purpose::STANDARD + .encode(SAML_RESPONSE_IDP_DESCRIPTOR), }, idp_entity_id: "https://some.idp.test/oxide_rack/".to_string(), @@ -1130,7 +1141,8 @@ async fn test_post_saml_response_with_relay_state( ) .raw_body(Some( serde_urlencoded::to_string(SamlLoginPost { - saml_response: base64::encode(SAML_RESPONSE), + saml_response: base64::engine::general_purpose::STANDARD + .encode(SAML_RESPONSE), relay_state: Some( console_api::RelayState { referer: Some("/some/actual/nexus/url".to_string()), diff --git a/nexus/tests/integration_tests/silos.rs b/nexus/tests/integration_tests/silos.rs index 17a815b8b72..614bea5e0d8 100644 --- a/nexus/tests/integration_tests/silos.rs +++ b/nexus/tests/integration_tests/silos.rs @@ -2,39 +2,39 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use crate::integration_tests::saml::SAML_IDP_DESCRIPTOR; use nexus_test_utils::http_testing::{AuthnMode, NexusRequest, RequestBuilder}; +use nexus_test_utils::resource_helpers::{ + create_local_user, create_organization, create_silo, grant_iam, + object_create, objects_list_page_authz, +}; +use nexus_test_utils_macros::nexus_test; +use omicron_common::api::external::ObjectIdentity; use omicron_common::api::external::{ IdentityMetadataCreateParams, LookupType, Name, }; use omicron_nexus::authn::silos::{AuthenticatedSubject, IdentityProviderType}; +use omicron_nexus::authn::{USER_TEST_PRIVILEGED, USER_TEST_UNPRIVILEGED}; +use omicron_nexus::authz::{self, SiloRole}; use omicron_nexus::context::OpContext; use omicron_nexus::db; +use omicron_nexus::db::fixed_data::silo::{DEFAULT_SILO, SILO_ID}; +use omicron_nexus::db::identity::Asset; use omicron_nexus::db::lookup::LookupPath; use omicron_nexus::external_api::views::{ self, IdentityProvider, Organization, SamlIdentityProvider, Silo, }; use omicron_nexus::external_api::{params, shared}; + use std::collections::{BTreeMap, HashSet}; use std::fmt::Write; use std::str::FromStr; +use base64::Engine; use http::method::Method; use http::StatusCode; -use nexus_test_utils::resource_helpers::{ - create_local_user, create_organization, create_silo, grant_iam, - object_create, objects_list_page_authz, -}; - -use crate::integration_tests::saml::SAML_IDP_DESCRIPTOR; -use nexus_test_utils_macros::nexus_test; -use omicron_nexus::authz::{self, SiloRole}; -use uuid::Uuid; - use httptest::{matchers::*, responders::*, Expectation, Server}; -use omicron_common::api::external::ObjectIdentity; -use omicron_nexus::authn::{USER_TEST_PRIVILEGED, USER_TEST_UNPRIVILEGED}; -use omicron_nexus::db::fixed_data::silo::{DEFAULT_SILO, SILO_ID}; -use omicron_nexus::db::identity::Asset; +use uuid::Uuid; type ControlPlaneTestContext = nexus_test_utils::ControlPlaneTestContext; @@ -538,7 +538,8 @@ async fn test_saml_idp_metadata_data_valid( }, idp_metadata_source: params::IdpMetadataSource::Base64EncodedXml { - data: base64::encode(SAML_IDP_DESCRIPTOR.to_string()), + data: base64::engine::general_purpose::STANDARD + .encode(SAML_IDP_DESCRIPTOR.to_string()), }, idp_entity_id: "entity_id".to_string(), @@ -602,7 +603,7 @@ async fn test_saml_idp_metadata_data_truncated( }, idp_metadata_source: params::IdpMetadataSource::Base64EncodedXml { - data: base64::encode({ + data: base64::engine::general_purpose::STANDARD.encode({ let mut saml_idp_descriptor = SAML_IDP_DESCRIPTOR.to_string(); saml_idp_descriptor.truncate(100); @@ -1856,7 +1857,8 @@ async fn test_local_silo_constraints(cptestctx: &ControlPlaneTestContext) { idp_metadata_source: params::IdpMetadataSource::Base64EncodedXml { - data: base64::encode(SAML_IDP_DESCRIPTOR.to_string()), + data: base64::engine::general_purpose::STANDARD + .encode(SAML_IDP_DESCRIPTOR.to_string()), }, idp_entity_id: "entity_id".to_string(), diff --git a/nexus/types/src/external_api/params.rs b/nexus/types/src/external_api/params.rs index efcd31f2473..e7722c8ec31 100644 --- a/nexus/types/src/external_api/params.rs +++ b/nexus/types/src/external_api/params.rs @@ -5,6 +5,7 @@ //! Params define the request bodies of API endpoints for creating or updating resources. use crate::external_api::shared; +use base64::Engine; use chrono::{DateTime, Utc}; use omicron_common::api::external::{ ByteCount, IdentityMetadataCreateParams, IdentityMetadataUpdateParams, @@ -297,12 +298,14 @@ impl<'de> Visitor<'de> for X509CertVisitor { where E: de::Error, { - let raw_bytes = base64::decode(&value.as_bytes()).map_err(|e| { - de::Error::custom(format!( - "could not base64 decode public_cert: {}", - e - )) - })?; + let raw_bytes = base64::engine::general_purpose::STANDARD + .decode(&value.as_bytes()) + .map_err(|e| { + de::Error::custom(format!( + "could not base64 decode public_cert: {}", + e + )) + })?; let _parsed = openssl::x509::X509::from_der(&raw_bytes).map_err(|e| { de::Error::custom(format!( @@ -342,12 +345,14 @@ impl<'de> Visitor<'de> for KeyVisitor { where E: de::Error, { - let raw_bytes = base64::decode(&value).map_err(|e| { - de::Error::custom(format!( - "could not base64 decode private_key: {}", - e - )) - })?; + let raw_bytes = base64::engine::general_purpose::STANDARD + .decode(&value) + .map_err(|e| { + de::Error::custom(format!( + "could not base64 decode private_key: {}", + e + )) + })?; // TODO: samael does not support ECDSA, update to generic PKey type when it does //let _parsed = openssl::pkey::PKey::private_key_from_der(&raw_bytes) @@ -423,7 +428,8 @@ pub struct SamlIdentityProviderCreate { /// sign some junk data and validate it with the key pair fn sign_junk_data(key_pair: &DerEncodedKeyPair) -> Result<(), anyhow::Error> { let private_key = { - let raw_bytes = base64::decode(&key_pair.private_key)?; + let raw_bytes = base64::engine::general_purpose::STANDARD + .decode(&key_pair.private_key)?; // TODO: samael does not support ECDSA, update to generic PKey type when it does //let parsed = openssl::pkey::PKey::private_key_from_der(&raw_bytes)?; let parsed = openssl::rsa::Rsa::private_key_from_der(&raw_bytes)?; @@ -432,7 +438,8 @@ fn sign_junk_data(key_pair: &DerEncodedKeyPair) -> Result<(), anyhow::Error> { }; let public_key = { - let raw_bytes = base64::decode(&key_pair.public_cert)?; + let raw_bytes = base64::engine::general_purpose::STANDARD + .decode(&key_pair.public_cert)?; let parsed = openssl::x509::X509::from_der(&raw_bytes)?; parsed.public_key()? }; @@ -708,14 +715,18 @@ impl UserData { where S: Serializer, { - base64::encode(data).serialize(serializer) + base64::engine::general_purpose::STANDARD + .encode(data) + .serialize(serializer) } pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { - match base64::decode(::deserialize(deserializer)?) { + match base64::engine::general_purpose::STANDARD + .decode(::deserialize(deserializer)?) + { Ok(buf) => { // if you change this, also update the stress test in crate::cidata if buf.len() > MAX_USER_DATA_BYTES { diff --git a/package-manifest.toml b/package-manifest.toml index bb030255a87..54ae5e6d31f 100644 --- a/package-manifest.toml +++ b/package-manifest.toml @@ -105,10 +105,10 @@ output.type = "zone" service_name = "propolis-server" source.type = "prebuilt" source.repo = "propolis" -source.commit = "666ded451b13bba0895485c0b34515c0e59c2c6e" +source.commit = "92508d573529a1ee50a9422fbca045a5e980a2b5" # The SHA256 digest is automatically posted to: # https://buildomat.eng.oxide.computer/public/file/oxidecomputer/propolis/image//propolis-server.sha256.txt -source.sha256 = "29b65817eaeb6e9e8f5ce9574f95385ea8f976f352091672a9cde2b2a5103dd3" +source.sha256 = "6fcbff8968addc95e6f7f099f3fc19fe68a4f1192a2aa9f90df2b75f2f94f7da" output.type = "zone" [package.maghemite]