2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-03-03 23:54:20 +08:00
discourse/spec/requests/discourse_id_controller_spec.rb

157 lines
5.1 KiB
Ruby

# frozen_string_literal: true
RSpec.describe Users::DiscourseIdController do
let(:client_id) { SiteSetting.discourse_id_client_id }
let(:hashed_secret) { Digest::SHA256.hexdigest(SiteSetting.discourse_id_client_secret) }
let(:identifier) { SecureRandom.hex }
let(:provider_name) { "discourse_id" }
let!(:user) { Fabricate(:user) }
let!(:user_associated_account) do
Fabricate(:user_associated_account, user:, provider_name:, provider_uid: identifier)
end
before do
SiteSetting.discourse_id_client_id = SecureRandom.hex
SiteSetting.discourse_id_client_secret = SecureRandom.hex
SiteSetting.enable_discourse_id = true
end
describe "#revoke" do
context "with valid parameters" do
it "revokes all auth tokens for the user" do
UserAuthToken.generate!(user_id: user.id)
UserAuthToken.generate!(user_id: user.id)
expect(UserAuthToken.where(user_id: user.id).count).to eq(2)
timestamp = Time.now.to_i
signature =
OpenSSL::HMAC.hexdigest(
"sha256",
hashed_secret,
"#{client_id}:#{identifier}:#{timestamp}",
)
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(200)
expect(response.parsed_body["success"]).to eq(true)
expect(UserAuthToken.where(user_id: user.id).count).to eq(0)
end
end
context "with invalid parameters" do
it "returns 400 when signature is invalid" do
timestamp = Time.now.to_i
signature = SecureRandom.hex
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(400)
expect(response.parsed_body["error"]).to match(/Signature is invalid/)
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(400)
end
it "returns 400 when timestamp is too old" do
timestamp = Time.now.to_i - 6.minutes.to_i
signature =
OpenSSL::HMAC.hexdigest(
"sha256",
hashed_secret,
"#{client_id}:#{identifier}:#{timestamp}",
)
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(400)
expect(response.parsed_body["error"]).to match(/Timestamp is expired/)
end
it "returns 400 when user_id is not found" do
identifier = "non_existent_user_id"
timestamp = Time.now.to_i
signature =
OpenSSL::HMAC.hexdigest(
"sha256",
hashed_secret,
"#{client_id}:#{identifier}:#{timestamp}",
)
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(400)
expect(response.parsed_body["error"]).to eq("Invalid request")
end
it "returns 400 when client_id or client_secret is blank" do
SiteSetting.discourse_id_client_id = ""
timestamp = Time.now.to_i
signature =
OpenSSL::HMAC.hexdigest(
"sha256",
hashed_secret,
"#{client_id}:#{identifier}:#{timestamp}",
)
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(400)
expect(response.parsed_body["error"]).to eq("Invalid request")
SiteSetting.discourse_id_client_id = SecureRandom.hex
SiteSetting.discourse_id_client_secret = ""
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(400)
expect(response.parsed_body["error"]).to eq("Invalid request")
end
end
context "when login_required is true" do
before { SiteSetting.login_required = true }
it "still allows anonymous revocation requests" do
UserAuthToken.generate!(user_id: user.id)
timestamp = Time.now.to_i
signature =
OpenSSL::HMAC.hexdigest(
"sha256",
hashed_secret,
"#{client_id}:#{identifier}:#{timestamp}",
)
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(200)
expect(response.parsed_body["success"]).to eq(true)
expect(UserAuthToken.where(user_id: user.id).count).to eq(0)
end
end
context "with rate limiting" do
before { RateLimiter.enable }
it "rate limits after 5 requests per minute for the same user_id" do
identifier = "non_existent_user_id"
timestamp = Time.now.to_i
signature = SecureRandom.hex
5.times do
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(400)
end
post "/auth/discourse_id/revoke.json", params: { signature:, identifier:, timestamp: }
expect(response.status).to eq(429)
end
end
end
end