Skip to content
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ arrow-string = "58.4"
as-any = "0.3.2"
async-trait = "0.1.89"
aws-config = "1.8.7"
aws-credential-types = "1.2"
aws-sdk-glue = { version = "1.85", default-features = false, features = [
"default-https-client",
"rt-tokio",
Expand All @@ -70,6 +71,10 @@ aws-sdk-s3tables = { version = "1.28", default-features = false, features = [
"default-https-client",
"rt-tokio",
] }
aws-sigv4 = { version = "1.4", default-features = false, features = [
"sign-http",
"http1",
] }
backon = "1.5.1"
base64 = "0.22.1"
bimap = "0.6"
Expand Down Expand Up @@ -99,6 +104,7 @@ form_urlencoded = "1.2.2"
fs-err = "3.1.0"
futures = "0.3"
hive_metastore = "0.2.0"
hmac = "0.12"
home = "0.5.12"
http = "1.2"
iceberg = { version = "0.10.0", path = "./crates/iceberg" }
Expand Down Expand Up @@ -142,6 +148,7 @@ serde_derive = "1.0.219"
serde_json = "1.0.142"
serde_repr = "0.1.16"
serde_with = "3.4"
sha2 = "0.10"
sqllogictest = "0.29"
sqlx = { version = "0.8.1", default-features = false }
stacker = "0.1.20"
Expand Down
11 changes: 11 additions & 0 deletions crates/catalog/rest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,17 @@ keywords = ["iceberg", "rest", "catalog"]
license = { workspace = true }
repository = { workspace = true }

[features]
default = []
# SigV4 request signing, for catalogs that authenticate the AWS way. Off by
# default so the AWS crates are not pulled in unless they are used.
sigv4 = ["dep:aws-credential-types", "dep:aws-sigv4", "dep:base64", "dep:sha2"]

[dependencies]
async-trait = { workspace = true }
aws-credential-types = { workspace = true, optional = true }
aws-sigv4 = { workspace = true, optional = true }
base64 = { workspace = true, optional = true }
chrono = { workspace = true }
http = { workspace = true }
iceberg = { workspace = true }
Expand All @@ -39,6 +48,7 @@ reqwest = { workspace = true }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
sha2 = { workspace = true, optional = true }
tokio = { workspace = true }
tracing = { workspace = true }
typed-builder = { workspace = true }
Expand All @@ -47,6 +57,7 @@ uuid = { workspace = true, features = ["v4"] }
[dev-dependencies]
bytes = { workspace = true }
futures = { workspace = true }
hmac = { workspace = true }
iceberg_test_utils = { path = "../../test_utils", features = ["tests"] }
mockito = { workspace = true }
# `stream` lets tests build a streaming body to exercise HttpRequestBody::Streaming.
Expand Down
38 changes: 38 additions & 0 deletions crates/catalog/rest/public-api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ impl<'a> core::fmt::Debug for iceberg_catalog_rest::HttpRequestBody<'a>
pub fn iceberg_catalog_rest::HttpRequestBody<'a>::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl<'a> core::marker::Copy for iceberg_catalog_rest::HttpRequestBody<'a>
impl<'a> core::marker::StructuralPartialEq for iceberg_catalog_rest::HttpRequestBody<'a>
pub enum iceberg_catalog_rest::PayloadHashMode
pub iceberg_catalog_rest::PayloadHashMode::IcebergRest
pub iceberg_catalog_rest::PayloadHashMode::StandardAws
impl core::clone::Clone for iceberg_catalog_rest::PayloadHashMode
pub fn iceberg_catalog_rest::PayloadHashMode::clone(&self) -> iceberg_catalog_rest::PayloadHashMode
impl core::cmp::Eq for iceberg_catalog_rest::PayloadHashMode
impl core::cmp::PartialEq for iceberg_catalog_rest::PayloadHashMode
pub fn iceberg_catalog_rest::PayloadHashMode::eq(&self, other: &iceberg_catalog_rest::PayloadHashMode) -> bool
impl core::fmt::Debug for iceberg_catalog_rest::PayloadHashMode
pub fn iceberg_catalog_rest::PayloadHashMode::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl core::marker::Copy for iceberg_catalog_rest::PayloadHashMode
impl core::marker::StructuralPartialEq for iceberg_catalog_rest::PayloadHashMode
pub struct iceberg_catalog_rest::CommitTableRequest
pub iceberg_catalog_rest::CommitTableRequest::identifier: core::option::Option<iceberg::catalog::TableIdent>
pub iceberg_catalog_rest::CommitTableRequest::requirements: alloc::vec::Vec<iceberg::catalog::TableRequirement>
Expand Down Expand Up @@ -331,6 +343,23 @@ impl core::default::Default for iceberg_catalog_rest::RestSessionCatalogBuilder
pub fn iceberg_catalog_rest::RestSessionCatalogBuilder::default() -> Self
impl core::fmt::Debug for iceberg_catalog_rest::RestSessionCatalogBuilder
pub fn iceberg_catalog_rest::RestSessionCatalogBuilder::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub struct iceberg_catalog_rest::SigV4AuthManager
impl iceberg_catalog_rest::SigV4AuthManager
pub async fn iceberg_catalog_rest::SigV4AuthManager::from_properties(delegate: alloc::sync::Arc<dyn iceberg_catalog_rest::AuthManager>, props: &std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> iceberg::error::Result<Self>
pub fn iceberg_catalog_rest::SigV4AuthManager::new(delegate: alloc::sync::Arc<dyn iceberg_catalog_rest::AuthManager>, signer: iceberg_catalog_rest::SigV4Signer, credentials: aws_credential_types::provider::credentials::SharedCredentialsProvider) -> Self
impl core::fmt::Debug for iceberg_catalog_rest::SigV4AuthManager
pub fn iceberg_catalog_rest::SigV4AuthManager::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
impl iceberg_catalog_rest::AuthManager for iceberg_catalog_rest::SigV4AuthManager
pub fn iceberg_catalog_rest::SigV4AuthManager::catalog_session<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, client: &'life1 iceberg_catalog_rest::HttpClient, props: &'life2 std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<alloc::sync::Arc<dyn iceberg_catalog_rest::AuthSession>>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait
pub fn iceberg_catalog_rest::SigV4AuthManager::init_session<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, client: &'life1 iceberg_catalog_rest::HttpClient, props: &'life2 std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<alloc::boxed::Box<dyn iceberg_catalog_rest::AuthSession>>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait
pub struct iceberg_catalog_rest::SigV4Signer
impl iceberg_catalog_rest::SigV4Signer
pub fn iceberg_catalog_rest::SigV4Signer::new(region: alloc::string::String, service: alloc::string::String, mode: iceberg_catalog_rest::PayloadHashMode) -> Self
pub fn iceberg_catalog_rest::SigV4Signer::sign(&self, request: &mut iceberg_catalog_rest::HttpRequest, credentials: &aws_credential_types::credentials_impl::Credentials) -> iceberg::error::Result<()>
impl core::clone::Clone for iceberg_catalog_rest::SigV4Signer
pub fn iceberg_catalog_rest::SigV4Signer::clone(&self) -> iceberg_catalog_rest::SigV4Signer
impl core::fmt::Debug for iceberg_catalog_rest::SigV4Signer
pub fn iceberg_catalog_rest::SigV4Signer::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
pub struct iceberg_catalog_rest::StorageCredential
pub iceberg_catalog_rest::StorageCredential::config: std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>
pub iceberg_catalog_rest::StorageCredential::prefix: alloc::string::String
Expand Down Expand Up @@ -379,10 +408,16 @@ impl<'de> serde_core::de::Deserialize<'de> for iceberg_catalog_rest::UpdateNames
pub fn iceberg_catalog_rest::UpdateNamespacePropertiesResponse::deserialize<__D>(__deserializer: __D) -> core::result::Result<Self, <__D as serde_core::de::Deserializer>::Error> where __D: serde_core::de::Deserializer<'de>
pub const iceberg_catalog_rest::AUTH_TYPE_NONE: &str
pub const iceberg_catalog_rest::AUTH_TYPE_OAUTH2: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_ACCESS_KEY_ID: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_AUTH_TYPE: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_DISABLE_HEADER_REDACTION: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_SECRET_ACCESS_KEY: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_SESSION_TOKEN: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_SIGNING_NAME: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_SIGNING_REGION: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_URI: &str
pub const iceberg_catalog_rest::REST_CATALOG_PROP_WAREHOUSE: &str
pub const iceberg_catalog_rest::SIGNING_NAME_DEFAULT: &str
pub trait iceberg_catalog_rest::AuthManager: core::fmt::Debug + core::marker::Send + core::marker::Sync
pub fn iceberg_catalog_rest::AuthManager::catalog_session<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, client: &'life1 iceberg_catalog_rest::HttpClient, props: &'life2 std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<alloc::sync::Arc<dyn iceberg_catalog_rest::AuthSession>>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait
pub fn iceberg_catalog_rest::AuthManager::init_session<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, client: &'life1 iceberg_catalog_rest::HttpClient, props: &'life2 std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<alloc::boxed::Box<dyn iceberg_catalog_rest::AuthSession>>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait
Expand All @@ -392,5 +427,8 @@ pub fn iceberg_catalog_rest::NoopAuthManager::init_session<'life0, 'life1, 'life
impl iceberg_catalog_rest::AuthManager for iceberg_catalog_rest::OAuth2Manager
pub fn iceberg_catalog_rest::OAuth2Manager::catalog_session<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, client: &'life1 iceberg_catalog_rest::HttpClient, props: &'life2 std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<alloc::sync::Arc<dyn iceberg_catalog_rest::AuthSession>>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait
pub fn iceberg_catalog_rest::OAuth2Manager::init_session<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, client: &'life1 iceberg_catalog_rest::HttpClient, props: &'life2 std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<alloc::boxed::Box<dyn iceberg_catalog_rest::AuthSession>>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait
impl iceberg_catalog_rest::AuthManager for iceberg_catalog_rest::SigV4AuthManager
pub fn iceberg_catalog_rest::SigV4AuthManager::catalog_session<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, client: &'life1 iceberg_catalog_rest::HttpClient, props: &'life2 std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<alloc::sync::Arc<dyn iceberg_catalog_rest::AuthSession>>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait
pub fn iceberg_catalog_rest::SigV4AuthManager::init_session<'life0, 'life1, 'life2, 'async_trait>(&'life0 self, client: &'life1 iceberg_catalog_rest::HttpClient, props: &'life2 std::collections::hash::map::HashMap<alloc::string::String, alloc::string::String>) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<alloc::boxed::Box<dyn iceberg_catalog_rest::AuthSession>>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait
pub trait iceberg_catalog_rest::AuthSession: core::fmt::Debug + core::marker::Send + core::marker::Sync
pub fn iceberg_catalog_rest::AuthSession::authenticate<'life0, 'life1, 'async_trait>(&'life0 self, request: &'life1 mut iceberg_catalog_rest::HttpRequest) -> core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = iceberg::error::Result<()>> + core::marker::Send + 'async_trait)>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait
8 changes: 8 additions & 0 deletions crates/catalog/rest/src/auth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
//! `AuthManager`/`AuthSession` API.

mod oauth2;
#[cfg(feature = "sigv4")]
mod sigv4;

use std::collections::HashMap;
use std::fmt::Debug;
Expand All @@ -27,6 +29,12 @@ use std::sync::Arc;
use async_trait::async_trait;
use iceberg::Result;
pub use oauth2::OAuth2Manager;
#[cfg(feature = "sigv4")]
pub use sigv4::{
PayloadHashMode, REST_CATALOG_PROP_ACCESS_KEY_ID, REST_CATALOG_PROP_SECRET_ACCESS_KEY,
REST_CATALOG_PROP_SESSION_TOKEN, REST_CATALOG_PROP_SIGNING_NAME,
REST_CATALOG_PROP_SIGNING_REGION, SIGNING_NAME_DEFAULT, SigV4AuthManager, SigV4Signer,
};

use crate::client::HttpClient;
use crate::request::HttpRequest;
Expand Down
Loading
Loading