Skip to content

Commit c35e40a

Browse files
committed
oauth_state_only
1 parent 4167288 commit c35e40a

File tree

3 files changed

+16
-68
lines changed

3 files changed

+16
-68
lines changed

lib/api_auth/src/oauth/github.rs

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
use bencher_endpoint::{CorsResponse, Endpoint, Get, Post, ResponseAccepted, ResponseOk};
2-
use bencher_json::{
3-
JsonOAuthUrl, JsonOAuthUser, Jwt, OrganizationUuid, PlanLevel, system::auth::JsonOAuth,
4-
};
2+
use bencher_json::{JsonOAuthUrl, JsonOAuthUser, system::auth::JsonOAuth};
53
use bencher_schema::{
64
context::ApiContext,
75
error::{payment_required_error, unauthorized_error},
86
};
97
use dropshot::{HttpError, Query, RequestContext, TypedBody, endpoint};
10-
use schemars::JsonSchema;
11-
use serde::Deserialize;
128
use slog::Logger;
139

1410
use crate::oauth::oauth_state::OAuthState;
@@ -28,24 +24,14 @@ pub async fn auth_github_options(
2824
Ok(Endpoint::cors(&[Get.into(), Post.into()]))
2925
}
3026

31-
#[derive(Debug, Deserialize, JsonSchema)]
32-
pub struct AuthGitHubQuery {
33-
/// Invitation JWT.
34-
pub invite: Option<Jwt>,
35-
/// Organization UUID to claim.
36-
pub claim: Option<OrganizationUuid>,
37-
/// Plan level.
38-
pub plan: Option<PlanLevel>,
39-
}
40-
4127
#[endpoint {
4228
method = GET,
4329
path = "/v0/auth/github",
4430
tags = ["auth"]
4531
}]
4632
pub async fn auth_github_get(
4733
rqctx: RequestContext<ApiContext>,
48-
query_params: Query<AuthGitHubQuery>,
34+
query_params: Query<OAuthState>,
4935
) -> Result<ResponseOk<JsonOAuthUrl>, HttpError> {
5036
let json = get_inner(&rqctx.log, rqctx.context(), query_params.into_inner()).await?;
5137
Ok(Get::pub_response_ok(json))
@@ -54,7 +40,7 @@ pub async fn auth_github_get(
5440
async fn get_inner(
5541
log: &Logger,
5642
context: &ApiContext,
57-
query_params: AuthGitHubQuery,
43+
oauth_state: OAuthState,
5844
) -> Result<JsonOAuthUrl, HttpError> {
5945
let Some(github_client) = &context.github_client else {
6046
let err = "GitHub OAuth2 is not configured";
@@ -63,20 +49,7 @@ async fn get_inner(
6349
};
6450
is_allowed_oauth(context).await?;
6551

66-
// TODO: Currently, we do not protect against CSRF attacks,
67-
// as we allow any client to use our authentication endpoints.
68-
// So the `state` parameter is currently just used to pass callback information.
69-
// In the future, we may want to restrict allowed clients,
70-
// at which point we should generate and validate a CSRF token here
71-
// along with the callback information.
72-
// https://datatracker.ietf.org/doc/html/rfc6749#section-10.12
73-
let AuthGitHubQuery {
74-
invite,
75-
claim,
76-
plan,
77-
} = query_params;
78-
let state_struct = OAuthState::new(invite, claim, plan);
79-
let state = state_struct.encode(log, &context.token_key)?;
52+
let state = oauth_state.encode(log, &context.token_key)?;
8053
let url = github_client.auth_url(state);
8154

8255
Ok(JsonOAuthUrl { url })

lib/api_auth/src/oauth/google.rs

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
use bencher_endpoint::{CorsResponse, Endpoint, Get, Post, ResponseAccepted, ResponseOk};
2-
use bencher_json::{
3-
JsonOAuthUrl, JsonOAuthUser, Jwt, OrganizationUuid, PlanLevel, system::auth::JsonOAuth,
4-
};
2+
use bencher_json::{JsonOAuthUrl, JsonOAuthUser, system::auth::JsonOAuth};
53
use bencher_schema::{
64
context::ApiContext,
75
error::{payment_required_error, unauthorized_error},
86
};
97
use dropshot::{HttpError, Query, RequestContext, TypedBody, endpoint};
10-
use schemars::JsonSchema;
11-
use serde::Deserialize;
128
use slog::Logger;
139

1410
use crate::oauth::oauth_state::OAuthState;
@@ -28,24 +24,14 @@ pub async fn auth_google_options(
2824
Ok(Endpoint::cors(&[Get.into(), Post.into()]))
2925
}
3026

31-
#[derive(Debug, Deserialize, JsonSchema)]
32-
pub struct AuthGoogleQuery {
33-
/// Invitation JWT.
34-
pub invite: Option<Jwt>,
35-
/// Organization UUID to claim.
36-
pub claim: Option<OrganizationUuid>,
37-
/// Plan level.
38-
pub plan: Option<PlanLevel>,
39-
}
40-
4127
#[endpoint {
4228
method = GET,
4329
path = "/v0/auth/google",
4430
tags = ["auth"]
4531
}]
4632
pub async fn auth_google_get(
4733
rqctx: RequestContext<ApiContext>,
48-
query_params: Query<AuthGoogleQuery>,
34+
query_params: Query<OAuthState>,
4935
) -> Result<ResponseOk<JsonOAuthUrl>, HttpError> {
5036
let json = get_inner(&rqctx.log, rqctx.context(), query_params.into_inner()).await?;
5137
Ok(Get::pub_response_ok(json))
@@ -54,7 +40,7 @@ pub async fn auth_google_get(
5440
async fn get_inner(
5541
log: &Logger,
5642
context: &ApiContext,
57-
query_params: AuthGoogleQuery,
43+
oauth_state: OAuthState,
5844
) -> Result<JsonOAuthUrl, HttpError> {
5945
let Some(google_client) = &context.google_client else {
6046
let err = "Google OAuth2 is not configured";
@@ -63,23 +49,8 @@ async fn get_inner(
6349
};
6450
is_allowed_oauth(context).await?;
6551

66-
// TODO: Currently, we do not protect against CSRF attacks,
67-
// as we allow any client to use our authentication endpoints.
68-
// So the `state` parameter is currently just used to pass callback information.
69-
// In the future, we may want to restrict allowed clients,
70-
// at which point we should generate and validate a CSRF token here
71-
// along with the callback information.
72-
// https://datatracker.ietf.org/doc/html/rfc6749#section-10.12
73-
let AuthGoogleQuery {
74-
invite,
75-
claim,
76-
plan,
77-
} = query_params;
78-
79-
let state_struct = OAuthState::new(invite, claim, plan);
80-
let state = state_struct.encode(log, &context.token_key)?;
52+
let state = oauth_state.encode(log, &context.token_key)?;
8153
let url = google_client.auth_url(state);
82-
8354
Ok(JsonOAuthUrl { url })
8455
}
8556

lib/api_auth/src/oauth/oauth_state.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use bencher_json::{Email, Jwt, OrganizationUuid, PlanLevel};
44
use bencher_schema::error::unauthorized_error;
55
use bencher_token::TokenKey;
66
use dropshot::HttpError;
7+
use schemars::JsonSchema;
78
use serde::{Deserialize, Serialize};
89
use slog::Logger;
910

@@ -13,11 +14,14 @@ const OAUTH_TTL: u32 = 600;
1314
static OAUTH_EMAIL: LazyLock<Email> =
1415
LazyLock::new(|| "[email protected]".parse().expect("Invalid OAuth email"));
1516

16-
#[derive(Debug, Serialize, Deserialize)]
17+
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
1718
pub struct OAuthState {
18-
invite: Option<Jwt>,
19-
claim: Option<OrganizationUuid>,
20-
plan: Option<PlanLevel>,
19+
/// Invitation JWT.
20+
pub invite: Option<Jwt>,
21+
/// Organization UUID to claim.
22+
pub claim: Option<OrganizationUuid>,
23+
/// Plan level.
24+
pub plan: Option<PlanLevel>,
2125
}
2226

2327
impl OAuthState {

0 commit comments

Comments
 (0)