-
Notifications
You must be signed in to change notification settings - Fork 13
feat(bitbucket): Migrate to OAuth 2.0 #772
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
Changes from 7 commits
d45d8bb
63d11ff
b879dc9
1d8cf9f
68e59cf
6e40505
ef14c54
308161b
433f3a9
7c1c15f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,5 @@ | ||
| import base64 | ||
| import logging | ||
| from urllib.parse import urlencode | ||
| import secrets | ||
|
|
||
| from asgiref.sync import async_to_sync | ||
| from django.conf import settings | ||
|
|
@@ -13,8 +12,10 @@ | |
| UserOnboardingMetricsService, | ||
| ) | ||
| from shared.torngit import Bitbucket | ||
| from shared.torngit.exceptions import TorngitServerFailureError | ||
| from utils.encryption import encryptor | ||
| from shared.torngit.exceptions import ( | ||
| TorngitClientGeneralError, | ||
| TorngitServerFailureError, | ||
| ) | ||
|
|
||
| log = logging.getLogger(__name__) | ||
|
|
||
|
|
@@ -53,23 +54,16 @@ def redirect_to_bitbucket_step(self, request): | |
| "secret": settings.BITBUCKET_CLIENT_SECRET, | ||
| } | ||
| ) | ||
| oauth_token_pair = repo_service.generate_request_token( | ||
| settings.BITBUCKET_REDIRECT_URI | ||
| state = secrets.token_urlsafe(32) | ||
| url_to_redirect = repo_service.generate_redirect_url( | ||
| settings.BITBUCKET_REDIRECT_URI, state=state | ||
| ) | ||
| oauth_token = oauth_token_pair["oauth_token"] | ||
| oauth_token_secret = oauth_token_pair["oauth_token_secret"] | ||
| url_params = urlencode({"oauth_token": oauth_token}) | ||
| url_to_redirect = f"{Bitbucket._OAUTH_AUTHORIZE_URL}?{url_params}" | ||
| response = redirect(url_to_redirect) | ||
| data = ( | ||
| base64.b64encode(oauth_token.encode()) | ||
| + b"|" | ||
| + base64.b64encode(oauth_token_secret.encode()) | ||
| ).decode() | ||
| response.set_signed_cookie( | ||
| "_oauth_request_token", | ||
| encryptor.encode(data).decode(), | ||
| "_bb_oauth_state", | ||
| state, | ||
| domain=settings.COOKIES_DOMAIN, | ||
| httponly=True, | ||
| ) | ||
| self.store_to_cookie_utm_tags(response) | ||
| return response | ||
drazisil-codecov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
@@ -81,19 +75,13 @@ def actual_login_step(self, request): | |
| "secret": settings.BITBUCKET_CLIENT_SECRET, | ||
| } | ||
| ) | ||
| oauth_verifier = request.GET.get("oauth_verifier") | ||
| request_cookie = request.get_signed_cookie("_oauth_request_token", default=None) | ||
| if not request_cookie: | ||
| log.warning( | ||
| "Request arrived with proper url params but not the proper cookies" | ||
| ) | ||
| expected_state = request.get_signed_cookie("_bb_oauth_state", default=None) | ||
| if not expected_state or request.GET.get("state") != expected_state: | ||
| log.warning("Bitbucket OAuth state mismatch — possible CSRF attempt") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: would it be worth it to add exc_info to this log? Or maybe some other identifying things |
||
| return redirect(reverse("bitbucket-login")) | ||
| request_cookie = encryptor.decode(request_cookie) | ||
| cookie_key, cookie_secret = [ | ||
| base64.b64decode(i).decode() for i in request_cookie.split("|") | ||
| ] | ||
| code = request.GET.get("code") | ||
| token = repo_service.generate_access_token( | ||
| cookie_key, cookie_secret, oauth_verifier | ||
| code, settings.BITBUCKET_REDIRECT_URI | ||
| ) | ||
| user_dict = self.fetch_user_data(token) | ||
| user = self.get_and_modify_owner(user_dict, request) | ||
|
|
@@ -102,7 +90,7 @@ def actual_login_step(self, request): | |
| redirection_url, user | ||
| ) | ||
| response = redirect(redirection_url) | ||
| response.delete_cookie("_oauth_request_token", domain=settings.COOKIES_DOMAIN) | ||
| response.delete_cookie("_bb_oauth_state", domain=settings.COOKIES_DOMAIN) | ||
| self.login_owner(user, request, response) | ||
| log.info("User successfully logged in", extra={"ownerid": user.ownerid}) | ||
| UserOnboardingMetricsService.create_user_onboarding_metric( | ||
|
|
@@ -115,7 +103,7 @@ def get(self, request): | |
| return redirect(f"{settings.CODECOV_DASHBOARD_URL}/login") | ||
|
|
||
| try: | ||
| if request.GET.get("oauth_verifier"): | ||
| if request.GET.get("code"): | ||
| log.info("Logging into bitbucket after authorization") | ||
| return self.actual_login_step(request) | ||
| else: | ||
|
|
@@ -124,3 +112,6 @@ def get(self, request): | |
| except TorngitServerFailureError: | ||
| log.warning("Bitbucket not available for login") | ||
| return redirect(reverse("bitbucket-login")) | ||
| except TorngitClientGeneralError: | ||
| log.warning("Bitbucket OAuth error during login") | ||
| return redirect(reverse("bitbucket-login")) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ def get_token_refresh_callback(owner: Owner) -> Callable[[dict], None]: | |
| return None | ||
|
|
||
| service = owner.service | ||
| if service == "bitbucket" or service == "bitbucket_server": | ||
| if service == "bitbucket_server": | ||
| return None | ||
|
|
||
| async def callback(new_token: dict) -> None: | ||
|
Comment on lines
+22
to
25
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: The worker's token refresh callback for Bitbucket updates Suggested FixAfter updating the Prompt for AI Agent |
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.