def get_bmo_auth_callback(request): """Handler for the third part of the Bugzilla auth-delegation process. After the above POST call is executed, Bugzilla then redirects back to this view, passing the return value of the POST handler, as `callback_result`, and optionally a redirect, passed from the original redirect to Bugzilla (from the MozReview login view). This handler then verifies the API key with Bugzilla and attempts to create or update the user in MozReview. If everything succeeds, the user is again redirected back to the original page (or the root page if there was no redirect passed in, e.g., in tests). Otherwise the user is shown an error page. """ bmo_username = request.GET.get('client_api_login', None) callback_result = request.GET.get('callback_result', None) redirect = request.GET.get('redirect', None) secret = request.GET.get('secret', None) if not (bmo_username and callback_result): logger.error('Bugzilla auth callback called without required ' 'parameters.') return show_error_page(request) # Delete expired unverified keys (5 minute lifetime). UnverifiedBugzillaApiKey.objects.filter( timestamp__lte=timezone.now() - timedelta(minutes=5)).delete() parsed = None if not redirect else urlparse(redirect) # Enforce relative redirects; we don't want people crafting auth links # that redirect to other sites. We check the scheme as well as the netloc # to catch data, file, and other such server-less URIs. if not parsed or parsed.scheme or parsed.netloc: redirect = '/' unverified_keys = UnverifiedBugzillaApiKey.objects.filter( bmo_username=bmo_username).order_by('timestamp') if not unverified_keys: logger.error('No unverified keys found for BMO user %s.' % bmo_username) return show_error_page(request) unverified_key = unverified_keys.last() if len(unverified_keys) > 1: logger.warning('Multiple unverified keys on file for BMO user %s. ' 'Using most recent, from %s.' % (bmo_username, unverified_key.timestamp)) if callback_result != unverified_key.callback_result: logger.error('Callback result does not match for BMO user %s.' % bmo_username) return show_error_page(request) if secret is None or request.COOKIES['bmo_auth_secret'] != secret: logger.error('Callback secret does not match cookie for user %s.' % bmo_username) return show_error_page(request) bmo_api_key = unverified_key.api_key unverified_key.delete() b = Bugzilla() try: if not b.valid_api_key(bmo_username, bmo_api_key): logger.error('Invalid API key for %s.' % bmo_username) return show_error_page(request) except BugzillaError as e: logger.error('Error validating API key: %s' % e.msg) return show_error_page(request) b.api_key = bmo_api_key try: user_data = b.get_user(bmo_username) except BugzillaError as e: logger.error('Error getting user data: %s' % e.msg) return show_error_page(request) if not user_data: logger.warning('Could not retrieve user info for %s after ' 'validating API key.' % bmo_username) return show_error_page(request) users = get_or_create_bugzilla_users(user_data) if not users: logger.warning('Failed to create user %s after validating API key.' % bmo_username) return show_error_page(request) user = users[0] assert user.email == bmo_username if not user.is_active: logger.warning('Validated API key but user %s is inactive.' % bmo_username) return show_error_page(request) set_bugzilla_api_key(user, bmo_api_key) try: associate_employee_ldap(user) except LDAPAssociationException as e: logger.info('LDAP association failed: %s' % str(e)) except Exception: logger.exception('Error while performing LDAP association') user.backend = 'rbbz.auth.BugzillaBackend' logger.info('BMO Auth callback succeeded for user: %s' % bmo_username) login(request, user) response = HttpResponseRedirect(redirect) response.delete_cookie('bmo_auth_secret') return response
def get_bmo_auth_callback(request): """Handler for the third part of the Bugzilla auth-delegation process. After the above POST call is executed, Bugzilla then redirects back to this view, passing the return value of the POST handler, as `callback_result`, and optionally a redirect, passed from the original redirect to Bugzilla (from the MozReview login view). This handler then verifies the API key with Bugzilla and attempts to create or update the user in MozReview. If everything succeeds, the user is again redirected back to the original page (or the root page if there was no redirect passed in, e.g., in tests). Otherwise the user is shown an error page. """ bmo_username = request.GET.get('client_api_login', None) callback_result = request.GET.get('callback_result', None) redirect = request.GET.get('redirect', None) secret = request.GET.get('secret', None) if not (bmo_username and callback_result): logger.error('Bugzilla auth callback called without required ' 'parameters.') return render_login_error(request) # Delete expired unverified keys (5 minute lifetime). UnverifiedBugzillaApiKey.objects.filter(timestamp__lte=timezone.now() - timedelta(minutes=5)).delete() parsed = None if not redirect else urlparse(redirect) # Enforce relative redirects; we don't want people crafting auth links # that redirect to other sites. We check the scheme as well as the netloc # to catch data, file, and other such server-less URIs. if not parsed or parsed.scheme or parsed.netloc: redirect = '/' unverified_keys = UnverifiedBugzillaApiKey.objects.filter( bmo_username=bmo_username).order_by('timestamp') if not unverified_keys: logger.error('No unverified keys found for BMO user %s.' % bmo_username) return render_login_error(request) unverified_key = unverified_keys.last() if len(unverified_keys) > 1: logger.warning('Multiple unverified keys on file for BMO user %s. ' 'Using most recent, from %s.' % (bmo_username, unverified_key.timestamp)) if callback_result != unverified_key.callback_result: logger.error('Callback result does not match for BMO user %s.' % bmo_username) return render_login_error(request) if secret is None or request.COOKIES['bmo_auth_secret'] != secret: logger.error('Callback secret does not match cookie for user %s.' % bmo_username) return render_login_error(request) bmo_api_key = unverified_key.api_key unverified_key.delete() b = Bugzilla() try: if not b.valid_api_key(bmo_username, bmo_api_key): logger.error('Invalid API key for %s.' % bmo_username) return render_login_error(request) except BugzillaError as e: logger.error('Error validating API key: %s' % e.msg) return render_login_error(request) b.api_key = bmo_api_key try: user_data = b.get_user(bmo_username) except BugzillaError as e: logger.error('Error getting user data: %s' % e.msg) return render_login_error(request) if not user_data: logger.warning('Could not retrieve user info for %s after ' 'validating API key.' % bmo_username) return render_login_error(request) users = get_or_create_bugzilla_users(user_data) if not users: logger.warning('Failed to create user %s after validating API key.' % bmo_username) return render_login_error(request) user = users[0] assert user.email == bmo_username if not user.is_active: logger.warning('Validated API key but user %s is inactive.' % bmo_username) return render_login_error(request) set_bugzilla_api_key(user, bmo_api_key) try: associate_employee_ldap(user) except LDAPAssociationException as e: logger.info('LDAP association failed: %s' % str(e)) except Exception: logger.exception('Error while performing LDAP association') user.backend = 'mozreview.bugzilla.auth.BugzillaBackend' logger.info('BMO Auth callback succeeded for user: %s' % bmo_username) login(request, user) response = HttpResponseRedirect(redirect) response.delete_cookie('bmo_auth_secret') return response
def get_bmo_auth_callback(request): """Handler for the second part of the Bugzilla auth-delegation process. After the above POST call is executed, Bugzilla then redirects back to this view, passing the return value of the POST handler, as `callback_result`, and optionally a redirect, passed from the original redirect to Bugzilla (from the MozReview login view). This handler then verifies the API key with Bugzilla and attempts to create or update the user in MozReview. If everything succeeds, the user is again redirected back to the original page (or the root page if there was no redirect passed in, e.g., in tests). Otherwise the user is shown an error page. """ bmo_username = request.GET.get('client_api_login', None) callback_result = request.GET.get('callback_result', None) redirect = request.GET.get('redirect', None) if not (bmo_username and callback_result): logging.error('Bugzilla auth callback called without required ' 'parameters.') return show_error_page(request) if not redirect: redirect = '/' unverified_keys = UnverifiedBugzillaApiKey.objects.filter( bmo_username=bmo_username).order_by('timestamp') if not unverified_keys: logging.error('No unverified keys found for BMO user %s.' % bmo_username) return show_error_page(request) unverified_key = unverified_keys.last() if len(unverified_keys) > 1: logging.warning('Multiple unverified keys on file for BMO user %s. ' 'Using most recent, from %s.' % (bmo_username, unverified_key.timestamp)) if callback_result != unverified_key.callback_result: logging.error('Callback result does not match for BMO user %s.' % bmo_username) return show_error_page(request) bmo_api_key = unverified_key.api_key unverified_key.delete() b = Bugzilla() try: if not b.valid_api_key(bmo_username, bmo_api_key): logging.error('Invalid API key for %s.' % bmo_username) return show_error_page(request) except BugzillaError as e: logging.error('Error validating API key: %s' % e.msg) return show_error_page(request) b.api_key = bmo_api_key try: user_data = b.get_user(bmo_username) except BugzillaError as e: logging.error('Error getting user data: %s' % e.msg) return show_error_page(request) if not user_data: logging.warning('Could not retrieve user info for %s after ' 'validating API key.' % bmo_username) return show_error_page(request) users = get_or_create_bugzilla_users(user_data) if not users: logging.warning('Failed to create user %s after validating API key.' % bmo_username) return show_error_page(request) user = users[0] assert user.email == bmo_username if not user.is_active: logging.warning('Validated API key but user %s is inactive.' % bmo_username) return show_error_page(request) set_bugzilla_api_key(user, bmo_api_key) user.backend = 'rbbz.auth.BugzillaBackend' login(request, user) return HttpResponseRedirect(redirect)