Skip to content

Commit a0e374c

Browse files
committed
feat: Further streamline policy enforcing
1 parent 3d82957 commit a0e374c

82 files changed

Lines changed: 803 additions & 1931 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/keystone/src/api/common.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -223,14 +223,10 @@ pub trait ResourceIdentifier {
223223
#[cfg(test)]
224224
mod tests {
225225
use rstest::rstest;
226-
use sea_orm::DatabaseConnection;
227-
use std::sync::Arc;
228226

229227
use super::*;
230-
228+
use crate::api::tests::get_mocked_state;
231229
use crate::config::Config;
232-
use crate::keystone::Service;
233-
use crate::policy::MockPolicyFactory;
234230
use crate::provider::Provider;
235231
use crate::resource::{MockResourceProvider, types::Domain};
236232

@@ -257,19 +253,12 @@ mod tests {
257253
..Default::default()
258254
}))
259255
});
260-
let provider = Provider::mocked_builder()
261-
.resource(resource_mock)
262-
.build()
263-
.unwrap();
264256

265-
let state = Arc::new(
266-
Service::new(
267-
Config::default(),
268-
DatabaseConnection::Disconnected,
269-
provider,
270-
MockPolicyFactory::new(),
271-
)
272-
.unwrap(),
257+
let state = get_mocked_state(
258+
Provider::mocked_builder().resource(resource_mock),
259+
true,
260+
None,
261+
Some(false),
273262
);
274263

275264
assert_eq!(

crates/keystone/src/api/mod.rs

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -129,72 +129,70 @@ pub(crate) mod tests {
129129
use crate::config::Config;
130130
use crate::identity::types::UserResponseBuilder;
131131
use crate::keystone::{Service, ServiceState};
132-
use crate::policy::{MockPolicy, MockPolicyFactory, PolicyError, PolicyEvaluationResult};
132+
use crate::policy::{MockPolicyEnforcer, PolicyError, PolicyEvaluationResult};
133133
use crate::provider::ProviderBuilder;
134134
use crate::token::{MockTokenProvider, Token, UnscopedPayload};
135135

136136
pub fn get_mocked_state(
137137
provider_builder: ProviderBuilder,
138138
policy_allowed: bool,
139139
policy_allowed_see_other_domains: Option<bool>,
140+
skip_default_token_provider: Option<bool>,
140141
) -> ServiceState {
141-
let mut token_mock = MockTokenProvider::default();
142-
token_mock.expect_validate_token().returning(|_, _, _, _| {
143-
Ok(Token::Unscoped(UnscopedPayload {
144-
user_id: "bar".into(),
145-
user: Some(
146-
UserResponseBuilder::default()
147-
.id("bar")
148-
.domain_id("udid")
149-
.enabled(true)
150-
.name("name")
151-
.build()
152-
.unwrap(),
153-
),
154-
..Default::default()
155-
}))
156-
});
157-
token_mock
158-
.expect_expand_token_information()
159-
.returning(|_, _| {
142+
let provider = if !skip_default_token_provider.is_some_and(|x| x) {
143+
let mut token_mock = MockTokenProvider::default();
144+
token_mock.expect_validate_token().returning(|_, _, _, _| {
160145
Ok(Token::Unscoped(UnscopedPayload {
161146
user_id: "bar".into(),
147+
user: Some(
148+
UserResponseBuilder::default()
149+
.id("bar")
150+
.domain_id("udid")
151+
.enabled(true)
152+
.name("name")
153+
.build()
154+
.unwrap(),
155+
),
162156
..Default::default()
163157
}))
164158
});
159+
token_mock
160+
.expect_expand_token_information()
161+
.returning(|_, _| {
162+
Ok(Token::Unscoped(UnscopedPayload {
163+
user_id: "bar".into(),
164+
..Default::default()
165+
}))
166+
});
167+
provider_builder.token(token_mock)
168+
} else {
169+
provider_builder
170+
}
171+
.build()
172+
.unwrap();
165173

166-
let provider = provider_builder.token(token_mock).build().unwrap();
174+
let mut policy_enforcer_mock = MockPolicyEnforcer::default();
167175

168-
let mut policy_factory_mock = MockPolicyFactory::default();
169-
if policy_allowed {
170-
policy_factory_mock.expect_instantiate().returning(move || {
171-
let mut policy_mock = MockPolicy::default();
172-
if policy_allowed_see_other_domains.is_some_and(|x| x) {
173-
policy_mock
174-
.expect_enforce()
175-
.returning(|_, _, _, _| Ok(PolicyEvaluationResult::allowed_admin()));
176+
policy_enforcer_mock
177+
.expect_enforce()
178+
.returning(move |_, _, _, _| {
179+
if policy_allowed {
180+
if policy_allowed_see_other_domains.is_some_and(|x| x) {
181+
Ok(PolicyEvaluationResult::allowed_admin())
182+
} else {
183+
Ok(PolicyEvaluationResult::allowed())
184+
}
176185
} else {
177-
policy_mock
178-
.expect_enforce()
179-
.returning(|_, _, _, _| Ok(PolicyEvaluationResult::allowed()));
180-
}
181-
Ok(policy_mock)
182-
});
183-
} else {
184-
policy_factory_mock.expect_instantiate().returning(|| {
185-
let mut policy_mock = MockPolicy::default();
186-
policy_mock.expect_enforce().returning(|_, _, _, _| {
187186
Err(PolicyError::Forbidden(PolicyEvaluationResult::forbidden()))
188-
});
189-
Ok(policy_mock)
187+
}
190188
});
191-
}
189+
192190
Arc::new(
193191
Service::new(
194192
Config::default(),
195193
DatabaseConnection::Disconnected,
196194
provider,
197-
policy_factory_mock,
195+
policy_enforcer_mock,
198196
)
199197
.unwrap(),
200198
)

crates/keystone/src/api/v3/auth/project/list.rs

Lines changed: 6 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
//! Get available project scopes.
1515
1616
use axum::{extract::State, response::IntoResponse};
17-
use mockall_double::double;
1817
use serde_json::Value;
1918
use std::collections::HashSet;
2019

@@ -25,8 +24,6 @@ use crate::assignment::{
2524
types::{AssignmentType, RoleAssignmentListParameters},
2625
};
2726
use crate::keystone::ServiceState;
28-
#[double]
29-
use crate::policy::Policy;
3027
use crate::resource::{ResourceApi, types::ProjectListParameters};
3128

3229
/// Get available project scopes.
@@ -44,14 +41,14 @@ use crate::resource::{ResourceApi, types::ProjectListParameters};
4441
#[tracing::instrument(
4542
name = "api::v3::auth::project::list",
4643
level = "debug",
47-
skip(state, user_auth, policy)
44+
skip(state, user_auth)
4845
)]
4946
pub(super) async fn list(
5047
Auth(user_auth): Auth,
51-
policy: Policy,
5248
State(state): State<ServiceState>,
5349
) -> Result<impl IntoResponse, KeystoneApiError> {
54-
policy
50+
state
51+
.policy_enforcer
5552
.enforce("identity/auth/project/list", &user_auth, Value::Null, None)
5653
.await?;
5754

@@ -105,78 +102,22 @@ mod tests {
105102
http::{Request, StatusCode},
106103
};
107104
use http_body_util::BodyExt; // for `collect`
108-
use sea_orm::DatabaseConnection;
109105
use std::collections::HashSet;
110-
use std::sync::Arc;
111106
use tower::ServiceExt; // for `call`, `oneshot`, and `ready`
112107
use tower_http::trace::TraceLayer;
113108

109+
use crate::api::tests::get_mocked_state;
114110
use crate::api::v3::project::types::ProjectShort;
115111
use crate::assignment::{MockAssignmentProvider, types::*};
116-
use crate::config::Config;
117-
use crate::keystone::{Service, ServiceState};
118-
use crate::policy::{MockPolicy, MockPolicyFactory, PolicyError, PolicyEvaluationResult};
119-
use crate::provider::{Provider, ProviderBuilder};
112+
use crate::provider::Provider;
120113
use crate::resource::{
121114
MockResourceProvider,
122115
types::{Project as ProviderProject, ProjectListParameters},
123116
};
124-
use crate::token::{MockTokenProvider, Token, UnscopedPayload};
125117

126118
use super::super::openapi_router;
127119
use super::*;
128120

129-
pub(super) fn get_mocked_state(
130-
provider_builder: ProviderBuilder,
131-
policy_allowed: bool,
132-
) -> ServiceState {
133-
let mut token_mock = MockTokenProvider::default();
134-
token_mock.expect_validate_token().returning(|_, _, _, _| {
135-
Ok(Token::Unscoped(UnscopedPayload {
136-
user_id: "bar".into(),
137-
..Default::default()
138-
}))
139-
});
140-
token_mock
141-
.expect_expand_token_information()
142-
.returning(|_, _| {
143-
Ok(Token::Unscoped(UnscopedPayload {
144-
user_id: "bar".into(),
145-
..Default::default()
146-
}))
147-
});
148-
149-
let provider = provider_builder.token(token_mock).build().unwrap();
150-
151-
let mut policy_factory_mock = MockPolicyFactory::default();
152-
if policy_allowed {
153-
policy_factory_mock.expect_instantiate().returning(move || {
154-
let mut policy_mock = MockPolicy::default();
155-
policy_mock
156-
.expect_enforce()
157-
.returning(|_, _, _, _| Ok(PolicyEvaluationResult::allowed()));
158-
Ok(policy_mock)
159-
});
160-
} else {
161-
policy_factory_mock.expect_instantiate().returning(|| {
162-
let mut policy_mock = MockPolicy::default();
163-
policy_mock.expect_enforce().returning(|_, _, _, _| {
164-
Err(PolicyError::Forbidden(PolicyEvaluationResult::forbidden()))
165-
});
166-
Ok(policy_mock)
167-
});
168-
}
169-
Arc::new(
170-
Service::new(
171-
Config::default(),
172-
DatabaseConnection::Disconnected,
173-
provider,
174-
policy_factory_mock,
175-
)
176-
.unwrap(),
177-
)
178-
}
179-
180121
#[tokio::test]
181122
async fn test_list() {
182123
let mut assignment_mock = MockAssignmentProvider::default();
@@ -255,7 +196,7 @@ mod tests {
255196
let provider_builder = Provider::mocked_builder()
256197
.assignment(assignment_mock)
257198
.resource(resource_mock);
258-
let state = get_mocked_state(provider_builder, true);
199+
let state = get_mocked_state(provider_builder, true, None, None);
259200

260201
let mut api = openapi_router()
261202
.layer(TraceLayer::new_for_http())

crates/keystone/src/api/v3/auth/token/common.rs

Lines changed: 8 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -142,29 +142,21 @@ pub(super) async fn get_authz_info(
142142

143143
#[cfg(test)]
144144
mod tests {
145-
use sea_orm::DatabaseConnection;
146-
use std::sync::Arc;
147145

146+
use super::super::types::*;
147+
use super::*;
148148
use crate::api::KeystoneApiError;
149-
149+
use crate::api::tests::get_mocked_state;
150150
use crate::auth::AuthenticatedInfo;
151-
use crate::config::Config;
152151
use crate::identity::{
153152
MockIdentityProvider,
154153
types::{UserPasswordAuthRequest, UserResponseBuilder},
155154
};
156-
use crate::keystone::Service;
157-
use crate::policy::MockPolicyFactory;
158155
use crate::provider::Provider;
159-
160156
use crate::token::MockTokenProvider;
161157

162-
use super::super::types::*;
163-
use super::*;
164-
165158
#[tokio::test]
166159
async fn test_authenticate_request_password() {
167-
let config = Config::default();
168160
let auth_info = AuthenticatedInfo::builder()
169161
.user_id("uid")
170162
.user(
@@ -189,21 +181,9 @@ mod tests {
189181
})
190182
.returning(move |_, _| Ok(auth_clone.clone()));
191183

192-
let provider = Provider::mocked_builder()
193-
.config(config.clone())
194-
.identity(identity_mock)
195-
.build()
196-
.unwrap();
184+
let provider = Provider::mocked_builder().identity(identity_mock);
197185

198-
let state = Arc::new(
199-
Service::new(
200-
config,
201-
DatabaseConnection::Disconnected,
202-
provider,
203-
MockPolicyFactory::new(),
204-
)
205-
.unwrap(),
206-
);
186+
let state = get_mocked_state(provider, true, None, None);
207187

208188
assert_eq!(
209189
auth_info,
@@ -234,8 +214,6 @@ mod tests {
234214

235215
#[tokio::test]
236216
async fn test_authenticate_request_token() {
237-
let config = Config::default();
238-
239217
let mut token_mock = MockTokenProvider::default();
240218
token_mock
241219
.expect_authenticate_by_token()
@@ -264,21 +242,10 @@ mod tests {
264242
});
265243

266244
let provider = Provider::mocked_builder()
267-
.config(config.clone())
268245
.identity(identity_mock)
269-
.token(token_mock)
270-
.build()
271-
.unwrap();
246+
.token(token_mock);
272247

273-
let state = Arc::new(
274-
Service::new(
275-
config,
276-
DatabaseConnection::Disconnected,
277-
provider,
278-
MockPolicyFactory::new(),
279-
)
280-
.unwrap(),
281-
);
248+
let state = get_mocked_state(provider, true, None, Some(true));
282249

283250
assert_eq!(
284251
AuthenticatedInfo::builder()
@@ -316,22 +283,7 @@ mod tests {
316283

317284
#[tokio::test]
318285
async fn test_authenticate_request_unsupported() {
319-
let config = Config::default();
320-
321-
let provider = Provider::mocked_builder()
322-
.config(config.clone())
323-
.build()
324-
.unwrap();
325-
326-
let state = Arc::new(
327-
Service::new(
328-
config,
329-
DatabaseConnection::Disconnected,
330-
provider,
331-
MockPolicyFactory::new(),
332-
)
333-
.unwrap(),
334-
);
286+
let state = get_mocked_state(Provider::mocked_builder(), true, None, Some(true));
335287

336288
let rsp = authenticate_request(
337289
&state,

0 commit comments

Comments
 (0)