-
Notifications
You must be signed in to change notification settings - Fork 86
Oauth Account System #182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Oauth Account System #182
Conversation
|
Only difference to #135 so far is that I squashed everything, and resolved some left over merge markers |
9eac557 to
bfd0e97
Compare
| pub async fn invalidate(mut auth: BasicAuth) -> Result<Status> { | ||
| match auth.user { | ||
| AuthenticatedUser::Legacy(legacy) => legacy.invalidate_all_tokens(auth.secret, &mut auth.connection).await?, | ||
| AuthenticatedUser::OAuth2(oauth) => oauth.invalidate_all_tokens(&mut auth.connection).await? // I have no clue what we'll do here |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mh, this still doesn't work though, because the parameter here is BasicAuth, meaning for oauth2 accounts we'll hit UNAUTHORIZED way before this point.
| + "&response_type=code" | ||
| + "&prompt=consent" | ||
| + "&scope=email%20profile" | ||
| + "&redirect_uri=http%3A%2F%2Flocalhost%3A1971%2Fapi%2Fv1%2Fauth%2Fcallback"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this needs to be updated to not point to localhost anymore
c8d65f1 to
b8fadcb
Compare
| if legacy.is_some() { | ||
| let legacy_cookie = Cookie::build(("legacy", "true")) | ||
| .http_only(true) | ||
| .same_site(SameSite::Strict) | ||
| .path("/"); | ||
|
|
||
| cookies.add(legacy_cookie); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This stuff also needs to be done a bit differently. We need to setup a state parameter that contains the user id of the account that was logged in when the request start, a random number, as well as a cryptographic hash of these two fields (signed with the account's secret). Then the random number gets stored as a cookie with short expiration (5 minutes or so). In the callback, we validate the hash, we validate the account id against the account id logged in when the callback URI is requested, and we validate the random number against the cookie.
That way, an attacker can only influence our flow by
- intercepting the uri to which google redirects us after successful authentication
- replacing the
codewith the code for their account - getting the user to click this modified link within 5 minutes of initiating the flow
There's no replay attacks possible beyond that because the random number part of the state changes every 5 minutes. There's also no tricking a user into clicking a callback link generated using a different pointercrate account, because the user id in the state parameter would mismatch.
It needs to be set for both the API and the pages crates. Otherwise, the frontend will just receive a 404 when registering. Signed-off-by: stadust <[email protected]>
a412629 to
65b9b93
Compare
| ("code", code), | ||
| ("client_id", &config::google_client_id()), | ||
| ("client_secret", &config::google_client_secret()), | ||
| ("redirect_uri", &config::google_redirect_uri()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to be set to the same value as the redirect_uri field in the original request that returned the code in the first place.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #182 +/- ##
==========================================
- Coverage 28.00% 27.21% -0.80%
==========================================
Files 116 121 +5
Lines 8231 8507 +276
==========================================
+ Hits 2305 2315 +10
- Misses 5926 6192 +266 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
c9b50ac to
3e1b0d2
Compare
`generate_jwt` and `validate_jwt` create and validate JWTs signed with the given `AuthenticatedUsers` signing key. They are generic over the claims, giing a generic API for managing JWTs without needing to make `jwt_secret` a public function. While we're at it, use the JWT standard `sub` field to store the user ID we are expecting, and use the jsonwebtoken library's validation to ensure we always get the expected `sub` value. Also switch CSRF token's to this generalized procedure. This has the consequence that now they are signed using the user's secret key, instead of the global one. No functional change should follow from this, however to ensure that CSRF tokens do not work as access tokens, annotate all claims structs with `serde(deny_unknown_fields)`. Also move the "read ID from jwt by unsafely decoding it" stuff into `auth/mod.rs`, for better encapsulation of the claims structs. Signed-off-by: stadust <[email protected]>
We were not doing anything with it anyway, and the check of the `exp` field is completely independent of it. Signed-off-by: stadust <[email protected]>
Move the `secret()` function from pointercrate-core to pointercrate-user, since the secret key is only used in pointercrate-user. Also opens us up for having more pointercrate-user specific configuration options (such as oauth client id). Signed-off-by: stadust <[email protected]>
e1968ce to
932e139
Compare
+ Moved google account id migration after all migrations added to master in the meantime. + Dropped change of password_hash to being optional + Break AuthenticatedUser::oauth2_callback into smaller functions + Drop `email_address` column from database. Was originally added when I only wanted to add email-based password reset, but with oauth there's no need. + Repurpose the `password_hash` field into a generic `salt` field for oauth accounts. This allows implementation the token reset. + Remove UserError::NotApplicable. It was the same as UserError::NonLegacy + Move the oauth endpoints to `pages.rs`, because they're not really part of the API (they cannot be used programmatically) commit 5bd3860920aad144dc90665569c9dd06e33ae07e Author: Natalia <[email protected]> Date: Sat Sep 14 21:24:35 2024 +0200 fix merge conflicts, (mostly) move over to feature flags commit 8730c89 Merge: 2734b86 5b6b7b3 Author: Natalia <[email protected]> Date: Sat Sep 14 21:24:31 2024 +0200 fix merge conflicts, (mostly) move over to feature flags commit 2734b86 Author: peony <[email protected]> Date: Tue Jul 9 11:27:55 2024 +0200 make lax cookies strict again commit e585a31 Author: peony <[email protected]> Date: Tue Jul 9 11:25:07 2024 +0200 minor fixes commit 0abfc86 Author: peony <[email protected]> Date: Sun Jul 7 23:01:06 2024 +0200 remove unnecessary endpoints commit e334894 Merge: 8d44dd9 00a6d38 Author: peony <[email protected]> Date: Sun Jul 7 22:55:28 2024 +0200 Merge branch 'master' into master commit 8d44dd9 Author: peony <[email protected]> Date: Sun Jul 7 22:53:39 2024 +0200 account linking commit d91dfe1 Author: peony <[email protected]> Date: Mon May 20 23:35:00 2024 +0200 code cleanup, add explanation for possibly questionable code commit da39d62 Author: peony <[email protected]> Date: Mon May 20 23:20:23 2024 +0200 google oauth2 stub, nullable password migration Signed-off-by: stadust <[email protected]>
62df64c to
be0d5b7
Compare
|
Superceded by #229 |
This is a continuation of #135, but I messed up pushing to @peonii's branch, and now cannot update that PR anymore 💀
License Acceptance
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.