Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions openstack_sdk/src/openstack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use openstack_sdk_core::auth::{
gather_auth_data,
};
use openstack_sdk_core::catalog::{CatalogError, ServiceEndpoint};
use openstack_sdk_core::config::{CloudConfig, ConfigFile};
use openstack_sdk_core::config::CloudConfig;
use openstack_sdk_core::error::{OpenStackError, OpenStackResult, RestError};
use openstack_sdk_core::types::{ApiVersion, ServiceType};
use openstack_sdk_core::utils::expand_tilde;
Expand Down Expand Up @@ -219,10 +219,8 @@ impl OpenStack {
client_builder = client_builder.danger_accept_invalid_certs(true);
}

let auth_cache = ConfigFile::new()
.ok()
.is_some_and(|c| c.is_auth_cache_enabled());
let session_ctx = session::SessionContext::new(config, auth, auth_cache)?;
// Pass CloudConfig.auth_cache as override; SessionContext resolves priority chain.
let session_ctx = session::SessionContext::new(config, auth, config.auth_cache)?;

Ok(OpenStack {
client: client_builder.build()?,
Expand Down Expand Up @@ -323,6 +321,18 @@ impl OpenStack {
self
}

/// Disable authentication caching for this session.
///
/// Clears any cached tokens and prevents further caching — both the
/// in-memory store and the on-disk state file. Useful for scenarios
/// requiring fresh authentication on every request.
pub fn disable_auth_cache(&self) -> &Self {
if let Ok(mut session) = self.session.write() {
session.state.disable_auth_cache();
}
self
}

pub fn authorize_with_auth_helper<A>(
&self,
scope: Option<AuthTokenScope>,
Expand Down
20 changes: 15 additions & 5 deletions openstack_sdk/src/openstack_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ use openstack_sdk_core::auth::{
gather_auth_data,
};
use openstack_sdk_core::catalog::{CatalogError, ServiceEndpoint};
use openstack_sdk_core::config::{CloudConfig, ConfigFile};
use openstack_sdk_core::config::CloudConfig;
use openstack_sdk_core::error::{OpenStackError, OpenStackResult, RestError};
use openstack_sdk_core::types::{ApiVersion, BoxedAsyncRead, ServiceType};
use openstack_sdk_core::utils::expand_tilde;
Expand Down Expand Up @@ -351,10 +351,8 @@ impl AsyncOpenStack {
client_builder = client_builder.gzip(true);
client_builder = client_builder.deflate(true);

let auth_cache = ConfigFile::new()
.ok()
.is_some_and(|c| c.is_auth_cache_enabled());
let session_ctx = session::SessionContext::new(config, auth, auth_cache)?;
// Pass CloudConfig.auth_cache as override; SessionContext resolves priority chain.
let session_ctx = session::SessionContext::new(config, auth, config.auth_cache)?;

Ok(AsyncOpenStack {
client: client_builder.build()?,
Expand Down Expand Up @@ -504,6 +502,18 @@ impl AsyncOpenStack {
Ok(())
}

/// Disable authentication caching for this session.
///
/// Clears any cached tokens and prevents further caching — both the
/// in-memory store and the on-disk state file. Useful for scenarios
/// requiring fresh authentication on every request.
pub fn disable_auth_cache(&self) -> &Self {
if let Ok(mut session) = self.session.write() {
session.state.disable_auth_cache();
}
self
}

/// Authorize against the cloud using provided credentials and get the session token with the
/// auth helper that may be invoked to interactively ask for the credentials.
pub async fn authorize_with_auth_helper<A>(
Expand Down
7 changes: 7 additions & 0 deletions sdk/core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,13 @@ pub struct CloudConfig {
/// Verify SSL Certificates.
pub verify: Option<bool>,

/// Override for authentication caching.
///
/// If `Some(true)`, enables; if `Some(false)`, disables.
/// If `None`, falls back to the global `cache.auth` setting in the
/// `clouds.yaml` ConfigFile (default: `true`).
pub auth_cache: Option<bool>,

/// Catch-all for additional configuration fields not explicitly typed.
/// Any extra YAML keys at this level are captured here.
#[serde(flatten)]
Expand Down
22 changes: 20 additions & 2 deletions sdk/core/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

use crate::auth::Auth;
use crate::catalog::Catalog;
use crate::config::{CloudConfig, ConfigFile, get_config_identity_hash};
use crate::state::State;

use crate::config::{CloudConfig, get_config_identity_hash};
use crate::error::OpenStackError;

use openstack_sdk_auth_core::authtoken::AuthTokenError;
Expand All @@ -39,10 +39,14 @@ impl SessionContext {
///
/// This is shared between sync and async clients — the ~30 lines of
/// catalog/state initialization are identical.
///
/// The `auth_cache` parameter is the session-level override. When `None`,
/// the CloudConfig's `auth_cache` field is checked, then the global
/// `ConfigFile` fallback, then defaults to `true`.
pub fn new(
config: &CloudConfig,
auth: Auth,
auth_cache_enabled: bool,
auth_cache: Option<bool>,
) -> Result<Self, OpenStackError> {
let mut catalog = Catalog::default();

Expand All @@ -65,6 +69,20 @@ impl SessionContext {

catalog.configure(config)?;

// Resolve auth cache priority:
// 1. explicit parameter override
// 2. CloudConfig.auth_cache
// 3. ConfigFile.cache.auth
// 4. default true
let auth_cache_enabled = auth_cache
.or(config.auth_cache)
.or_else(|| {
ConfigFile::new()
.ok()
.and_then(|cf| cf.cache.as_ref().and_then(|c| c.auth))
})
.unwrap_or(true);

let mut state = State::new();
state
.set_auth_hash_key(get_config_identity_hash(config))
Expand Down
11 changes: 11 additions & 0 deletions sdk/core/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ impl State {
self
}

/// Disable all authorization caching (in-memory and on-disk).
///
/// When disabled, `get_scope_auth()` and `get_any_valid_auth()` will
/// always return `None`, and `set_scope_auth()` will skip both the
/// in-memory store and file persistence.
pub fn disable_auth_cache(&mut self) -> &mut Self {
self.auth_cache_enabled = false;
self.auth_state.0.clear();
self
}

/// Set authz into the state
pub fn set_scope_auth(&mut self, scope: &AuthTokenScope, authz: &AuthToken) {
self.auth_state.filter_invalid_auths();
Expand Down
Loading