def test_backwards_compatible_url(self):
        """Ensure that the old 2FA URLs still work."""
        user = get_user_model().objects.create(username='******')
        user.set_password('doe')
        user.save()
        totp_model = user.totpdevice_set.create()

        resp = self.client.post(reverse('account_login'),
                                {'login': '******',
                                 'password': '******'})
        self.assertRedirects(resp,
                             reverse('two-factor-authenticate'),
                             fetch_redirect_response=False)

        # Now ensure that logging in actually works.
        totp = TOTP(totp_model.bin_key, totp_model.step, totp_model.t0, totp_model.digits)

        # The old URL doesn't have a trailing slash.
        url = reverse('two-factor-authenticate').rstrip('/')

        resp = self.client.post(url, {'otp_token': totp.token()})
        self.assertRedirects(resp,
                             settings.LOGIN_REDIRECT_URL,
                             fetch_redirect_response=False)

        # Ensure the signal is received as expected.
        self.assertEqual(self.user_logged_in_count, 1)
Exemple #2
0
    def clean(self):
        cleaned_data = super().clean()
        try:
            token = int(cleaned_data.get('otp_token'))
        except (TypeError, ValueError):
            verified = False
        else:
            # django-otp setting.
            OTP_TOTP_SYNC = getattr(settings, 'OTP_TOTP_SYNC', True)
            # Device verification using the current instance.
            totp = TOTP(self.instance.bin_key, self.instance.step,
                        self.instance.t0, self.instance.digits,
                        self.instance.drift)
            totp.time = time.time()

            verified = totp.verify(token, self.instance.tolerance,
                                   self.instance.last_t)
            if verified:
                # Device is verified, update attributes and prepare the
                # instance to be saved.
                self.instance.last_t = totp.t()
                if OTP_TOTP_SYNC:
                    self.instance.drift = totp.drift
        if not verified:
            raise forms.ValidationError(self.error_messages['invalid'])
        try:
            return cleaned_data
        finally:
            if TOTP_SESSION_KEY in self.request.session:  # pragma: no cover
                del self.request.session[TOTP_SESSION_KEY]
    def test_backwards_compatible_url(self):
        """Ensure that the old 2FA URLs still work."""
        user = get_user_model().objects.create(username='******')
        user.set_password('doe')
        user.save()
        totp_model = user.totpdevice_set.create()

        resp = self.client.post(reverse('account_login'),
                                {'login': '******',
                                 'password': '******'})
        self.assertRedirects(resp,
                             reverse('two-factor-authenticate'),
                             fetch_redirect_response=False)

        # Now ensure that logging in actually works.
        totp = TOTP(totp_model.bin_key, totp_model.step, totp_model.t0, totp_model.digits)

        # The old URL doesn't have a trailing slash.
        url = reverse('two-factor-authenticate').rstrip('/')

        resp = self.client.post(url, {'otp_token': totp.token()})
        self.assertRedirects(resp,
                             settings.LOGIN_REDIRECT_URL,
                             fetch_redirect_response=False)

        # Ensure the signal is received as expected.
        self.assertEqual(self.user_logged_in_count, 1)
Exemple #4
0
    def test_2fa_login(self):
        """Test login behavior when 2FA is configured."""
        user = get_user_model().objects.create(username='******')
        user.set_password('doe')
        user.save()
        totp_model = user.totpdevice_set.create()

        resp = self.client.post(reverse('account_login'), {
            'login': '******',
            'password': '******'
        })
        self.assertRedirects(resp,
                             reverse('two-factor-authenticate'),
                             fetch_redirect_response=False)

        # Now ensure that logging in actually works.
        totp = TOTP(totp_model.bin_key, totp_model.step, totp_model.t0,
                    totp_model.digits)
        resp = self.client.post(reverse('two-factor-authenticate'),
                                {'otp_token': totp.token()})
        self.assertRedirects(resp,
                             settings.LOGIN_REDIRECT_URL,
                             fetch_redirect_response=False)

        # Ensure the signal is received as expected.
        self.assertEqual(self.user_logged_in_count, 1)
Exemple #5
0
    def verify_token(self, token):
        OTP_TOTP_SYNC = getattr(settings, 'OTP_TOTP_SYNC', True)

        verify_allowed, _ = self.verify_is_allowed()
        if not verify_allowed:
            return False

        try:
            token = int(token)
        except Exception:
            verified = False
        else:
            key = self.bin_key

            totp = TOTP(key, self.step, self.t0, self.digits, self.drift)
            totp.time = time.time()

            verified = totp.verify(token, self.tolerance, self.last_t + 1)
            if verified:
                self.last_t = totp.t()
                if OTP_TOTP_SYNC:
                    self.drift = totp.drift
                self.throttle_reset(commit=False)
                self.save()

        if not verified:
            self.throttle_increment(commit=True)

        return verified
Exemple #6
0
    def test_redirect_to_2fa_to_settings(self):
        self.user.require_2fa = True
        self.user.needs_password_change = True
        self.user.save()

        response = self.client.post('/control/login?next=/control/events/', {
            'email': '*****@*****.**',
            'password': '******',
        })

        self.assertEqual(response.status_code, 302)
        self.assertIn('/control/login/2fa?next=/control/events/',
                      response['Location'])

        d = TOTPDevice.objects.create(user=self.user, name='test')
        totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
        totp.time = time.time()

        self.client.post(
            '/control/login/2fa?next=/control/events/'.format(d.pk),
            {'token': str(totp.token())})
        response = self.client.get('/control/events/')

        self.assertEqual(response.status_code, 302)
        self.assertIn('/control/settings?next=/control/events/',
                      response['Location'])
Exemple #7
0
    def test_totp_validate(self):
        """test flow with otp stages"""
        sleep(1)
        # Setup TOTP Device
        user = USER()
        device = TOTPDevice.objects.create(user=user, confirmed=True, digits=6)

        flow: Flow = Flow.objects.get(slug="default-authentication-flow")
        FlowStageBinding.objects.create(
            target=flow,
            order=30,
            stage=AuthenticatorValidateStage.objects.create())

        self.driver.get(self.url("authentik_core:if-flow",
                                 flow_slug=flow.slug))
        self.login()

        # Get expected token
        totp = TOTP(device.bin_key, device.step, device.t0, device.digits,
                    device.drift)

        flow_executor = self.get_shadow_root("ak-flow-executor")
        validation_stage = self.get_shadow_root(
            "ak-stage-authenticator-validate", flow_executor)
        code_stage = self.get_shadow_root(
            "ak-stage-authenticator-validate-code", validation_stage)

        code_stage.find_element(By.CSS_SELECTOR,
                                "input[name=code]").send_keys(totp.token())
        code_stage.find_element(By.CSS_SELECTOR,
                                "input[name=code]").send_keys(Keys.ENTER)
        self.wait_for_url(self.if_admin_url("/library"))
        self.assert_user(USER())
Exemple #8
0
    def totp_object(self):
        # Create TOTP object
        totp = TOTP(key=self.bin_key, step=self.step, digits=self.digits)

        # Set TOTP time as current time
        totp.time = time.time()
        return totp
Exemple #9
0
    def verify_token(self, token):
        verify_allowed, _ = self.verify_is_allowed()
        if not verify_allowed:
            return False

        try:
            token = int(token)
        except Exception:
            verified = False
        else:
            key = self.bin_key

            totp = TOTP(key, step=self.step, t0=self.start_time, digits=self.digits)
            verified = totp.verify(
                token,
                tolerance=settings.MULTIFACTOR_TOLERANCE,
                min_t=self.start_time + 1,
            )
            if verified:
                self.last_time = totp.t()
                self.throttle_reset(commit=False)
                self.save()

        if not verified:
            self.throttle_increment(commit=True)

        return verified
Exemple #10
0
 def totp_obj(self):
     # create a TOTP object
     totp = TOTP(key=self.key,
                 step=self.token_validity_period,
                 digits=self.number_of_digits)
     # the current time will be used to generate a counter
     totp.time = time.time()
     return totp
def get_token(user, phone_number, email=''):
    if email and user.email_id != email:
        raise
    totp = TOTP(TOTP_SECRET_KEY+str(randint(10000, 99999))+str(phone_number))
    totp.time = 30
    token = totp.token()
    save_otp(user, token, email)
    return token
 def totp_obj(self):
     """
     create a TOTP object
     """
     totp = TOTP(key=self.key,
                 step=self.token_validity_period,
                 digits=self.number_of_digits)
     totp.time = time.time()
     return totp
 def totp_obj(self):
     """
     create a TOTP object.
     the current time will be used to generate a counter
     """
     totp = TOTP(key=bytes(self.key.encode()),
                 step=self.token_validity_period,
                 digits=self.number_of_digits)
     totp.time = time.time()
     return totp
Exemple #14
0
 def test_totp_invalid(self):
     response = self.client.get('/control/login/2fa')
     assert 'token' in response.rendered_content
     d = TOTPDevice.objects.create(user=self.user, name='test')
     totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
     totp.time = time.time()
     response = self.client.post('/control/login/2fa'.format(d.pk),
                                 {'token': str(totp.token() + 2)})
     self.assertEqual(response.status_code, 302)
     self.assertIn('/control/login/2fa', response['Location'])
Exemple #15
0
def code(username, time, offset=0):
    token = get_token(username)
    totp = TOTP(
        token.bin_key,
        token.step,
        token.t0,
        token.digits,
        token.drift + offset,
    )
    totp.time = time
    return totp.token()
Exemple #16
0
 def test_totp_invalid(self):
     response = self.client.get('/control/login/2fa')
     assert 'token' in response.rendered_content
     d = TOTPDevice.objects.create(user=self.user, name='test')
     totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
     totp.time = time.time()
     response = self.client.post('/control/login/2fa'.format(d.pk), {
         'token': str(totp.token() + 2)
     })
     self.assertEqual(response.status_code, 302)
     self.assertIn('/control/login/2fa', response['Location'])
Exemple #17
0
 def authenticate_with_otp(self):
     totp_device = TOTPDevice.objects.create(name='totp device', user=self.current_person.user)
     totp_device.refresh_from_db()
     totp = TOTP(key=totp_device.bin_key)
     data = {
         'username': self.current_person.user.username,
         'password': self.current_person_password,
         'otp_token': totp.token()
     }
     response = self.client.post('/api-auth', data=data)
     self.client.defaults['HTTP_AUTHORIZATION'] = 'Bearer {}'.format(response.data['token'])
Exemple #18
0
    def save(self, commit=True):
        user = super(RegistrationForm, self).save(commit=False)
        user.phone_number = self.cleaned_data['phone_number']
        # user.is_verified = False
        totp = TOTP("JBSWY3DPEHPK3PXP")
        token_number = totp.token()
        user.token_number = token_number
        user.set_password(self.cleaned_data['password1'])
        if commit:
            user.save()

        return user
Exemple #19
0
 def test_totp_valid(self):
     response = self.client.get('/control/login/2fa')
     assert 'token' in response.rendered_content
     d = TOTPDevice.objects.create(user=self.user, name='test')
     totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
     totp.time = time.time()
     response = self.client.post('/control/login/2fa?next=/control/events/'.format(d.pk), {
         'token': str(totp.token())
     })
     self.assertEqual(response.status_code, 302)
     self.assertIn('/control/events/', response['Location'])
     assert time.time() - self.client.session['pretix_auth_login_time'] < 60
     assert not self.client.session['pretix_auth_long_session']
Exemple #20
0
 def test_totp_valid(self):
     response = self.client.get('/control/login/2fa')
     assert 'token' in response.content.decode()
     d = TOTPDevice.objects.create(user=self.user, name='test')
     totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
     totp.time = time.time()
     response = self.client.post(
         '/control/login/2fa?next=/control/events/'.format(d.pk),
         {'token': str(totp.token())})
     self.assertEqual(response.status_code, 302)
     self.assertIn('/control/events/', response['Location'])
     assert time.time() - self.client.session['pretix_auth_login_time'] < 60
     assert not self.client.session['pretix_auth_long_session']
 def test_confirm_totp_failed(self):
     self.client.post('/control/settings/2fa/add', {
         'devicetype': 'totp',
         'name': 'Foo'
     }, follow=True)
     d = TOTPDevice.objects.first()
     totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
     totp.time = time.time()
     r = self.client.post('/control/settings/2fa/totp/{}/confirm'.format(d.pk), {
         'token': str(totp.token() - 2)
     }, follow=True)
     assert 'alert-danger' in r.content.decode()
     d.refresh_from_db()
     assert not d.confirmed
Exemple #22
0
 def test_confirm_totp_failed(self):
     self.client.post('/control/settings/2fa/add', {
         'devicetype': 'totp',
         'name': 'Foo'
     }, follow=True)
     d = TOTPDevice.objects.first()
     totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
     totp.time = time.time()
     r = self.client.post('/control/settings/2fa/totp/{}/confirm'.format(d.pk), {
         'token': str(totp.token() - 2)
     }, follow=True)
     assert 'alert-danger' in r.rendered_content
     d.refresh_from_db()
     assert not d.confirmed
Exemple #23
0
 def generate_token(self):
     print(self.key)
     self.t0 = time.time()
     self.key = random_hex(20)
     totp = TOTP(key=bytearray(self.key, 'utf-8'))
     self.last_t = totp
     return self.last_t
Exemple #24
0
    def tokens(self, instance):
        """
        Just display current acceptable TOTP tokens
        """
        if not instance.pk:
            # e.g.: Use will create a new TOTP entry
            return "-"

        totp = TOTP(instance.bin_key, instance.step, instance.t0, instance.digits)

        tokens = []
        for offset in range(-instance.tolerance, instance.tolerance + 1):
            totp.drift = instance.drift + offset
            tokens.append(totp.token())

        return " ".join(["%s" % token for token in tokens])
Exemple #25
0
 def totp_from_device(self, device):
     url = urlsplit(device.config_url)
     params = parse_qs(url.query)
     return TOTP(b32decode(params['secret'][0]),
                 step=int(params['period'][0]),
                 digits=int(params['digits'][0]),
                 t0=0,
                 drift=0)
 def test_confirm_totp(self):
     self.client.post('/control/settings/2fa/add', {
         'devicetype': 'totp',
         'name': 'Foo'
     }, follow=True)
     d = TOTPDevice.objects.first()
     totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
     totp.time = time.time()
     r = self.client.post('/control/settings/2fa/totp/{}/confirm'.format(d.pk), {
         'token': str(totp.token()),
         'activate': 'on'
     }, follow=True)
     d.refresh_from_db()
     assert d.confirmed
     assert 'alert-success' in r.content.decode()
     self.user.refresh_from_db()
     assert self.user.require_2fa
Exemple #27
0
 def test_confirm_totp(self):
     self.client.post('/control/settings/2fa/add', {
         'devicetype': 'totp',
         'name': 'Foo'
     }, follow=True)
     d = TOTPDevice.objects.first()
     totp = TOTP(d.bin_key, d.step, d.t0, d.digits, d.drift)
     totp.time = time.time()
     r = self.client.post('/control/settings/2fa/totp/{}/confirm'.format(d.pk), {
         'token': str(totp.token()),
         'activate': 'on'
     }, follow=True)
     d.refresh_from_db()
     assert d.confirmed
     assert 'alert-success' in r.rendered_content
     self.user.refresh_from_db()
     assert self.user.require_2fa
Exemple #28
0
    def verify_token(self, token):
        OTP_TOTP_SYNC = getattr(settings, 'OTP_TOTP_SYNC', True)

        try:
            token = int(token)
        except Exception:
            verified = False
        else:
            key = self.bin_key

            totp = TOTP(key, self.step, self.t0, self.digits)
            totp.time = time.time()

            for offset in range(-self.tolerance, self.tolerance + 1):
                totp.drift = self.drift + offset
                if (totp.t() > self.last_t) and (totp.token() == token):
                    self.last_t = totp.t()
                    if (offset != 0) and OTP_TOTP_SYNC:
                        self.drift += offset
                    self.save()

                    verified = True
                    break
            else:
                verified = False

        return verified
Exemple #29
0
    def test_totp_setup(self):
        """test TOTP Setup stage"""
        flow: Flow = Flow.objects.get(slug="default-authentication-flow")

        self.driver.get(self.url("authentik_core:if-flow",
                                 flow_slug=flow.slug))
        self.login()

        self.wait_for_url(self.if_admin_url("/library"))
        self.assert_user(USER())

        self.driver.get(
            self.url(
                "authentik_flows:configure",
                stage_uuid=AuthenticatorTOTPStage.objects.first().stage_uuid,
            ))

        flow_executor = self.get_shadow_root("ak-flow-executor")
        totp_stage = self.get_shadow_root("ak-stage-authenticator-totp",
                                          flow_executor)
        wait = WebDriverWait(totp_stage, self.wait_timeout)

        wait.until(
            ec.presence_of_element_located(
                (By.CSS_SELECTOR, "input[name=otp_uri]")))
        otp_uri = totp_stage.find_element(
            By.CSS_SELECTOR, "input[name=otp_uri]").get_attribute("value")

        # Parse the OTP URI, extract the secret and get the next token
        otp_args = urlparse(otp_uri)
        self.assertEqual(otp_args.scheme, "otpauth")
        otp_qs = parse_qs(otp_args.query)
        secret_key = b32decode(otp_qs["secret"][0])

        totp = TOTP(secret_key)

        totp_stage.find_element(By.CSS_SELECTOR,
                                "input[name=code]").send_keys(totp.token())
        totp_stage.find_element(By.CSS_SELECTOR,
                                "input[name=code]").send_keys(Keys.ENTER)
        sleep(3)

        self.assertTrue(
            TOTPDevice.objects.filter(user=USER(), confirmed=True).exists())
Exemple #30
0
    def verify_token(self, token):
        OTP_TOTP_SYNC = getattr(settings, 'OTP_TOTP_SYNC', True)

        try:
            token = int(token)
        except Exception:
            verified = False
        else:
            key = self.bin_key

            totp = TOTP(key, self.step, self.t0, self.digits, self.drift)
            totp.time = time.time()

            verified = totp.verify(token, self.tolerance, self.last_t + 1)
            if verified:
                self.last_t = totp.t()
                if OTP_TOTP_SYNC:
                    self.drift = totp.drift
                self.save()

        return verified
    def test_2fa(self):
        """Test login behavior when 2FA is configured."""
        user = get_user_model().objects.create(username='******')
        user.set_password('doe')
        user.save()
        totp_model = user.totpdevice_set.create()

        resp = self.client.post(reverse('account_login'),
                                {'login': '******',
                                 'password': '******'})
        self.assertRedirects(resp,
                             reverse('two-factor-authenticate'),
                             fetch_redirect_response=False)

        # Now ensure that logging in actually works.
        totp = TOTP(totp_model.bin_key, totp_model.step, totp_model.t0, totp_model.digits)
        resp = self.client.post(reverse('two-factor-authenticate'),
                                {'otp_token': totp.token()})
        # The user ends up on the normal redirect login page.
        self.assertRedirects(resp,
                             settings.LOGIN_REDIRECT_URL,
                             fetch_redirect_response=False)
Exemple #32
0
 def post(self, request, *args, **kwargs):
     code = request.data.get("code", None)
     if code is None:
         return Response(status=status.HTTP_400_BAD_REQUEST)
     model = OTP.objects.get(user=request.user)
     if model is None:
         return Response(status=status.HTTP_400_BAD_REQUEST)
     if model.validated:
         return Response(status=status.HTTP_423_LOCKED)
     if TOTP(base64.b32decode(model.secret)).verify(code):
         model.validated = True
         model.save()
         return Response(status=status.HTTP_200_OK)
     return Response(status=status.HTTP_401_UNAUTHORIZED)
    def test_2fa(self):
        """Test login behavior when 2FA is configured."""
        user = get_user_model().objects.create(username="******")
        user.set_password("doe")
        user.save()
        totp_model = user.totpdevice_set.create()

        resp = self.client.post(reverse("account_login"), {
            "login": "******",
            "password": "******"
        })
        self.assertRedirects(resp,
                             reverse("two-factor-authenticate"),
                             fetch_redirect_response=False)

        # Now ensure that logging in actually works.
        totp = TOTP(totp_model.bin_key, totp_model.step, totp_model.t0,
                    totp_model.digits)
        resp = self.client.post(reverse("two-factor-authenticate"),
                                {"otp_token": totp.token()})
        # The user ends up on the normal redirect login page.
        self.assertRedirects(resp,
                             settings.LOGIN_REDIRECT_URL,
                             fetch_redirect_response=False)
def generate_otp(phone_number):
    totp = TOTP(settings.TOTP_SECRET_KEY+str(randint(10000,99999))+str(phone_number))
    totp.time = 30
    token = totp.token()
    return token
Exemple #35
0
def _totp(device, now):
    totp = TOTP(device.bin_key, device.step, device.t0, device.digits)
    totp.time = now.timestamp()
    return totp.token()
 def generate_totp(self, request=None):
     key = self.bin_key
     totp = TOTP(key, self.step, self.t0, self.digits, self.drift)
     totp.time = time.time()
     return totp
Exemple #37
0
def _totp(device, now):
    totp = TOTP(device.bin_key, device.step, device.t0, device.digits)
    totp.time = now.timestamp()
    return totp.token()
Exemple #38
0
 def totp_obj(self):
     totp = TOTP(key=self.bin_key, step=self.step, digits=self.digits)
     totp.time = time.time()
     return totp
Exemple #39
0
    def totp_obj(self):
        totp = TOTP(self.bin_key, step=1)
        totp.time = time.time()

        return totp
Exemple #40
0
 def totp_obj(key):
     totp = TOTP(key=key, step=100, digits=6)
     totp.time = time.time()
     return totp