98 lines
3.3 KiB
Ruby
98 lines
3.3 KiB
Ruby
require "net/http"
|
|
|
|
class SessionsController < ApplicationController
|
|
skip_before_action :authenticate_user!, only: [ :auth_request, :steam_callback ]
|
|
|
|
def auth_request
|
|
# Build Steam OpenID URL
|
|
steam_openid_url = "https://steamcommunity.com/openid/login"
|
|
# Use the actual request host/protocol for both return_to and realm to avoid signature mismatch
|
|
base_url = request.base_url
|
|
return_url = "#{base_url}#{steam_callback_path}"
|
|
|
|
Rails.logger.info("Steam auth_request return_url=#{return_url} realm=#{base_url}")
|
|
|
|
params = {
|
|
"openid.ns" => "http://specs.openid.net/auth/2.0",
|
|
"openid.identity" => "http://specs.openid.net/auth/2.0/identifier_select",
|
|
"openid.claimed_id" => "http://specs.openid.net/auth/2.0/identifier_select",
|
|
"openid.mode" => "checkid_setup",
|
|
"openid.return_to" => return_url,
|
|
"openid.realm" => base_url,
|
|
"openid.ns.sreg" => "http://openid.net/extensions/sreg/1.1",
|
|
"openid.sreg.required" => "email"
|
|
}
|
|
|
|
redirect_to "#{steam_openid_url}?#{params.to_query}", allow_other_host: true
|
|
end
|
|
|
|
def steam_callback
|
|
# Get the OpenID response
|
|
openid_response = request.params
|
|
|
|
# Verify the response with Steam
|
|
if verify_steam_response(openid_response)
|
|
# Extract Steam ID from identity URL
|
|
# Format: http://steamcommunity.com/openid/id/[STEAMID]
|
|
identity_url = openid_response["openid.identity"]
|
|
|
|
if identity_url && identity_url.include?("/id/")
|
|
steam_id = identity_url.split("/id/").last
|
|
|
|
# Create mock auth_hash for compatibility with our User model
|
|
auth_hash = {
|
|
"uid" => steam_id,
|
|
"info" => {
|
|
"nickname" => "Steam User #{steam_id}"
|
|
}
|
|
}
|
|
|
|
user = User.find_or_create_from_steam(auth_hash)
|
|
session[:user_id] = user.id
|
|
redirect_to dashboard_path, notice: "Logged in successfully!"
|
|
else
|
|
redirect_to root_path, alert: "Could not extract Steam ID from response."
|
|
end
|
|
else
|
|
redirect_to root_path, alert: "Steam authentication failed: Invalid response signature."
|
|
end
|
|
end
|
|
|
|
def logout
|
|
session[:user_id] = nil
|
|
redirect_to root_path, notice: "Logged out successfully!"
|
|
end
|
|
|
|
private
|
|
|
|
def verify_steam_response(response)
|
|
# Steam expects only openid.* keys and mode=check_auth for validation
|
|
openid_params = response.to_h.select { |k, _| k.to_s.start_with?("openid.") }
|
|
return false unless openid_params["openid.mode"] == "id_res"
|
|
|
|
# Per OpenID 2.0 spec, the verification mode is "check_authentication"
|
|
verify_params = openid_params.merge("openid.mode" => "check_authentication")
|
|
|
|
Rails.logger.info("Steam verify payload: #{verify_params.inspect}")
|
|
|
|
uri = URI.parse("https://steamcommunity.com/openid/login")
|
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
http.use_ssl = true
|
|
|
|
request = Net::HTTP::Post.new(uri.path)
|
|
request.set_form_data(verify_params)
|
|
|
|
begin
|
|
response = http.request(request)
|
|
Rails.logger.info("Steam verify response body: #{response.body.inspect}")
|
|
response.body.include?("is_valid:true")
|
|
rescue StandardError => e
|
|
Rails.logger.error("Steam verification error: #{e.message}")
|
|
false
|
|
end
|
|
end
|
|
|
|
def omniauth_failure
|
|
redirect_to root_path, alert: "Steam authentication failed: #{params[:message]}"
|
|
end
|
|
end
|