def handleResendSMS(self, action):
        """
        Handle resend SMS action.
        """
        if not action.title == _(u'Resend SMS'):
            return

        logger.debug('resend sms')

        data, errors = self.extractData()
        #if errors:
        #    return False

        token = data.get('token', '')

        user = None
        username = self.request.get('auth_user', '')

        if username:
            user = api.user.get(username=username)

            # Validating the signed request data. If invalid (likely throttled with or expired), generate an
            # appropriate error message.
            user_data_validation_result = validate_user_data(
                request=self.request, user=user)
            if not user_data_validation_result.result:
                if 'Signature timestamp expired!' in user_data_validation_result.reason:
                    # Remove used authentication code
                    user.setMemberProperties(
                        mapping={
                            'mobile_number_authentication_code': '',
                        })
                IStatusMessage(self.request).addStatusMessage(
                    _("Invalid data. Details: {0}").format(' '.join(
                        user_data_validation_result.reason)), 'error')
                return

        mobile_number_authentication_code = generate_code(user)
        mobile_number = user.getProperty('mobile_number')

        # Send the SMS
        sms_sent = send_login_code_sms(mobile_number=mobile_number,
                                       code=mobile_number_authentication_code)

        if sms_sent:
            # Save the `signature` value to the `mobile_number_reset_token`.
            user.setMemberProperties(
                mapping={
                    'mobile_number_authentication_code':
                    mobile_number_authentication_code,
                })
            IStatusMessage(self.request).addStatusMessage(
                _("Your SMS has just been resent."), 'info')

        self.request.response.redirect("{0}?{1}".format(
            self.request.ACTUAL_URL, self.request.QUERY_STRING))
Ejemplo n.º 2
0
    def handleSubmit(self, action):
        if bool(api.user.is_anonymous()) is True:
            self.request.response.setStatus(401, _('Forbidden for anonymous'),
                                            True)
            return False

        data, errors = self.extractData()
        if errors:
            return False

        mobile_number = data.get('mobile_number', '')
        reason = None

        if mobile_number:
            try:
                # Set the ``enable_two_step_verification`` to True
                user = api.user.get_current()

                # Send a code to confirm the mobile number
                mobile_number_confirmation_code = generate_code(user)

                # Send the SMS
                send_mobile_number_setup_confirmation_code_sms(
                    mobile_number=mobile_number,
                    code=mobile_number_confirmation_code)

                user.setMemberProperties(
                    mapping={
                        'mobile_number':
                        mobile_number,
                        'mobile_number_reset_code':
                        mobile_number_confirmation_code,
                    })

                IStatusMessage(self.request).addStatusMessage(
                    _("A confirmation SMS message has been sent to the mobile number specified."
                      ), 'info')
                redirect_url = "{0}/@@setup-two-step-verification".format(
                    self.context.absolute_url())
            except Exception as e:
                reason = _(str(e))
        else:
            reason = _("Invalid mobile number.")

        if reason is not None:
            IStatusMessage(self.request).addStatusMessage(
                _("Setup failed! {0}".format(reason)), 'error')
            redirect_url = "{0}/@@setup-mobile-number".format(
                self.context.absolute_url())

        self.request.response.redirect(redirect_url)
    def handleSubmit(self, action):
        if bool(api.user.is_anonymous()) is True:
            self.request.response.setStatus(401, _('Forbidden for anonymous'), True)
            return False

        data, errors = self.extractData()
        if errors:
            return False

        mobile_number = data.get('mobile_number', '')
        reason = None

        if mobile_number:
            try:
                # Set the ``enable_two_step_verification`` to True
                user = api.user.get_current()

                # Send a code to confirm the mobile number
                mobile_number_confirmation_code = generate_code(user)

                # Send the SMS
                send_mobile_number_setup_confirmation_code_sms(
                    mobile_number = mobile_number,
                    code = mobile_number_confirmation_code
                    )

                user.setMemberProperties(
                    mapping = {
                        'mobile_number': mobile_number,
                        'mobile_number_reset_code': mobile_number_confirmation_code,
                    }
                    )

                IStatusMessage(self.request).addStatusMessage(
                    _("A confirmation SMS message has been sent to the mobile number specified."),
                    'info'
                    )
                redirect_url = "{0}/@@setup-two-step-verification".format(self.context.absolute_url())
            except Exception as e:
                reason = _(str(e))
        else:
            reason = _("Invalid mobile number.")

        if reason is not None:
            IStatusMessage(self.request).addStatusMessage(_("Setup failed! {0}".format(reason)), 'error')
            redirect_url = "{0}/@@setup-mobile-number".format(self.context.absolute_url())

        self.request.response.redirect(redirect_url)
Ejemplo n.º 4
0
    def authenticateCredentials(self, credentials):
        """
        Place to actually validate the user credentials specified and return a
         tuple (login, login) on success or (None, None) on failure.

        If we find one and two-step verification is not enabled for the
         account, we consider the authentication passed and log the user in.
        If two-step verification has been enabled for the account, the first
         step of authentication is considered to be passed and we go to
        the next page (having the user and pass remembered), where we check
         for the token generated by the token generator (SMS Authenticator).
        If the token is valid too, we log the user in.
        """
        login = credentials['login']
        password = credentials['password']

        if not login:
            return None

        user = api.user.get(username=login)

        two_step_verification_enabled = user.getProperty(
            'enable_two_step_verification')

        if two_step_verification_enabled:
            # First see, if the password is correct.
            # We fetch the user manager plugin to chekc that.
            auth_plugins = self._getPAS().plugins.listPlugins(
                IAuthenticationPlugin)
            user_manager = authorized = None
            for plugid, authplugin in auth_plugins:
                if 'user' in plugid:
                    user_manager = authplugin
                    break
            if user_manager:
                authorized = user_manager.authenticateCredentials(credentials)
            # Not logged in, we want the user to be authorized before
            # we do our part
            if authorized is None:
                return None
            if is_whitelisted_client(request=self.REQUEST, user=user):
                return None

            # Setting the data in the session doesn't seem to work. That's
            #  why we use the `ska` package.
            # The secret key would be then a combination of username,
            # secret stored in users' profile and the browser version.
            request = self.REQUEST
            response = request['RESPONSE']
            response.setCookie('__ac', '', path='/')

            # Redirect to token thing...
            signed_url = sign_user_data(request=request,
                                        user=user,
                                        url='@@sms-authenticator-token')

            came_from_adapter = ICameFrom(request)
            # Appending possible `came_from`, but give it another name.
            came_from = came_from_adapter.getCameFrom()
            if came_from:
                signed_url = '{0}&next_url={1}'.format(signed_url, came_from)

            # ****************************************
            # Generate the login code and send the SMS
            mobile_number = user.getProperty('mobile_number')
            mobile_number_authentication_code = user.getProperty(
                'mobile_number_authentication_code')

            # If user doesn't have yet a mobile numer specified, redirect
            # him to the reset mobile number view.
            if not mobile_number:
                IStatusMessage(request).addStatusMessage(
                    _("Two-step verification is enabled for your account, but "
                      "you haven't specified a mobile number yet! In order to"
                      " be able to log in, you have to go through mobile "
                      "number recovery procedure first."), 'warning')
                response.redirect(
                    '@@request-mobile-number-reset/?username={0}'.format(
                        login),
                    lock=1)
                return None

            # Generate a code
            mobile_number_authentication_code = generate_code(user)

            # Send the SMS
            sms_sent = send_login_code_sms(
                mobile_number=mobile_number,
                code=mobile_number_authentication_code)

            if sms_sent:
                # Save the `signature` value to the `mobile_number_reset_token`
                user.setMemberProperties(
                    mapping={
                        'mobile_number_authentication_code':
                        mobile_number_authentication_code,
                    })

            # Redirecting user to authentication code validation page.
            response.redirect(signed_url, lock=1)
            return None

        if credentials.get('extractor') != self.getId():
            return None

        return None
    def handleResendSMS(self, action):
        """
        Handle resend SMS action.
        """
        if not action.title == _(u'Resend SMS'):
            return

        logger.debug('resend sms')

        data, errors = self.extractData()
        #if errors:
        #    return False

        token = data.get('token', '')

        user = None
        username = self.request.get('auth_user', '')

        if username:
            user = api.user.get(username=username)

            # Validating the signed request data. If invalid (likely throttled with or expired), generate an
            # appropriate error message.
            user_data_validation_result = validate_user_data(request=self.request, user=user)
            if not user_data_validation_result.result:
                if 'Signature timestamp expired!' in user_data_validation_result.reason:
                    # Remove used authentication code
                    user.setMemberProperties(
                        mapping = {
                            'mobile_number_authentication_code': '',
                            }
                        )
                IStatusMessage(self.request).addStatusMessage(
                    _("Invalid data. Details: {0}").format(
                        ' '.join(user_data_validation_result.reason)
                     ),
                    'error'
                )
                return

        mobile_number_authentication_code = generate_code(user)
        mobile_number = user.getProperty('mobile_number')

        # Send the SMS
        sms_sent = send_login_code_sms(
            mobile_number = mobile_number,
            code = mobile_number_authentication_code
            )

        if sms_sent:
            # Save the `signature` value to the `mobile_number_reset_token`.
            user.setMemberProperties(
                mapping = {
                    'mobile_number_authentication_code': mobile_number_authentication_code,
                }
                )
            IStatusMessage(self.request).addStatusMessage(
                _("Your SMS has just been resent."), 'info'
                )

        self.request.response.redirect("{0}?{1}".format(self.request.ACTUAL_URL, self.request.QUERY_STRING))
    def authenticateCredentials(self, credentials):
        """
        Place to actually validate the user credentials specified and return a
         tuple (login, login) on success or (None, None) on failure.

        If we find one and two-step verification is not enabled for the
         account, we consider the authentication passed and log the user in.
        If two-step verification has been enabled for the account, the first
         step of authentication is considered to be passed and we go to
        the next page (having the user and pass remembered), where we check
         for the token generated by the token generator (SMS Authenticator).
        If the token is valid too, we log the user in.
        """
        login = credentials['login']
        password = credentials['password']

        if not login:
            return None

        user = api.user.get(username=login)

        two_step_verification_enabled = user.getProperty(
            'enable_two_step_verification')

        if two_step_verification_enabled:
            # First see, if the password is correct.
            # We fetch the user manager plugin to chekc that.
            auth_plugins = self._getPAS().plugins.listPlugins(
                IAuthenticationPlugin)
            user_manager = authorized = None
            for plugid, authplugin in auth_plugins:
                if 'user' in plugid:
                    user_manager = authplugin
                    break
            if user_manager:
                authorized = user_manager.authenticateCredentials(credentials)
            # Not logged in, we want the user to be authorized before
            # we do our part
            if authorized is None:
                return None
            if is_whitelisted_client(request=self.REQUEST, user=user):
                return None

            # Setting the data in the session doesn't seem to work. That's
            #  why we use the `ska` package.
            # The secret key would be then a combination of username,
            # secret stored in users' profile and the browser version.
            request = self.REQUEST
            response = request['RESPONSE']
            response.setCookie('__ac', '', path='/')

            # Redirect to token thing...
            signed_url = sign_user_data(
                request=request, user=user, url='@@sms-authenticator-token')

            came_from_adapter = ICameFrom(request)
            # Appending possible `came_from`, but give it another name.
            came_from = came_from_adapter.getCameFrom()
            if came_from:
                signed_url = '{0}&next_url={1}'.format(signed_url, came_from)

            # ****************************************
            # Generate the login code and send the SMS
            mobile_number = user.getProperty('mobile_number')
            mobile_number_authentication_code = user.getProperty(
                'mobile_number_authentication_code')

            # If user doesn't have yet a mobile numer specified, redirect
            # him to the reset mobile number view.
            if not mobile_number:
                IStatusMessage(request).addStatusMessage(
                    _("Two-step verification is enabled for your account, but "
                      "you haven't specified a mobile number yet! In order to"
                      " be able to log in, you have to go through mobile "
                      "number recovery procedure first."), 'warning'
                    )
                response.redirect(
                    '@@request-mobile-number-reset/?username={0}'.format(
                        login), lock=1)
                return None

            # Generate a code
            mobile_number_authentication_code = generate_code(user)

            # Send the SMS
            sms_sent = send_login_code_sms(
                mobile_number=mobile_number,
                code=mobile_number_authentication_code
                )

            if sms_sent:
                # Save the `signature` value to the `mobile_number_reset_token`
                user.setMemberProperties(
                    mapping={
                        'mobile_number_authentication_code':
                        mobile_number_authentication_code,
                    }
                    )

            # Redirecting user to authentication code validation page.
            response.redirect(signed_url, lock=1)
            return None

        if credentials.get('extractor') != self.getId():
            return None

        return None
    def handleSubmit(self, action):
        data, errors = self.extractData()
        if errors:
            return False

        username = data.get('username', '')
        mobile_number = data.get('mobile_number', '')

        user = api.user.get(username=username)

        reason = None
        if user:
            try:
                # Here we need to generate a token which is valid for let's say, 2 hours
                # using which it should be possible to reset the mobile number. The `signature`
                # generated should be saved in the user profile `mobile_number_reset_token`.
                ska_secret_key = get_ska_secret_key(request=self.request, user=user)

                # We also need to generate another token (no security, just a random string)
                # to sent to users' mobile number.
                mobile_number_reset_code = generate_code(user)

                token_lifetime = get_ska_token_lifetime()

                signature = Signature.generate_signature(
                    auth_user = username,
                    secret_key = ska_secret_key,
                    lifetime = token_lifetime,
                    extra = {'mobile_number': mobile_number}
                    )

                request_helper = RequestHelper(
                    signature_param = 'signature',
                    auth_user_param = 'auth_user',
                    valid_until_param = 'valid_until'
                    )

                signed_url = request_helper.signature_to_url(
                    signature = signature,
                    endpoint_url = '{0}/{1}'.format(self.context.absolute_url(), '@@reset-mobile-number')
                )

                # Send the SMS
                sms_sent = send_mobile_number_reset_confirmation_code_sms(
                    mobile_number = mobile_number,
                    code = mobile_number_reset_code
                    )

                if not sms_sent:
                    IStatusMessage(self.request).addStatusMessage(
                        _("An error occured while sending the SMS to the number specified."),
                        'info'
                        )
                    redirect_url = "{0}".format(self.context.absolute_url())
                    self.request.response.redirect(redirect_url)
                    return

                # Save the `signature` value to the `mobile_number_reset_token`.
                user.setMemberProperties(
                    mapping = {
                        'mobile_number_reset_token': str(signature),
                        'mobile_number_reset_code': mobile_number_reset_code,
                        'mobile_number_authentication_code': '',
                        }
                    )

                # Now we need to send an email to user with URL in and a small explanations.
                try:
                    host = getToolByName(self, 'MailHost')

                    mail_text_template = self.context.restrictedTraverse('request_mobile_number_reset_email')
                    mail_text = mail_text_template(
                        member = user,
                        mobile_number_reset_url = signed_url,
                        charset = 'utf-8'
                        )
                    mail_text = mail_text.format(mobile_number_reset_url=signed_url)

                    host.send(
                        mail_text.encode('UTF-8'),
                        immediate = True,
                        msg_type = 'text/html'
                        )
                except SMTPRecipientsRefused as e:
                    raise SMTPRecipientsRefused('Recipient address rejected by server')

                IStatusMessage(self.request).addStatusMessage(
                    _("An email with further instructions for (re)setting your mobile number has been sent."),
                    'info'
                    )
                redirect_url = "{0}/@@reset-email-sent".format(self.context.absolute_url())
                self.request.response.redirect(redirect_url)
            except ValueError as e:
                reason = _(str(e))
        else:
            reason = _("Invalid username.")

        if reason is not None:
            IStatusMessage(self.request).addStatusMessage(
                _("Request for mobile number reset is failed! {0}").format(reason),
                'error'
                )
Ejemplo n.º 8
0
    def handleSubmit(self, action):
        data, errors = self.extractData()
        if errors:
            return False

        username = data.get('username', '')
        mobile_number = data.get('mobile_number', '')

        user = api.user.get(username=username)

        reason = None
        if user:
            try:
                # Here we need to generate a token which is valid for let's say, 2 hours
                # using which it should be possible to reset the mobile number. The `signature`
                # generated should be saved in the user profile `mobile_number_reset_token`.
                ska_secret_key = get_ska_secret_key(request=self.request,
                                                    user=user)

                # We also need to generate another token (no security, just a random string)
                # to sent to users' mobile number.
                mobile_number_reset_code = generate_code(user)

                token_lifetime = get_ska_token_lifetime()

                signature = Signature.generate_signature(
                    auth_user=username,
                    secret_key=ska_secret_key,
                    lifetime=token_lifetime,
                    extra={'mobile_number': mobile_number})

                request_helper = RequestHelper(signature_param='signature',
                                               auth_user_param='auth_user',
                                               valid_until_param='valid_until')

                signed_url = request_helper.signature_to_url(
                    signature=signature,
                    endpoint_url='{0}/{1}'.format(self.context.absolute_url(),
                                                  '@@reset-mobile-number'))

                # Send the SMS
                sms_sent = send_mobile_number_reset_confirmation_code_sms(
                    mobile_number=mobile_number, code=mobile_number_reset_code)

                if not sms_sent:
                    IStatusMessage(self.request).addStatusMessage(
                        _("An error occured while sending the SMS to the number specified."
                          ), 'info')
                    redirect_url = "{0}".format(self.context.absolute_url())
                    self.request.response.redirect(redirect_url)
                    return

                # Save the `signature` value to the `mobile_number_reset_token`.
                user.setMemberProperties(
                    mapping={
                        'mobile_number_reset_token': str(signature),
                        'mobile_number_reset_code': mobile_number_reset_code,
                        'mobile_number_authentication_code': '',
                    })

                # Now we need to send an email to user with URL in and a small explanations.
                try:
                    host = getToolByName(self, 'MailHost')

                    mail_text_template = self.context.restrictedTraverse(
                        'request_mobile_number_reset_email')
                    mail_text = mail_text_template(
                        member=user,
                        mobile_number_reset_url=signed_url,
                        charset='utf-8')
                    mail_text = mail_text.format(
                        mobile_number_reset_url=signed_url)

                    host.send(mail_text.encode('UTF-8'),
                              immediate=True,
                              msg_type='text/html')
                except SMTPRecipientsRefused as e:
                    raise SMTPRecipientsRefused(
                        'Recipient address rejected by server')

                IStatusMessage(self.request).addStatusMessage(
                    _("An email with further instructions for (re)setting your mobile number has been sent."
                      ), 'info')
                redirect_url = "{0}/@@reset-email-sent".format(
                    self.context.absolute_url())
                self.request.response.redirect(redirect_url)
            except ValueError as e:
                reason = _(str(e))
        else:
            reason = _("Invalid username.")

        if reason is not None:
            IStatusMessage(self.request).addStatusMessage(
                _("Request for mobile number reset is failed! {0}").format(
                    reason), 'error')