mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-24 00:52:24 +00:00
refactor(rust): split auth facade from shared types
This commit is contained in:
parent
6814373a48
commit
3fd2dd635b
22 changed files with 172 additions and 104 deletions
26
litellm-rust/Cargo.lock
generated
26
litellm-rust/Cargo.lock
generated
|
|
@ -1976,11 +1976,10 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
|||
name = "litellm-auth"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"subtle",
|
||||
"thiserror 2.0.19",
|
||||
"tokio",
|
||||
"veil",
|
||||
"litellm-auth-aws",
|
||||
"litellm-auth-azure",
|
||||
"litellm-auth-gcp",
|
||||
"litellm-auth-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1993,7 +1992,7 @@ dependencies = [
|
|||
"aws-sigv4",
|
||||
"aws-smithy-runtime-api",
|
||||
"aws-types",
|
||||
"litellm-auth",
|
||||
"litellm-auth-types",
|
||||
"litellm-http",
|
||||
"moka",
|
||||
"reqwest 0.12.28",
|
||||
|
|
@ -2009,7 +2008,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"azure_core",
|
||||
"azure_identity",
|
||||
"litellm-auth",
|
||||
"litellm-auth-types",
|
||||
"moka",
|
||||
"rstest",
|
||||
"serde_json",
|
||||
|
|
@ -2024,13 +2023,24 @@ name = "litellm-auth-gcp"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gcp_auth",
|
||||
"litellm-auth",
|
||||
"litellm-auth-types",
|
||||
"moka",
|
||||
"serde_json",
|
||||
"sha2 0.10.9",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "litellm-auth-types"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"subtle",
|
||||
"thiserror 2.0.19",
|
||||
"tokio",
|
||||
"veil",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "litellm-cache"
|
||||
version = "0.1.0"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ litellm-host = { path = "crates/host" }
|
|||
litellm-callbacks-legacy-python = { path = "crates/callbacks-legacy-python" }
|
||||
litellm-framing = { path = "crates/framer" }
|
||||
litellm-auth = { path = "crates/auth" }
|
||||
litellm-auth-types = { path = "crates/auth-types" }
|
||||
litellm-auth-aws = { path = "crates/auth-aws" }
|
||||
litellm-auth-azure = { path = "crates/auth-azure" }
|
||||
litellm-auth-gcp = { path = "crates/auth-gcp" }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ license.workspace = true
|
|||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
litellm-auth.workspace = true
|
||||
litellm-auth-types.workspace = true
|
||||
litellm-http.workspace = true
|
||||
|
||||
moka = { workspace = true, features = ["sync"] }
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub enum Error {
|
|||
AwsMissingWebIdentityCredentials,
|
||||
}
|
||||
|
||||
impl From<Error> for litellm_auth::Error {
|
||||
impl From<Error> for litellm_auth_types::Error {
|
||||
fn from(error: Error) -> Self {
|
||||
Self::ProviderAuthentication(error.to_string())
|
||||
}
|
||||
|
|
@ -34,11 +34,11 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn converts_to_shared_auth_error_without_losing_context() {
|
||||
let error = litellm_auth::Error::from(Error::AwsProfile("profile not found".into()));
|
||||
let error = litellm_auth_types::Error::from(Error::AwsProfile("profile not found".into()));
|
||||
|
||||
assert_eq!(
|
||||
error,
|
||||
litellm_auth::Error::ProviderAuthentication(
|
||||
litellm_auth_types::Error::ProviderAuthentication(
|
||||
"AWS profile credentials failed: profile not found".into()
|
||||
)
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ license.workspace = true
|
|||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
litellm-auth.workspace = true
|
||||
litellm-auth-types.workspace = true
|
||||
|
||||
moka.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||
use azure_core::credentials::TokenCredential;
|
||||
use moka::future::Cache;
|
||||
|
||||
use litellm_auth::Error;
|
||||
use litellm_auth_types::Error;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct AzureCredentialProviderCacheKey {
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ use azure_identity::{
|
|||
};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use litellm_auth::Error;
|
||||
use litellm_auth::{InputSource, ResolvedCredential, SecretValue, Sourced};
|
||||
use litellm_auth_types::Error;
|
||||
use litellm_auth_types::{InputSource, ResolvedCredential, SecretValue, Sourced};
|
||||
|
||||
use super::credential_provider_cache::{
|
||||
AzureCredentialProviderCache, AzureCredentialProviderCacheKey,
|
||||
|
|
@ -484,7 +484,7 @@ mod tests {
|
|||
use azure_core::{Bytes, Result};
|
||||
|
||||
use super::{NativeAzureRequest, NativeAzureTokenAcquirer, ValidatedAzureRequest};
|
||||
use litellm_auth::{InputSource, SecretValue, Sourced};
|
||||
use litellm_auth_types::{InputSource, SecretValue, Sourced};
|
||||
|
||||
fn deployment<T>(value: T) -> Sourced<T> {
|
||||
Sourced::new(value, InputSource::Deployment)
|
||||
|
|
@ -649,7 +649,7 @@ mod tests {
|
|||
|
||||
assert!(matches!(
|
||||
error,
|
||||
litellm_auth::Error::MixedAzureCredentialSources
|
||||
litellm_auth_types::Error::MixedAzureCredentialSources
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -679,7 +679,10 @@ mod tests {
|
|||
authority,
|
||||
))
|
||||
.unwrap_err();
|
||||
assert!(matches!(error, litellm_auth::Error::InvalidAzureAuthority));
|
||||
assert!(matches!(
|
||||
error,
|
||||
litellm_auth_types::Error::InvalidAzureAuthority
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use litellm_auth::Error;
|
||||
use litellm_auth::{
|
||||
use litellm_auth_types::Error;
|
||||
use litellm_auth_types::{
|
||||
CredentialFileRef, CredentialLookup, CredentialRef, InputSource, ResolvedCredential,
|
||||
SecretValue, Sourced, TokenProviderHandle,
|
||||
};
|
||||
|
|
@ -451,9 +451,9 @@ mod tests {
|
|||
};
|
||||
use crate::native::ValidatedAzureRequest;
|
||||
use crate::types::AzureAuthInputs;
|
||||
use litellm_auth::Error;
|
||||
use litellm_auth::ResolvedCredential;
|
||||
use litellm_auth::{
|
||||
use litellm_auth_types::Error;
|
||||
use litellm_auth_types::ResolvedCredential;
|
||||
use litellm_auth_types::{
|
||||
CredentialFileRef, CredentialLookup, CredentialLookupFuture, CredentialRef,
|
||||
CredentialResolver, CredentialResolverHandle, InputSource, SecretValue, Sourced,
|
||||
};
|
||||
|
|
@ -661,8 +661,8 @@ mod tests {
|
|||
#[derive(Debug)]
|
||||
struct CallerToken(&'static str);
|
||||
|
||||
impl litellm_auth::TokenProvider for CallerToken {
|
||||
fn acquire(&self) -> litellm_auth::TokenFuture<'_> {
|
||||
impl litellm_auth_types::TokenProvider for CallerToken {
|
||||
fn acquire(&self) -> litellm_auth_types::TokenFuture<'_> {
|
||||
Box::pin(async move {
|
||||
Ok(ResolvedCredential::AccessToken {
|
||||
token: SecretValue::new(self.0),
|
||||
|
|
@ -675,7 +675,7 @@ mod tests {
|
|||
fn caller_inputs(token: &'static str) -> AzureAuthInputs {
|
||||
let params = json!({"azure_ad_token": "static-token"});
|
||||
AzureAuthInputs {
|
||||
azure_ad_token_provider: Some(litellm_auth::TokenProviderHandle::new(Arc::new(
|
||||
azure_ad_token_provider: Some(litellm_auth_types::TokenProviderHandle::new(Arc::new(
|
||||
CallerToken(token),
|
||||
))),
|
||||
..AzureAuthInputs::from_optional_params(params.as_object().unwrap()).unwrap()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use litellm_auth::{
|
||||
use litellm_auth_types::{
|
||||
CredentialResolverHandle, Error, InputSource, SecretValue, Sourced, TokenProviderHandle,
|
||||
};
|
||||
use serde_json::{Map, Value};
|
||||
|
|
@ -126,7 +126,7 @@ fn source_for(sources: &BTreeMap<String, InputSource>, name: &str) -> InputSourc
|
|||
mod tests {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use litellm_auth::{InputSource, Sourced};
|
||||
use litellm_auth_types::{InputSource, Sourced};
|
||||
use serde_json::json;
|
||||
|
||||
use super::{AzureAuthInputs, AzureCredentialType, ConfigValue};
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ license.workspace = true
|
|||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
litellm-auth.workspace = true
|
||||
litellm-auth-types.workspace = true
|
||||
|
||||
moka.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::BTreeMap, future::Future, path::Path, pin::Pin, sync::Arc};
|
||||
|
||||
use gcp_auth::{CustomServiceAccount, TokenProvider};
|
||||
use litellm_auth::{
|
||||
use litellm_auth_types::{
|
||||
CredentialPlacement, Error, InputSource, SecretValue, Sourced, http::apply_credential,
|
||||
};
|
||||
use moka::future::Cache;
|
||||
|
|
|
|||
15
litellm-rust/crates/auth-types/Cargo.toml
Normal file
15
litellm-rust/crates/auth-types/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "litellm-auth-types"
|
||||
version = "0.1.0"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde.workspace = true
|
||||
subtle.workspace = true
|
||||
thiserror.workspace = true
|
||||
veil.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tokio.workspace = true
|
||||
|
|
@ -5,9 +5,7 @@ use std::sync::Arc;
|
|||
|
||||
use veil::Redact;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::{ResolvedCredential, SecretValue, TokenProviderHandle};
|
||||
use crate::{Error, ResolvedCredential, SecretValue, TokenProviderHandle};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum CredentialFileRef {
|
||||
|
|
@ -40,9 +40,6 @@ pub fn apply_credential(
|
|||
)
|
||||
}
|
||||
|
||||
/// How the upstream call is authenticated. API-key strategies become headers
|
||||
/// in `prepare`; SigV4 covers the serialized body, so it is applied where the
|
||||
/// outbound request is built.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum RequestAuth {
|
||||
Header {
|
||||
57
litellm-rust/crates/auth-types/src/lib.rs
Normal file
57
litellm-rust/crates/auth-types/src/lib.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#![forbid(unsafe_code)]
|
||||
|
||||
mod credential;
|
||||
mod error;
|
||||
pub mod http;
|
||||
mod policy;
|
||||
mod secret;
|
||||
mod token;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InputSource {
|
||||
Request,
|
||||
#[default]
|
||||
Deployment,
|
||||
Environment,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct Sourced<T> {
|
||||
value: T,
|
||||
source: InputSource,
|
||||
}
|
||||
|
||||
impl<T> Sourced<T> {
|
||||
pub fn new(value: T, source: InputSource) -> Self {
|
||||
Self { value, source }
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &T {
|
||||
&self.value
|
||||
}
|
||||
|
||||
pub fn source(&self) -> InputSource {
|
||||
self.source
|
||||
}
|
||||
|
||||
pub fn into_value(self) -> T {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn map<U>(self, map: impl FnOnce(T) -> U) -> Sourced<U> {
|
||||
Sourced::new(map(self.value), self.source)
|
||||
}
|
||||
}
|
||||
|
||||
pub use credential::{
|
||||
CredentialFileRef, CredentialLookup, CredentialLookupFuture, CredentialPlan,
|
||||
CredentialPlanResolution, CredentialRef, CredentialResolver, CredentialResolverHandle,
|
||||
};
|
||||
pub use error::Error;
|
||||
pub use http::{CredentialPlacement, RequestAuth};
|
||||
pub use policy::{CredentialPlanKind, CredentialRule, ExistingHeaderBehavior, ProviderAuthPolicy};
|
||||
pub use secret::SecretValue;
|
||||
pub use token::{ResolvedCredential, TokenFuture, TokenProvider, TokenProviderHandle};
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
use crate::Error;
|
||||
|
||||
use super::http::apply_credential;
|
||||
use super::{CredentialPlacement, ResolvedCredential};
|
||||
use crate::http::apply_credential;
|
||||
use crate::{CredentialPlacement, Error, ResolvedCredential};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum CredentialPlanKind {
|
||||
|
|
@ -5,9 +5,7 @@ use std::time::SystemTime;
|
|||
|
||||
use veil::Redact;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
use super::secret::SecretValue;
|
||||
use crate::{Error, SecretValue};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ResolvedCredential {
|
||||
|
|
@ -5,11 +5,14 @@ edition.workspace = true
|
|||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
serde.workspace = true
|
||||
subtle.workspace = true
|
||||
thiserror.workspace = true
|
||||
veil.workspace = true
|
||||
[features]
|
||||
default = []
|
||||
aws = ["dep:litellm-auth-aws"]
|
||||
azure = ["dep:litellm-auth-azure"]
|
||||
gcp = ["dep:litellm-auth-gcp"]
|
||||
|
||||
[dev-dependencies]
|
||||
tokio.workspace = true
|
||||
[dependencies]
|
||||
litellm-auth-types.workspace = true
|
||||
litellm-auth-aws = { workspace = true, optional = true }
|
||||
litellm-auth-azure = { workspace = true, optional = true }
|
||||
litellm-auth-gcp = { workspace = true, optional = true }
|
||||
|
|
|
|||
|
|
@ -1,55 +1,10 @@
|
|||
mod credential;
|
||||
mod error;
|
||||
pub mod http;
|
||||
mod policy;
|
||||
mod secret;
|
||||
mod token;
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use litellm_auth_types::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InputSource {
|
||||
Request,
|
||||
#[default]
|
||||
Deployment,
|
||||
Environment,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub struct Sourced<T> {
|
||||
value: T,
|
||||
source: InputSource,
|
||||
}
|
||||
|
||||
impl<T> Sourced<T> {
|
||||
pub fn new(value: T, source: InputSource) -> Self {
|
||||
Self { value, source }
|
||||
}
|
||||
|
||||
pub fn value(&self) -> &T {
|
||||
&self.value
|
||||
}
|
||||
|
||||
pub fn source(&self) -> InputSource {
|
||||
self.source
|
||||
}
|
||||
|
||||
pub fn into_value(self) -> T {
|
||||
self.value
|
||||
}
|
||||
|
||||
pub fn map<U>(self, map: impl FnOnce(T) -> U) -> Sourced<U> {
|
||||
Sourced::new(map(self.value), self.source)
|
||||
}
|
||||
}
|
||||
|
||||
pub use credential::{
|
||||
CredentialFileRef, CredentialLookup, CredentialLookupFuture, CredentialPlan,
|
||||
CredentialPlanResolution, CredentialRef, CredentialResolver, CredentialResolverHandle,
|
||||
};
|
||||
pub use error::Error;
|
||||
pub use http::{CredentialPlacement, RequestAuth};
|
||||
pub use policy::{CredentialPlanKind, CredentialRule, ExistingHeaderBehavior, ProviderAuthPolicy};
|
||||
pub use secret::SecretValue;
|
||||
pub use token::{ResolvedCredential, TokenFuture, TokenProvider, TokenProviderHandle};
|
||||
#[cfg(feature = "aws")]
|
||||
pub use litellm_auth_aws as aws;
|
||||
#[cfg(feature = "azure")]
|
||||
pub use litellm_auth_azure as azure;
|
||||
#[cfg(feature = "gcp")]
|
||||
pub use litellm_auth_gcp as gcp;
|
||||
|
|
|
|||
33
litellm-rust/crates/auth/tests/facade.rs
Normal file
33
litellm-rust/crates/auth/tests/facade.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use litellm_auth::{
|
||||
CredentialPlacement, CredentialPlanKind, CredentialRule, ExistingHeaderBehavior,
|
||||
ProviderAuthPolicy, ResolvedCredential, SecretValue,
|
||||
};
|
||||
|
||||
const RULES: &[CredentialRule] = &[CredentialRule {
|
||||
kind: CredentialPlanKind::Static,
|
||||
placement: CredentialPlacement::Header("x-api-key"),
|
||||
}];
|
||||
|
||||
#[test]
|
||||
fn facade_applies_shared_auth_policy() {
|
||||
let policy = ProviderAuthPolicy {
|
||||
rules: RULES,
|
||||
accepted_existing_headers: &["x-api-key"],
|
||||
existing_header_behavior: ExistingHeaderBehavior::Preserve,
|
||||
scope: None,
|
||||
audience: None,
|
||||
};
|
||||
|
||||
let headers = policy
|
||||
.apply(
|
||||
Vec::new(),
|
||||
CredentialPlanKind::Static,
|
||||
&ResolvedCredential::Static(SecretValue::new("secret")),
|
||||
)
|
||||
.expect("facade policy applies");
|
||||
|
||||
assert_eq!(
|
||||
headers,
|
||||
vec![("x-api-key".to_string(), "secret".to_string())]
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue