Our Personal Data Server from scratch! tranquil.farm
pds rust database fun oauth atproto
229
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(oauth): indigo client send empty assertions

Lewis: May this revision serve well! <lu5a@proton.me>

authored by lu5a.myatproto.social and committed by

Tangled a20e4e05 3e7a1997

+51 -8
+14 -6
crates/tranquil-oauth-server/src/endpoints/par.rs
··· 138 138 } 139 139 140 140 fn determine_client_auth(request: &ParRequest) -> Result<ClientAuth, OAuthError> { 141 - if let (Some(assertion), Some(assertion_type)) = 142 - (&request.client_assertion, &request.client_assertion_type) 143 - { 141 + let assertion = request 142 + .client_assertion 143 + .as_deref() 144 + .filter(|s| !s.is_empty()); 145 + let assertion_type = request 146 + .client_assertion_type 147 + .as_deref() 148 + .filter(|s| !s.is_empty()); 149 + let secret = request.client_secret.as_deref().filter(|s| !s.is_empty()); 150 + 151 + if let (Some(assertion), Some(assertion_type)) = (assertion, assertion_type) { 144 152 if assertion_type != "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" { 145 153 return Err(OAuthError::InvalidRequest( 146 154 "Unsupported client_assertion_type".to_string(), 147 155 )); 148 156 } 149 157 return Ok(ClientAuth::PrivateKeyJwt { 150 - client_assertion: assertion.clone(), 158 + client_assertion: assertion.to_string(), 151 159 }); 152 160 } 153 - if let Some(secret) = &request.client_secret { 161 + if let Some(secret) = secret { 154 162 return Ok(ClientAuth::SecretPost { 155 - client_secret: secret.clone(), 163 + client_secret: secret.to_string(), 156 164 }); 157 165 } 158 166 Ok(ClientAuth::None)
+6 -2
crates/tranquil-oauth-server/src/endpoints/token/types.rs
··· 138 138 } 139 139 }; 140 140 141 - let client_auth = match (self.client_assertion, self.client_assertion_type) { 141 + let assertion = self.client_assertion.filter(|s| !s.is_empty()); 142 + let assertion_type = self.client_assertion_type.filter(|s| !s.is_empty()); 143 + let client_secret = self.client_secret.filter(|s| !s.is_empty()); 144 + 145 + let client_auth = match (assertion, assertion_type) { 142 146 (Some(assertion), Some(assertion_type)) => RequestClientAuth::PrivateKeyJwt { 143 147 client_id: self.client_id, 144 148 assertion, 145 149 assertion_type, 146 150 }, 147 - _ => match self.client_secret { 151 + _ => match client_secret { 148 152 Some(secret) => RequestClientAuth::SecretPost { 149 153 client_id: self.client_id, 150 154 client_secret: secret,
+31
crates/tranquil-pds/tests/oauth.rs
··· 188 188 } 189 189 190 190 #[tokio::test] 191 + async fn test_par_public_client_empty_assertion_fields() { 192 + let url = base_url().await; 193 + let client = client(); 194 + let redirect_uri = "https://nels.evil.oauth.pet/callback"; 195 + let mock_client = setup_mock_client_metadata(redirect_uri).await; 196 + let client_id = mock_client.uri(); 197 + let (_, code_challenge) = generate_pkce(); 198 + let par_res = client 199 + .post(format!("{}/oauth/par", url)) 200 + .form(&[ 201 + ("response_type", "code"), 202 + ("client_id", &client_id), 203 + ("redirect_uri", redirect_uri), 204 + ("code_challenge", &code_challenge), 205 + ("code_challenge_method", "S256"), 206 + ("scope", "atproto"), 207 + ("state", "test-state"), 208 + ("client_assertion", ""), 209 + ("client_assertion_type", ""), 210 + ]) 211 + .send() 212 + .await 213 + .unwrap(); 214 + assert_eq!( 215 + par_res.status(), 216 + StatusCode::CREATED, 217 + "PAR with empty assertion fields from a public client should succeed" 218 + ); 219 + } 220 + 221 + #[tokio::test] 191 222 async fn test_full_oauth_flow() { 192 223 let url = base_url().await; 193 224 let http_client = client();