Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
    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)
Beispiel #4
0
    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)
Beispiel #5
0
    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)
Beispiel #6
0
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)
Beispiel #7
0
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)