diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index 21e8259db..e252ec6b3 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -20,7 +20,11 @@ class SessionController < ApplicationController end if SiteSetting.enable_sso? - redirect_to DiscourseSingleSignOn.generate_url(return_path) + sso = DiscourseSingleSignOn.generate_sso(return_path) + if SiteSetting.verbose_sso_logging + Rails.logger.warn("Verbose SSO log: Started SSO process\n\n#{sso.diagnostics}") + end + redirect_to sso.to_url else render nothing: true, status: 404 end @@ -69,10 +73,16 @@ class SessionController < ApplicationController sso = DiscourseSingleSignOn.parse(request.query_string) if !sso.nonce_valid? + if SiteSetting.verbose_sso_logging + Rails.logger.warn("Verbose SSO log: Nonce has already expired\n\n#{sso.diagnostics}") + end return render(text: I18n.t("sso.timeout_expired"), status: 419) end if ScreenedIpAddress.should_block?(request.remote_ip) + if SiteSetting.verbose_sso_logging + Rails.logger.warn("Verbose SSO log: IP address is blocked #{request.remote_ip}\n\n#{sso.diagnostics}") + end return render(text: I18n.t("sso.unknown_error"), status: 500) end @@ -95,6 +105,9 @@ class SessionController < ApplicationController session["user_created_message"] = activation.message redirect_to users_account_created_path and return else + if SiteSetting.verbose_sso_logging + Rails.logger.warn("Verbose SSO log: User was logged on #{user.username}\n\n#{sso.diagnostics}") + end log_on_user user end @@ -115,14 +128,9 @@ class SessionController < ApplicationController rescue ActiveRecord::RecordInvalid => e render text: I18n.t("sso.unknown_error"), status: 500 rescue => e - details = {} - SingleSignOn::ACCESSORS.each do |a| - details[a] = sso.send(a) - end - message = "Failed to create or lookup user: #{e}." message << "\n\n" << "-" * 100 << "\n\n" - message << details.map { |k,v| "#{k}: #{v}" }.join("\n") + message << sso.diagnostics message << "\n\n" << "-" * 100 << "\n\n" message << e.backtrace.join("\n") diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index ba03249bd..deffc3396 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -10,12 +10,16 @@ class DiscourseSingleSignOn < SingleSignOn SiteSetting.sso_secret end - def self.generate_url(return_path="/") + def self.generate_sso(return_path="/") sso = new sso.nonce = SecureRandom.hex sso.register_nonce(return_path) sso.return_sso_url = Discourse.base_url + "/session/sso_login" - sso.to_url + sso + end + + def self.generate_url(return_path="/") + generate_sso(return_path).to_url end def register_nonce(return_path) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 8cde59cb7..b07da3cf1 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -943,6 +943,7 @@ en: block_common_passwords: "Don't allow passwords that are in the 10,000 most common passwords." enable_sso: "Enable single sign on via an external site (WARNING: USERS' EMAIL ADDRESSES *MUST* BE VALIDATED BY THE EXTERNAL SITE!)" + verbose_sso_logging: "Log verbose SSO related diagnostics to /logs" enable_sso_provider: "Implement Discourse SSO provider protocol at the /session/sso_provider endpoint, requires sso_secret to be set" sso_url: "URL of single sign on endpoint (must include http:// or https://)" sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer" diff --git a/config/site_settings.yml b/config/site_settings.yml index f3fb12829..772b96beb 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -266,6 +266,7 @@ login: client: true default: false enable_sso_provider: false + verbose_sso_logging: true sso_url: default: '' regex: '^https?:\/\/.+[^\/]$' diff --git a/lib/single_sign_on.rb b/lib/single_sign_on.rb index e2d566a7c..b35142502 100644 --- a/lib/single_sign_on.rb +++ b/lib/single_sign_on.rb @@ -55,6 +55,12 @@ class SingleSignOn sso end + def diagnostics + SingleSignOn::ACCESSORS.map do |a| + "#{a}: #{sso.send(a)}" + end.join("\n") + end + def sso_secret @sso_secret || self.class.sso_secret end