Skip to content

Commit 1714ff1

Browse files
committed
add allow_rp_initiated_logout config
1 parent 12d0a85 commit 1714ff1

23 files changed

+175
-95
lines changed

crates/cli/src/sync.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ pub async fn config_sync(
292292
fetch_userinfo: provider.fetch_userinfo,
293293
userinfo_signed_response_alg: provider.userinfo_signed_response_alg,
294294
response_mode,
295+
allow_rp_initiated_logout: provider.allow_rp_initiated_logout,
295296
additional_authorization_parameters: provider
296297
.additional_authorization_parameters
297298
.into_iter()

crates/config/src/sections/upstream_oauth2.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,12 @@ pub struct Provider {
535535
#[serde(default, skip_serializing_if = "ClaimsImports::is_default")]
536536
pub claims_imports: ClaimsImports,
537537

538+
/// Whether to allow RP-initiated logout
539+
///
540+
/// Defaults to `false`.
541+
#[serde(default)]
542+
pub allow_rp_initiated_logout: bool,
543+
538544
/// Additional parameters to include in the authorization request
539545
///
540546
/// Orders of the keys are not preserved.

crates/data-model/src/upstream_oauth2/provider.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ pub struct UpstreamOAuthProvider {
240240
pub created_at: DateTime<Utc>,
241241
pub disabled_at: Option<DateTime<Utc>>,
242242
pub claims_imports: ClaimsImports,
243+
pub allow_rp_initiated_logout: bool,
243244
pub additional_authorization_parameters: Vec<(String, String)>,
244245
}
245246

crates/handlers/src/admin/v1/upstream_oauth_links/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ mod test_utils {
4242
token_endpoint_override: None,
4343
userinfo_endpoint_override: None,
4444
jwks_uri_override: None,
45+
allow_rp_initiated_logout: false,
4546
additional_authorization_parameters: Vec::new(),
4647
ui_order: 0,
4748
}

crates/handlers/src/upstream_oauth2/cache.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ mod tests {
422422
created_at: clock.now(),
423423
disabled_at: None,
424424
claims_imports: UpstreamOAuthProviderClaimsImports::default(),
425+
allow_rp_initiated_logout: false,
425426
additional_authorization_parameters: Vec::new(),
426427
};
427428

crates/handlers/src/upstream_oauth2/link.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ mod tests {
948948
discovery_mode: mas_data_model::UpstreamOAuthProviderDiscoveryMode::Oidc,
949949
pkce_mode: mas_data_model::UpstreamOAuthProviderPkceMode::Auto,
950950
response_mode: None,
951+
allow_rp_initiated_logout: false,
951952
additional_authorization_parameters: Vec::new(),
952953
ui_order: 0,
953954
},

crates/handlers/src/upstream_oauth2/logout.rs

Lines changed: 59 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -91,55 +91,72 @@ pub async fn get_rp_initiated_logout_endpoints<E>(
9191
if session_ids.is_empty() {
9292
return Ok(result);
9393
}
94-
// We only support the first upstrea session at a time for now
95-
let upstream_session_id = session_ids[0];
96-
let upstream_session = repo
97-
.upstream_oauth_session()
98-
.lookup(upstream_session_id)
99-
.await?
100-
.ok_or(RouteError::SessionNotFound)?;
94+
// We only support the first upstream session
95+
let mut provider = None;
96+
let mut upstream_session = None;
97+
98+
for session_id in session_ids {
99+
// Get the session and assign its value, wrapped in Some
100+
let session = repo
101+
.upstream_oauth_session()
102+
.lookup(session_id)
103+
.await?
104+
.ok_or(RouteError::SessionNotFound)?;
105+
106+
// Get the provider and assign its value, wrapped in Some
107+
let prov = repo.upstream_oauth_provider()
108+
.lookup(session.provider_id)
109+
.await?
110+
.ok_or(RouteError::ProviderNotFound)?;
101111

102-
let provider = repo.upstream_oauth_provider()
103-
.lookup(upstream_session.provider_id)
104-
.await?
105-
.ok_or(RouteError::ProviderNotFound)?;
112+
if prov.allow_rp_initiated_logout {
113+
upstream_session = Some(session);
114+
provider = Some(prov);
115+
break;
116+
}
117+
}
106118

107-
// Look for end session endpoint
108-
// In a real implementation, we'd have end_session_endpoint fields in the provider
109-
// For now, we'll try to construct one from the issuer if available
110-
if let Some(issuer) = &provider.issuer {
111-
let end_session_endpoint = format!("{}/protocol/openid-connect/logout", issuer);
112-
let mut logout_url = end_session_endpoint;
113-
114-
// Add post_logout_redirect_uri
115-
if let Some(post_uri) = &result.post_logout_redirect_uri {
116-
if let Ok(mut url) = Url::parse(&logout_url) {
117-
url.query_pairs_mut()
118-
.append_pair("post_logout_redirect_uri", post_uri);
119-
url.query_pairs_mut()
120-
.append_pair("client_id", &provider.client_id);
119+
// Check if we found a provider with allow_rp_initiated_logout
120+
if let Some(provider) = provider {
121+
// Look for end session endpoint
122+
// In a real implementation, we'd have end_session_endpoint fields in the provider
123+
// For now, we'll try to construct one from the issuer if available
124+
if let Some(issuer) = &provider.issuer {
125+
let end_session_endpoint = format!("{}/protocol/openid-connect/logout", issuer);
126+
let mut logout_url = end_session_endpoint;
121127

122-
// Add id_token_hint if available
123-
if upstream_session.id_token().is_some(){
128+
// Add post_logout_redirect_uri
129+
if let Some(post_uri) = &result.post_logout_redirect_uri {
130+
if let Ok(mut url) = Url::parse(&logout_url) {
124131
url.query_pairs_mut()
125-
.append_pair("id_token_hint", upstream_session.id_token().unwrap());
132+
.append_pair("post_logout_redirect_uri", post_uri);
133+
url.query_pairs_mut()
134+
.append_pair("client_id", &provider.client_id);
135+
136+
// Add id_token_hint if available
137+
if let Some(session) = &upstream_session {
138+
if let Some(id_token) = session.id_token() {
139+
url.query_pairs_mut()
140+
.append_pair("id_token_hint", id_token);
141+
}
142+
}
143+
logout_url = url.to_string();
126144
}
127-
logout_url = url.to_string();
128145
}
146+
147+
info!(
148+
upstream_oauth_provider.id = %provider.id,
149+
logout_url = %logout_url,
150+
"Adding RP-initiated logout URL based on issuer"
151+
);
152+
153+
result.logout_endpoints = logout_url.clone();
154+
} else {
155+
info!(
156+
upstream_oauth_provider.id = %provider.id,
157+
"Provider has no issuer defined, cannot construct RP-initiated logout URL"
158+
);
129159
}
130-
131-
info!(
132-
upstream_oauth_provider.id = %provider.id,
133-
logout_url = %logout_url,
134-
"Adding RP-initiated logout URL based on issuer"
135-
);
136-
137-
result.logout_endpoints = logout_url.clone();
138-
} else {
139-
info!(
140-
upstream_oauth_provider.id = %provider.id,
141-
"Provider has no issuer defined, cannot construct RP-initiated logout URL"
142-
);
143160
}
144161

145162
Ok(result)

crates/handlers/src/views/login.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,7 @@ mod test {
452452
discovery_mode: mas_data_model::UpstreamOAuthProviderDiscoveryMode::Oidc,
453453
pkce_mode: mas_data_model::UpstreamOAuthProviderPkceMode::Auto,
454454
response_mode: None,
455+
allow_rp_initiated_logout: false,
455456
additional_authorization_parameters: Vec::new(),
456457
ui_order: 0,
457458
},
@@ -493,6 +494,7 @@ mod test {
493494
discovery_mode: mas_data_model::UpstreamOAuthProviderDiscoveryMode::Oidc,
494495
pkce_mode: mas_data_model::UpstreamOAuthProviderPkceMode::Auto,
495496
response_mode: None,
497+
allow_rp_initiated_logout: false,
496498
additional_authorization_parameters: Vec::new(),
497499
ui_order: 1,
498500
},

crates/storage-pg/.sqlx/query-72de26d5e3c56f4b0658685a95b45b647bb6637e55b662a5a548aa3308c62a8a.json

Lines changed: 0 additions & 44 deletions
This file was deleted.

crates/storage-pg/.sqlx/query-e25af41189846e26da99e5d8a1462eab5efe330f60ef8c6c813c747424ba7ec9.json renamed to crates/storage-pg/.sqlx/query-7c8fb255bd0d4f29bfdfc17f382ad1b4f2782498ed8f9582c8f28d94c42b3a95.json

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)