def process_do_auth(self, user_profile, *args, **kwargs): # type: (UserProfile, *Any, **Any) -> Optional[HttpResponse] # This function needs to be imported from here due to the cyclic # dependency. from zerver.views.auth import (login_or_register_remote_user, redirect_to_subdomain_login_url) from zerver.views.registration import redirect_and_log_into_subdomain return_data = kwargs.get('return_data', {}) inactive_user = return_data.get('inactive_user') inactive_realm = return_data.get('inactive_realm') invalid_subdomain = return_data.get('invalid_subdomain') if inactive_user or inactive_realm: return None strategy = self.strategy # type: ignore # This comes from Python Social Auth. request = strategy.request email_address = self.get_email_address(*args, **kwargs) full_name = self.get_full_name(*args, **kwargs) subdomain = strategy.session_get('subdomain') if not subdomain: return login_or_register_remote_user(request, email_address, user_profile, full_name, bool(invalid_subdomain)) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: return redirect_to_subdomain_login_url() return redirect_and_log_into_subdomain(realm, full_name, email_address)
def process_do_auth(self, user_profile, *args, **kwargs): # type: (UserProfile, *Any, **Any) -> Optional[HttpResponse] # This function needs to be imported from here due to the cyclic # dependency. from zerver.views.auth import (login_or_register_remote_user, redirect_to_subdomain_login_url) from zerver.views.registration import redirect_and_log_into_subdomain return_data = kwargs.get('return_data', {}) inactive_user = return_data.get('inactive_user') inactive_realm = return_data.get('inactive_realm') invalid_subdomain = return_data.get('invalid_subdomain') if inactive_user or inactive_realm: return None strategy = self.strategy # type: ignore # This comes from Python Social Auth. request = strategy.request email_address = self.get_email_address(*args, **kwargs) full_name = self.get_full_name(*args, **kwargs) subdomain = strategy.session_get('subdomain') if not subdomain: return login_or_register_remote_user(request, email_address, user_profile, full_name, bool(invalid_subdomain)) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: return redirect_to_subdomain_login_url() return redirect_and_log_into_subdomain(realm, full_name, email_address)
def process_do_auth(self, user_profile, *args, **kwargs): # type: (UserProfile, *Any, **Any) -> Optional[HttpResponse] # These functions need to be imported here to avoid cyclic # dependency. from zerver.views.auth import (login_or_register_remote_user, redirect_to_subdomain_login_url) from zerver.views.registration import redirect_and_log_into_subdomain return_data = kwargs.get('return_data', {}) inactive_user = return_data.get('inactive_user') inactive_realm = return_data.get('inactive_realm') invalid_subdomain = return_data.get('invalid_subdomain') invalid_email = return_data.get('invalid_email') if inactive_user or inactive_realm: # Redirect to login page. We can't send to registration # workflow with these errors. We will redirect to login page. return None if invalid_email: # In case of invalid email, we will end up on registration page. # This seems better than redirecting to login page. logging.warning("{} got invalid email argument.".format( self.auth_backend_name)) strategy = self.strategy # type: ignore # This comes from Python Social Auth. request = strategy.request email_address = self.get_email_address(*args, **kwargs) full_name = self.get_full_name(*args, **kwargs) is_signup = strategy.session_get('is_signup') == '1' mobile_flow_otp = strategy.session_get('mobile_flow_otp') subdomain = strategy.session_get('subdomain') if not subdomain: # At least in our tests, this can be None; and it's not # clear what the exact semantics of `session_get` are or # what values it might return. Historically we treated # any falsy value here as the root domain, so defensively # continue that behavior. subdomain = Realm.SUBDOMAIN_FOR_ROOT_DOMAIN if (subdomain == Realm.SUBDOMAIN_FOR_ROOT_DOMAIN or mobile_flow_otp is not None): return login_or_register_remote_user( request, email_address, user_profile, full_name, invalid_subdomain=bool(invalid_subdomain), mobile_flow_otp=mobile_flow_otp, is_signup=is_signup) realm = get_realm(subdomain) if realm is None: return redirect_to_subdomain_login_url() return redirect_and_log_into_subdomain(realm, full_name, email_address, is_signup=is_signup)
def process_do_auth(self, user_profile, *args, **kwargs): # type: (UserProfile, *Any, **Any) -> Optional[HttpResponse] # These functions need to be imported here to avoid cyclic # dependency. from zerver.views.auth import (login_or_register_remote_user, redirect_to_subdomain_login_url) from zerver.views.registration import redirect_and_log_into_subdomain return_data = kwargs.get('return_data', {}) inactive_user = return_data.get('inactive_user') inactive_realm = return_data.get('inactive_realm') invalid_subdomain = return_data.get('invalid_subdomain') invalid_email = return_data.get('invalid_email') if inactive_user or inactive_realm: # Redirect to login page. We can't send to registration # workflow with these errors. We will redirect to login page. return None if invalid_email: # In case of invalid email, we will end up on registration page. # This seems better than redirecting to login page. logging.warning("{} got invalid email argument.".format( self.auth_backend_name)) strategy = self.strategy # type: ignore # This comes from Python Social Auth. request = strategy.request email_address = self.get_email_address(*args, **kwargs) full_name = self.get_full_name(*args, **kwargs) is_signup = strategy.session_get('is_signup') == '1' subdomain = strategy.session_get('subdomain') mobile_flow_otp = strategy.session_get('mobile_flow_otp') if not subdomain or mobile_flow_otp is not None: return login_or_register_remote_user( request, email_address, user_profile, full_name, invalid_subdomain=bool(invalid_subdomain), mobile_flow_otp=mobile_flow_otp, is_signup=is_signup) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: return redirect_to_subdomain_login_url() return redirect_and_log_into_subdomain(realm, full_name, email_address, is_signup=is_signup)
def process_do_auth(self, user_profile, *args, **kwargs): # type: (UserProfile, *Any, **Any) -> Optional[HttpResponse] # These functions need to be imported here to avoid cyclic # dependency. from zerver.views.auth import (login_or_register_remote_user, redirect_to_subdomain_login_url) from zerver.views.registration import redirect_and_log_into_subdomain return_data = kwargs.get('return_data', {}) inactive_user = return_data.get('inactive_user') inactive_realm = return_data.get('inactive_realm') invalid_subdomain = return_data.get('invalid_subdomain') invalid_email = return_data.get('invalid_email') if inactive_user or inactive_realm: # Redirect to login page. We can't send to registration # workflow with these errors. We will redirect to login page. return None if invalid_email: # In case of invalid email, we will end up on registration page. # This seems better than redirecting to login page. logging.warning( "{} got invalid email argument.".format(self.auth_backend_name) ) strategy = self.strategy # type: ignore # This comes from Python Social Auth. request = strategy.request email_address = self.get_email_address(*args, **kwargs) full_name = self.get_full_name(*args, **kwargs) is_signup = strategy.session_get('is_signup') == '1' subdomain = strategy.session_get('subdomain') if not subdomain: return login_or_register_remote_user(request, email_address, user_profile, full_name, invalid_subdomain=bool(invalid_subdomain), is_signup=is_signup) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: return redirect_to_subdomain_login_url() return redirect_and_log_into_subdomain(realm, full_name, email_address, is_signup=is_signup)
def finish_google_oauth2(request): # type: (HttpRequest) -> HttpResponse error = request.GET.get('error') if error == 'access_denied': return redirect('/') elif error is not None: logging.warning('Error from google oauth2 login: %s' % (request.GET.get("error"), )) return HttpResponse(status=400) csrf_state = request.GET.get('state') if csrf_state is None or len(csrf_state.split(':')) != 5: logging.warning('Missing Google oauth2 CSRF state') return HttpResponse(status=400) (csrf_data, hmac_value) = csrf_state.rsplit(':', 1) if hmac_value != google_oauth2_csrf(request, csrf_data): logging.warning('Google oauth2 CSRF error') return HttpResponse(status=400) cur_time, subdomain, mobile_flow_otp, is_signup = csrf_data.split(':') if mobile_flow_otp == '0': mobile_flow_otp = None is_signup = bool(is_signup == '1') resp = requests.post( 'https://www.googleapis.com/oauth2/v3/token', data={ 'code': request.GET.get('code'), 'client_id': settings.GOOGLE_OAUTH2_CLIENT_ID, 'client_secret': settings.GOOGLE_OAUTH2_CLIENT_SECRET, 'redirect_uri': ''.join(( settings.EXTERNAL_URI_SCHEME, settings.EXTERNAL_HOST, reverse('zerver.views.auth.finish_google_oauth2'), )), 'grant_type': 'authorization_code', }, ) if resp.status_code == 400: logging.warning( 'User error converting Google oauth2 login to token: %s' % (resp.text, )) return HttpResponse(status=400) elif resp.status_code != 200: logging.error( 'Could not convert google oauth2 code to access_token: %s' % (resp.text, )) return HttpResponse(status=400) access_token = resp.json()['access_token'] resp = requests.get('https://www.googleapis.com/plus/v1/people/me', params={'access_token': access_token}) if resp.status_code == 400: logging.warning('Google login failed making info API call: %s' % (resp.text, )) return HttpResponse(status=400) elif resp.status_code != 200: logging.error('Google login failed making API call: %s' % (resp.text, )) return HttpResponse(status=400) body = resp.json() try: full_name = body['name']['formatted'] except KeyError: # Only google+ users have a formated name. I am ignoring i18n here. full_name = u'{} {}'.format(body['name']['givenName'], body['name']['familyName']) for email in body['emails']: if email['type'] == 'account': break else: logging.error('Google oauth2 account email not found: %s' % (body, )) return HttpResponse(status=400) email_address = email['value'] if not subdomain or mobile_flow_otp is not None: # When request was not initiated from subdomain. user_profile, return_data = authenticate_remote_user( request, email_address, subdomain=subdomain) invalid_subdomain = bool(return_data.get('invalid_subdomain')) return login_or_register_remote_user(request, email_address, user_profile, full_name, invalid_subdomain, mobile_flow_otp=mobile_flow_otp, is_signup=is_signup) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: return redirect_to_subdomain_login_url() return redirect_and_log_into_subdomain(realm, full_name, email_address, is_signup=is_signup)
def finish_google_oauth2(request): # type: (HttpRequest) -> HttpResponse error = request.GET.get('error') if error == 'access_denied': return redirect('/') elif error is not None: logging.warning('Error from google oauth2 login: %s' % (request.GET.get("error"),)) return HttpResponse(status=400) csrf_state = request.GET.get('state') if csrf_state is None or len(csrf_state.split(':')) != 3: logging.warning('Missing Google oauth2 CSRF state') return HttpResponse(status=400) value, hmac_value, subdomain = csrf_state.split(':') if hmac_value != google_oauth2_csrf(request, value + subdomain): logging.warning('Google oauth2 CSRF error') return HttpResponse(status=400) resp = requests.post( 'https://www.googleapis.com/oauth2/v3/token', data={ 'code': request.GET.get('code'), 'client_id': settings.GOOGLE_OAUTH2_CLIENT_ID, 'client_secret': settings.GOOGLE_OAUTH2_CLIENT_SECRET, 'redirect_uri': ''.join(( settings.EXTERNAL_URI_SCHEME, settings.EXTERNAL_HOST, reverse('zerver.views.auth.finish_google_oauth2'), )), 'grant_type': 'authorization_code', }, ) if resp.status_code == 400: logging.warning('User error converting Google oauth2 login to token: %s' % (resp.text,)) return HttpResponse(status=400) elif resp.status_code != 200: logging.error('Could not convert google oauth2 code to access_token: %s' % (resp.text,)) return HttpResponse(status=400) access_token = resp.json()['access_token'] resp = requests.get( 'https://www.googleapis.com/plus/v1/people/me', params={'access_token': access_token} ) if resp.status_code == 400: logging.warning('Google login failed making info API call: %s' % (resp.text,)) return HttpResponse(status=400) elif resp.status_code != 200: logging.error('Google login failed making API call: %s' % (resp.text,)) return HttpResponse(status=400) body = resp.json() try: full_name = body['name']['formatted'] except KeyError: # Only google+ users have a formated name. I am ignoring i18n here. full_name = u'{} {}'.format( body['name']['givenName'], body['name']['familyName'] ) for email in body['emails']: if email['type'] == 'account': break else: logging.error('Google oauth2 account email not found: %s' % (body,)) return HttpResponse(status=400) email_address = email['value'] if not subdomain: # When request was not initiated from subdomain. user_profile, return_data = authenticate_remote_user(request, email_address) invalid_subdomain = bool(return_data.get('invalid_subdomain')) return login_or_register_remote_user(request, email_address, user_profile, full_name, invalid_subdomain) try: realm = Realm.objects.get(string_id=subdomain) except Realm.DoesNotExist: return redirect_to_subdomain_login_url() return redirect_and_log_into_subdomain(realm, full_name, email_address)