2
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-03-03 23:54:20 +08:00
discourse/spec/support/discourse_connect_support_helpers.rb
David Taylor e0dc8fefbb
DEV: Improvements to DiscourseConnect spec helpers (#35173)
- Rename SSO -> DiscourseConnect. SSO is the general term for all
external login methods. DiscourseConnect is the name for this protocol
- Allocate different IP for each parallel spec environment, so they
don't clash. This will resolve some flaky specs we're seeing
- Only bind to localhost. No need to make this available from other
machines
2025-10-03 14:53:56 +01:00

73 lines
1.9 KiB
Ruby

# frozen_string_literal: true
require "webrick"
module DiscourseConnectHelpers
def self.provider_port=(port)
@provider_port = port
end
def self.provider_port
@provider_port
end
def build_discourse_connect_payload(return_url)
secret = SiteSetting.discourse_connect_provider_secrets.split("|")[1]
nonce = SecureRandom.hex
payload = "nonce=#{CGI.escape(nonce)}&return_sso_url=#{CGI.escape(return_url)}"
sso = Base64.strict_encode64(payload)
sig = OpenSSL::HMAC.hexdigest("sha256", secret, sso)
[sso, sig]
end
def setup_test_discourse_connect_server(user:, sso_secret:)
raise "Provider port not set" unless DiscourseConnectHelpers.provider_port
before_next_spec { shutdown_test_discourse_connect_server }
@server =
WEBrick::HTTPServer.new(
Port: DiscourseConnectHelpers.provider_port,
Logger: WEBrick::Log.new(File.open(File::NULL, "w")),
AccessLog: [],
BindAddress: "localhost",
)
@server.mount_proc "/sso" do |req, res|
decoded = Base64.decode64(req.query["sso"])
params = Rack::Utils.parse_query(decoded)
response_sso = DiscourseConnectBase.new
response_sso.nonce = params["nonce"]
response_sso.sso_secret = sso_secret
response_sso.external_id = "foo-bar"
response_sso.email = user.email
response_sso.username = user.username
res.status = 302
res["Location"] = "#{params["return_sso_url"]}?#{response_sso.payload}"
end
@server_thread = Thread.new { @server.start }
until server_responding?("http://localhost:#{DiscourseConnectHelpers.provider_port}/sso")
sleep 0.1
end
DiscourseConnectHelpers.provider_port
end
def shutdown_test_discourse_connect_server
@server&.shutdown
@server_thread&.kill
end
def server_responding?(sso_url)
Net::HTTP.get_response(URI(sso_url))
true
rescue StandardError
false
end
end