Exemplo n.º 1
0
    def clean_code(self):
        code = self.cleaned_data['code']

        if not bool(match_token(self.request.user, code)):
            raise forms.ValidationError(_("The 2FA code is invalid"))

        return code
Exemplo n.º 2
0
    def post(self, request, *args, **kwargs):
        token = request.POST.get('token', '').strip().replace(' ', '')

        valid = False
        if '_u2f_challenge' in self.request.session and token.startswith('{'):
            devices = [
                DeviceRegistration.wrap(device.json_data)
                for device in U2FDevice.objects.filter(confirmed=True,
                                                       user=self.user)
            ]
            challenge = self.request.session.pop('_u2f_challenge')
            try:
                u2f.verify_authenticate(devices, challenge, token,
                                        [self.app_id])
                valid = True
            except Exception:
                logger.exception('U2F login failed')
        else:
            valid = match_token(self.user, token)

        if valid:
            auth_login(request, self.user)
            request.session['pretix_auth_login_time'] = int(time.time())
            del request.session['pretix_auth_2fa_user']
            del request.session['pretix_auth_2fa_time']
            if "next" in request.GET and is_safe_url(request.GET.get("next")):
                return redirect(request.GET.get("next"))
            return redirect(reverse('control:index'))
        else:
            messages.error(request, _('Invalid code, please try again.'))
            return redirect('control:auth.login.2fa')
Exemplo n.º 3
0
 def post(self, request):
     ret = {"status": False, 'msg': None}
     username = request.POST.get("username")
     password = request.POST.get("password")
     password_len = len(password)
     valid_code = request.POST.get('valid_code')
     code_session = request.session.get("valid_code", "")
     if valid_code and valid_code.upper() == code_session.upper():
         if password_len <= 6:
             ret['msg'] = "密码输入错误,请重新输入"
         qrcode = password[-6:]
         password = password[:password_len - 6]
         u = auth.authenticate(email=username, password=password)
         if u:
             if match_token(u, qrcode) != None:
                 auth.login(request, u)
                 request.session['is_login'] = True
                 request.session.set_expiry(3600)
                 login_ip = request.META['REMOTE_ADDR']
                 models.Loginlog.objects.create(user=request.user,
                                                ip=login_ip,
                                                action="***login***")
                 ret["status"] = True
         else:
             ret['msg'] = "用户名或者密码错误"
     else:
         ret['msg'] = "验证码错误"
     return JsonResponse(ret)
Exemplo n.º 4
0
    def post(self, request, *args, **kwargs):
        token = request.POST.get('token', '').strip().replace(' ', '')

        valid = False
        if '_u2f_challenge' in self.request.session and token.startswith('{'):
            devices = [DeviceRegistration.wrap(device.json_data)
                       for device in U2FDevice.objects.filter(confirmed=True, user=self.user)]
            challenge = self.request.session.pop('_u2f_challenge')
            try:
                u2f.verify_authenticate(devices, challenge, token, [self.app_id])
                valid = True
            except Exception:
                logger.exception('U2F login failed')
        else:
            valid = match_token(self.user, token)

        if valid:
            auth_login(request, self.user)
            request.session['pretix_auth_login_time'] = int(time.time())
            del request.session['pretix_auth_2fa_user']
            del request.session['pretix_auth_2fa_time']
            if "next" in request.GET and is_safe_url(request.GET.get("next"), allowed_hosts=None):
                return redirect(request.GET.get("next"))
            return redirect(reverse('control:index'))
        else:
            messages.error(request, _('Invalid code, please try again.'))
            return redirect('control:auth.login.2fa')
Exemplo n.º 5
0
        def _inner(request, domain, *args, **kwargs):
            domain_obj = Domain.get_by_name(domain)
            couch_user = _ensure_request_couch_user(request)
            if (not api_key
                    and not getattr(request, 'skip_two_factor_check', False)
                    and domain_obj and _two_factor_required(
                        view_func, domain_obj, couch_user)):
                token = request.META.get('HTTP_X_COMMCAREHQ_OTP')
                if not token and 'otp' in request.GET:
                    with mutable_querydict(request.GET):
                        # remove the param from the query dict so that we don't interfere with places
                        # that use the query dict to generate dynamic filters
                        token = request.GET.pop('otp')[-1]
                if not token:
                    return JsonResponse(OTP_AUTH_FAIL_RESPONSE, status=401)
                otp_device = match_token(request.user, token)
                if not otp_device:
                    return JsonResponse({"error": "OTP token is incorrect"},
                                        status=401)

                # set otp device and is_verified function on user to be consistent with OTP middleware
                request.user.otp_device = otp_device
                request.user.is_verified = lambda: True
                return fn(request, domain, *args, **kwargs)
            return fn(request, domain, *args, **kwargs)
Exemplo n.º 6
0
def validate_challenge_code(code: str, request: HttpRequest, user: User) -> str:
    """Validate code-based challenges. We test against every device, on purpose, as
    the user mustn't choose between totp and static devices."""
    device = match_token(user, code)
    if not device:
        raise ValidationError(_("Invalid Token"))
    return code
Exemplo n.º 7
0
        def _inner(request, domain, *args, **kwargs):
            domain_obj = Domain.get_by_name(domain)
            couch_user = _ensure_request_couch_user(request)
            if (
                not api_key and
                not getattr(request, 'skip_two_factor_check', False) and
                domain_obj and
                _two_factor_required(view_func, domain_obj, couch_user)
            ):
                token = request.META.get('HTTP_X_COMMCAREHQ_OTP')
                if not token and 'otp' in request.GET:
                    with mutable_querydict(request.GET):
                        # remove the param from the query dict so that we don't interfere with places
                        # that use the query dict to generate dynamic filters
                        token = request.GET.pop('otp')[-1]
                if not token:
                    return JsonResponse(OTP_AUTH_FAIL_RESPONSE, status=401)
                otp_device = match_token(request.user, token)
                if not otp_device:
                    return JsonResponse({"error": "OTP token is incorrect"}, status=401)

                # set otp device and is_verified function on user to be consistent with OTP middleware
                request.user.otp_device = otp_device
                request.user.is_verified = lambda: True
                return fn(request, domain, *args, **kwargs)
            return fn(request, domain, *args, **kwargs)
Exemplo n.º 8
0
def login(request):
    err_msg = ''
    if request.method == 'GET':
        return render(request, 'login.html', {'err_msg': err_msg})
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        password_len = len(password)
        if password_len <= 6:
            return render(request, 'login.html',
                          {'err_msg': 'user or password errors'})
        qrcode = password[-6:]
        password = password[:password_len - 6]
        u = auth.authenticate(username=username, password=password)
        if u:
            if match_token(u, qrcode) != None:
                auth.login(request, u)
                request.session['is_login'] = True
                request.session.set_expiry(3600)
                login_ip = request.META['REMOTE_ADDR']

            return redirect('/')
        else:
            return render(request, 'login.html',
                          {'err_msg': 'user or password errors'})

    return render(request, 'login.html', {'err_msg': err_msg})
Exemplo n.º 9
0
 def _inner(request, domain, *args, **kwargs):
     if not api_key and Domain.get_by_name(domain).two_factor_auth:
         token = request.META.get('HTTP_X_COMMCAREHQ_OTP')
         if token and match_token(request.user, token):
             return fn(request, *args, **kwargs)
         else:
             return JsonResponse({"error": "must send X-CommcareHQ-OTP header"}, status=401)
     return fn(request, domain, *args, **kwargs)
Exemplo n.º 10
0
 def clean_otp_token(self):
     otp_token = self.cleaned_data["otp_token"]
     if not django_otp.match_token(self.user, otp_token):
         raise ValidationError(
             self.error_messages['token_incorrect'],
             code='token_incorrect',
         )
     return otp_token
Exemplo n.º 11
0
 def clean_otp_token(self):
     otp_token = self.cleaned_data["otp_token"]
     aidant = self.aidant
     good_token = match_token(aidant, otp_token)
     if good_token:
         return otp_token
     else:
         raise ValidationError("Ce code n'est pas valide.")
Exemplo n.º 12
0
    def post(self, request, *args, **kwargs):
        token = request.POST.get('token', '').strip().replace(' ', '')

        valid = False
        if 'webauthn_challenge' in self.request.session and token.startswith(
                '{'):
            challenge = self.request.session['webauthn_challenge']

            resp = json.loads(self.request.POST.get("token"))
            try:
                devices = [
                    WebAuthnDevice.objects.get(user=self.user,
                                               credential_id=resp.get("id"))
                ]
            except WebAuthnDevice.DoesNotExist:
                devices = U2FDevice.objects.filter(user=self.user)

            for d in devices:
                try:
                    wu = d.webauthnuser

                    if isinstance(d, U2FDevice):
                        # RP_ID needs to be appId for U2F devices, but we can't
                        # set it that way in U2FDevice.webauthnuser, since that
                        # breaks the frontend part.
                        wu.rp_id = settings.SITE_URL

                    webauthn_assertion_response = webauthn.WebAuthnAssertionResponse(
                        wu,
                        resp,
                        challenge,
                        settings.SITE_URL,
                        uv_required=False  # User Verification
                    )
                    sign_count = webauthn_assertion_response.verify()
                except Exception:
                    logger.exception('U2F login failed')
                else:
                    if isinstance(d, WebAuthnDevice):
                        d.sign_count = sign_count
                        d.save()
                    valid = True
                    break
        else:
            valid = match_token(self.user, token)

        if valid:
            auth_login(request, self.user)
            request.session['pretix_auth_login_time'] = int(time.time())
            del request.session['pretix_auth_2fa_user']
            del request.session['pretix_auth_2fa_time']
            if "next" in request.GET and is_safe_url(request.GET.get("next"),
                                                     allowed_hosts=None):
                return redirect(request.GET.get("next"))
            return redirect(reverse('control:index'))
        else:
            messages.error(request, _('Invalid code, please try again.'))
            return redirect('control:auth.login.2fa')
Exemplo n.º 13
0
def reverify(request, plan, pk):
    try:
        request.session['reverify'] = None
        if not request.session['reverify']:
            totp = TOTPDevice.objects.get(user_id=request.user.id)
            form = otpform(request.POST)
            temp = totp.config_url.replace("/", "%2F")
            if request.method == 'POST':
                if form.is_valid():
                    otp_token = form.cleaned_data['otp_token']
                    result = match_token(request.user, otp_token)
                    if not result:
                        errors = form._errors.setdefault(
                            "Incorrect OTP", ErrorList())
                        return render(
                            request, 'users/otp_setup.html', {
                                'form':
                                form,
                                'otpstring':
                                "https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl="
                                + str(temp),
                                'verification':
                                True,
                                'plan':
                                plan,
                                'pk':
                                pk
                            })
                    request.session['reverify'] = 1
                    if plan == "confirm_transactions":
                        return HttpResponseRedirect(
                            reverse(plan, kwargs={'pk': pk}))
                    if plan == "confirm_accept_cash_request":
                        return HttpResponseRedirect(
                            reverse(plan, kwargs={'pk': pk}))
                    if plan == "confirm_send_group_request":
                        return HttpResponseRedirect(
                            reverse(plan, kwargs={'pk': pk}))
                    return HttpResponseRedirect(reverse(plan))
                else:
                    return redirect(reverse('homepage'))
            else:
                return render(
                    request, 'users/otp_setup.html', {
                        'form':
                        form,
                        'otpstring':
                        "https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl="
                        + str(temp),
                        'verification':
                        True,
                        'plan':
                        plan
                    })
        else:
            return redirect(reverse('homepage'))
    except:
        return redirect(reverse('homepage'))
Exemplo n.º 14
0
 def _inner(request, domain, *args, **kwargs):
     dom = Domain.get_by_name(domain)
     if not api_key and dom and dom.two_factor_auth:
         token = request.META.get('HTTP_X_COMMCAREHQ_OTP')
         if token and match_token(request.user, token):
             return fn(request, *args, **kwargs)
         else:
             return JsonResponse({"error": "must send X-CommcareHQ-OTP header"}, status=401)
     return fn(request, domain, *args, **kwargs)
Exemplo n.º 15
0
    def _verify_token(self, user, token, device=None):
        if device is not None:
            device = device if device.verify_token(token) else None
        else:
            device = match_token(user, token)

        if device is None:
            self.verify()

            raise forms.ValidationError(_('Invalid token. Please make sure you have entered it correctly.'), code='invalid')

        return device
Exemplo n.º 16
0
def get(
    request,
    path,
):
    token = request.POST.get("token", None)
    if token:  # token
        if django_otp.match_token(request.user, token):
            if request.user.is_staff:
                pde = PDE.objects.all()
            else:
                pde = PDE.objects.filter(user=request.user.get_username())
            for p in pde:
                print(p.pde)

                if p.pde == "pde/files/" + path:
                    with open(
                            os.path.join(
                                os.path.join(settings.MEDIA_ROOT, 'pde/files'),
                                path), "rb") as f:
                        content = f.read()
                    content = Cryptographer.decrypted(content)
                    m = hashlib.md5()
                    m.update(content)
                    message = 'Hi %(username)s,\n\n' \
                              'You\'ve verified yourself and just downloaded a PDE file with the following details: \n\n' \
                              'File: %(path)s\n' \
                              'MD5: %(md5)s\n' \
                              % {'username': request.user.get_username(), 'path': path, 'md5': m.hexdigest()}
                    print(message)
                    request.user.email_user(subject='PDE Download Success',
                                            message=message)

                    response = HttpResponse(
                        content,
                        content_type=magic.Magic(
                            mime=True).from_buffer(content))
                    response[
                        'Content-Disposition'] = 'attachment; filename=' + path
                    return response

            return HttpResponse(status=401)
        else:
            return HttpResponse(status=401)
    else:
        context = {
            'dfi': request.user,
        }
        return render(request, 'pde/otp.html', context)
Exemplo n.º 17
0
 def _inner(request, domain, *args, **kwargs):
     dom = Domain.get_by_name(domain)
     couch_user = _ensure_request_couch_user(request)
     if not api_key and dom and _two_factor_required(
             view_func, dom, couch_user):
         token = request.META.get('HTTP_X_COMMCAREHQ_OTP')
         if not token:
             return JsonResponse(
                 {"error": "must send X-CommcareHQ-OTP header"},
                 status=401)
         elif not match_token(request.user, token):
             return JsonResponse(
                 {"error": "X-CommcareHQ-OTP token is incorrect"},
                 status=401)
         else:
             return fn(request, domain, *args, **kwargs)
     return fn(request, domain, *args, **kwargs)
Exemplo n.º 18
0
def change_totp(request, add=False):
    bad_password = False
    bad_token = None
    otp_png = None
    confirmed = False

    request.session['add_device'] = add

    if request.method == 'POST' and 'token' in request.POST:

        if not django_otp.match_token(request.user, request.POST['token']):
            bad_token = True

        if not authenticate(username=request.user.username,
                            password=request.POST['password']):
            bad_password = True

        if not (bad_password or bad_token):
            new_device = add_device(request.user, request.POST['new_name'])
            request.session['new_device'] = new_device.id
            otp_png = get_png(request.user, new_device)

    if request.method == 'POST' and 'new_token' in request.POST:
        new_device = devices.get(request.user, request.session['new_device'])
        otp_png = get_png(request.user, new_device)
        if new_device.verify_token(request.POST['new_token']):
            new_device.confirmed = True
            new_device.save()
            confirmed = True
            if not request.session['add_device']:
                devices.delete_all(request.user, keep=new_device)
        else:
            bad_token = True

    return render(
        request, 'totp-change-form.html', {
            'bad_token': bad_token,
            'bad_password': bad_password,
            'add_device': request.session['add_device'],
            'otp_png': otp_png,
            'confirmed': confirmed,
        })
Exemplo n.º 19
0
def totp_remove(request):
    bad_token = False
    bad_password = False
    success = False

    if request.method == 'POST' and 'token' in request.POST:
        device = django_otp.match_token(request.user, request.POST['token'])
        if not device:
            bad_token = True

        if not authenticate(username=request.user.username,
                            password=request.POST['password']):
            bad_password = True

        if not bad_password and not bad_token:
            devices.delete_all(request.user, keep=device)
            success = True

    return render(request, 'totp-remove.html', {
        'bad_token': bad_token,
        'bad_password': bad_password,
        'success': success,
    })
Exemplo n.º 20
0
 def validate_code(self, value):
     device = django_otp.match_token(self.context["user"], value)
     if device is None:
         raise serializers.ValidationError(_("This code is invalid"))
     return device
Exemplo n.º 21
0
def login(request):
    """ The login page """
    user = None
    oreq = request.session.get('openid_request', None)
    # this can be POST or GET, and can be null or empty
    next = request.REQUEST.get('next') or reverse(index)
    is_otp = False
    login_form = None
    login_form_class = OpenIDLoginForm if oreq else LoginForm
    strong_auth_req = 'strong_auth_requested' in request.session

    try:
        if request.method != 'POST':
            pass
        elif 'cancel' in request.POST:
            # note: this wipes request.session
            _logout(request)
            if oreq is not None:
                oresp = oreq.answer(False)
                return render_openid_response(request, oresp)
        elif 'otp_token' in request.POST:
            # if user's not authenticated, go back to square one
            if not request.user.is_authenticated():
                raise OkupyError('OTP verification timed out')

            is_otp = True
            otp_form = OTPForm(request.POST)
            if otp_form.is_valid():
                token = otp_form.cleaned_data['otp_token']
            else:
                raise OkupyError('OTP verification failed')

            dev = django_otp.match_token(request.user, token)
            if not dev:
                raise OkupyError('OTP verification failed')
            django_otp.login(request, dev)
        else:
            login_form = login_form_class(request.POST)
            if login_form.is_valid():
                username = login_form.cleaned_data['username']
                password = login_form.cleaned_data['password']
            else:
                raise OkupyError('Login failed')
            """
            Perform authentication, if it retrieves a user object then
            it was successful. If it retrieves None then it failed to login
            """
            try:
                user = authenticate(username=username, password=password)
            except Exception as error:
                logger.critical(error, extra=log_extra_data(request))
                logger_mail.exception(error)
                raise OkupyError(
                    "Can't contact the LDAP server or the database")
            if not user:
                raise OkupyError('Login failed')

            if oreq:
                request.session['auto_logout'] = (
                    login_form.cleaned_data['auto_logout'])
    except OkupyError as error:
        messages.error(request, str(error))

    if user and user.is_active:
        _login(request, user)
        # prepare devices, and see if OTP is enabled
        init_otp(request)
        try:
            set_secondary_password(request=request, password=password)
        except Exception as error:
            logger.critical(error, extra=log_extra_data(request))
            logger_mail.exception(error)
            raise OkupyError("Can't contact LDAP server")
    if (request.user.is_authenticated()
            and (not strong_auth_req
                 or 'secondary_password' in request.session)):
        if request.user.is_verified():
            return redirect(next)
        login_form = OTPForm()
        is_otp = True
    if login_form is None:
        login_form = login_form_class()

    if is_otp or strong_auth_req:
        ssl_auth_form = None
        ssl_auth_uri = None
    else:
        if 'encrypted_id' not in request.session:
            # .cache_key is a very good property since it ensures
            # that the cache is actually created, and works from first
            # request
            session_id = request.session.cache_key

            # since it always starts with the backend module name
            # and __init__() expects pure id, we can strip that
            assert(session_id.startswith('django.contrib.sessions.cache'))
            session_id = session_id[29:]
            request.session['encrypted_id'] = base64.b64encode(
                cipher.encrypt(session_id))

        # TODO: it fails when:
        # 1. site is accessed via IP (auth.127.0.0.1),
        # 2. HTTP used on non-standard port (https://...:8000).
        ssl_auth_form = SSLCertLoginForm({
            'session_id': request.session['encrypted_id'],
            'next': request.build_absolute_uri(next),
            'login_uri': request.build_absolute_uri(request.get_full_path()),
        })

        ssl_auth_host = 'auth.' + request.get_host()
        ssl_auth_path = reverse(ssl_auth)
        ssl_auth_uri = urljoin('https://' + ssl_auth_host, ssl_auth_path)

    return render(request, 'login.html', {
        'login_form': login_form,
        'openid_request': oreq,
        'next': next,
        'ssl_auth_uri': ssl_auth_uri,
        'ssl_auth_form': ssl_auth_form,
        'is_otp': is_otp,
    })
Exemplo n.º 22
0
def login(request):
    """ The login page """
    user = None
    oreq = request.session.get('openid_request', None)
    # this can be POST or GET, and can be null or empty
    next = request.REQUEST.get('next') or reverse(index)
    is_otp = False
    login_form = None
    strong_auth_req = 'strong_auth_requested' in request.session

    if oreq:
        login_form_class = OpenIDLoginForm
    elif ('strong_auth_requested' in request.session
          and request.user.is_authenticated()):
        login_form_class = StrongAuthForm
    else:
        login_form_class = LoginForm

    try:
        if request.method != 'POST':
            pass
        elif 'cancel' in request.POST:
            # note: this wipes request.session
            _logout(request)
            if oreq is not None:
                oresp = oreq.answer(False)
                return render_openid_response(request, oresp)
        elif 'otp_token' in request.POST:
            # if user's not authenticated, go back to square one
            if not request.user.is_authenticated():
                raise OkupyError('OTP verification timed out')

            is_otp = True
            otp_form = OTPForm(request.POST)
            if otp_form.is_valid():
                token = otp_form.cleaned_data['otp_token']
            else:
                raise OkupyError('OTP verification failed')

            # prevent replay attacks and race conditions
            if not RevokedToken.add(token, request.user):
                raise OkupyError('OTP verification failed')
            dev = django_otp.match_token(request.user, token)
            if not dev:
                raise OkupyError('OTP verification failed')
            django_otp.login(request, dev)
        else:
            login_form = login_form_class(request.POST)
            if login_form.is_valid():
                if login_form_class != StrongAuthForm:
                    username = login_form.cleaned_data['username']
                else:
                    username = request.user.username
                password = login_form.cleaned_data['password']
            else:
                raise OkupyError('Login failed')
            """
            Perform authentication, if it retrieves a user object then
            it was successful. If it retrieves None then it failed to login
            """
            try:
                user = authenticate(request=request,
                                    username=username,
                                    password=password)
            except Exception as error:
                logger.critical(error, extra=log_extra_data(request))
                logger_mail.exception(error)
                raise OkupyError(
                    "Can't contact the LDAP server or the database")
            if not user:
                raise OkupyError('Login failed')

            if oreq:
                request.session['auto_logout'] = (
                    login_form.cleaned_data['auto_logout'])
    except OkupyError as error:
        messages.error(request, str(error))

    if user and user.is_active:
        _login(request, user)
        # prepare devices, and see if OTP is enabled
        init_otp(request)
        set_secondary_password(request=request, password=password)
    if request.user.is_authenticated():
        if (strong_auth_req and not 'secondary_password' in request.session):
            if request.method != 'POST':
                messages.info(
                    request, 'You need to type in your password' +
                    ' again to perform this action')
        else:
            if request.user.is_verified():
                return redirect(next)
            login_form = OTPForm()
            is_otp = True
    if login_form is None:
        login_form = login_form_class()

    if is_otp or strong_auth_req:
        ssl_auth_form = None
        ssl_auth_uri = None
        ssh_auth_command = None
    else:
        encrypted_id = sessionrefcipher.encrypt(request.session)

        # TODO: it fails when:
        # 1. site is accessed via IP (auth.127.0.0.1),
        # 2. HTTP used on non-standard port (https://...:8000).
        ssl_auth_form = SSLCertLoginForm({
            'session':
            encrypted_id,
            'next':
            request.build_absolute_uri(next),
            'login_uri':
            request.build_absolute_uri(request.get_full_path()),
        })

        ssl_auth_host = 'auth.' + request.get_host()
        ssl_auth_path = reverse(ssl_auth)
        ssl_auth_uri = urljoin('https://' + ssl_auth_host, ssl_auth_path)

        if settings.SSH_BIND[1] == 22:
            ssh_port_opt = ''
        else:
            ssh_port_opt = '-p %d ' % settings.SSH_BIND[1]

        ssh_auth_command = 'ssh %sauth+%s@%s' % (
            ssh_port_opt, encrypted_id, request.get_host().split(':')[0])

    return render(
        request, 'login.html', {
            'login_form': login_form,
            'openid_request': oreq,
            'next': next,
            'ssl_auth_uri': ssl_auth_uri,
            'ssl_auth_form': ssl_auth_form,
            'ssh_auth_command': ssh_auth_command,
            'is_otp': is_otp,
        })
Exemplo n.º 23
0
def login(request):
    # import ipdb;ipdb.set_trace()
    # otp_url = '/otp?%s' % request.META.get('QUERY_STRING', '')
    r_url = request.GET.get('next', '/')
    if request.user.is_authenticated():
        if r_url.startswith('/admin') and not request.user.is_staff:
            # 登陆用户无权限访问后台
            r_url = '/'
        return HttpResponseRedirect(r_url)
    # elif 'login_user_id' in request.session:
    #     # 已登陆但未进行otp验证
    #     return HttpResponseRedirect(otp_url)

    html = 'otp.html' if 'login_user_id' in request.session else 'login.html'

    if 'login_user_id' in request.session:
        # otp页显示
        uid = request.session['login_user_id']
        try:
            user = User.objects.get(id=uid)
        except:
            print 'Error: user_id (%d) del ??????!!!!!!!!' % uid
            del request.session['login_user_id']
            return HttpResponseRedirect('/login')

        userprofile = get_userprofile(user)
        if userprofile.show_otp:
            # 首次otp验证或人工设置,显示otp二维码
            show_otp = 1
            try:
                totpdevice = user.totpdevice_set.filter(confirmed=1)[0]
                otp_data = totpdevice.config_url  # 二维码对应实际数据otpauth://totp/user?digits=
                # print otp_data, 444
                # 提取secret内容,用于Google Authentication
                import urlparse
                result = urlparse.urlparse(otp_data)
                secret = urlparse.parse_qs(result.query).get('secret', ['Error!'])
                # 开始生成二维码
                import qrcode
                from io import BytesIO
                import base64
                mio = BytesIO()  # 用于替代磁盘临时文件,在内存中保存二维码图片
                qr = qrcode.QRCode(version=1, box_size=4, border=1,)
                qr.add_data(otp_data)
                qr.make()
                img = qr.make_image()
                img.save(mio)
                base64_data = base64.b64encode(mio.getvalue())
                # print base64_data
                if not base64_data:
                    error_msg = "(用户 %s) T-otp二维码图片生成失败" % user
                # return render(request, html, locals())

            except IndexError:
                # 正常情况下,totpdevice在userprofile创建后自动生成,无需人工添加
                error_msg = "Error: 用户 %s otp设备获取失败,请联系管理员登陆后台查看是否有当前用户对应的“TOTP device”,或者device被禁用" % user

    if request.method == "POST":
        totp = request.POST.get("totp")
        u = request.POST.get("username")
        p = request.POST.get("password")

        try:
            if totp:
                # otp验证
                try:
                    # locals()已有变量userprofile、user
                    userprofile
                except:
                    # 非法构建表单进行提交
                    return HttpResponse('', status=404)

                if match_token(user, totp):
                    if userprofile.show_otp:
                        # 首次otp验证通过后,以后登陆将不再显示二维码
                        userprofile.show_otp = 0
                        userprofile.save()
                    # 验证通过
                else:
                    error_msg = "(用户 %s) T-otp验证码失败,请等待otp《数字更新》后,重新尝试,<br/>若仍然失败则可能为网站时间和用户手机时间不一致导致,请联系管理员确认CMDB服务器时间是否为标准时间(%s)" % (user, datetime.now())
                    raise

            else:
                # 用户密码验证
                user = auth.authenticate(username=u, password=p)
                if user:
                    userprofile = get_userprofile(user)
                    if userprofile.chk_yx():
                        error_msg = "账号过期,已停用,请联系管理员处理"
                        raise
                    else:
                        request.session['login_user_id'] = user.id
                        if userprofile.otp:
                            return HttpResponseRedirect(request.get_full_path())  # 重新打开页面,用于判断是否显示二维码
                        # 管理员已设置当前用户无需进行otp验证
                    # 验证通过

                else:
                    error_msg = "用户名/密码错误,或用户已停用"
                    raise

            # 用户登陆
            auth.login(request, user)
            # 检查密码过期
            if userprofile.chk_expired():
                r_url = '/password_change?next=%s' % r_url
            return HttpResponseRedirect(r_url)
        except Exception as e:
            # print e, 22222
            pass

    return render(request, html, locals())
Exemplo n.º 24
0
 def clean_tfa_code(self):
     code = self.cleaned_data["tfa_code"]
     device = django_otp.match_token(self.user, code)
     if device is None:
         raise forms.ValidationError(_("This code is invalid"))
     return device
Exemplo n.º 25
0
 def run(self):
     self.verified = match_token(self.user, self.token)
     connection.close()
Exemplo n.º 26
0
def login(request):
    """ The login page """
    user = None
    oreq = request.session.get('openid_request', None)
    # this can be POST or GET, and can be null or empty
    next = request.REQUEST.get('next') or reverse(index)
    is_otp = False
    login_form = None
    strong_auth_req = 'strong_auth_requested' in request.session

    if oreq:
        login_form_class = OpenIDLoginForm
    elif ('strong_auth_requested' in request.session
            and request.user.is_authenticated()):
        login_form_class = StrongAuthForm
    else:
        login_form_class = LoginForm

    try:
        if request.method != 'POST':
            pass
        elif 'cancel' in request.POST:
            # note: this wipes request.session
            _logout(request)
            if oreq is not None:
                oresp = oreq.answer(False)
                return render_openid_response(request, oresp)
        elif 'otp_token' in request.POST:
            # if user's not authenticated, go back to square one
            if not request.user.is_authenticated():
                raise OkupyError('OTP verification timed out')

            is_otp = True
            otp_form = OTPForm(request.POST)
            if otp_form.is_valid():
                token = otp_form.cleaned_data['otp_token']
            else:
                raise OkupyError('OTP verification failed')

            # prevent replay attacks and race conditions
            if not RevokedToken.add(token, request.user):
                raise OkupyError('OTP verification failed')
            dev = django_otp.match_token(request.user, token)
            if not dev:
                raise OkupyError('OTP verification failed')
            django_otp.login(request, dev)
        else:
            login_form = login_form_class(request.POST)
            if login_form.is_valid():
                if login_form_class != StrongAuthForm:
                    username = login_form.cleaned_data['username']
                else:
                    username = request.user.username
                password = login_form.cleaned_data['password']
            else:
                raise OkupyError('Login failed')
            """
            Perform authentication, if it retrieves a user object then
            it was successful. If it retrieves None then it failed to login
            """
            try:
                user = authenticate(
                    request=request,
                    username=username,
                    password=password)
            except Exception as error:
                logger.critical(error, extra=log_extra_data(request))
                logger_mail.exception(error)
                raise OkupyError(
                    "Can't contact the LDAP server or the database")
            if not user:
                raise OkupyError('Login failed')

            if oreq:
                request.session['auto_logout'] = (
                    login_form.cleaned_data['auto_logout'])
    except OkupyError as error:
        messages.error(request, str(error))

    if user and user.is_active:
        _login(request, user)
        # prepare devices, and see if OTP is enabled
        init_otp(request)
        set_secondary_password(request=request, password=password)
    if request.user.is_authenticated():
        if (strong_auth_req
                and not 'secondary_password' in request.session):
            if request.method != 'POST':
                messages.info(request, 'You need to type in your password'
                              + ' again to perform this action')
        else:
            if request.user.is_verified():
                return redirect(next)
            login_form = OTPForm()
            is_otp = True
    if login_form is None:
        login_form = login_form_class()

    if is_otp or strong_auth_req:
        ssl_auth_form = None
        ssl_auth_uri = None
        ssh_auth_command = None
    else:
        encrypted_id = sessionrefcipher.encrypt(request.session)

        # TODO: it fails when:
        # 1. site is accessed via IP (auth.127.0.0.1),
        # 2. HTTP used on non-standard port (https://...:8000).
        ssl_auth_form = SSLCertLoginForm({
            'session': encrypted_id,
            'next': request.build_absolute_uri(next),
            'login_uri': request.build_absolute_uri(request.get_full_path()),
        })

        ssl_auth_host = 'auth.' + request.get_host()
        ssl_auth_path = reverse(ssl_auth)
        ssl_auth_uri = urljoin('https://' + ssl_auth_host, ssl_auth_path)

        if settings.SSH_BIND[1] == 22:
            ssh_port_opt = ''
        else:
            ssh_port_opt = '-p %d ' % settings.SSH_BIND[1]

        ssh_auth_command = 'ssh %sauth+%s@%s' % (
            ssh_port_opt,
            encrypted_id,
            request.get_host().split(':')[0])

    return render(request, 'login.html', {
        'login_form': login_form,
        'openid_request': oreq,
        'next': next,
        'ssl_auth_uri': ssl_auth_uri,
        'ssl_auth_form': ssl_auth_form,
        'ssh_auth_command': ssh_auth_command,
        'is_otp': is_otp,
    })
Exemplo n.º 27
0
    def test_match_token(self):
        verified = match_token(self.alice, 'bogus')
        self.assertIsNone(verified)

        verified = match_token(self.alice, 'alice')
        self.assertEqual(verified, self.alice.staticdevice_set.first())
Exemplo n.º 28
0
 def clean_code(self):
     code = self.cleaned_data['code']
     if user_has_device(self.user) and not match_token(self.user, code):
         raise forms.ValidationError(_("Wrong two factor code informed"))
     return code