コード例 #1
0
ファイル: services.py プロジェクト: dsyed/warehouse
    def check_password(self, userid, password):
        # The very first thing we want to do is check to see if we've hit our
        # global rate limit or not, assuming that we've been configured with a
        # global rate limiter anyways.
        if not self.ratelimiters["global"].test():
            logger.warning("Global failed login threshold reached.")
            raise TooManyFailedLogins(resets_in=self.ratelimiters["global"].resets_in())

        user = self.get_user(userid)
        if user is not None:
            # Now, check to make sure that we haven't hitten a rate limit on a
            # per user basis.
            if not self.ratelimiters["user"].test(user.id):
                raise TooManyFailedLogins(
                    resets_in=self.ratelimiters["user"].resets_in(user.id)
                )

            # Check LDAP for valid credentials
            try:
                res = self.ldap.simple_bind_s(
                    "uid={},{}".format(user.username, LDAP_BASE_DN),
                    password
                )
                return res[0] == 97
            except ldap.LDAPError:
                return False

        # If we've gotten here, then we'll want to record a failed login in our
        # rate limiting before returning False to indicate a failed password
        # verification.
        if user is not None:
            self.ratelimiters["user"].hit(user.id)
        self.ratelimiters["global"].hit()

        return False
コード例 #2
0
ファイル: services.py プロジェクト: hmilkovi/warehouse
    def check_recovery_code(self, user_id, code):
        self._metrics.increment("warehouse.authentication.recovery_code.start")

        # The very first thing we want to do is check to see if we've hit our
        # global rate limit or not, assuming that we've been configured with a
        # global rate limiter anyways.
        if not self.ratelimiters["global"].test():
            logger.warning("Global failed login threshold reached.")
            self._metrics.increment(
                "warehouse.authentication.recovery_code.ratelimited",
                tags=["ratelimiter:global"],
            )
            raise TooManyFailedLogins(resets_in=self.ratelimiters["global"].resets_in())

        # Now, check to make sure that we haven't hitten a rate limit on a
        # per user basis.
        if not self.ratelimiters["user"].test(user_id):
            self._metrics.increment(
                "warehouse.authentication.recovery_code.ratelimited",
                tags=["ratelimiter:user"],
            )
            raise TooManyFailedLogins(
                resets_in=self.ratelimiters["user"].resets_in(user_id)
            )

        user = self.get_user(user_id)

        if not user.has_recovery_codes:
            self._metrics.increment(
                "warehouse.authentication.recovery_code.failure",
                tags=["failure_reason:no_recovery_codes"],
            )
            # If we've gotten here, then we'll want to record a failed attempt in our
            # rate limiting before returning False to indicate a failed recovery code
            # verification.
            self.ratelimiters["user"].hit(user_id)
            self.ratelimiters["global"].hit()
            return False

        valid = False
        for stored_recovery_code in self.get_recovery_codes(user.id):
            if self.hasher.verify(code, stored_recovery_code.code):
                self.db.delete(stored_recovery_code)
                self.db.flush()
                valid = True

        if valid:
            self._metrics.increment("warehouse.authentication.recovery_code.ok")
        else:
            self._metrics.increment(
                "warehouse.authentication.recovery_code.failure",
                tags=["failure_reason:invalid_recovery_code"],
            )
            # If we've gotten here, then we'll want to record a failed attempt in our
            # rate limiting before returning False to indicate a failed recovery code
            # verification.
            self.ratelimiters["user"].hit(user_id)
            self.ratelimiters["global"].hit()

        return valid
コード例 #3
0
ファイル: services.py プロジェクト: robindboer/warehouse
    def check_totp_value(self, user_id, totp_value, *, tags=None):
        """
        Returns True if the given TOTP is valid against the user's secret.

        If the user doesn't have a TOTP secret or isn't allowed
        to use second factor methods, returns False.
        """
        tags = tags if tags is not None else []
        self._metrics.increment("warehouse.authentication.two_factor.start",
                                tags=tags)

        # The very first thing we want to do is check to see if we've hit our
        # global rate limit or not, assuming that we've been configured with a
        # global rate limiter anyways.
        if not self.ratelimiters["global"].test():
            logger.warning("Global failed login threshold reached.")
            self._metrics.increment(
                "warehouse.authentication.two_factor.ratelimited",
                tags=tags + ["ratelimiter:global"],
            )
            raise TooManyFailedLogins(
                resets_in=self.ratelimiters["global"].resets_in())

        # Now, check to make sure that we haven't hitten a rate limit on a
        # per user basis.
        if not self.ratelimiters["user"].test(user_id):
            self._metrics.increment(
                "warehouse.authentication.two_factor.ratelimited",
                tags=tags + ["ratelimiter:user"],
            )
            raise TooManyFailedLogins(
                resets_in=self.ratelimiters["user"].resets_in(user_id))

        totp_secret = self.get_totp_secret(user_id)

        if totp_secret is None:
            self._metrics.increment(
                "warehouse.authentication.two_factor.failure",
                tags=tags + ["failure_reason:no_totp"],
            )
            return False

        valid = otp.verify_totp(totp_secret, totp_value)

        if valid:
            self._metrics.increment("warehouse.authentication.two_factor.ok",
                                    tags=tags)
        else:
            self._metrics.increment(
                "warehouse.authentication.two_factor.failure",
                tags=tags + ["failure_reason:invalid_totp"],
            )

        return valid
コード例 #4
0
ファイル: test_forms.py プロジェクト: merwok-forks/warehouse
    def test_validate_password_too_many_failed(self):
        request = pretend.stub(remote_addr="1.2.3.4")
        user_service = pretend.stub(
            find_userid=pretend.call_recorder(lambda userid: 1),
            check_password=pretend.call_recorder(
                pretend.raiser(TooManyFailedLogins(resets_in=None))),
            is_disabled=pretend.call_recorder(lambda userid: (False, None)),
        )
        breach_service = pretend.stub()
        form = forms.LoginForm(
            data={"username": "******"},
            request=request,
            user_service=user_service,
            breach_service=breach_service,
        )
        field = pretend.stub(data="pw")

        with pytest.raises(wtforms.validators.ValidationError):
            form.validate_password(field)

        assert user_service.find_userid.calls == [
            pretend.call("my_username"),
            pretend.call("my_username"),
        ]
        assert user_service.is_disabled.calls == [pretend.call(1)]
        assert user_service.check_password.calls == [
            pretend.call(1, "pw", tags=None)
        ]
コード例 #5
0
ファイル: services.py プロジェクト: uploadskill/warehouse
    def check_password(self, userid, password):
        # The very first thing we want to do is check to see if we've hit our
        # global rate limit or not, assuming that we've been configured with a
        # global rate limiter anyways.
        if not self.ratelimiters["global"].test():
            logger.warning("Global failed login threshold reached.")
            raise TooManyFailedLogins(
                resets_in=self.ratelimiters["global"].resets_in(),
            )

        user = self.get_user(userid)
        if user is not None:
            # Now, check to make sure that we haven't hitten a rate limit on a
            # per user basis.
            if not self.ratelimiters["user"].test(user.id):
                raise TooManyFailedLogins(
                    resets_in=self.ratelimiters["user"].resets_in(user.id),
                )

            # Actually check our hash, optionally getting a new hash for it if
            # we should upgrade our saved hashed.
            ok, new_hash = self.hasher.verify_and_update(
                password,
                user.password,
            )

            # First, check to see if the password that we were given was OK.
            if ok:
                # Then, if the password was OK check to see if we've been given
                # a new password hash from the hasher, if so we'll want to save
                # that hash.
                if new_hash:
                    user.password = new_hash

                return True

        # If we've gotten here, then we'll want to record a failed login in our
        # rate limiting before returning False to indicate a failed password
        # verification.
        if user is not None:
            self.ratelimiters["user"].hit(user.id)
        self.ratelimiters["global"].hit()

        return False
コード例 #6
0
ファイル: test_views.py プロジェクト: ytaniguchi8/warehouse
class TestFailedLoginView:
    exc = TooManyFailedLogins(resets_in=datetime.timedelta(seconds=600))
    request = pretend.stub()

    resp = views.failed_logins(exc, request)

    assert resp.status == "429 Too Many Failed Login Attempts"
    assert resp.detail == (
        "There have been too many unsuccessful login attempts. "
        "Try again later.")
    assert dict(resp.headers).get("Retry-After") == "600"
コード例 #7
0
    def _check_ratelimits(self, userid=None, tags=None):
        tags = tags if tags is not None else []

        # First we want to check if a single IP is exceeding our rate limiter.
        if self.remote_addr is not None:
            if not self.ratelimiters["ip.login"].test(self.remote_addr):
                logger.warning("IP failed login threshold reached.")
                self._metrics.increment(
                    "warehouse.authentication.ratelimited",
                    tags=tags + ["ratelimiter:ip"],
                )
                raise TooManyFailedLogins(
                    resets_in=self.ratelimiters["ip.login"].resets_in(self.remote_addr)
                )

        # Next check to see if we've hit our global rate limit or not,
        # assuming that we've been configured with a global rate limiter anyways.
        if not self.ratelimiters["global.login"].test():
            logger.warning("Global failed login threshold reached.")
            self._metrics.increment(
                "warehouse.authentication.ratelimited",
                tags=tags + ["ratelimiter:global"],
            )
            raise TooManyFailedLogins(
                resets_in=self.ratelimiters["global.login"].resets_in()
            )

        # Now, check to make sure that we haven't hitten a rate limit on a
        # per user basis.
        if userid is not None:
            if not self.ratelimiters["user.login"].test(userid):
                self._metrics.increment(
                    "warehouse.authentication.ratelimited",
                    tags=tags + ["ratelimiter:user"],
                )
                raise TooManyFailedLogins(
                    resets_in=self.ratelimiters["user.login"].resets_in(userid)
                )
コード例 #8
0
 def check_password(userid, password, tags=None):
     raise TooManyFailedLogins(resets_in=None)
コード例 #9
0
    def check_password(self, userid, password, *, tags=None):
        tags = tags if tags is not None else []

        self._metrics.increment("warehouse.authentication.start", tags=tags)

        # The very first thing we want to do is check to see if we've hit our
        # global rate limit or not, assuming that we've been configured with a
        # global rate limiter anyways.
        if not self.ratelimiters["global.login"].test():
            logger.warning("Global failed login threshold reached.")
            self._metrics.increment(
                "warehouse.authentication.ratelimited",
                tags=tags + ["ratelimiter:global"],
            )
            raise TooManyFailedLogins(
                resets_in=self.ratelimiters["global.login"].resets_in())

        user = self.get_user(userid)
        if user is not None:
            # Now, check to make sure that we haven't hitten a rate limit on a
            # per user basis.
            if not self.ratelimiters["user.login"].test(user.id):
                self._metrics.increment(
                    "warehouse.authentication.ratelimited",
                    tags=tags + ["ratelimiter:user"],
                )
                raise TooManyFailedLogins(
                    resets_in=self.ratelimiters["user.login"].resets_in(
                        user.id))

            # Actually check our hash, optionally getting a new hash for it if
            # we should upgrade our saved hashed.
            ok, new_hash = self.hasher.verify_and_update(
                password, user.password)

            # First, check to see if the password that we were given was OK.
            if ok:
                # Then, if the password was OK check to see if we've been given
                # a new password hash from the hasher, if so we'll want to save
                # that hash.
                if new_hash:
                    user.password = new_hash

                self._metrics.increment("warehouse.authentication.ok",
                                        tags=tags)

                return True
            else:
                self._metrics.increment(
                    "warehouse.authentication.failure",
                    tags=tags + ["failure_reason:password"],
                )
        else:
            self._metrics.increment("warehouse.authentication.failure",
                                    tags=tags + ["failure_reason:user"])

        # If we've gotten here, then we'll want to record a failed login in our
        # rate limiting before returning False to indicate a failed password
        # verification.
        if user is not None:
            self.ratelimiters["user.login"].hit(user.id)
        self.ratelimiters["global.login"].hit()

        return False