Skip to content

Commit a4421aa

Browse files
committed
Support receiving parameters through a form POST
1 parent 6efe8bf commit a4421aa

File tree

3 files changed

+47
-7
lines changed

3 files changed

+47
-7
lines changed

crates/axum-utils/src/cookies.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,15 @@ impl CookieOption {
101101
cookie.set_http_only(true);
102102
cookie.set_secure(self.secure());
103103
cookie.set_path(self.path().to_owned());
104-
cookie.set_same_site(SameSite::Lax);
104+
105+
// The `form_post` callback requires that, as it means a 3rd party origin will
106+
// POST to MAS. This is presumably fine, as our forms are protected with a CSRF
107+
// token
108+
cookie.set_same_site(if self.secure() {
109+
SameSite::None
110+
} else {
111+
SameSite::Lax
112+
});
105113
cookie
106114
}
107115
}

crates/handlers/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,8 @@ where
402402
)
403403
.route(
404404
mas_router::UpstreamOAuth2Callback::route(),
405-
get(self::upstream_oauth2::callback::get),
405+
get(self::upstream_oauth2::callback::handler)
406+
.post(self::upstream_oauth2::callback::handler),
406407
)
407408
.route(
408409
mas_router::UpstreamOAuth2Link::route(),

crates/handlers/src/upstream_oauth2/callback.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
use axum::{
88
extract::{Path, Query, State},
99
response::IntoResponse,
10+
Form,
1011
};
1112
use hyper::StatusCode;
1213
use mas_axum_utils::{cookies::CookieJar, sentry::SentryEventID};
13-
use mas_data_model::UpstreamOAuthProvider;
14+
use mas_data_model::{UpstreamOAuthProvider, UpstreamOAuthProviderResponseMode};
1415
use mas_keystore::{Encrypter, Keystore};
1516
use mas_oidc_client::requests::{
1617
authorization_code::AuthorizationValidationData, jose::JwtVerificationData,
@@ -35,7 +36,7 @@ use super::{
3536
use crate::{impl_from_error_for_route, upstream_oauth2::cache::MetadataCache};
3637

3738
#[derive(Deserialize)]
38-
pub struct QueryParams {
39+
pub struct Params {
3940
state: String,
4041

4142
#[serde(flatten)]
@@ -91,6 +92,20 @@ pub(crate) enum RouteError {
9192
#[error("Missing session cookie")]
9293
MissingCookie,
9394

95+
#[error("Missing query parameters")]
96+
MissingQueryParams,
97+
98+
#[error("Missing form parameters")]
99+
MissingFormParams,
100+
101+
#[error("Ambiguous parameters: got both query and form parameters")]
102+
AmbiguousParams,
103+
104+
#[error("Invalid response mode, expected '{expected}'")]
105+
InvalidParamsMode {
106+
expected: UpstreamOAuthProviderResponseMode,
107+
},
108+
94109
#[error(transparent)]
95110
Internal(Box<dyn std::error::Error>),
96111
}
@@ -117,13 +132,13 @@ impl IntoResponse for RouteError {
117132
}
118133

119134
#[tracing::instrument(
120-
name = "handlers.upstream_oauth2.callback.get",
135+
name = "handlers.upstream_oauth2.callback.handler",
121136
fields(upstream_oauth_provider.id = %provider_id),
122137
skip_all,
123138
err,
124139
)]
125140
#[allow(clippy::too_many_lines, clippy::too_many_arguments)]
126-
pub(crate) async fn get(
141+
pub(crate) async fn handler(
127142
mut rng: BoxRng,
128143
clock: BoxClock,
129144
State(metadata_cache): State<MetadataCache>,
@@ -134,7 +149,8 @@ pub(crate) async fn get(
134149
State(client): State<reqwest::Client>,
135150
cookie_jar: CookieJar,
136151
Path(provider_id): Path<Ulid>,
137-
Query(params): Query<QueryParams>,
152+
query_params: Option<Query<Params>>,
153+
form_params: Option<Form<Params>>,
138154
) -> Result<impl IntoResponse, RouteError> {
139155
let provider = repo
140156
.upstream_oauth_provider()
@@ -143,6 +159,21 @@ pub(crate) async fn get(
143159
.filter(UpstreamOAuthProvider::enabled)
144160
.ok_or(RouteError::ProviderNotFound)?;
145161

162+
// Read the parameters from the query or the form, depending on what
163+
// response_mode the provider uses
164+
let params = match (provider.response_mode, query_params, form_params) {
165+
(UpstreamOAuthProviderResponseMode::Query, Some(query_params), None) => query_params.0,
166+
(UpstreamOAuthProviderResponseMode::FormPost, None, Some(form_params)) => form_params.0,
167+
(UpstreamOAuthProviderResponseMode::Query, None, None) => {
168+
return Err(RouteError::MissingQueryParams)
169+
}
170+
(UpstreamOAuthProviderResponseMode::FormPost, None, None) => {
171+
return Err(RouteError::MissingFormParams)
172+
}
173+
(_, Some(_), Some(_)) => return Err(RouteError::AmbiguousParams),
174+
(expected, _, _) => return Err(RouteError::InvalidParamsMode { expected }),
175+
};
176+
146177
let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar);
147178
let (session_id, _post_auth_action) = sessions_cookie
148179
.find_session(provider_id, &params.state)

0 commit comments

Comments
 (0)