2019-04-30 08:27:42 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-07-28 10:27:38 +08:00
|
|
|
RSpec.describe Auth::DefaultCurrentUserProvider do
|
2020-07-21 13:43:28 +08:00
|
|
|
# careful using fab! here is can lead to an erratic test
|
|
|
|
# we want a distinct user object per test so last_seen_at is
|
|
|
|
# handled correctly
|
|
|
|
let(:user) { Fabricate(:user) }
|
2014-05-23 06:13:25 +08:00
|
|
|
|
2017-02-01 06:21:37 +08:00
|
|
|
class TestProvider < Auth::DefaultCurrentUserProvider
|
|
|
|
attr_reader :env
|
2018-09-04 14:17:05 +08:00
|
|
|
def initialize(env)
|
|
|
|
super(env)
|
2017-02-01 06:21:37 +08:00
|
|
|
end
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
|
|
|
|
def cookie_jar
|
|
|
|
@cookie_jar ||= ActionDispatch::Request.new(env).cookie_jar
|
|
|
|
end
|
2017-02-01 06:21:37 +08:00
|
|
|
end
|
|
|
|
|
2014-05-23 06:13:25 +08:00
|
|
|
def provider(url, opts = nil)
|
|
|
|
opts ||= { method: "GET" }
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
env = create_request_env(path: url).merge(opts)
|
2018-09-04 14:17:05 +08:00
|
|
|
TestProvider.new(env)
|
2014-05-23 06:13:25 +08:00
|
|
|
end
|
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
def get_cookie_info(cookie_jar, name)
|
|
|
|
headers = {}
|
|
|
|
cookie_jar.always_write_cookie = true
|
|
|
|
cookie_jar.write(headers)
|
|
|
|
|
|
|
|
header = headers["Set-Cookie"]
|
|
|
|
return if header.nil?
|
|
|
|
|
|
|
|
info = {}
|
|
|
|
|
|
|
|
line = header.split("\n").find { |l| l.start_with?("#{name}=") }
|
|
|
|
parts = line.split(";").map(&:strip)
|
|
|
|
|
|
|
|
info[:value] = parts.shift.split("=")[1]
|
|
|
|
parts.each do |p|
|
|
|
|
key, value = p.split("=")
|
|
|
|
info[key.downcase.to_sym] = value || true
|
|
|
|
end
|
|
|
|
|
|
|
|
info
|
|
|
|
end
|
|
|
|
|
2017-12-12 16:40:35 +08:00
|
|
|
it "can be used to pretend that a user doesn't exist" do
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider = TestProvider.new(create_request_env(path: "/"))
|
2017-12-12 16:40:35 +08:00
|
|
|
expect(provider.current_user).to eq(nil)
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "server header api" do
|
2019-11-05 22:10:23 +08:00
|
|
|
it "raises for a revoked key" do
|
2020-04-07 06:55:44 +08:00
|
|
|
api_key = ApiKey.create!
|
|
|
|
params = { "HTTP_API_USERNAME" => user.username.downcase, "HTTP_API_KEY" => api_key.key }
|
2019-11-05 22:10:23 +08:00
|
|
|
expect(
|
2020-04-07 06:55:44 +08:00
|
|
|
provider("/", params).current_user.id
|
2019-11-05 22:10:23 +08:00
|
|
|
).to eq(user.id)
|
|
|
|
|
2020-04-07 06:55:44 +08:00
|
|
|
api_key.reload.update(revoked_at: Time.zone.now, last_used_at: nil)
|
|
|
|
expect(api_key.reload.last_used_at).to eq(nil)
|
|
|
|
params = { "HTTP_API_USERNAME" => user.username.downcase, "HTTP_API_KEY" => api_key.key }
|
2019-11-05 22:10:23 +08:00
|
|
|
|
|
|
|
expect {
|
2020-04-07 06:55:44 +08:00
|
|
|
provider("/", params).current_user
|
2019-11-05 22:10:23 +08:00
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
|
2020-04-07 06:55:44 +08:00
|
|
|
api_key.reload
|
|
|
|
expect(api_key.last_used_at).to eq(nil)
|
2017-12-11 08:07:22 +08:00
|
|
|
end
|
2014-11-20 12:21:49 +08:00
|
|
|
|
2019-03-09 00:13:31 +08:00
|
|
|
it "raises errors for incorrect api_key" do
|
|
|
|
params = { "HTTP_API_KEY" => "INCORRECT" }
|
|
|
|
expect {
|
|
|
|
provider("/", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess, /API username or key is invalid/)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "finds a user for a correct per-user api key" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(user_id: user.id, created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key }
|
2019-03-09 00:13:31 +08:00
|
|
|
|
|
|
|
good_provider = provider("/", params)
|
2020-07-21 13:43:28 +08:00
|
|
|
|
|
|
|
expect do
|
|
|
|
expect(good_provider.current_user.id).to eq(user.id)
|
|
|
|
end.to change { api_key.reload.last_used_at }
|
|
|
|
|
2019-03-09 00:13:31 +08:00
|
|
|
expect(good_provider.is_api?).to eq(true)
|
|
|
|
expect(good_provider.is_user_api?).to eq(false)
|
|
|
|
expect(good_provider.should_update_last_seen?).to eq(false)
|
|
|
|
|
|
|
|
user.update_columns(active: false)
|
|
|
|
|
|
|
|
expect {
|
|
|
|
provider("/", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
|
|
|
|
user.update_columns(active: true, suspended_till: 1.day.from_now)
|
|
|
|
|
|
|
|
expect {
|
|
|
|
provider("/", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises for a user pretending" do
|
|
|
|
user2 = Fabricate(:user)
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(user_id: user.id, created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key, "HTTP_API_USERNAME" => user2.username.downcase }
|
2019-03-09 00:13:31 +08:00
|
|
|
|
|
|
|
expect {
|
|
|
|
provider("/", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises for a user with a mismatching ip" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(user_id: user.id, created_by_id: -1, allowed_ips: ['10.0.0.0/24'])
|
2019-03-09 00:13:31 +08:00
|
|
|
params = {
|
2019-11-29 23:16:06 +08:00
|
|
|
"HTTP_API_KEY" => api_key.key,
|
2019-03-09 00:13:31 +08:00
|
|
|
"HTTP_API_USERNAME" => user.username.downcase,
|
|
|
|
"REMOTE_ADDR" => "10.1.0.1"
|
|
|
|
}
|
|
|
|
|
|
|
|
expect {
|
|
|
|
provider("/", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "allows a user with a matching ip" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(user_id: user.id, created_by_id: -1, allowed_ips: ['100.0.0.0/24'])
|
2019-03-09 00:13:31 +08:00
|
|
|
params = {
|
2019-11-29 23:16:06 +08:00
|
|
|
"HTTP_API_KEY" => api_key.key,
|
2019-03-09 00:13:31 +08:00
|
|
|
"HTTP_API_USERNAME" => user.username.downcase,
|
|
|
|
"REMOTE_ADDR" => "100.0.0.22",
|
|
|
|
}
|
|
|
|
|
|
|
|
found_user = provider("/", params).current_user
|
|
|
|
|
|
|
|
expect(found_user.id).to eq(user.id)
|
|
|
|
|
|
|
|
params = {
|
2019-11-29 23:16:06 +08:00
|
|
|
"HTTP_API_KEY" => api_key.key,
|
2019-03-09 00:13:31 +08:00
|
|
|
"HTTP_API_USERNAME" => user.username.downcase,
|
|
|
|
"HTTP_X_FORWARDED_FOR" => "10.1.1.1, 100.0.0.22"
|
|
|
|
}
|
|
|
|
|
|
|
|
found_user = provider("/", params).current_user
|
|
|
|
expect(found_user.id).to eq(user.id)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "finds a user for a correct system api key" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key, "HTTP_API_USERNAME" => user.username.downcase }
|
2019-03-09 00:13:31 +08:00
|
|
|
expect(provider("/", params).current_user.id).to eq(user.id)
|
|
|
|
end
|
|
|
|
|
2019-03-13 07:16:42 +08:00
|
|
|
it "raises for a mismatched api_key header and param username" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key }
|
2019-03-13 07:16:42 +08:00
|
|
|
expect {
|
|
|
|
provider("/?api_username=#{user.username.downcase}", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
end
|
|
|
|
|
2019-03-09 00:13:31 +08:00
|
|
|
it "finds a user for a correct system api key with external id" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(created_by_id: -1)
|
2019-03-09 00:13:31 +08:00
|
|
|
SingleSignOnRecord.create(user_id: user.id, external_id: "abc", last_payload: '')
|
2019-11-29 23:16:06 +08:00
|
|
|
params = { "HTTP_API_KEY" => api_key.key, "HTTP_API_USER_EXTERNAL_ID" => "abc" }
|
2019-03-09 00:13:31 +08:00
|
|
|
expect(provider("/", params).current_user.id).to eq(user.id)
|
|
|
|
end
|
|
|
|
|
2019-03-13 07:16:42 +08:00
|
|
|
it "raises for a mismatched api_key header and param external id" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(created_by_id: -1)
|
2019-03-13 07:16:42 +08:00
|
|
|
SingleSignOnRecord.create(user_id: user.id, external_id: "abc", last_payload: '')
|
2019-11-29 23:16:06 +08:00
|
|
|
params = { "HTTP_API_KEY" => api_key.key }
|
2019-03-13 07:16:42 +08:00
|
|
|
expect {
|
|
|
|
provider("/?api_user_external_id=abc", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
end
|
|
|
|
|
2019-03-09 00:13:31 +08:00
|
|
|
it "finds a user for a correct system api key with id" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key, "HTTP_API_USER_ID" => user.id }
|
2019-03-09 00:13:31 +08:00
|
|
|
expect(provider("/", params).current_user.id).to eq(user.id)
|
|
|
|
end
|
|
|
|
|
2019-03-13 07:16:42 +08:00
|
|
|
it "raises for a mismatched api_key header and param user id" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key }
|
2019-03-13 07:16:42 +08:00
|
|
|
expect {
|
|
|
|
provider("/?api_user_id=#{user.id}", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
end
|
|
|
|
|
2020-07-21 13:43:28 +08:00
|
|
|
describe "when readonly mode is enabled due to postgres" do
|
|
|
|
before do
|
|
|
|
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
|
|
|
end
|
|
|
|
|
|
|
|
after do
|
|
|
|
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should not update ApiKey#last_used_at" do
|
|
|
|
api_key = ApiKey.create!(user_id: user.id, created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key }
|
|
|
|
|
|
|
|
good_provider = provider("/", params)
|
|
|
|
|
|
|
|
expect do
|
|
|
|
expect(good_provider.current_user.id).to eq(user.id)
|
|
|
|
end.to_not change { api_key.reload.last_used_at }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "with rate limiting" do
|
2019-03-09 00:13:31 +08:00
|
|
|
before do
|
|
|
|
RateLimiter.enable
|
|
|
|
end
|
|
|
|
|
2021-06-03 17:52:43 +08:00
|
|
|
it "rate limits admin api requests" do
|
|
|
|
global_setting :max_admin_api_reqs_per_minute, 3
|
2019-03-09 00:13:31 +08:00
|
|
|
|
|
|
|
freeze_time
|
2021-06-03 17:52:43 +08:00
|
|
|
RateLimiter.new(nil, "admin_api_min", 3, 60).clear!
|
2019-03-09 00:13:31 +08:00
|
|
|
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key, "HTTP_API_USERNAME" => user.username.downcase }
|
2019-03-09 00:13:31 +08:00
|
|
|
system_params = params.merge("HTTP_API_USERNAME" => "system")
|
|
|
|
|
|
|
|
provider("/", params).current_user
|
|
|
|
provider("/", system_params).current_user
|
|
|
|
provider("/", params).current_user
|
|
|
|
|
|
|
|
expect do
|
|
|
|
provider("/", system_params).current_user
|
|
|
|
end.to raise_error(RateLimiter::LimitExceeded)
|
|
|
|
|
|
|
|
freeze_time 59.seconds.from_now
|
|
|
|
|
|
|
|
expect do
|
|
|
|
provider("/", system_params).current_user
|
|
|
|
end.to raise_error(RateLimiter::LimitExceeded)
|
|
|
|
|
|
|
|
freeze_time 2.seconds.from_now
|
|
|
|
|
|
|
|
# 1 minute elapsed
|
|
|
|
provider("/", system_params).current_user
|
|
|
|
|
|
|
|
# should not rate limit a random key
|
|
|
|
api_key.destroy
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(created_by_id: -1)
|
|
|
|
params = { "HTTP_API_KEY" => api_key.key, "HTTP_API_USERNAME" => user.username.downcase }
|
2019-03-09 00:13:31 +08:00
|
|
|
provider("/", params).current_user
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-21 13:29:29 +08:00
|
|
|
describe "#current_user" do
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
let(:cookie) do
|
2019-01-22 18:07:48 +08:00
|
|
|
new_provider = provider('/')
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
new_provider.log_on_user(user, {}, new_provider.cookie_jar)
|
2022-05-19 22:58:31 +08:00
|
|
|
CGI.escape(new_provider.cookie_jar["_t"])
|
2019-01-22 18:07:48 +08:00
|
|
|
end
|
|
|
|
|
2020-08-31 06:54:42 +08:00
|
|
|
before do
|
|
|
|
@orig = freeze_time
|
|
|
|
user.clear_last_seen_cache!(@orig)
|
|
|
|
end
|
|
|
|
|
2019-01-21 13:29:29 +08:00
|
|
|
after do
|
2020-08-31 06:54:42 +08:00
|
|
|
user.clear_last_seen_cache!(@orig)
|
2019-01-21 13:29:29 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should not update last seen for suspended users" do
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2 = provider("/", "HTTP_COOKIE" => "_t=#{cookie}")
|
2018-07-18 23:04:57 +08:00
|
|
|
u = provider2.current_user
|
|
|
|
u.reload
|
2020-03-11 05:13:17 +08:00
|
|
|
expect(u.last_seen_at).to eq_time(Time.zone.now)
|
2018-07-18 23:04:57 +08:00
|
|
|
|
|
|
|
freeze_time 20.minutes.from_now
|
|
|
|
|
|
|
|
u.last_seen_at = nil
|
|
|
|
u.suspended_till = 1.year.from_now
|
|
|
|
u.save!
|
|
|
|
|
2020-08-31 06:54:42 +08:00
|
|
|
u.clear_last_seen_cache!
|
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2 = provider("/", "HTTP_COOKIE" => "_t=#{cookie}")
|
2018-07-18 23:04:57 +08:00
|
|
|
expect(provider2.current_user).to eq(nil)
|
|
|
|
|
|
|
|
u.reload
|
|
|
|
expect(u.last_seen_at).to eq(nil)
|
|
|
|
end
|
2019-01-22 18:07:48 +08:00
|
|
|
|
|
|
|
describe "when readonly mode is enabled due to postgres" do
|
|
|
|
before do
|
|
|
|
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
|
|
|
end
|
|
|
|
|
2019-01-22 18:21:32 +08:00
|
|
|
after do
|
2019-01-22 18:07:48 +08:00
|
|
|
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
|
|
|
end
|
|
|
|
|
2020-07-21 13:43:28 +08:00
|
|
|
it "should not update User#last_seen_at" do
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2 = provider("/", "HTTP_COOKIE" => "_t=#{cookie}")
|
2019-01-22 18:07:48 +08:00
|
|
|
u = provider2.current_user
|
|
|
|
u.reload
|
|
|
|
expect(u.last_seen_at).to eq(nil)
|
|
|
|
end
|
|
|
|
end
|
2022-07-01 16:18:24 +08:00
|
|
|
|
|
|
|
it "should not cache an invalid user when Rails hasn't set `path_parameters` on the request yet" do
|
|
|
|
SiteSetting.login_required = true
|
|
|
|
user = Fabricate(:user)
|
|
|
|
api_key = ApiKey.create!(user_id: user.id, created_by_id: Discourse.system_user)
|
|
|
|
url = "/latest.rss?api_key=#{api_key.key}&api_username=#{user.username_lower}"
|
|
|
|
env = { ActionDispatch::Http::Parameters::PARAMETERS_KEY => nil }
|
|
|
|
|
|
|
|
provider = provider(url, env)
|
|
|
|
env = provider.env
|
|
|
|
|
|
|
|
expect(env[ActionDispatch::Http::Parameters::PARAMETERS_KEY]).to be_nil
|
|
|
|
expect(provider.env[Auth::DefaultCurrentUserProvider::CURRENT_USER_KEY]).to be_nil
|
|
|
|
|
|
|
|
u = provider.current_user
|
|
|
|
|
|
|
|
expect(u).to eq(user)
|
|
|
|
expect(env[ActionDispatch::Http::Parameters::PARAMETERS_KEY]).to be_blank
|
|
|
|
expect(provider.env[Auth::DefaultCurrentUserProvider::CURRENT_USER_KEY]).to eq(u)
|
|
|
|
end
|
2018-07-18 23:04:57 +08:00
|
|
|
end
|
|
|
|
|
2019-04-16 00:34:34 +08:00
|
|
|
it "should update last seen for non ajax" do
|
|
|
|
expect(provider("/topic/anything/goes", method: "POST").should_update_last_seen?).to eq(true)
|
|
|
|
expect(provider("/topic/anything/goes", method: "GET").should_update_last_seen?).to eq(true)
|
|
|
|
end
|
|
|
|
|
2017-03-01 01:34:57 +08:00
|
|
|
it "should update ajax reqs with discourse visible" do
|
|
|
|
expect(provider("/topic/anything/goes",
|
|
|
|
:method => "POST",
|
|
|
|
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
|
2020-03-26 14:35:32 +08:00
|
|
|
"HTTP_DISCOURSE_PRESENT" => "true"
|
2017-03-01 01:34:57 +08:00
|
|
|
).should_update_last_seen?).to eq(true)
|
|
|
|
end
|
|
|
|
|
2020-03-26 14:35:32 +08:00
|
|
|
it "should not update last seen for ajax calls without Discourse-Present header" do
|
2019-04-16 00:34:34 +08:00
|
|
|
expect(provider("/topic/anything/goes",
|
|
|
|
:method => "POST",
|
|
|
|
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest"
|
|
|
|
).should_update_last_seen?).to eq(false)
|
|
|
|
end
|
|
|
|
|
2020-03-26 14:35:32 +08:00
|
|
|
it "should update last seen for API calls with Discourse-Present header" do
|
2019-11-29 23:16:06 +08:00
|
|
|
api_key = ApiKey.create!(user_id: user.id, created_by_id: -1)
|
2019-04-16 00:34:34 +08:00
|
|
|
params = { :method => "POST",
|
|
|
|
"HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
|
2019-11-29 23:16:06 +08:00
|
|
|
"HTTP_API_KEY" => api_key.key
|
2019-04-16 00:34:34 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
expect(provider("/topic/anything/goes", params).should_update_last_seen?).to eq(false)
|
2020-03-26 14:35:32 +08:00
|
|
|
expect(provider("/topic/anything/goes", params.merge("HTTP_DISCOURSE_PRESENT" => "true")).should_update_last_seen?).to eq(true)
|
2014-05-23 06:13:25 +08:00
|
|
|
end
|
2016-07-25 10:07:31 +08:00
|
|
|
|
2020-09-11 13:11:13 +08:00
|
|
|
it "supports non persistent sessions" do
|
|
|
|
SiteSetting.persistent_sessions = false
|
|
|
|
|
|
|
|
@provider = provider('/')
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
|
|
|
|
|
|
|
cookie_info = get_cookie_info(@provider.cookie_jar, "_t")
|
|
|
|
expect(cookie_info[:expires]).to eq(nil)
|
|
|
|
end
|
2020-09-11 13:11:13 +08:00
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
it "v0 of auth cookie is still acceptable" do
|
|
|
|
token = UserAuthToken.generate!(user_id: user.id).unhashed_auth_token
|
|
|
|
ip = "10.0.0.1"
|
|
|
|
env = { "HTTP_COOKIE" => "_t=#{token}", "REMOTE_ADDR" => ip }
|
|
|
|
expect(provider('/', env).current_user.id).to eq(user.id)
|
2020-09-11 13:11:13 +08:00
|
|
|
end
|
|
|
|
|
2017-02-01 06:21:37 +08:00
|
|
|
it "correctly rotates tokens" do
|
2016-07-25 10:07:31 +08:00
|
|
|
SiteSetting.maximum_session_age = 3
|
2017-02-01 06:21:37 +08:00
|
|
|
@provider = provider('/')
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
2017-02-01 06:21:37 +08:00
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
cookie = @provider.cookie_jar["_t"]
|
|
|
|
unhashed_token = decrypt_auth_cookie(cookie)[:token]
|
2022-05-19 22:58:31 +08:00
|
|
|
cookie = CGI.escape(cookie)
|
2017-02-01 06:21:37 +08:00
|
|
|
|
|
|
|
token = UserAuthToken.find_by(user_id: user.id)
|
|
|
|
|
|
|
|
expect(token.auth_token_seen).to eq(false)
|
|
|
|
expect(token.auth_token).not_to eq(unhashed_token)
|
|
|
|
expect(token.auth_token).to eq(UserAuthToken.hash_token(unhashed_token))
|
|
|
|
|
|
|
|
# at this point we are going to try to rotate token
|
|
|
|
freeze_time 20.minutes.from_now
|
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2 = provider("/", "HTTP_COOKIE" => "_t=#{cookie}")
|
2017-02-01 06:21:37 +08:00
|
|
|
provider2.current_user
|
|
|
|
|
|
|
|
token.reload
|
|
|
|
expect(token.auth_token_seen).to eq(true)
|
2016-07-25 10:07:31 +08:00
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2.refresh_session(user, {}, provider2.cookie_jar)
|
|
|
|
expect(
|
|
|
|
decrypt_auth_cookie(provider2.cookie_jar["_t"])[:token]
|
|
|
|
).not_to eq(unhashed_token)
|
|
|
|
expect(
|
|
|
|
decrypt_auth_cookie(provider2.cookie_jar["_t"])[:token].size
|
|
|
|
).to eq(32)
|
2017-02-01 06:21:37 +08:00
|
|
|
|
|
|
|
token.reload
|
|
|
|
expect(token.auth_token_seen).to eq(false)
|
|
|
|
|
|
|
|
freeze_time 21.minutes.from_now
|
|
|
|
|
|
|
|
old_token = token.prev_auth_token
|
|
|
|
unverified_token = token.auth_token
|
|
|
|
|
|
|
|
# old token should still work
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2 = provider("/", "HTTP_COOKIE" => "_t=#{cookie}")
|
2017-02-01 06:21:37 +08:00
|
|
|
expect(provider2.current_user.id).to eq(user.id)
|
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2.refresh_session(user, {}, provider2.cookie_jar)
|
2017-02-01 06:21:37 +08:00
|
|
|
|
|
|
|
token.reload
|
|
|
|
|
|
|
|
# because this should cause a rotation since we can safely
|
|
|
|
# assume it never reached the client
|
|
|
|
expect(token.prev_auth_token).to eq(old_token)
|
|
|
|
expect(token.auth_token).not_to eq(unverified_token)
|
2016-07-25 10:07:31 +08:00
|
|
|
|
2016-07-26 09:37:41 +08:00
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "events" do
|
2020-04-15 00:32:24 +08:00
|
|
|
before do
|
|
|
|
@refreshes = 0
|
|
|
|
|
|
|
|
@increase_refreshes = -> (user) { @refreshes += 1 }
|
|
|
|
DiscourseEvent.on(:user_session_refreshed, &@increase_refreshes)
|
|
|
|
end
|
|
|
|
|
|
|
|
after do
|
|
|
|
DiscourseEvent.off(:user_session_refreshed, &@increase_refreshes)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "fires event when updating last seen" do
|
|
|
|
@provider = provider('/')
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
|
|
|
cookie = @provider.cookie_jar["_t"]
|
|
|
|
unhashed_token = decrypt_auth_cookie(cookie)[:token]
|
2022-05-19 22:58:31 +08:00
|
|
|
cookie = CGI.escape(cookie)
|
2020-04-15 00:32:24 +08:00
|
|
|
freeze_time 20.minutes.from_now
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2 = provider("/", "HTTP_COOKIE" => "_t=#{cookie}")
|
|
|
|
provider2.refresh_session(user, {}, provider2.cookie_jar)
|
2020-04-15 00:32:24 +08:00
|
|
|
expect(@refreshes).to eq(1)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not fire an event when last seen does not update" do
|
|
|
|
@provider = provider('/')
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
|
|
|
cookie = @provider.cookie_jar["_t"]
|
|
|
|
unhashed_token = decrypt_auth_cookie(cookie)[:token]
|
2022-05-19 22:58:31 +08:00
|
|
|
cookie = CGI.escape(cookie)
|
2020-04-15 00:32:24 +08:00
|
|
|
freeze_time 2.minutes.from_now
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
provider2 = provider("/", "HTTP_COOKIE" => "_t=#{cookie}")
|
|
|
|
provider2.refresh_session(user, {}, provider2.cookie_jar)
|
2020-04-15 00:32:24 +08:00
|
|
|
expect(@refreshes).to eq(0)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "rate limiting" do
|
2017-12-04 18:23:11 +08:00
|
|
|
before do
|
|
|
|
RateLimiter.enable
|
|
|
|
end
|
2016-07-28 10:58:49 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
it "can only try 10 bad cookies a minute" do
|
|
|
|
token = UserAuthToken.generate!(user_id: user.id)
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
cookie = create_auth_cookie(
|
|
|
|
token: token.unhashed_auth_token,
|
|
|
|
user_id: user.id,
|
|
|
|
trust_level: user.trust_level,
|
|
|
|
issued_at: 5.minutes.ago
|
|
|
|
)
|
2016-08-09 08:02:18 +08:00
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
2016-07-28 10:58:49 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
RateLimiter.new(nil, "cookie_auth_10.0.0.1", 10, 60).clear!
|
|
|
|
RateLimiter.new(nil, "cookie_auth_10.0.0.2", 10, 60).clear!
|
2016-08-09 08:02:18 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
ip = "10.0.0.1"
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
bad_cookie = create_auth_cookie(
|
|
|
|
token: SecureRandom.hex,
|
|
|
|
user_id: user.id,
|
|
|
|
trust_level: user.trust_level,
|
|
|
|
issued_at: 5.minutes.ago,
|
|
|
|
)
|
|
|
|
|
|
|
|
env = { "HTTP_COOKIE" => "_t=#{bad_cookie}", "REMOTE_ADDR" => ip }
|
2017-02-01 06:21:37 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
10.times do
|
|
|
|
provider('/', env).current_user
|
|
|
|
end
|
2017-12-04 15:17:18 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
expect {
|
|
|
|
provider('/', env).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
2017-12-04 15:17:18 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
expect {
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
env["HTTP_COOKIE"] = "_t=#{cookie}"
|
2017-12-04 18:23:11 +08:00
|
|
|
provider("/", env).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
|
|
|
|
env["REMOTE_ADDR"] = "10.0.0.2"
|
|
|
|
|
|
|
|
expect {
|
|
|
|
provider('/', env).current_user
|
|
|
|
}.not_to raise_error
|
|
|
|
end
|
2016-07-28 10:58:49 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "correctly removes invalid cookies" do
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
bad_cookie = create_auth_cookie(
|
|
|
|
token: SecureRandom.hex,
|
|
|
|
user_id: 1,
|
|
|
|
trust_level: 4,
|
|
|
|
issued_at: 5.minutes.ago,
|
|
|
|
)
|
|
|
|
@provider = provider('/')
|
|
|
|
@provider.cookie_jar["_t"] = bad_cookie
|
|
|
|
@provider.refresh_session(nil, {}, @provider.cookie_jar)
|
|
|
|
expect(@provider.cookie_jar.key?("_t")).to eq(false)
|
2016-07-28 10:58:49 +08:00
|
|
|
end
|
|
|
|
|
2017-02-01 06:21:37 +08:00
|
|
|
it "logging on user always creates a new token" do
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
|
|
|
@provider2 = provider('/')
|
|
|
|
@provider2.log_on_user(user, {}, @provider2.cookie_jar)
|
2017-02-01 06:21:37 +08:00
|
|
|
|
|
|
|
expect(UserAuthToken.where(user_id: user.id).count).to eq(2)
|
2016-07-25 10:07:31 +08:00
|
|
|
end
|
|
|
|
|
2019-11-27 20:39:31 +08:00
|
|
|
it "cleans up old sessions when a user logs in" do
|
|
|
|
yesterday = 1.day.ago
|
|
|
|
|
|
|
|
UserAuthToken.insert_all((1..(UserAuthToken::MAX_SESSION_COUNT + 2)).to_a.map do |i|
|
|
|
|
{
|
|
|
|
user_id: user.id,
|
|
|
|
created_at: yesterday + i.seconds,
|
|
|
|
updated_at: yesterday + i.seconds,
|
|
|
|
rotated_at: yesterday + i.seconds,
|
|
|
|
prev_auth_token: "abc#{i}",
|
|
|
|
auth_token: "abc#{i}"
|
|
|
|
}
|
|
|
|
end)
|
|
|
|
|
|
|
|
# Check the oldest 3 still exist
|
|
|
|
expect(UserAuthToken.where(auth_token: (1..3).map { |i| "abc#{i}" }).count).to eq(3)
|
|
|
|
|
|
|
|
# On next login, gets fixed
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
2019-11-27 20:39:31 +08:00
|
|
|
expect(UserAuthToken.where(user_id: user.id).count).to eq(UserAuthToken::MAX_SESSION_COUNT)
|
|
|
|
|
|
|
|
# Oldest sessions are 1, 2, 3. They should now be deleted
|
|
|
|
expect(UserAuthToken.where(auth_token: (1..3).map { |i| "abc#{i}" }).count).to eq(0)
|
|
|
|
end
|
|
|
|
|
2017-02-24 01:01:28 +08:00
|
|
|
it "sets secure, same site lax cookies" do
|
|
|
|
SiteSetting.force_https = false
|
|
|
|
SiteSetting.same_site_cookies = "Lax"
|
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
2017-02-24 01:01:28 +08:00
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
cookie_info = get_cookie_info(@provider.cookie_jar, "_t")
|
|
|
|
expect(cookie_info[:samesite]).to eq("Lax")
|
|
|
|
expect(cookie_info[:httponly]).to eq(true)
|
|
|
|
expect(cookie_info.key?(:secure)).to eq(false)
|
2017-02-24 01:01:28 +08:00
|
|
|
|
|
|
|
SiteSetting.force_https = true
|
|
|
|
SiteSetting.same_site_cookies = "Disabled"
|
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
2017-02-24 01:01:28 +08:00
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
cookie_info = get_cookie_info(@provider.cookie_jar, "_t")
|
|
|
|
expect(cookie_info[:secure]).to eq(true)
|
|
|
|
expect(cookie_info.key?(:same_site)).to eq(false)
|
2017-02-24 01:01:28 +08:00
|
|
|
end
|
|
|
|
|
2016-07-25 10:07:31 +08:00
|
|
|
it "correctly expires session" do
|
|
|
|
SiteSetting.maximum_session_age = 2
|
2017-02-01 06:21:37 +08:00
|
|
|
token = UserAuthToken.generate!(user_id: user.id)
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
cookie = create_auth_cookie(
|
|
|
|
token: token.unhashed_auth_token,
|
|
|
|
user_id: user.id,
|
|
|
|
trust_level: user.trust_level,
|
|
|
|
issued_at: 5.minutes.ago
|
|
|
|
)
|
2017-02-01 06:21:37 +08:00
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
2016-07-25 10:07:31 +08:00
|
|
|
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
expect(provider("/", "HTTP_COOKIE" => "_t=#{cookie}").current_user.id).to eq(user.id)
|
2016-07-25 10:07:31 +08:00
|
|
|
|
|
|
|
freeze_time 3.hours.from_now
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
expect(provider("/", "HTTP_COOKIE" => "_t=#{cookie}").current_user).to eq(nil)
|
2016-07-25 10:07:31 +08:00
|
|
|
end
|
2016-08-15 15:58:33 +08:00
|
|
|
|
2018-05-13 23:00:02 +08:00
|
|
|
it "always unstage users" do
|
2020-07-21 13:43:28 +08:00
|
|
|
user.update!(staged: true)
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
@provider = provider("/")
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
2020-07-21 13:43:28 +08:00
|
|
|
user.reload
|
|
|
|
expect(user.staged).to eq(false)
|
2018-05-13 23:00:02 +08:00
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
describe "user api" do
|
2019-05-07 11:12:20 +08:00
|
|
|
fab! :user do
|
2016-08-15 15:58:33 +08:00
|
|
|
Fabricate(:user)
|
|
|
|
end
|
|
|
|
|
|
|
|
let :api_key do
|
|
|
|
UserApiKey.create!(
|
|
|
|
application_name: 'my app',
|
|
|
|
client_id: '1234',
|
2020-09-29 17:57:48 +08:00
|
|
|
scopes: ['read'].map { |name| UserApiKeyScope.new(name: name) },
|
2016-08-15 15:58:33 +08:00
|
|
|
user_id: user.id
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2018-08-22 10:56:49 +08:00
|
|
|
it "can clear old duplicate keys correctly" do
|
|
|
|
dupe = UserApiKey.create!(
|
|
|
|
application_name: 'my app',
|
|
|
|
client_id: '12345',
|
2020-09-29 17:57:48 +08:00
|
|
|
scopes: ['read'].map { |name| UserApiKeyScope.new(name: name) },
|
2018-08-22 10:56:49 +08:00
|
|
|
user_id: user.id
|
|
|
|
)
|
|
|
|
|
|
|
|
params = {
|
|
|
|
"REQUEST_METHOD" => "GET",
|
|
|
|
"HTTP_USER_API_KEY" => api_key.key,
|
|
|
|
"HTTP_USER_API_CLIENT_ID" => dupe.client_id,
|
|
|
|
}
|
|
|
|
|
|
|
|
good_provider = provider("/", params)
|
|
|
|
expect(good_provider.current_user.id).to eq(user.id)
|
|
|
|
expect(UserApiKey.find_by(id: dupe.id)).to eq(nil)
|
|
|
|
end
|
|
|
|
|
2016-08-15 15:58:33 +08:00
|
|
|
it "allows user API access correctly" do
|
|
|
|
params = {
|
|
|
|
"REQUEST_METHOD" => "GET",
|
2016-08-18 12:38:33 +08:00
|
|
|
"HTTP_USER_API_KEY" => api_key.key,
|
2016-08-15 15:58:33 +08:00
|
|
|
}
|
|
|
|
|
2016-12-16 09:05:20 +08:00
|
|
|
good_provider = provider("/", params)
|
|
|
|
|
2020-07-21 13:43:28 +08:00
|
|
|
expect do
|
|
|
|
expect(good_provider.current_user.id).to eq(user.id)
|
|
|
|
end.to change { api_key.reload.last_used_at }
|
|
|
|
|
2016-12-16 09:05:20 +08:00
|
|
|
expect(good_provider.is_api?).to eq(false)
|
|
|
|
expect(good_provider.is_user_api?).to eq(true)
|
2018-10-25 20:38:57 +08:00
|
|
|
expect(good_provider.should_update_last_seen?).to eq(false)
|
2016-08-15 15:58:33 +08:00
|
|
|
|
|
|
|
expect {
|
|
|
|
provider("/", params.merge("REQUEST_METHOD" => "POST")).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
|
|
|
|
2017-02-18 00:02:33 +08:00
|
|
|
user.update_columns(suspended_till: 1.year.from_now)
|
|
|
|
|
|
|
|
expect {
|
|
|
|
provider("/", params).current_user
|
|
|
|
}.to raise_error(Discourse::InvalidAccess)
|
2020-07-21 13:43:28 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
describe "when readonly mode is enabled due to postgres" do
|
|
|
|
before do
|
|
|
|
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
|
|
|
end
|
2017-02-18 00:02:33 +08:00
|
|
|
|
2020-07-21 13:43:28 +08:00
|
|
|
after do
|
|
|
|
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should not update ApiKey#last_used_at' do
|
|
|
|
params = {
|
|
|
|
"REQUEST_METHOD" => "GET",
|
|
|
|
"HTTP_USER_API_KEY" => api_key.key,
|
|
|
|
}
|
|
|
|
|
|
|
|
good_provider = provider("/", params)
|
|
|
|
|
|
|
|
expect do
|
|
|
|
expect(good_provider.current_user.id).to eq(user.id)
|
|
|
|
end.to_not change { api_key.reload.last_used_at }
|
|
|
|
end
|
2016-08-15 15:58:33 +08:00
|
|
|
end
|
|
|
|
|
2022-07-28 00:14:14 +08:00
|
|
|
context "with rate limiting" do
|
2017-12-04 18:23:11 +08:00
|
|
|
before do
|
|
|
|
RateLimiter.enable
|
|
|
|
end
|
2016-08-15 15:58:33 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
it "rate limits api usage" do
|
2021-10-22 00:43:26 +08:00
|
|
|
limiter1 = RateLimiter.new(nil, "user_api_day_#{ApiKey.hash_key(api_key.key)}", 10, 60)
|
|
|
|
limiter2 = RateLimiter.new(nil, "user_api_min_#{ApiKey.hash_key(api_key.key)}", 10, 60)
|
2017-12-04 18:23:11 +08:00
|
|
|
limiter1.clear!
|
|
|
|
limiter2.clear!
|
2016-08-15 15:58:33 +08:00
|
|
|
|
2017-12-11 08:07:22 +08:00
|
|
|
global_setting :max_user_api_reqs_per_day, 3
|
|
|
|
global_setting :max_user_api_reqs_per_minute, 4
|
2016-08-15 15:58:33 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
params = {
|
|
|
|
"REQUEST_METHOD" => "GET",
|
|
|
|
"HTTP_USER_API_KEY" => api_key.key,
|
|
|
|
}
|
2016-08-15 15:58:33 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
3.times do
|
|
|
|
provider("/", params).current_user
|
|
|
|
end
|
2016-08-15 15:58:33 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
expect {
|
|
|
|
provider("/", params).current_user
|
|
|
|
}.to raise_error(RateLimiter::LimitExceeded)
|
2017-12-04 15:17:18 +08:00
|
|
|
|
2017-12-11 08:07:22 +08:00
|
|
|
global_setting :max_user_api_reqs_per_day, 4
|
|
|
|
global_setting :max_user_api_reqs_per_minute, 3
|
2016-08-15 15:58:33 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
limiter1.clear!
|
|
|
|
limiter2.clear!
|
|
|
|
|
|
|
|
3.times do
|
|
|
|
provider("/", params).current_user
|
|
|
|
end
|
2017-12-04 15:17:18 +08:00
|
|
|
|
2017-12-04 18:23:11 +08:00
|
|
|
expect {
|
|
|
|
provider("/", params).current_user
|
|
|
|
}.to raise_error(RateLimiter::LimitExceeded)
|
|
|
|
end
|
2016-08-15 15:58:33 +08:00
|
|
|
end
|
|
|
|
end
|
FEATURE: Apply rate limits per user instead of IP for trusted users (#14706)
Currently, Discourse rate limits all incoming requests by the IP address they
originate from regardless of the user making the request. This can be
frustrating if there are multiple users using Discourse simultaneously while
sharing the same IP address (e.g. employees in an office).
This commit implements a new feature to make Discourse apply rate limits by
user id rather than IP address for users at or higher than the configured trust
level (1 is the default).
For example, let's say a Discourse instance is configured to allow 200 requests
per minute per IP address, and we have 10 users at trust level 4 using
Discourse simultaneously from the same IP address. Before this feature, the 10
users could only make a total of 200 requests per minute before they got rate
limited. But with the new feature, each user is allowed to make 200 requests
per minute because the rate limits are applied on user id rather than the IP
address.
The minimum trust level for applying user-id-based rate limits can be
configured by the `skip_per_ip_rate_limit_trust_level` global setting. The
default is 1, but it can be changed by either adding the
`DISCOURSE_SKIP_PER_IP_RATE_LIMIT_TRUST_LEVEL` environment variable with the
desired value to your `app.yml`, or changing the setting's value in the
`discourse.conf` file.
Requests made with API keys are still rate limited by IP address and the
relevant global settings that control API keys rate limits.
Before this commit, Discourse's auth cookie (`_t`) was simply a 32 characters
string that Discourse used to lookup the current user from the database and the
cookie contained no additional information about the user. However, we had to
change the cookie content in this commit so we could identify the user from the
cookie without making a database query before the rate limits logic and avoid
introducing a bottleneck on busy sites.
Besides the 32 characters auth token, the cookie now includes the user id,
trust level and the cookie's generation date, and we encrypt/sign the cookie to
prevent tampering.
Internal ticket number: t54739.
2021-11-18 04:27:30 +08:00
|
|
|
|
|
|
|
it "ignores a valid auth cookie that has been tampered with" do
|
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
|
|
|
|
|
|
|
cookie = @provider.cookie_jar["_t"]
|
|
|
|
cookie = swap_2_different_characters(cookie)
|
|
|
|
|
|
|
|
ip = "10.0.0.1"
|
|
|
|
env = { "HTTP_COOKIE" => "_t=#{cookie}", "REMOTE_ADDR" => ip }
|
|
|
|
expect(provider('/', env).current_user).to eq(nil)
|
|
|
|
end
|
2022-04-21 02:15:40 +08:00
|
|
|
|
|
|
|
it "copes with json-serialized auth cookies" do
|
|
|
|
# We're switching to :json during the Rails 7 upgrade, but we want a clean revert path
|
|
|
|
# back to Rails 6 if needed
|
|
|
|
|
|
|
|
@provider = provider('/', { # The upcoming default
|
|
|
|
ActionDispatch::Cookies::COOKIES_SERIALIZER => :json,
|
|
|
|
method: "GET",
|
|
|
|
})
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
2022-05-19 22:58:31 +08:00
|
|
|
cookie = CGI.escape(@provider.cookie_jar["_t"])
|
2022-04-21 02:15:40 +08:00
|
|
|
|
|
|
|
ip = "10.0.0.1"
|
|
|
|
env = { "HTTP_COOKIE" => "_t=#{cookie}", "REMOTE_ADDR" => ip }
|
|
|
|
provider2 = provider('/', env)
|
|
|
|
expect(provider2.current_user).to eq(user)
|
|
|
|
expect(provider2.cookie_jar.encrypted["_t"].keys).to include("user_id", "token") # (strings)
|
|
|
|
end
|
2022-07-04 23:01:19 +08:00
|
|
|
|
|
|
|
describe "#log_off_user" do
|
|
|
|
it "should work when the current user was cached by a different provider instance" do
|
|
|
|
user_provider = provider('/')
|
|
|
|
user_provider.log_on_user(user, {}, user_provider.cookie_jar)
|
|
|
|
cookie = CGI.escape(user_provider.cookie_jar["_t"])
|
|
|
|
env = create_request_env(path: "/").merge({ method: "GET", "HTTP_COOKIE" => "_t=#{cookie}" })
|
|
|
|
|
|
|
|
user_provider = TestProvider.new(env)
|
|
|
|
expect(user_provider.current_user).to eq(user)
|
|
|
|
expect(UserAuthToken.find_by(user_id: user.id)).to be_present
|
|
|
|
|
|
|
|
user_provider = TestProvider.new(env)
|
|
|
|
user_provider.log_off_user({}, user_provider.cookie_jar)
|
|
|
|
expect(UserAuthToken.find_by(user_id: user.id)).to be_nil
|
|
|
|
end
|
|
|
|
end
|
2022-10-06 13:16:38 +08:00
|
|
|
|
|
|
|
describe "first admin user" do
|
|
|
|
before do
|
2022-10-06 15:45:19 +08:00
|
|
|
user.update!(admin: false, email: "blah@test.com")
|
|
|
|
Rails.configuration.stubs(:developer_emails).returns(["blah@test.com"])
|
2022-10-06 13:16:38 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "makes the user into an admin if their email is in DISCOURSE_DEVELOPER_EMAILS" do
|
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
|
|
|
expect(user.reload.admin).to eq(true)
|
|
|
|
user2 = Fabricate(:user)
|
|
|
|
@provider.log_on_user(user2, {}, @provider.cookie_jar)
|
|
|
|
expect(user2.reload.admin).to eq(false)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "adds the user to the correct staff/admin auto groups" do
|
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
|
|
|
user.reload
|
|
|
|
expect(user.in_any_groups?([Group::AUTO_GROUPS[:staff]])).to eq(true)
|
|
|
|
expect(user.in_any_groups?([Group::AUTO_GROUPS[:admins]])).to eq(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "runs the job to enable bootstrap mode" do
|
|
|
|
@provider = provider('/')
|
|
|
|
@provider.log_on_user(user, {}, @provider.cookie_jar)
|
|
|
|
expect_job_enqueued(job: :enable_bootstrap_mode, args: { user_id: user.id })
|
|
|
|
end
|
|
|
|
end
|
2014-05-23 06:13:25 +08:00
|
|
|
end
|