Skip to content

Commit 1888073

Browse files
authored
Fixes a few issues with csrf cookies (#402)
* Encode user provided state * Update cookie settings * More cookie adjustments * Unused imports * Fix handler return * Update test * Fmt
1 parent 0a2ee67 commit 1888073

2 files changed

Lines changed: 36 additions & 11 deletions

File tree

v-api/src/endpoints/handlers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ mod macros {
283283
rqctx: RequestContext<$context_type>,
284284
path: Path<OAuthProviderNameParam>,
285285
query: Query<OAuthAuthzCodeReturnQuery>,
286-
) -> Result<HttpResponseTemporaryRedirect, HttpError> {
286+
) -> Result<Response<Body>, HttpError> {
287287
authz_code_callback_op(&rqctx, path, query).await
288288
}
289289

v-api/src/endpoints/login/oauth/code.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
use base64::{prelude::BASE64_URL_SAFE_NO_PAD, Engine};
66
use chrono::{TimeDelta, Utc};
7+
use cookie::{Cookie, SameSite};
78
use dropshot::{
8-
http_response_temporary_redirect, Body, ClientErrorStatusCode, HttpError, HttpResponseOk,
9-
HttpResponseTemporaryRedirect, Path, Query, RequestContext, RequestInfo, SharedExtractor,
10-
TypedBody,
9+
Body, ClientErrorStatusCode, HttpError, HttpResponseOk, Path, Query, RequestContext,
10+
RequestInfo, SharedExtractor, TypedBody,
1111
};
1212
use dropshot_authorization_header::basic::BasicAuth;
1313
use http::{
@@ -250,8 +250,13 @@ fn oauth_redirect_response(
250250

251251
// Create an attempt cookie header for storing the login attempt. This also acts as our csrf
252252
// check
253-
let login_cookie = HeaderValue::from_str(&format!("{}={}", LOGIN_ATTEMPT_COOKIE, attempt.id))
254-
.map_err(to_internal_error)?;
253+
let mut cookie = Cookie::new(LOGIN_ATTEMPT_COOKIE, attempt.id.to_string());
254+
cookie.set_http_only(true);
255+
cookie.set_same_site(SameSite::Lax);
256+
cookie.set_secure(public_url.starts_with("https"));
257+
cookie.set_max_age(cookie::time::Duration::seconds(600));
258+
259+
let login_cookie = HeaderValue::from_str(&cookie.to_string()).map_err(to_internal_error)?;
255260

256261
// Generate the url to the remote provider that the user will be redirected to
257262
let mut authz_url = client
@@ -342,7 +347,7 @@ pub async fn authz_code_callback_op<T>(
342347
rqctx: &RequestContext<impl ApiContext<AppPermissions = T>>,
343348
path: Path<OAuthProviderNameParam>,
344349
query: Query<OAuthAuthzCodeReturnQuery>,
345-
) -> Result<HttpResponseTemporaryRedirect, HttpError>
350+
) -> Result<Response<Body>, HttpError>
346351
where
347352
T: VAppPermission + PermissionStorage,
348353
{
@@ -359,9 +364,25 @@ where
359364
// Verify and extract the attempt id before performing any work
360365
let attempt_id = verify_csrf(&rqctx.request, &query)?;
361366

362-
http_response_temporary_redirect(
363-
authz_code_callback_op_inner(ctx, &attempt_id, query.code, query.error).await?,
364-
)
367+
// Clear the login attempt cookie
368+
let mut cookie = Cookie::new(LOGIN_ATTEMPT_COOKIE, "");
369+
cookie.set_http_only(true);
370+
cookie.set_same_site(SameSite::Lax);
371+
cookie.set_secure(ctx.public_url().starts_with("https"));
372+
cookie.set_max_age(cookie::time::Duration::seconds(0));
373+
let login_cookie = HeaderValue::from_str(&cookie.to_string()).map_err(to_internal_error)?;
374+
375+
Ok(Response::builder()
376+
.status(StatusCode::TEMPORARY_REDIRECT)
377+
.header(SET_COOKIE, login_cookie)
378+
.header(
379+
LOCATION,
380+
HeaderValue::from_str(
381+
&authz_code_callback_op_inner(ctx, &attempt_id, query.code, query.error).await?,
382+
)
383+
.map_err(to_internal_error)?,
384+
)
385+
.body(Body::empty())?)
365386
}
366387

367388
pub async fn authz_code_callback_op_inner<T>(
@@ -930,7 +951,11 @@ mod tests {
930951
.unwrap()
931952
);
932953
assert_eq!(
933-
attempt.id.to_string().as_str(),
954+
format!(
955+
"{}; HttpOnly; SameSite=Lax; Secure; Max-Age=600",
956+
attempt.id
957+
)
958+
.as_str(),
934959
String::from_utf8(
935960
response
936961
.headers()

0 commit comments

Comments
 (0)