Skip to content

Commit b0bc692

Browse files
authored
Fix the upstream OAuth 2.0 callback form deserialisation (#4010)
Fixes #3957 This was broken since #3893
2 parents eafe017 + 8dac005 commit b0bc692

File tree

1 file changed

+43
-38
lines changed

1 file changed

+43
-38
lines changed

crates/handlers/src/upstream_oauth2/callback.rs

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,32 +41,33 @@ use crate::{impl_from_error_for_route, upstream_oauth2::cache::MetadataCache, Pr
4141

4242
#[derive(Serialize, Deserialize)]
4343
pub struct Params {
44-
state: String,
44+
state: Option<String>,
4545

4646
/// An extra parameter to track whether the POST request was re-made by us
4747
/// to the same URL to escape Same-Site cookies restrictions
4848
#[serde(default)]
4949
did_mas_repost_to_itself: bool,
5050

51+
code: Option<String>,
52+
53+
error: Option<ClientErrorCode>,
54+
error_description: Option<String>,
55+
#[allow(dead_code)]
56+
error_uri: Option<String>,
57+
5158
#[serde(flatten)]
52-
code_or_error: CodeOrError,
59+
extra_callback_parameters: Option<serde_json::Value>,
5360
}
5461

55-
#[derive(Serialize, Deserialize)]
56-
#[serde(untagged)]
57-
enum CodeOrError {
58-
Code {
59-
code: String,
60-
61-
#[serde(flatten)]
62-
extra_callback_parameters: Option<serde_json::Value>,
63-
},
64-
Error {
65-
error: ClientErrorCode,
66-
error_description: Option<String>,
67-
#[allow(dead_code)]
68-
error_uri: Option<String>,
69-
},
62+
impl Params {
63+
/// Returns true if none of the fields are set
64+
pub fn is_empty(&self) -> bool {
65+
self.state.is_none()
66+
&& self.code.is_none()
67+
&& self.error.is_none()
68+
&& self.error_description.is_none()
69+
&& self.error_uri.is_none()
70+
}
7071
}
7172

7273
#[derive(Debug, Error)]
@@ -86,6 +87,12 @@ pub(crate) enum RouteError {
8687
#[error("State parameter mismatch")]
8788
StateMismatch,
8889

90+
#[error("Missing state parameter")]
91+
MissingState,
92+
93+
#[error("Missing code parameter")]
94+
MissingCode,
95+
8996
#[error("Could not extract subject from ID token")]
9097
ExtractSubject(#[source] minijinja::Error),
9198

@@ -161,7 +168,7 @@ pub(crate) async fn handler(
161168
PreferredLanguage(locale): PreferredLanguage,
162169
cookie_jar: CookieJar,
163170
Path(provider_id): Path<Ulid>,
164-
Form(params): Form<Option<Params>>,
171+
Form(params): Form<Params>,
165172
) -> Result<Response, RouteError> {
166173
let provider = repo
167174
.upstream_oauth_provider()
@@ -172,7 +179,7 @@ pub(crate) async fn handler(
172179

173180
let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar);
174181

175-
let Some(params) = params else {
182+
if params.is_empty() {
176183
if let Method::GET = method {
177184
return Err(RouteError::MissingQueryParams);
178185
}
@@ -204,8 +211,19 @@ pub(crate) async fn handler(
204211
(Some(expected), _) => return Err(RouteError::InvalidResponseMode { expected }),
205212
}
206213

214+
if let Some(error) = params.error {
215+
return Err(RouteError::ClientError {
216+
error,
217+
error_description: params.error_description.clone(),
218+
});
219+
}
220+
221+
let Some(state) = params.state else {
222+
return Err(RouteError::MissingState);
223+
};
224+
207225
let (session_id, _post_auth_action) = sessions_cookie
208-
.find_session(provider_id, &params.state)
226+
.find_session(provider_id, &state)
209227
.map_err(|_| RouteError::MissingCookie)?;
210228

211229
let session = repo
@@ -219,7 +237,7 @@ pub(crate) async fn handler(
219237
return Err(RouteError::ProviderMismatch);
220238
}
221239

222-
if params.state != session.state_str {
240+
if state != session.state_str {
223241
// The state in the session cookie should match the one from the params
224242
return Err(RouteError::StateMismatch);
225243
}
@@ -230,21 +248,8 @@ pub(crate) async fn handler(
230248
}
231249

232250
// Let's extract the code from the params, and return if there was an error
233-
let (code, extra_callback_parameters) = match params.code_or_error {
234-
CodeOrError::Error {
235-
error,
236-
error_description,
237-
..
238-
} => {
239-
return Err(RouteError::ClientError {
240-
error,
241-
error_description,
242-
})
243-
}
244-
CodeOrError::Code {
245-
code,
246-
extra_callback_parameters,
247-
} => (code, extra_callback_parameters),
251+
let Some(code) = params.code else {
252+
return Err(RouteError::MissingCode);
248253
};
249254

250255
let mut lazy_metadata = LazyProviderInfos::new(&metadata_cache, &provider, &client);
@@ -326,7 +331,7 @@ pub(crate) async fn handler(
326331
context = context.with_id_token_claims(claims);
327332
}
328333

329-
if let Some(extra_callback_parameters) = extra_callback_parameters.clone() {
334+
if let Some(extra_callback_parameters) = params.extra_callback_parameters.clone() {
330335
context = context.with_extra_callback_parameters(extra_callback_parameters);
331336
}
332337

@@ -432,7 +437,7 @@ pub(crate) async fn handler(
432437
session,
433438
&link,
434439
token_response.id_token,
435-
extra_callback_parameters,
440+
params.extra_callback_parameters,
436441
userinfo,
437442
)
438443
.await?;

0 commit comments

Comments
 (0)