def social_associate_user_helper(backend: BaseAuth, return_data: Dict[str, Any], *args: Any, **kwargs: Any) -> Optional[UserProfile]: """Responsible for doing the Zulip-account lookup and validation parts of the Zulip Social auth pipeline (similar to the authenticate() methods in most other auth backends in this file). """ subdomain = backend.strategy.session_get('subdomain') realm = get_realm(subdomain) if realm is None: return_data["invalid_realm"] = True return None return_data["realm_id"] = realm.id if not auth_enabled_helper([backend.auth_backend_name], realm): return_data["auth_backend_disabled"] = True return None if 'auth_failed_reason' in kwargs.get('response', {}): return_data["social_auth_failed_reason"] = kwargs['response'][ "auth_failed_reason"] return None elif hasattr(backend, 'get_verified_emails'): # Some social backends, like GitHubAuthBackend, don't guarantee that # the `details` data is validated. verified_emails = backend.get_verified_emails(*args, **kwargs) if len(verified_emails) == 0: # TODO: Provide a nice error message screen to the user # for this case, rather than just logging a warning. logging.warning( "Social auth (%s) failed because user has no verified emails" % (backend.auth_backend_name, )) return_data["email_not_verified"] = True return None # TODO: ideally, we'd prompt the user for which email they # want to use with another pipeline stage here. validated_email = verified_emails[0] else: # nocoverage # This code path isn't used by GitHubAuthBackend validated_email = kwargs["details"].get("email") if not validated_email: # nocoverage # This code path isn't used with GitHubAuthBackend, but may be relevant for other # social auth backends. return_data['invalid_email'] = True return None try: validate_email(validated_email) except ValidationError: return_data['invalid_email'] = True return None return_data["valid_attestation"] = True return_data['validated_email'] = validated_email user_profile = common_get_active_user(validated_email, realm, return_data) if 'fullname' in kwargs["details"]: return_data["full_name"] = kwargs["details"]["fullname"] else: # If we add support for any of the social auth backends that # don't provide this feature, we'll need to add code here. raise AssertionError("Social auth backend doesn't provide fullname") return user_profile
def social_associate_user_helper(backend: BaseAuth, return_data: Dict[str, Any], *args: Any, **kwargs: Any) -> Optional[UserProfile]: """Responsible for doing the Zulip-account lookup and validation parts of the Zulip Social auth pipeline (similar to the authenticate() methods in most other auth backends in this file). Returns a UserProfile object for successful authentication, and None otherwise. """ subdomain = backend.strategy.session_get('subdomain') try: realm = get_realm(subdomain) except Realm.DoesNotExist: return_data["invalid_realm"] = True return None return_data["realm_id"] = realm.id if not auth_enabled_helper([backend.auth_backend_name], realm): return_data["auth_backend_disabled"] = True return None if 'auth_failed_reason' in kwargs.get('response', {}): return_data["social_auth_failed_reason"] = kwargs['response']["auth_failed_reason"] return None elif hasattr(backend, 'get_verified_emails'): # Some social backends, like GitHubAuthBackend, don't # guarantee that the `details` data is validated (i.e., it's # possible users can put any string they want in the "email" # field of the `details` object). For those backends, we have # custom per-backend code to properly fetch only verified # email addresses from the appropriate third-party API. verified_emails = backend.get_verified_emails(*args, **kwargs) verified_emails_length = len(verified_emails) if verified_emails_length == 0: # TODO: Provide a nice error message screen to the user # for this case, rather than just logging a warning. logging.warning("Social auth (%s) failed because user has no verified emails" % (backend.auth_backend_name,)) return_data["email_not_verified"] = True return None if verified_emails_length == 1: chosen_email = verified_emails[0] else: chosen_email = backend.strategy.request_data().get('email') if not chosen_email: avatars = {} # Dict[str, str] for email in verified_emails: existing_account = common_get_active_user(email, realm, {}) if existing_account is not None: avatars[email] = avatar_url(existing_account) return render(backend.strategy.request, 'zerver/social_auth_select_email.html', context = { 'primary_email': verified_emails[0], 'verified_non_primary_emails': verified_emails[1:], 'backend': 'github', 'avatar_urls': avatars, }) try: validate_email(chosen_email) except ValidationError: return_data['invalid_email'] = True return None if chosen_email not in verified_emails: # If a user edits the submit value for the choose email form, we might # end up with a wrong email associated with the account. The below code # takes care of that. logging.warning("Social auth (%s) failed because user has no verified" " emails associated with the account" % (backend.auth_backend_name,)) return_data["email_not_associated"] = True return None validated_email = chosen_email else: # nocoverage # This code path isn't used by GitHubAuthBackend validated_email = kwargs["details"].get("email") if not validated_email: # nocoverage # This code path isn't used with GitHubAuthBackend, but may be relevant for other # social auth backends. return_data['invalid_email'] = True return None return_data["valid_attestation"] = True return_data['validated_email'] = validated_email user_profile = common_get_active_user(validated_email, realm, return_data) if 'fullname' in kwargs["details"]: return_data["full_name"] = kwargs["details"]["fullname"] else: # If we add support for any of the social auth backends that # don't provide this feature, we'll need to add code here. raise AssertionError("Social auth backend doesn't provide fullname") return user_profile
def social_associate_user_helper(backend: BaseAuth, return_data: Dict[str, Any], *args: Any, **kwargs: Any) -> Optional[UserProfile]: """Responsible for doing the Zulip-account lookup and validation parts of the Zulip Social auth pipeline (similar to the authenticate() methods in most other auth backends in this file). Returns a UserProfile object for successful authentication, and None otherwise. """ subdomain = backend.strategy.session_get('subdomain') realm = get_realm(subdomain) if realm is None: return_data["invalid_realm"] = True return None return_data["realm_id"] = realm.id if not auth_enabled_helper([backend.auth_backend_name], realm): return_data["auth_backend_disabled"] = True return None if 'auth_failed_reason' in kwargs.get('response', {}): return_data["social_auth_failed_reason"] = kwargs['response']["auth_failed_reason"] return None elif hasattr(backend, 'get_verified_emails'): # Some social backends, like GitHubAuthBackend, don't # guarantee that the `details` data is validated (i.e., it's # possible users can put any string they want in the "email" # field of the `details` object). For those backends, we have # custom per-backend code to properly fetch only verified # email addresses from the appropriate third-party API. verified_emails = backend.get_verified_emails(*args, **kwargs) if len(verified_emails) == 0: # TODO: Provide a nice error message screen to the user # for this case, rather than just logging a warning. logging.warning("Social auth (%s) failed because user has no verified emails" % (backend.auth_backend_name,)) return_data["email_not_verified"] = True return None # TODO: ideally, we'd prompt the user for which email they # want to use with another pipeline stage here. validated_email = verified_emails[0] else: # nocoverage # This code path isn't used by GitHubAuthBackend validated_email = kwargs["details"].get("email") if not validated_email: # nocoverage # This code path isn't used with GitHubAuthBackend, but may be relevant for other # social auth backends. return_data['invalid_email'] = True return None try: validate_email(validated_email) except ValidationError: return_data['invalid_email'] = True return None return_data["valid_attestation"] = True return_data['validated_email'] = validated_email user_profile = common_get_active_user(validated_email, realm, return_data) if 'fullname' in kwargs["details"]: return_data["full_name"] = kwargs["details"]["fullname"] else: # If we add support for any of the social auth backends that # don't provide this feature, we'll need to add code here. raise AssertionError("Social auth backend doesn't provide fullname") return user_profile