DEV: Move logic for rate limiting user second factor to one place (#11941)

This moves all the rate limiting for user second factor (based on `params[:second_factor_token]` existing) to the one place, which rate limits by IP and also by username if a user is found.
This commit is contained in:
Martin Brennan
2021-02-04 09:03:30 +10:00
committed by GitHub
parent 61f5d501cb
commit e58f9f7a55
7 changed files with 132 additions and 25 deletions

View File

@@ -1735,11 +1735,12 @@ RSpec.describe SessionController do
RateLimiter.enable
RateLimiter.clear_all!
3.times do |x|
6.times do |x|
post "/session.json", params: {
login: "#{user.username}#{x}",
password: 'myawesomepassword',
second_factor_token: '000000'
second_factor_token: '000000',
second_factor_method: UserSecondFactor.methods[:totp]
}
expect(response.status).to eq(200)
end
@@ -1747,7 +1748,8 @@ RSpec.describe SessionController do
post "/session.json", params: {
login: user.username,
password: 'myawesomepassword',
second_factor_token: '000000'
second_factor_token: '000000',
second_factor_method: UserSecondFactor.methods[:totp]
}
expect(response.status).to eq(429)
@@ -1759,11 +1761,12 @@ RSpec.describe SessionController do
RateLimiter.enable
RateLimiter.clear_all!
3.times do |x|
6.times do |x|
post "/session.json", params: {
login: user.username,
password: 'myawesomepassword',
second_factor_token: '000000'
second_factor_token: '000000',
second_factor_method: UserSecondFactor.methods[:totp]
}, env: { "REMOTE_ADDR": "1.2.3.#{x}" }
expect(response.status).to eq(200)
@@ -1773,7 +1776,8 @@ RSpec.describe SessionController do
post "/session.json", params: {
login: username,
password: 'myawesomepassword',
second_factor_token: '000000'
second_factor_token: '000000',
second_factor_method: UserSecondFactor.methods[:totp]
}, env: { "REMOTE_ADDR": "1.2.4.#{x}" }
expect(response.status).to eq(429)

View File

@@ -323,7 +323,6 @@ describe UsersController do
end
context "rate limiting" do
before { RateLimiter.clear_all!; RateLimiter.enable }
after { RateLimiter.disable }
@@ -332,7 +331,7 @@ describe UsersController do
token = user.email_tokens.create!(email: user.email).token
3.times do
6.times do
put "/u/password-reset/#{token}", params: {
second_factor_token: 123456,
second_factor_method: 1
@@ -349,6 +348,27 @@ describe UsersController do
expect(response.status).to eq(429)
end
it "rate limits reset passwords by username" do
freeze_time
token = user.email_tokens.create!(email: user.email).token
6.times do |x|
put "/u/password-reset/#{token}", params: {
second_factor_token: 123456,
second_factor_method: 1
}, env: { "REMOTE_ADDR": "1.2.3.#{x}" }
expect(response.status).to eq(200)
end
put "/u/password-reset/#{token}", params: {
second_factor_token: 123456,
second_factor_method: 1
}, env: { "REMOTE_ADDR": "1.2.3.4" }
expect(response.status).to eq(429)
end
end
context '2 factor authentication required' do
@@ -3997,6 +4017,36 @@ describe UsersController do
expect(user.user_second_factors.count).to eq(1)
end
it "rate limits by IP address" do
RateLimiter.enable
RateLimiter.clear_all!
create_totp
staged_totp_key = read_secure_session["staged-totp-#{user.id}"]
token = ROTP::TOTP.new(staged_totp_key).now
7.times do |x|
post "/users/enable_second_factor_totp.json", params: { name: "test", second_factor_token: token }
end
expect(response.status).to eq(429)
end
it "rate limits by username" do
RateLimiter.enable
RateLimiter.clear_all!
create_totp
staged_totp_key = read_secure_session["staged-totp-#{user.id}"]
token = ROTP::TOTP.new(staged_totp_key).now
7.times do |x|
post "/users/enable_second_factor_totp.json", params: { name: "test", second_factor_token: token }, env: { "REMOTE_ADDR": "1.2.3.#{x}" }
end
expect(response.status).to eq(429)
end
context "when an incorrect token is provided" do
before do
create_totp

View File

@@ -131,6 +131,57 @@ describe UsersEmailController do
user.reload
expect(user.email).to eq("new.n.cool@example.com")
end
context "rate limiting" do
before { RateLimiter.clear_all!; RateLimiter.enable }
after { RateLimiter.disable }
it "rate limits by IP" do
freeze_time
6.times do
put "/u/confirm-new-email", params: {
token: "blah",
second_factor_token: "000000",
second_factor_method: UserSecondFactor.methods[:totp]
}
expect(response.status).to eq(302)
end
put "/u/confirm-new-email", params: {
token: "blah",
second_factor_token: "000000",
second_factor_method: UserSecondFactor.methods[:totp]
}
expect(response.status).to eq(429)
end
it "rate limits by username" do
freeze_time
6.times do |x|
user.email_change_requests.last.update(change_state: EmailChangeRequest.states[:complete])
put "/u/confirm-new-email", params: {
token: user.email_tokens.last.token,
second_factor_token: "000000",
second_factor_method: UserSecondFactor.methods[:totp]
}, env: { "REMOTE_ADDR": "1.2.3.#{x}" }
expect(response.status).to eq(302)
end
user.email_change_requests.last.update(change_state: EmailChangeRequest.states[:authorizing_new])
put "/u/confirm-new-email", params: {
token: user.email_tokens.last.token,
second_factor_token: "000000",
second_factor_method: UserSecondFactor.methods[:totp]
}, env: { "REMOTE_ADDR": "1.2.3.4" }
expect(response.status).to eq(429)
end
end
end
context "security key required" do