Skip to content

refactor: Redesign SecurityContext with two-phase validation#717

Merged
gtema merged 1 commit into
mainfrom
token_refactor2
May 23, 2026
Merged

refactor: Redesign SecurityContext with two-phase validation#717
gtema merged 1 commit into
mainfrom
token_refactor2

Conversation

@gtema
Copy link
Copy Markdown
Collaborator

@gtema gtema commented May 22, 2026

Access control and encapsulation:

  • Make all SecurityContext fields pub(crate) with explicit getter/setter methods to enforce encapsulation
  • Replace for_testing() with SecurityContextTestingBuilder for structured test fixture construction

Validation architecture:

  • Remove validator crate dependency from auth.rs, replacing opaque ValidationErrors with typed AuthenticationError variants
  • Merge dual validate/xvalidate split into single validate() method per auth type returning specific errors: UserDisabled(id), DomainDisabled(id), AuthzPrincipalMismatch, PrincipalDomainIdMissing
  • Add validate() to PrincipalInfo, IdentityInfo, UserIdentityInfo, PrincipalIdentityInfo, ScopeInfo, and SecurityContext

Structural improvements:

  • Box ScopeInfo::TrustProject variant as TrustProjectInfo to control enum size (smaller variants remain stack-allocated)
  • Replace new_with_roles() with new_for_scope(ctx, scope, state) taking explicit scope parameter for unambiguous caller control
  • Add #[must_use] with descriptive messages on validate() methods

@gtema gtema force-pushed the token_refactor2 branch 2 times, most recently from 420272b to 369f289 Compare May 22, 2026 19:05
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 22, 2026

🦢 Load Test Results

Goose Attack Report

Plan Overview

Action Started Stopped Elapsed Users
Increasing 26-05-23 14:42:26 26-05-23 14:42:28 00:00:02 0 → 4
Maintaining 26-05-23 14:42:28 26-05-23 14:42:58 00:00:30 4
Decreasing 26-05-23 14:42:58 26-05-23 14:42:58 00:00:00 0 ← 4

Request Metrics

Method Name # Requests # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
GET 6978 0 16.69 10 38 232.60 0.00
Aggregated 6978 0 16.69 10 38 232.60 0.00

Response Time Metrics

Method Name 50%ile (ms) 60%ile (ms) 70%ile (ms) 80%ile (ms) 90%ile (ms) 95%ile (ms) 99%ile (ms) 100%ile (ms)
GET 15 18 20 21 22 23 26 38
Aggregated 15 18 20 21 22 23 26 38

Status Code Metrics

Method Name Status Codes
GET 6,978 [200]
Aggregated 6,978 [200]

Transaction Metrics

Transaction # Times Run # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
ListUsers
0.0 0 0 0.00 0 0 0.00 0.00
0.1 4211 0 13.78 10 31 140.37 0.00
ValidateToken
1.0 0 0 0.00 0 0 0.00 0.00
1.1 2767 0 21.25 16 38 92.23 0.00
Aggregated 6978 0 16.69 10 38 232.60 0.00

Scenario Metrics

Transaction # Users # Times Run Average (ms) Min (ms) Max (ms) Scenarios/s Iterations
ListUsers 2 4209 13.78 10 31 140.30 2104.50
ValidateToken 2 2765 21.25 17 38 92.17 1382.50
Aggregated 4 6974 16.75 10 38 232.47 3487.00

View full report

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 22, 2026

🐰 Bencher Report

Branchtoken_refactor2
Testbedubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
nanoseconds (ns)
(Result Δ%)
Upper Boundary
nanoseconds (ns)
(Limit %)
Command_Serde/apply/remove📈 view plot
🚷 view threshold
84,407.00 ns
(-38.34%)Baseline: 136,889.80 ns
363,880.12 ns
(23.20%)
Command_Serde/apply/set📈 view plot
🚷 view threshold
82,967.00 ns
(-36.37%)Baseline: 130,398.25 ns
241,779.95 ns
(34.32%)
Command_Serde/pack/delete📈 view plot
🚷 view threshold
124.66 ns
(+1.11%)Baseline: 123.30 ns
145.91 ns
(85.43%)
Command_Serde/pack/delete_index📈 view plot
🚷 view threshold
116.56 ns
(+1.21%)Baseline: 115.16 ns
135.36 ns
(86.11%)
Command_Serde/pack/set📈 view plot
🚷 view threshold
195.88 ns
(-2.05%)Baseline: 199.97 ns
237.89 ns
(82.34%)
Command_Serde/pack/set_index📈 view plot
🚷 view threshold
116.26 ns
(+0.77%)Baseline: 115.38 ns
135.51 ns
(85.80%)
Command_Serde/unpack/delete📈 view plot
🚷 view threshold
203.82 ns
(+9.10%)Baseline: 186.82 ns
232.62 ns
(87.62%)
Command_Serde/unpack/delete_index📈 view plot
🚷 view threshold
194.69 ns
(+20.83%)Baseline: 161.13 ns
198.74 ns
(97.96%)
Command_Serde/unpack/set📈 view plot
🚷 view threshold
272.81 ns
(+11.63%)Baseline: 244.38 ns
290.07 ns
(94.05%)
Command_Serde/unpack/set_index📈 view plot
🚷 view threshold
175.31 ns
(+9.70%)Baseline: 159.81 ns
199.77 ns
(87.76%)
Payload_encryption/pack/inner📈 view plot
🚷 view threshold
68.21 ns
(+4.58%)Baseline: 65.22 ns
77.11 ns
(88.45%)
Payload_encryption/pack/remove_cmd📈 view plot
🚷 view threshold
120.75 ns
(-2.03%)Baseline: 123.25 ns
147.29 ns
(81.98%)
Payload_encryption/pack/set_cmd📈 view plot
🚷 view threshold
223.14 ns
(-5.58%)Baseline: 236.33 ns
293.35 ns
(76.07%)
Payload_encryption/unpack/inner📈 view plot
🚷 view threshold
164.92 ns
(+0.89%)Baseline: 163.47 ns
192.08 ns
(85.86%)
Payload_encryption/unpack/remove_cmd📈 view plot
🚷 view threshold
209.49 ns
(+6.74%)Baseline: 196.26 ns
240.59 ns
(87.07%)
Payload_encryption/unpack/set_cmd📈 view plot
🚷 view threshold
270.23 ns
(+4.12%)Baseline: 259.53 ns
321.43 ns
(84.07%)
Raft_1Node_Latency/prefix/1node📈 view plot
🚷 view threshold
6,564,900.00 ns
(+85.38%)Baseline: 3,541,268.18 ns
6,586,735.26 ns
(99.67%)
Raft_1Node_Latency/read/1node📈 view plot
🚷 view threshold
594.28 ns
(+8.03%)Baseline: 550.13 ns
785.42 ns
(75.66%)
Raft_1Node_Latency/remove/1node📈 view plot
🚷 view threshold
250,260.00 ns
(-30.50%)Baseline: 360,108.18 ns
646,479.38 ns
(38.71%)
Raft_1Node_Latency/write/1node📈 view plot
🚷 view threshold
251,780.00 ns
(-33.09%)Baseline: 376,302.27 ns
820,133.08 ns
(30.70%)
build_snapshot/default📈 view plot
🚷 view threshold
95,168.00 ns
(+5.52%)Baseline: 90,192.50 ns
145,067.03 ns
(65.60%)
fernet token/project📈 view plot
🚷 view threshold
1,440.90 ns
(-2.67%)Baseline: 1,480.39 ns
1,593.72 ns
(90.41%)
get_data_keyspace📈 view plot
🚷 view threshold
0.35 ns
(+10.45%)Baseline: 0.32 ns
0.37 ns
(94.43%)
get_db📈 view plot
🚷 view threshold
0.35 ns
(+11.51%)Baseline: 0.32 ns
0.37 ns
(95.03%)
get_fernet_token_timestamp/project📈 view plot
🚷 view threshold
145.80 ns
(-2.24%)Baseline: 149.14 ns
173.52 ns
(84.03%)
get_keyspace📈 view plot
🚷 view threshold
4.83 ns
(+1.43%)Baseline: 4.76 ns
9.31 ns
(51.84%)
🐰 View full continuous benchmarking report in Bencher

pub fn from_security_context<S: Into<String>>(
ctx: &SecurityContext,
trust: &Trust,
trust: S,
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be renamed to trust_id

Comment thread crates/core/src/api/v3/auth/token.rs Outdated
type Error = openstack_keystone_core_types::error::BuilderError;

fn try_from(vsc: &crate::auth::ValidatedSecurityContext) -> Result<Self, Self::Error> {
use openstack_keystone_api_types::v3::auth::token::{TokenBuilder, UserBuilder};
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move imports to module top

Comment thread crates/core/src/api/v3/auth/token.rs Outdated
response.methods(methods);
}

let (user_id, user_name, auth_domain, user_password_expires_at) = build_user_info(ctx)?;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auth_domain ->user_domain

Comment thread crates/core/src/api/v3/auth/token.rs Outdated
}
}

fn build_user_info(
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fill User builder instead

Comment thread crates/core/src/policy.rs Outdated
}
ScopeInfo::Unscoped => {}
}
match authz.effective_roles() {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps the whole construct can be simplified

Comment thread crates/core-types/src/token.rs Outdated
AuthenticationContext::Trust { .. } => {
Err(AuthenticationError::ScopeNotAllowed.into())
}
_ => Ok(Self::DomainScope(
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not implement fallback here

let authz_info = get_authz_info(&state, &req).await?;

if let Some(bound) = ctx.authorization()
&& bound.scope != authz_info
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it fail if e.g., description field changes?

Comment thread crates/keystone/src/policy.rs Outdated
/// # Parameters
/// * `policy_name` - The name of the policy to evaluate.
/// * `credentials` - The token containing the requester's credentials.
/// * `credentials` - The SecurityContext of the connection.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its perhaps a request and not connection

..Default::default()
};

let auth = AuthenticationResultBuilder::default()
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check whether fixture in core can be used

Access control and encapsulation:
- Make all SecurityContext fields pub(crate) with explicit
  getter/setter methods to enforce encapsulation
- Replace for_testing() with SecurityContextTestingBuilder
  for structured test fixture construction

Validation architecture:
- Remove validator crate dependency from auth.rs, replacing
  opaque ValidationErrors with typed AuthenticationError variants
- Merge dual validate/xvalidate split into single validate()
  method per auth type returning specific errors:
  UserDisabled(id), DomainDisabled(id), AuthzPrincipalMismatch,
  PrincipalDomainIdMissing
- Add validate() to PrincipalInfo, IdentityInfo, UserIdentityInfo,
  PrincipalIdentityInfo, ScopeInfo, and SecurityContext

Structural improvements:
- Box ScopeInfo::TrustProject variant as TrustProjectInfo to
  control enum size (smaller variants remain stack-allocated)
- Replace new_with_roles() with new_for_scope(ctx, scope, state)
  taking explicit scope parameter for unambiguous caller control
- Add #[must_use] with descriptive messages on validate() methods
@gtema gtema force-pushed the token_refactor2 branch from 369f289 to ac904fe Compare May 23, 2026 14:29
@gtema gtema merged commit d946d90 into main May 23, 2026
33 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant