ruby-samlで「Invalid settings, idp_sso_service_url is not set!」が発生した場合の対処法

こんにちは!kossyです!




今回はSSOを実現するGem「ruby-saml」で「Invalid settings, idp_sso_service_url is not set!」が発生した場合の対処法について、

備忘録としてブログに残してみたいと思います。





環境
Ruby 2.6.8
Rails 6.0.4
MacOS BigSur
ruby-saml 1.13.0



エラーの発生箇所のコードリーディング

まずはどこで例外が投げられているのか、binding.pryで処理を止めて、

pry-byebug Gemを入れると使用できるstepコマンドを使いながら確認してみます。

class SamlController < ApplicationController
  skip_before_action :verify_authenticity_token, :only => [:acs, :logout]

  # 省略

  def sso
    settings = Account.get_saml_settings(get_url_base)
    if settings.nil?
      render :action => :no_settings
      return
    end

    request = OneLogin::RubySaml::Authrequest.new

    binding.pry
    redirect_to(request.create(settings))
  end

  # 省略
end

localhost:3000/saml/sso にアクセスすると、処理が止まります。

From: /app/app/controllers/saml_controller.rb:18 SamlController#sso:

     8: def sso
     9:   settings = Account.get_saml_settings(get_url_base)
    10:   if settings.nil?
    11:     render :action => :no_settings
    12:     return
    13:   end
    14:
    15:   request = OneLogin::RubySaml::Authrequest.new
    16:
    17:   binding.pry
 => 18:   redirect_to(request.create(settings))
    19: end

この状態でstepコマンドでcreateメソッドの処理を見に行ってみます。

From: /usr/local/bundle/gems/ruby-saml-1.13.0/lib/onelogin/ruby-saml/authrequest.rb:37 OneLogin::RubySaml::Authrequest#create:

    36: def create(settings, params = {})
 => 37:   params = create_params(settings, params)
    38:   params_prefix = (settings.idp_sso_service_url =~ /\?/) ? '&' : '?'
    39:   saml_request = CGI.escape(params.delete("SAMLRequest"))
    40:   request_params = "#{params_prefix}SAMLRequest=#{saml_request}"
    41:   params.each_pair do |key, value|
    42:     request_params << "&#{key.to_s}=#{CGI.escape(value.to_s)}"
    43:   end
    44:   raise SettingError.new "Invalid settings, idp_sso_service_url is not set!" if settings.idp_sso_service_url.nil? or settings.idp_sso_service_url.empty?
    45:   @login_url = settings.idp_sso_service_url + request_params
    46: end

44行目が今回の例外をraiseしているところですね。

$  settings.idp_sso_service_url.nil? or settings.idp_sso_service_url.empty?
=> true

true が返りました。 タイトルの例外が生じた原因は、settingsオブジェクトのidp_sso_service_url属性がnilまたは空だったからですね。

idp_sso_service_urlはsettingsオブジェクトのメソッドになっていました。

github.com

      # @return [String] IdP Single Sign On Service URL
      #
      def idp_sso_service_url
        @idp_sso_service_url || @idp_sso_target_url
      end

idp_sso_service_url属性がDBに保存されているか、はたまたconfig値を引っ張ってきているかは各々のアプリケーション次第かと思いますが、

settingsオブジェクトの生成時に、idp_sso_service_url属性に値が必ず入るようにすればOKそうですね。


まとめ

ruby-samlのReadMe通りに実装してテストしているときにはあまり遭遇しないかもしれませんが、

DBから値を引っ張ってくるような構成の場合は、きちんと制約をかけてあげていないと、ハマってしまうかもしれませんね。

github.com


大いに参考にさせていただいたサイト

素晴らしいコンテンツの提供、誠にありがとうございます。

ruby-saml/README.md at master · onelogin/ruby-saml · GitHub