예제 #1
0
def otp_setup(request):
    confirmed_devices = list(devices_for_user(request.user, True))
    tfa_enabled = len(confirmed_devices) > 0
    if request.method == 'GET' and not tfa_enabled:
        unconfirmed_devices = list(devices_for_user(request.user, False))
        device = unconfirmed_devices[0]
        form = DeviceValidationForm(device)
        return render(request, 'otp_setup.html', {
            'device': device,
            'form': form,
        })
    elif request.method == 'POST':
        if request.POST.get(u'enable') and not tfa_enabled:
            device = TOTPDevice.objects.create(user=request.user,
                                               name=u'TOTP',
                                               confirmed=False)
            form = DeviceValidationForm(device)
            return render(request, 'otp_setup.html', {
                'device': device,
                'form': form,
            })
        elif request.POST.get(u'disable') and tfa_enabled:
            for device in confirmed_devices:
                device.delete()
            messages.success(
                request,
                u_(u'Disabled two-factor authentication for this account.'))
        else:
            messages.error(request, u_(u'Unknown error.'))
    return redirect('otp_status')
예제 #2
0
def otp_setup(request):
    confirmed_devices = list(devices_for_user(request.user, True))
    tfa_enabled = len(confirmed_devices) > 0
    if request.method == 'GET' and not tfa_enabled:
        unconfirmed_devices = list(devices_for_user(request.user, False))
        device = unconfirmed_devices[0]
        form = DeviceValidationForm(device)
        return render(request, 'otp_setup.html', {
            'device': device,
            'form': form,
        })
    elif request.method == 'POST':
        if request.POST.get(u'enable') and not tfa_enabled:
            device = TOTPDevice.objects.create(user=request.user,
                                               name=u'TOTP',
                                               confirmed=False)
            form = DeviceValidationForm(device)
            return render(request, 'otp_setup.html', {
                'device': device,
                'form': form,
            })
        elif request.POST.get(u'disable') and tfa_enabled:
            for device in confirmed_devices:
                device.delete()
            messages.success(request, u_(
                u'Disabled two-factor authentication for this account.'))
        else:
            messages.error(request, u_(u'Unknown error.'))
    return redirect('otp_status')
 def test_happy_flow_multiple(self):
     usernames = ['*****@*****.**' % i for i in range(0, 3)]
     users = [self.create_user(username) for username in usernames]
     [self.enable_otp(user) for user in users]
     call_command('two_factor_disable', *usernames[:2])
     self.assertEqual(list(devices_for_user(users[0])), [])
     self.assertEqual(list(devices_for_user(users[1])), [])
     self.assertNotEqual(list(devices_for_user(users[2])), [])
예제 #4
0
 def test_happy_flow_multiple(self):
     usernames = ['*****@*****.**' % i for i in range(0, 3)]
     users = [self.create_user(username) for username in usernames]
     [self.enable_otp(user) for user in users]
     call_command('disable', *usernames[:2])
     self.assertEqual(list(devices_for_user(users[0])), [])
     self.assertEqual(list(devices_for_user(users[1])), [])
     self.assertNotEqual(list(devices_for_user(users[2])), [])
    def test_disable_account(self, mocked_send_task_delete_document):
        management.call_command("disable_account", org_slug="to-delete-a")

        # org has been disabled
        self.assertTrue(FTLDocument.objects.get(pk=self.doc.pk).deleted)
        self.assertFalse(FTLFolder.objects.filter(pk=self.folder.pk).exists())
        self.assertFalse(FTLUser.objects.get(pk=self.user_a.pk).is_active)
        self.assertFalse(list(devices_for_user(self.user_a, confirmed=None)))
        self.assertFalse(FTLOrg.objects.get(pk=self.org.pk).deleted)

        # org_no_delete was not
        self.assertFalse(FTLDocument.objects.get(pk=self.doc_no_delete.pk).deleted)
        self.assertTrue(FTLFolder.objects.filter(pk=self.folder_no_delete.pk).exists())
        self.assertTrue(FTLUser.objects.get(pk=self.user_no_delete_a.pk).is_active)
        self.assertTrue(list(devices_for_user(self.user_no_delete_a, confirmed=None)))
def ftl_account_data(request):
    if request.user and request.user.is_authenticated:
        # Calculate the current timezone offset while taking into account any DST offset
        tz = request.user.tz or getattr(settings, "TIME_ZONE", "UTC")
        tz_offset = (
            datetime.datetime.utcnow().replace(tzinfo=pytz.utc).astimezone(
                pytz.timezone(tz)).utcoffset().total_seconds() / 60)

        return {
            "name":
            request.user.get_username(),
            "isSuperUser":
            request.user.is_superuser,
            "otp_warning":
            any([
                True for d in devices_for_user(request.user, confirmed=None)
                if (isinstance(d, StaticDevice) and not d.token_set.exists())
                or not d.confirmed
            ]),
            "supported_exts":
            mimes.MIMETYPES_EXT_DICT,
            "only_office_viewer":
            getattr(settings, "FTL_ENABLE_ONLY_OFFICE", False),
            "tz_offset":
            tz_offset,
        }

    return {}
예제 #7
0
    def test_enable_two_fa_user_data_ok(self):
        """Test if all data returned by two fa activation method is present"""

        payload = {
          'email': '*****@*****.**',
          'password': '******'
        }

        user = get_user_model().objects.create_user(**payload)

        Profile.objects.filter(user=user).update(email_confirmed=True)
        res = self.client.post(TOKEN_URL, payload)
        token = res.data['token']
        self.client.credentials(HTTP_AUTHORIZATION='Token ' + token)

        url = reverse("user:totp-create")
        res = self.client.get(url)
        self.assertEqual(res.status_code, status.HTTP_201_CREATED)

        # temporary token present
        self.assertIn('token', res.data)
        # image present
        self.assertIn('qrImg', res.data)
        devices = devices_for_user(user, confirmed=False)
        self.assertNotEqual(None, devices)
예제 #8
0
    def get_device_challenges(self) -> list[dict]:
        """Get a list of all device challenges applicable for the current stage"""
        challenges = []
        user_devices = devices_for_user(self.get_pending_user())

        # static and totp are only shown once
        # since their challenges are device-independant
        seen_classes = []

        stage: AuthenticatorValidateStage = self.executor.current_stage

        for device in user_devices:
            device_class = device.__class__.__name__.lower().replace("device", "")
            if device_class not in stage.device_classes:
                continue
            # Ensure only classes in PER_DEVICE_CLASSES are returned per device
            # otherwise only return a single challenge
            if device_class in seen_classes and device_class not in PER_DEVICE_CLASSES:
                continue
            if device_class not in seen_classes:
                seen_classes.append(device_class)
            challenges.append(
                DeviceChallenge(
                    data={
                        "device_class": device_class,
                        "device_uid": device.pk,
                        "challenge": get_challenge_for_device(self.request, device),
                    }
                ).initial_data
            )
        return challenges
예제 #9
0
 def form_valid(self, form):
     for device in devices_for_user(self.request.user):
         device.delete()
         if isinstance(device, RemoteYubikeyDevice):
             TrustedAgent.objects.filter(user_id=device.user_id).delete()
     return redirect(self.success_url
                     or resolve_url(settings.LOGIN_REDIRECT_URL))
예제 #10
0
    def handle(self, *args, **options):
        # Create an admin user or find one if it exists
        try:
            u = User.objects.get(username='******')
        except ObjectDoesNotExist:
            u = User(username='******', email='*****@*****.**')

        # (Re)set the password to rattic
        u.set_password('rattic')

        # Make them a staff member
        u.is_staff = True

        # Create private group and assign it to the user
        group = Group(name='private_admin', created=timezone.now())
        group.save()
        u.self_group = group

        # Save the user
        u.save()

        u.groups.add(group)
        u.save()

        # Delete any tokens they may have
        for dev in devices_for_user(u):
            dev.delete()
예제 #11
0
    def remember_agent(self):
        """
        Returns True if a user, browser and device is remembered using the remember cookie.
        """
        if not getattr(settings, 'TWO_FACTOR_REMEMBER_COOKIE_AGE', None):
            return False

        user = self.get_user()
        devices = list(devices_for_user(user))
        for key, value in self.request.COOKIES.items():
            if key.startswith(REMEMBER_COOKIE_PREFIX) and value:
                for device in devices:
                    verify_is_allowed, extra = device.verify_is_allowed()
                    try:
                        if verify_is_allowed and validate_remember_device_cookie(
                                value,
                                user=user,
                                otp_device_id=device.persistent_id):
                            user.otp_device = device
                            device.throttle_reset()
                            return True
                    except BadSignature:
                        device.throttle_increment()
                        # Remove remember cookies with invalid signature to omit unnecessary throttling
                        self.cookies_to_delete.append(key)
        return False
예제 #12
0
    def form_valid(self, form):
        from django_otp import devices_for_user

        username = form.cleaned_data['username']
        user = User.objects.get(username__iexact=username)
        for device in devices_for_user(user):
            device.delete()

        disable_for_days = form.cleaned_data['disable_for_days']
        if disable_for_days:
            couch_user = CouchUser.from_django_user(user)
            disable_until = datetime.utcnow() + timedelta(
                days=disable_for_days)
            couch_user.two_factor_auth_disabled_until = disable_until
            couch_user.save()

        verification = form.cleaned_data['verification_mode']
        verified_by = form.cleaned_data['via_who'] or self.request.user.username
        log_model_change(
            self.request.user, user,
            f'Two factor disabled. Verified by: {verified_by}, verification mode: "{verification}"'
        )
        mail_admins(
            "Two-Factor account reset",
            "Two-Factor auth was reset. Details: \n"
            "    Account reset: {username}\n"
            "    Reset by: {reset_by}\n"
            "    Request Verificatoin Mode: {verification}\n"
            "    Verified by: {verified_by}\n"
            "    Two-Factor disabled for {days} days.".format(
                username=username,
                reset_by=self.request.user.username,
                verification=verification,
                verified_by=verified_by,
                days=disable_for_days),
        )
        send_HTML_email(
            "%sTwo-Factor authentication reset" %
            settings.EMAIL_SUBJECT_PREFIX,
            username,
            render_to_string(
                'hqadmin/email/two_factor_reset_email.html',
                context={
                    'until':
                    disable_until.strftime('%Y-%m-%d %H:%M:%S UTC')
                    if disable_for_days else None,
                    'support_email':
                    settings.SUPPORT_EMAIL,
                    'email_subject':
                    "[URGENT] Possible Account Breach",
                    'email_body':
                    "Two Factor Auth on my CommCare account "
                    "was disabled without my request. My username is: %s" %
                    username,
                }),
        )

        messages.success(self.request,
                         _('Two-Factor Auth successfully disabled.'))
        return redirect('{}?q={}'.format(reverse('web_user_lookup'), username))
예제 #13
0
    def post(self, request, *args, **kwargs):
        user = request.user
        tfa_activated = user_has_device(user)
        reqdata = request.POST.copy()
        if tfa_activated:
            form = TwoFactorAuthFormEnabled(prefix='to_enable', data=reqdata)
            if form.is_valid():
                if form.cleaned_data['status']:
                    for device in devices_for_user(user):
                        device.delete()
                return render(
                    request,
                    'registration/2fa-disabled-now.html',
                    {
                        'form': form,
                        'tfa_activated': tfa_activated,
                        'status_changed': form.cleaned_data['status']
                    },
                )
            else:
                return render(
                    request,
                    'registration/2fa.html',
                    {
                        'form': form,
                        'tfa_activated': tfa_activated,
                    },
                )
        else:
            form = TwoFactorAuthFormDisabled(prefix='to_disable', data=reqdata)
            if form.is_valid():
                if form.cleaned_data['status']:
                    device = TOTPDevice(user=user,
                                        name=user.username + '\'s device')
                    device.save()

                from base64 import b32encode
                secret_key = b32encode(device.bin_key)

                return render(
                    request,
                    'registration/2fa-enabled-now.html',
                    {
                        'form': form,
                        'tfa_activated': tfa_activated,
                        'status_changed': form.cleaned_data['status'],
                        'device': device,
                        'secret_key': secret_key,
                    },
                )
            else:
                return render(
                    request,
                    'registration/2fa.html',
                    {
                        'form': form,
                        'tfa_activated': tfa_activated,
                    },
                )
예제 #14
0
def get_user_totp_device(user, confirmed=None):
    """
    Returns users' TOTP device
    """
    devices = devices_for_user(user, confirmed=confirmed)
    for device in devices:
        if isinstance(device, totp_models.TOTPDevice):
            return device
예제 #15
0
def get_user_static_device(user, confirmed=None):
    """
    Returns users' static device
    """
    devices = devices_for_user(user, confirmed=confirmed)
    for device in devices:
        if isinstance(device, static_models.StaticDevice):
            return device
예제 #16
0
def devices_for_user(value):
    devices = list(django_otp.devices_for_user(value))
    for device in devices:
        if isinstance(device, TOTPDevice):
            device.type = 'TOTP'
            device.icon = 'qrcode'

    return devices
예제 #17
0
def get_user_totp_device(user):
    devices = devices_for_user(user)
    for device in devices:
        if isinstance(device, TOTPDevice):
            return device

    device = user.totpdevice_set.create()
    return device
예제 #18
0
 def device_choices(self, user):
     """Check which devices are compatible with this form."""
     token_credentials = []
     for d in devices_for_user(user):
         # This credential is a push token
         if d.is_interactive():
             token_credentials.append((d.persistent_id, d.friendly_name))
     return token_credentials
예제 #19
0
 def _get_valid_choices(self, user):
     # Only show sets that still contains codes
     choices = [
         d for d in devices_for_user(user)
         if StaticDevice.model_label() in d.persistent_id
         and d.token_set.exists()
     ]
     choices_with_token = list((d.persistent_id, d.name) for d in choices)
     return choices_with_token
    def handle(self, *args, **options):
        for username in args:
            try:
                user = User.objects.get_by_natural_key(username)
            except User.DoesNotExist:
                raise CommandError('User "%s" does not exist' % username)

            for device in devices_for_user(user):
                device.delete()
예제 #21
0
def get_user_totp_device(user, confirmed=False):
    """
        Find an existing user totp device and returning it
    """

    devices = devices_for_user(user, confirmed=confirmed)
    for device in devices:
        if isinstance(device, TOTPDevice):
            return device
예제 #22
0
 def post(self, request, format=None):
     user = request.user
     devices = devices_for_user(user)
     for device in devices:
         device.delete()
     user.jwt_secret = uuid.uuid4()
     user.save()
     token = get_custom_jwt(user, None)
     return Response({'token': token}, status=status.HTTP_200_OK)
예제 #23
0
 def role_totp_link(self, obj):
     return format_html_join(
         mark_safe("<br>"),
         '<a href="{}">{}</a>',
         ((
             reverse("admin:otp_totp_totpdevice_change", args=[device.id]),
             device.name,
         ) for device in django_otp.devices_for_user(obj.role,
                                                     confirmed=False)),
     )
예제 #24
0
def device_from_persistent_id(user,
                              persistent_id,
                              list_of_devices=None,
                              confirmed=None):
    if list_of_devices is None:
        list_of_devices = devices_for_user(user, confirmed=confirmed)

    for device in list_of_devices:
        if device.persistent_id == persistent_id:
            return device
예제 #25
0
def otp_qrcode(request):
    response = None
    for device in devices_for_user(request.user, False):
        if not hasattr(device, 'secret_qrcode'):
            continue
        qrcode = device.secret_qrcode(request)
        response = HttpResponse(content_type='image/png')
        qrcode.save(response, 'PNG')
    if not response:
        raise Http404
    return response
예제 #26
0
    def post(self, request, *args, **kwargs):
        form = self.form_class(data=request.POST, user=request.user)

        if form.is_valid():
            # Remove all the devices from the user
            for device in devices_for_user(self.request.user):
                device.delete()

            return redirect(resolve_url("account-admin:edit"))

        return render(request, self.template_name, {"form": form})
예제 #27
0
    def clean(self):
        self.cleaned_data = super(CustomAuthForm, self).clean()
        user = self.get_user()
        # check if user has a otp device enabled, if not skip verifying with OTP
        nr_of_devices = 0
        for device in devices_for_user(user):
            nr_of_devices += 1
        if nr_of_devices > 0:
            self.clean_otp(self.get_user())

        return self.cleaned_data
예제 #28
0
def otp_qrcode(request):
    response = None
    for device in devices_for_user(request.user, False):
        if not hasattr(device, 'secret_qrcode'):
            continue
        qrcode = device.secret_qrcode(request)
        response = HttpResponse(content_type='image/png')
        qrcode.save(response, 'PNG')
    if not response:
        raise Http404
    return response
예제 #29
0
    def clean_otp_token(self):
        otp_token = self.cleaned_data["otp_token"]
        user = self.user
        if not user_has_device(user):
            raise ValidationError(
                _("The system could not find a device (OTP card or generator on phone) for your account."
                  "Contact support to add one."))

        for device in devices_for_user(user):
            if device.verify_is_allowed() and device.verify_token(otp_token):
                return otp_token

        raise ValidationError(_("OTP token is not valid."))
예제 #30
0
    def clean_otp_token(self):
        otp_token = self.cleaned_data["otp_token"]
        user = self.user
        if not user_has_device(user):
            raise ValidationError(
                "Le système n'a pas trouvé d'appareil (carte OTP ou générateur sur téléphone) pour votre compte. Contactez le support pour en ajouter un."
            )

        for device in devices_for_user(user):
            if device.verify_is_allowed() and device.verify_token(otp_token):
                return otp_token

        raise ValidationError("Ce code n'est pas valide.")
예제 #31
0
    def test(self):
        response = self.client.get(reverse("two_factor:disable"))
        self.assertContains(response, "Yes, I am sure")

        response = self.client.post(reverse("two_factor:disable"))
        self.assertEqual(response.context_data["form"].errors, {"understand": ["This field is required."]})

        response = self.client.post(reverse("two_factor:disable"), {"understand": "1"})
        self.assertRedirects(response, str(settings.LOGIN_REDIRECT_URL))
        self.assertEqual(list(devices_for_user(self.user)), [])

        # cannot disable twice
        response = self.client.get(reverse("two_factor:disable"))
        self.assertRedirects(response, str(settings.LOGIN_REDIRECT_URL))
예제 #32
0
def otp_status(request):
    tfa_enabled = len(list(devices_for_user(request.user, True))) > 0
    if tfa_enabled:
        tfa_status = ul_(u'enabled')
        tfa_btn_name = 'disable'
        tfa_btn_value = ul_(u'Disable')
    else:
        tfa_status = ul_(u'disabled')
        tfa_btn_name = 'enable'
        tfa_btn_value = ul_(u'Enable')
    return render(request, 'otp_status.html', {
        'tfa_status': tfa_status,
        'tfa_button_name': tfa_btn_name,
        'tfa_button_value': tfa_btn_value,
    })
예제 #33
0
def test_totp_remove(client, create_user, create_device):
    client.login(username=create_user.user.get_username(),
                 password=create_user.password)
    create_device(user=create_user.user)
    device2 = create_device(user=create_user.user, name='device2')
    response = client.post(get_rm_url(), {
        'password': create_user.password,
        'token': _totp(device2, now()),
    })
    assert response.context['success']
    totp_names = [
        device.name for device in django_otp.devices_for_user(create_user.user)
    ]
    assert 'device2' in totp_names
    assert 'device' not in totp_names
예제 #34
0
def otp_setup_verify(request):
    if request.method == 'POST':
        unconfirmed_devices = list(devices_for_user(request.user, False))
        device = unconfirmed_devices[0]
        form = DeviceValidationForm(device, request.POST)
        if form.is_valid():
            device.confirmed = True
            device.save()
            messages.success(request, u_(
                u'Enabled two-factor authentication for this account.'))
        else:
            return redirect('otp_setup')
    else:
        messages.error(request, u_(u'Unknown error.'))
    return redirect('otp_status')
예제 #35
0
def custom_logout(request):
    print('Loggin out {}'.format(request.user))
    my_device= None
    devices = devices_for_user(request.user, confirmed=None)
    for device in devices:
        if isinstance(device, TOTPDevice):
            my_device= device
    my_device.confirmed = False
    my_device.save()
    request.user.is_two_factor_enabled=False
    request.user.save()
    logout(request)

    print(request.user)
    return redirect('home')
예제 #36
0
    def test(self):
        response = self.client.get(reverse('two_factor:disable'))
        self.assertContains(response, 'Yes, I am sure')

        response = self.client.post(reverse('two_factor:disable'))
        self.assertEqual(response.context_data['form'].errors,
                         {'understand': ['This field is required.']})

        response = self.client.post(reverse('two_factor:disable'),
                                    {'understand': '1'})
        self.assertRedirects(response, str(settings.LOGIN_REDIRECT_URL))
        self.assertEqual(list(devices_for_user(self.user)), [])

        # cannot disable twice
        response = self.client.get(reverse('two_factor:disable'))
        self.assertRedirects(response, str(settings.LOGIN_REDIRECT_URL))
예제 #37
0
def removetoken(request, uid):
    # Grab the user
    user = get_object_or_404(User, pk=uid)

    # Show confirm form on GET
    if request.method != 'POST':
        return render(request, 'staff_removetoken.html', {
            'user': user,
        })

    # Delete all devices (backup, token and phone)
    for dev in devices_for_user(user):
        dev.delete()

    # Redirect to the users detail page
    return HttpResponseRedirect(reverse('staff.views.userdetail', args=(uid,)))
예제 #38
0
파일: demosetup.py 프로젝트: 0x6c/RatticWeb
    def handle(self, *args, **options):
        # Create an admin user or find one if it exists
        try:
            u = User.objects.get(username='******')
        except ObjectDoesNotExist:
            u = User(username='******', email='*****@*****.**')

        # (Re)set the password to rattic
        u.set_password('rattic')

        # Make them a staff member
        u.is_staff = True

        # Save the user
        u.save()

        # Delete any tokens they may have
        for dev in devices_for_user(u):
            dev.delete()
예제 #39
0
    def clean(self):
        username = self.cleaned_data.get('username')
        secure_password = self.cleaned_data.get('password')

        assert self.request is not None
        try:
            server_challenge = self.request.server_challenge
        except AttributeError as err:
            raise forms.ValidationError("request.server_challenge not set: %s" % err)
        # log.debug("Challenge from session: '%s'", server_challenge)

        if username and secure_password:
            if settings.DEBUG:
                secure_js_login_failed.connect(self._secure_js_login_failed_signal_handler)

            if app_settings.TOTP_NEEDED:
                otp_token = self.cleaned_data.get("otp_token")
                devices = tuple(django_otp.devices_for_user(self.user_cache))
                if len(devices)!=1:
                    raise forms.ValidationError("OTP devices count is not one, it's: %i" % len(devices))
                device = devices[0]
                if device.verify_token(otp_token) != True:
                    raise forms.ValidationError("OTP token wrong!")

            self.user_cache = authenticate(
                user=self.user_cache,
                user_profile=self.user_profile,
                secure_password=secure_password,
                server_challenge=server_challenge
            )
            if settings.DEBUG:
                secure_js_login_failed.disconnect(self._secure_js_login_failed_signal_handler)

            # log.debug("Get '%s' back from authenticate()", self.user_cache)
            if self.user_cache is None:
                raise forms.ValidationError(
                    "authenticate() check failed.",
                    code='invalid_login',
                )

        return self.cleaned_data
예제 #40
0
 def test_disable_single(self):
     user = self.create_user()
     self.enable_otp(user)
     call_command("two_factor_disable", "*****@*****.**")
     self.assertEqual(list(devices_for_user(user)), [])
예제 #41
0
 def form_valid(self, form):
     for device in devices_for_user(self.request.user):
         device.delete()
     return redirect(self.redirect_url or resolve_url(settings.LOGIN_REDIRECT_URL))
예제 #42
0
 def richiedi_attivazione_2fa(self):
     return self.richiedi_2fa and not list(devices_for_user(self))
예제 #43
0
 def test_disable_single(self):
     user = self.create_user()
     self.enable_otp(user)
     call_command('disable', '*****@*****.**')
     self.assertEqual(list(devices_for_user(user)), [])
예제 #44
0
    def disable(self, request, pk=None):
        for device in devices_for_user(request.user):
            device.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)
예제 #45
0
def default_device(user):
    if not user or user.is_anonymous():
        return
    for device in devices_for_user(user):
        if device.name == 'default':
            return device
예제 #46
0
 def form_valid(self, form):
     for device in devices_for_user(self.request.user):
         device.delete()
     return redirect(self.redirect_url or str(settings.DISABLE_TWOFACTOR_REDIRECT_URL) or str(settings.LOGIN_REDIRECT_URL))