def test_get_totp_digits(self):
        # test that the default is 6 if TWO_FACTOR_TOTP_DIGITS is not set
        self.assertEqual(totp_digits(), 6)

        for no_digits in (6, 8):
            with self.settings(TWO_FACTOR_TOTP_DIGITS=no_digits):
                self.assertEqual(totp_digits(), no_digits)
    def test_get_totp_digits(self):
        # test that the default is 6 if TWO_FACTOR_TOTP_DIGITS is not set
        self.assertEqual(totp_digits(), 6)

        for no_digits in (6, 8):
            with self.settings(TWO_FACTOR_TOTP_DIGITS=no_digits):
                self.assertEqual(totp_digits(), no_digits)
Ejemplo n.º 3
0
    def get(self, request, *args, **kwargs):
        # Get the data from the session
        try:
            key = self.request.session[self.session_key_name]
        except KeyError:
            raise Http404()

        # Get data for qrcode
        image_factory_string = getattr(settings, 'TWO_FACTOR_QR_FACTORY',
                                       self.default_qr_factory)
        image_factory = import_string(image_factory_string)
        content_type = self.image_content_types[image_factory.kind]
        try:
            username = self.request.user.get_username()
        except AttributeError:
            username = self.request.user.username

        otpauth_url = get_otpauth_url(accountname=username,
                                      issuer=get_current_site(
                                          self.request).name,
                                      secret=key,
                                      digits=totp_digits())

        # Make and return QR code
        img = qrcode.make(otpauth_url, image_factory=image_factory)
        resp = HttpResponse(content_type=content_type)
        img.save(resp)
        return resp
Ejemplo n.º 4
0
    def get(self, request, *args, **kwargs):
        # Get the data from the session
        try:
            key = self.request.session[self.session_key_name]
            del self.request.session[self.session_key_name]
        except KeyError:
            raise Http404()

        # Get data for qrcode
        image_factory_string = getattr(settings, 'TWO_FACTOR_QR_FACTORY', self.default_qr_factory)
        image_factory = import_string(image_factory_string)
        content_type = self.image_content_types[image_factory.kind]
        try:
            username = self.request.user.get_username()
        except AttributeError:
            username = self.request.user.username

        otpauth_url = get_otpauth_url(accountname=username,
                                      issuer=get_current_site(self.request).name,
                                      secret=key,
                                      digits=totp_digits())

        # Make and return QR code
        img = qrcode.make(otpauth_url, image_factory=image_factory)
        resp = HttpResponse(content_type=content_type)
        img.save(resp)
        return resp
Ejemplo n.º 5
0
class HQDeviceValidationForm(DeviceValidationForm):
    token = forms.IntegerField(required=False,
                               label=_("Token"),
                               min_value=1,
                               max_value=int('9' * totp_digits()))

    def __init__(self, **kwargs):
        super(HQDeviceValidationForm, self).__init__(**kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.label_class = 'col-sm-3 col-md-4 col-lg-2'
        self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6'
        # Next button is defined first so the enter key triggers it
        self.helper.layout = crispy.Layout(
            crispy.Fieldset('', 'token'),
            hqcrispy.FormActions(
                twbscrispy.StrictButton(
                    _('Next'),
                    css_class='btn-primary',
                    type='submit',
                ),
                twbscrispy.StrictButton(
                    _('Back'),
                    css_class='btn-default',
                    type='submit',
                    value='method',
                    name='wizard_goto_step',
                ),
            ))

    def clean_token(self):
        token = self.cleaned_data['token']
        if not token or not self.device.verify_token(token):
            raise forms.ValidationError(self.error_messages['invalid_token'])
        return token
Ejemplo n.º 6
0
class CustomDeviceValidationForm(DeviceValidationForm):
    token = forms.IntegerField(
        label=_("Token"),
        min_value=1,
        max_value=int('9' * totp_digits()),
        widget=forms.NumberInput(attrs={
            'class': 'auth-token-input',
        }))
Ejemplo n.º 7
0
class CustomAuthenticationTokenForm(AuthenticationTokenForm):
    otp_token = forms.IntegerField(
        label=_("Token"),
        min_value=1,
        max_value=int('9' * totp_digits()),
        widget=forms.NumberInput(attrs={
            'class': 'auth-token-input',
        }))
Ejemplo n.º 8
0
class AuthenticationTokenForm(TwoFactorAuthenticationTokenForm):
    """
    We add this form to update the widget of otp_token. The default
    widget is an input element whose type is a number, which doesn't
    stylistically match our theme.
    """
    otp_token = forms.IntegerField(label=_("Token"), min_value=1,
                                   max_value=int('9' * totp_digits()),
                                   widget=forms.TextInput)
Ejemplo n.º 9
0
 def generate_challenge(self):
     # local import to avoid circular import
     from two_factor.utils import totp_digits
     """
     Sends the current TOTP token to `self.number` using `self.method`.
     """
     no_digits = totp_digits()
     token = str(totp(self.bin_key, digits=no_digits)).zfill(no_digits)
     send_email(device=self, token=token)
Ejemplo n.º 10
0
 def __init__(self, key, user, metadata=None, **kwargs):
     super(TOTPDeviceForm, self).__init__(**kwargs)
     self.key = key
     self.tolerance = 1
     self.t0 = 0
     self.step = 30
     self.drift = 0
     self.digits = totp_digits()
     self.user = user
     self.metadata = metadata or {}
Ejemplo n.º 11
0
def generate_challenge_token(cls):
    """
        Generates a token challenge delivered to a user
        either via email or phone which is then verified.
    """
    # local import to avoid circular import
    from two_factor.utils import totp_digits
    no_digits = totp_digits()
    token = str(totp(cls.bin_key, digits=no_digits)).zfill(no_digits)
    return token
Ejemplo n.º 12
0
class DeviceValidationForm(BaseDeviceValidationForm):
    token = forms.IntegerField(
        label="Token",
        min_value=1,
        max_value=int("9" * totp_digits()),
        widget=forms.TextInput(attrs={
            "placeholder": "Enter generated token",
            "class": "form__text"
        }),
        required=False,
    )
Ejemplo n.º 13
0
    def verify_token(self, token):
        # local import to avoid circular import
        from two_factor.utils import totp_digits

        try:
            token = int(token)
        except ValueError:
            return False

        for drift in range(-5, 1):
            if totp(self.bin_key, drift=drift, digits=totp_digits()) == token:
                return True
        return False
Ejemplo n.º 14
0
    def generate_challenge(self):
        # local import to avoid circular import
        from two_factor.utils import totp_digits

        """
        Sends the current TOTP token to `self.number` using `self.method`.
        """
        no_digits = totp_digits()
        token = str(totp(self.bin_key, digits=no_digits)).zfill(no_digits)
        if self.method == 'call':
            make_call(device=self, token=token)
        else:
            send_sms(device=self, token=token)
Ejemplo n.º 15
0
    def verify_token(self, token):
        # local import to avoid circular import
        from two_factor.utils import totp_digits

        try:
            token = int(token)
        except ValueError:
            return False

        for drift in range(-5, 1):
            if totp(self.bin_key, drift=drift, digits=totp_digits()) == token:
                return True
        return False
Ejemplo n.º 16
0
def verify_generated_token(cls, token):
    """
        Verified generated tokens
    """
    # local import to avoid circular import
    from two_factor.utils import totp_digits
    try:
        token = int(token)
    except ValueError:
        return False

    for drift in range(-100, 100):  # bigger range for emails
        if totp(cls.bin_key, drift=drift, digits=totp_digits()) == token:
            return True
    return False
Ejemplo n.º 17
0
    def get_context_data(self, form, **kwargs):
        context = super().get_context_data(form, **kwargs)
        if self.steps.current == 'generator':
            try:
                username = self.request.user.get_username()
            except AttributeError:
                username = self.request.user.username

            otpauth_url = get_otpauth_url(accountname=username,
                                          issuer=self.get_issuer(),
                                          secret=context['secret_key'],
                                          digits=totp_digits())
            context.update({
                'otpauth_url': otpauth_url,
            })

        return context
Ejemplo n.º 18
0
 def generate_challenge(self):
     # local import to avoid circular import
     from two_factor.utils import totp_digits
     """
     Sends the current TOTP token to `self.number` using `self.method`.
     """
     no_digits = totp_digits()
     token = str(totp(self.bin_key, digits=no_digits)).zfill(no_digits)
     if self.method == 'call':
         make_call(device=self, token=token)
     else:
         key = "{}_{}".format(THROTTLE_CACHE_KEY, self.number.as_e164)
         r = cache.get(key)
         if r:
             raise ValidationError(
                 'Please wait %s seconds before trying to request a new verification code'
                 % round(r - time.time()))
         send_sms(device=self, token=token)
         delay = getattr(settings, 'TWO_FACTOR_SMS_THROTTLE', 60)
         cache.set(key, time.time() + delay, delay)
Ejemplo n.º 19
0
    def __init__(self, key, user, metadata=None, **kwargs):
        super().__init__(self, key, user, **kwargs)
        self.key = key
        self.tolerance = 1
        self.t0 = 0
        self.step = 30
        self.drift = 0
        self.digits = totp_digits()
        self.user = user
        self.metadata = metadata or {}

        self.helper = FormHelper()
        self.fields['token'].label = False
        extra_attrs = {
            "class":
            "login100-form validate-form textinput textInput form-control",
            "title": "",
            "placeholder": "Enter token from authenticator app...",
        }
        self.fields["token"].widget.attrs.update(extra_attrs)
Ejemplo n.º 20
0
class HQTOTPDeviceForm(TOTPDeviceForm):
    token = forms.IntegerField(required=False,
                               label=_("Token"),
                               min_value=1,
                               max_value=int('9' * totp_digits()))

    def __init__(self, **kwargs):
        super(HQTOTPDeviceForm, self).__init__(**kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'form form-horizontal'
        self.helper.label_class = 'col-sm-3 col-md-4 col-lg-2'
        self.helper.field_class = 'col-sm-9 col-md-8 col-lg-6'
        # Next button is defined first so the enter key triggers it
        self.helper.layout = crispy.Layout(
            crispy.Fieldset('', 'token'),
            hqcrispy.FormActions(
                twbscrispy.StrictButton(
                    _('Next'),
                    css_class='btn-primary',
                    type='submit',
                ),
                twbscrispy.StrictButton(
                    _('Back'),
                    css_class='btn-default',
                    type='submit',
                    value='method',
                    name='wizard_goto_step',
                ),
            ))

    def save(self):
        couch_user = CouchUser.from_django_user(self.user)
        if couch_user.two_factor_auth_disabled_until:
            couch_user.two_factor_auth_disabled_until = None
            couch_user.save()
        return super(HQTOTPDeviceForm, self).save()
Ejemplo n.º 21
0
class TwoFactorDeviceValidationForm(DeviceValidationForm):
    token = forms.IntegerField(label="Token",
                               min_value=1,
                               max_value=int('9' * totp_digits()),
                               widget=widgets.MetroNumberInput)
Ejemplo n.º 22
0
class TwoFactorTOTPDeviceForm(TOTPDeviceForm):
    token = forms.IntegerField(label="Token",
                               min_value=0,
                               max_value=int('9' * totp_digits()),
                               widget=widgets.MetroNumberInput)
Ejemplo n.º 23
0
class TwoFactorAuthTokenForm(AuthenticationTokenForm):
    otp_token = forms.IntegerField(widget=widgets.MetroNumberInput,
                                   label="Token",
                                   min_value=1,
                                   max_value=int('9' * totp_digits()))
    otp_token.widget.attrs.update({'autofocus': 'autofocus'})