Skip to content

Commit ba499de

Browse files
authored
feat: Implement trust token validation (#484)
1 parent 88a15da commit ba499de

File tree

65 files changed

+2342
-440
lines changed

Some content is hidden

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

65 files changed

+2342
-440
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Python Keystone service in place for existing users and workflows.
2020
As development progressed, however, the breadth of new functionality (and the
2121
opportunity to revisit some of the existing limitations) led to a partial
2222
re-implementation of certain core identity flows in Rust. This allows us to
23-
benefit from Rusts memory safety, concurrency model, performance, and modern
23+
benefit from Rust's memory safety, concurrency model, performance, and modern
2424
tooling, while still preserving the upstream Keystone Python service as the
2525
canonical “master” identity service, routing only the new endpoints and
2626
capabilities through the Rust component.
@@ -58,7 +58,7 @@ the trusted, mature baseline and incrementally build the “Keystone-NG” Rust
5858
service as the complement.
5959

6060
We believe this approach allows the best of both worlds: the trusted maturity
61-
of Keystones Python code-base, combined with the modern, high-safety,
61+
of Keystone's Python code-base, combined with the modern, high-safety,
6262
high-performance capabilities of Rust where they matter most.
6363

6464
## Documentation

doc/src/intro.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Keystone service in place for existing users and workflows.
2020
As development progressed, however, the breadth of new functionality (and the
2121
opportunity to revisit some of the existing limitations) led to a partial
2222
re-implementation of certain core identity flows in Rust. This allows us to
23-
benefit from Rusts memory safety, concurrency model, performance, and modern
23+
benefit from Rust's memory safety, concurrency model, performance, and modern
2424
tooling, while still preserving the upstream Keystone Python service as the
2525
canonical “master” identity service, routing only the new endpoints and
2626
capabilities through the Rust component.
@@ -57,7 +57,7 @@ trusted, mature baseline and incrementally build the “Keystone-NG” Rust serv
5757
as the complement.
5858

5959
We believe this approach allows the best of both worlds: the trusted maturity of
60-
Keystones Python code-base, combined with the modern, high-safety,
60+
Keystone's Python code-base, combined with the modern, high-safety,
6161
high-performance capabilities of Rust where they matter most.
6262

6363
## Compatibility

rustfmt.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
# format_code_in_doc_comments = true
2-
# unstable_features = true
3-
# wrap_comments = true
1+
format_code_in_doc_comments = true
2+
unstable_features = true
3+
wrap_comments = true

src/api/auth.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ where
5151
let token = state
5252
.provider
5353
.get_token_provider()
54-
.validate_token(&state, auth_header, Some(false), None, Some(true))
54+
.validate_token(&state, auth_header, Some(false), None)
5555
.await
5656
.inspect_err(|e| error!("{:#?}", e))
5757
.map_err(|_| KeystoneApiError::Unauthorized(None))?;

src/api/error.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,18 @@ impl From<TokenProviderError> for KeystoneApiError {
258258
fn from(value: TokenProviderError) -> Self {
259259
match value {
260260
TokenProviderError::AuthenticationInfo(source) => source.into(),
261+
TokenProviderError::DomainDisabled(x) => Self::NotFound {
262+
resource: "domain".into(),
263+
identifier: x,
264+
},
261265
TokenProviderError::TokenRestrictionNotFound(x) => Self::NotFound {
262266
resource: "token restriction".into(),
263267
identifier: x,
264268
},
269+
TokenProviderError::ProjectDisabled(x) => Self::NotFound {
270+
resource: "project".into(),
271+
identifier: x,
272+
},
265273
other => Self::InternalError(other.to_string()),
266274
}
267275
}

src/api/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl From<Vec<(Service, Vec<ProviderEndpoint>)>> for Catalog {
222222
/// ID is sufficient to uniquely identify a project but if a project is
223223
/// specified by name, then the domain of the project must also be specified in
224224
/// order to uniquely identify the project by name. A domain scope may be
225-
/// specified by either the domains ID or name with equivalent results.
225+
/// specified by either the domain's ID or name with equivalent results.
226226
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, ToSchema)]
227227
#[serde(rename_all = "lowercase")]
228228
pub enum Scope {

src/api/v3/auth/token/delete.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub(super) async fn delete(
6767
let token = state
6868
.provider
6969
.get_token_provider()
70-
.validate_token(&state, &subject_token, None, None, None)
70+
.validate_token(&state, &subject_token, None, None)
7171
.await
7272
.inspect_err(|e| error!("{:?}", e.to_string()))
7373
.map_err(|_| KeystoneApiError::NotFound {
@@ -126,8 +126,8 @@ mod tests {
126126
let decoded_auth_token_clone1 = decoded_auth_token.clone();
127127
token_mock
128128
.expect_validate_token()
129-
.withf(|_, token: &'_ str, _, _, _| token == "foo")
130-
.returning(move |_, _, _, _, _| Ok(decoded_auth_token_clone1.clone()));
129+
.withf(|_, token: &'_ str, _, _| token == "foo")
130+
.returning(move |_, _, _, _| Ok(decoded_auth_token_clone1.clone()));
131131
// auth-token expanded
132132
let decoded_auth_token_clone2 = decoded_auth_token.clone();
133133
token_mock
@@ -161,8 +161,8 @@ mod tests {
161161
let decoded_subject_token_clone = decoded_subject_token.clone();
162162
token_mock
163163
.expect_validate_token()
164-
.withf(|_, token: &'_ str, _, _, _| token == "baz")
165-
.returning(move |_, _, _, _, _| Ok(decoded_subject_token_clone.clone()));
164+
.withf(|_, token: &'_ str, _, _| token == "baz")
165+
.returning(move |_, _, _, _| Ok(decoded_subject_token_clone.clone()));
166166

167167
let mut revoke_mock = MockRevokeProvider::default();
168168
// subject token revoked
@@ -215,8 +215,8 @@ mod tests {
215215
// subject token validated
216216
token_mock
217217
.expect_validate_token()
218-
.withf(|_, token: &'_ str, _, _, _| token == "baz")
219-
.returning(move |_, _, _, _, _| Err(TokenProviderError::Expired));
218+
.withf(|_, token: &'_ str, _, _| token == "baz")
219+
.returning(move |_, _, _, _| Err(TokenProviderError::Expired));
220220

221221
let provider = Provider::mocked_builder()
222222
.token(token_mock)
@@ -260,8 +260,8 @@ mod tests {
260260
// subject token validated
261261
token_mock
262262
.expect_validate_token()
263-
.withf(|_, token: &'_ str, _, _, _| token == "baz")
264-
.returning(move |_, _, _, _, _| Err(TokenProviderError::TokenRevoked));
263+
.withf(|_, token: &'_ str, _, _| token == "baz")
264+
.returning(move |_, _, _, _| Err(TokenProviderError::TokenRevoked));
265265

266266
let provider = Provider::mocked_builder()
267267
.token(token_mock)

src/api/v3/auth/token/show.rs

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,7 @@ pub(super) async fn show(
8383
let token = state
8484
.provider
8585
.get_token_provider()
86-
.validate_token(
87-
&state,
88-
&subject_token,
89-
query.allow_expired,
90-
None,
91-
// Do not expand the token for the policy evaluation
92-
Some(true),
93-
)
86+
.validate_token(&state, &subject_token, query.allow_expired, None)
9487
.await
9588
.inspect_err(|e| error!("{:?}", e.to_string()))
9689
.map_err(|_| KeystoneApiError::NotFound {
@@ -180,14 +173,12 @@ mod tests {
180173
}))
181174
});
182175
let mut token_mock = MockTokenProvider::default();
183-
token_mock
184-
.expect_validate_token()
185-
.returning(|_, _, _, _, _| {
186-
Ok(ProviderToken::Unscoped(UnscopedPayload {
187-
user_id: "bar".into(),
188-
..Default::default()
189-
}))
190-
});
176+
token_mock.expect_validate_token().returning(|_, _, _, _| {
177+
Ok(ProviderToken::Unscoped(UnscopedPayload {
178+
user_id: "bar".into(),
179+
..Default::default()
180+
}))
181+
});
191182
token_mock
192183
.expect_expand_token_information()
193184
.returning(|_, _| {
@@ -280,19 +271,19 @@ mod tests {
280271
let mut token_mock = MockTokenProvider::default();
281272
token_mock
282273
.expect_validate_token()
283-
.withf(|_, token: &'_ str, _, _, _| token == "foo")
284-
.returning(|_, _, _, _, _| {
274+
.withf(|_, token: &'_ str, _, _| token == "foo")
275+
.returning(|_, _, _, _| {
285276
Ok(ProviderToken::Unscoped(UnscopedPayload {
286277
user_id: "bar".into(),
287278
..Default::default()
288279
}))
289280
});
290281
token_mock
291282
.expect_validate_token()
292-
.withf(|_, token: &'_ str, allow_expired: &Option<bool>, _, _| {
283+
.withf(|_, token: &'_ str, allow_expired: &Option<bool>, _| {
293284
token == "bar" && *allow_expired == Some(true)
294285
})
295-
.returning(|_, _, _, _, _| {
286+
.returning(|_, _, _, _| {
296287
Ok(ProviderToken::Unscoped(UnscopedPayload {
297288
user_id: "bar".into(),
298289
..Default::default()
@@ -354,17 +345,17 @@ mod tests {
354345
let mut token_mock = MockTokenProvider::default();
355346
token_mock
356347
.expect_validate_token()
357-
.withf(|_, token: &'_ str, _, _, _| token == "foo")
358-
.returning(|_, _, _, _, _| {
348+
.withf(|_, token: &'_ str, _, _| token == "foo")
349+
.returning(|_, _, _, _| {
359350
Ok(ProviderToken::Unscoped(UnscopedPayload {
360351
user_id: "bar".into(),
361352
..Default::default()
362353
}))
363354
});
364355
token_mock
365356
.expect_validate_token()
366-
.withf(|_, token: &'_ str, _, _, _| token == "baz")
367-
.returning(|_, _, _, _, _| Err(TokenProviderError::Expired));
357+
.withf(|_, token: &'_ str, _, _| token == "baz")
358+
.returning(|_, _, _, _| Err(TokenProviderError::Expired));
368359

369360
let provider = Provider::mocked_builder()
370361
.token(token_mock)
@@ -406,17 +397,17 @@ mod tests {
406397
let mut token_mock = MockTokenProvider::default();
407398
token_mock
408399
.expect_validate_token()
409-
.withf(|_, token: &'_ str, _, _, _| token == "foo")
410-
.returning(|_, _, _, _, _| {
400+
.withf(|_, token: &'_ str, _, _| token == "foo")
401+
.returning(|_, _, _, _| {
411402
Ok(ProviderToken::Unscoped(UnscopedPayload {
412403
user_id: "bar".into(),
413404
..Default::default()
414405
}))
415406
});
416407
token_mock
417408
.expect_validate_token()
418-
.withf(|_, token: &'_ str, _, _, _| token == "baz")
419-
.returning(|_, _, _, _, _| Err(TokenProviderError::TokenRevoked));
409+
.withf(|_, token: &'_ str, _, _| token == "baz")
410+
.returning(|_, _, _, _| Err(TokenProviderError::TokenRevoked));
420411

421412
let provider = Provider::mocked_builder()
422413
.token(token_mock)

0 commit comments

Comments
 (0)