devise_saml_authenticatable + LINE WORKS で SAMLを使ったSSOを実装してみる

こんにちは!kossyです!




さて、今回はdevise_saml_authenticatable + LINE WORKS で SAMLを使ったSSOを実装してみたので、備忘録としてブログに残してみたいと思います。





偉大なる本家レポジトリ

github.com



環境
Ruby 2.6.8
Rails 6.0.4.1
MacOS Catalina


Railsアプリの新規作成

rails newでサンプルアプリを作ります。

$ bundle exec rails new devise_saml_sp -d postgresql -T

$ cd devise_saml_sp

$ bundle exec rails db:create

Gemの導入

deviseとdevise_saml_authenticatableを導入します。

# Gemfile

gem 'devise'
gem 'devise_saml_authenticatable'

その後bundle installを実行します。

$ bundle instal

DeviseのインストールとUserモデルの作成・編集

$ bundle exec rails g devise:install

$ bundle exec rails g devise user

作成されたUserモデルに修正を加えます。

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :saml_authenticatable # saml_authenticatableを追加
end

ビューにフラッシュメッセージを表示するための記述を追記します。

  <body>
    # ここから追加
    <% if flash[:notice] %>
      <div>
        <%= flash[:notice] %>
      </div>
    <% end %>
    <% if flash[:alert] %>
      <div>
        <%= flash[:alert] %>
      </div>
    <% end %>
    # ここまで

    <%= yield %>
  </body>

config/devise.rbにsamlの設定を追加

    config.saml_configure do |settings|
      # assertion_consumer_service_url is required starting with ruby-saml 1.4.3: https://github.com/onelogin/ruby-saml#updating-from-142-to-143
      settings.assertion_consumer_service_url     = "http://localhost:3000/users/saml/auth"
      settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
      settings.protocol_binding                   = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
      settings.name_identifier_format             = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
      settings.issuer                             = "http://localhost:3000/users/saml/metadata"
      settings.authn_context                      = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
      settings.idp_entity_id                      = "https://auth.worksmobile.com/saml2/your_group_name"
      settings.idp_slo_service_url                = "https://auth.worksmobile.com/saml2/idp/your_group_name/logout"
      settings.idp_sso_service_url                = "https://auth.worksmobile.com/saml2/idp/your_group_name"
      settings.idp_cert_fingerprint               = "後ほど設定します"
      settings.idp_cert_fingerprint_algorithm     = XMLSecurity::Document::SHA256
    end

仮のトップページの作成

$ rails g controller home index
# app/views/home/index.html.erb

<% if current_user.present? %>
  <p>ID: <%= current_user.email %></p>
  <p><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></p>
<% else %>
  <p>ログインしてね☆</p>
  <p><%= link_to "メアドとパスワードでログイン", new_user_session_path %></p>
  <p><%= link_to "SAMLでログイン", new_user_sso_session_path %></p>
<% end %>
# config/routes.rb

Rails.application.routes.draw do
  root 'home#index' # 追加

  # 省略
end

config/attribute-map.ymlの作成

SAMLの値とUserモデルの値をマッピングするためのconfigファイルを作成します。

"urn:mace:dir:attribute-def:email": "email"

LINE WORKSにSAML Appsを新規登録

LINE WORKSでSAML2.0によるSSO機能を使うには、有料アカウントで登録する必要があります。(2021年10月時点。ライトプラン・ユーザー一人当たり月額360円)

360円は自己投資だと思うようにしましょう(技術書よりは全然安いし、、、)

line.worksmobile.com

料金表はこちらです。

line.worksmobile.com


まずは無料でアカウントを作成し、その後にライトプランにアップグレードする必要があります。

無事課金し終えてライトプランにアップグレードできましたら、LINE WORKSのデベロッパーコンソールからSSO機能を利用するアプリの登録を行う必要があります。

f:id:kossy-web-engineer:20211017204035p:plain

・Application Nameにはsaml-sp

ACS URLには http://localhost:3000/users/saml/auth

・SP Issuer(Entity ID)には http://localhost:3000/users/saml/metadata

を入力してください。

f:id:kossy-web-engineer:20211113203509p:plain

「次へ」をクリックし、以下の表示が出れば設定成功です。

f:id:kossy-web-engineer:20211016211905p:plain
registered

登録後、以下URLにアクセスすると、

https://developers.worksmobile.com/jp/console/idp/saml/view

f:id:kossy-web-engineer:20211016212325p:plain
SAML Apps

先ほど追加したサービスが表示されていると思いますので、まずは使用状態を「無効」から「有効」に切り替えます。

「変更」をクリックすると、以下のモーダルが表示されますので、ラジオボタンの「有効」をクリックし、「保存」をクリックすると、使用状態を切り替えられます。

f:id:kossy-web-engineer:20211016212543p:plain

次に、「LINE WORKS Identity Provider情報」をクリックすると、SSO URL と Response Issuer の確認と Certificate のダウンロードが行えますので、

SSO URL と Response Issuer は一旦どこかにコピペしておき、 Certificateのダウンロードを行ってください。

f:id:kossy-web-engineer:20211016212856p:plain
Identity_provider_information

ダウンロードしたCertificateを使って、以下コマンドを叩いてフィンガープリントを取得してください。

$ openssl x509 -text -noout -in ~/Downloads/<your file name> -fingerprint -sha256

出力された値はおそらく以下のような感じになるはず。

SHA256 Fingerprint=59:10:LO:D0:9L:31:PO:AM:59:10:LO:D0:9L:31:PO:AM:59:10:LO:D0:9L:31:PO:AM:59:10:LO:D0:9L:31:PO:AM

この出力された値を settings.idp_cert_fingerprint に設定してください。

    config.saml_configure do |settings|
      # assertion_consumer_service_url is required starting with ruby-saml 1.4.3: https://github.com/onelogin/ruby-saml#updating-from-142-to-143
      settings.assertion_consumer_service_url     = "http://localhost:3000/users/saml/auth"
      settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
      settings.protocol_binding                   = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
      settings.name_identifier_format             = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
      settings.issuer                             = "http://localhost:3000/users/saml/metadata"
      settings.authn_context                      = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
      settings.idp_entity_id                      = "https://auth.worksmobile.com/saml2/your_group_name"
      settings.idp_slo_service_url                = "https://auth.worksmobile.com/saml2/idp/your_group_name/logout"
      settings.idp_sso_service_url                = "https://auth.worksmobile.com/saml2/idp/your_group_name"
      settings.idp_cert_fingerprint               = "59:10:LO:D0:9L:31:PO:AM:59:10:LO:D0:9L:31:PO:AM:59:10:LO:D0:9L:31:PO:AM:59:10:LO:D0:9L:31:PO:AM"
      settings.idp_cert_fingerprint_algorithm     = XMLSecurity::Document::SHA256
    end

これで準備完了です。

動作確認

まず、Userモデルにレコードを追加します。この時、LINE WORKSのIDと同じ値をemailに設定する必要があります。

$ rails c

$ User.create!(email: "your_line_works_id@your_group_name", password: "1234test")

f:id:kossy-web-engineer:20211113204255p:plain

その後、トップページの「SAMLでログイン」のリンクを踏んでください。諸々の設定が正しければLINE WORKSのログイン画面に遷移します。

f:id:kossy-web-engineer:20211113204458p:plain

IDとPASSWORDを入力してログインを押すと、自分のアプリにリダイレクトされます。

f:id:kossy-web-engineer:20211113205016p:plain

ログアウトボタンを押すと正常にログアウトできます。

メールアドレスとパスワードでのログインも試してみましょう。

正しいメールアドレスとパスワードであればフラッシュメッセージと共にトップページにリダイレクトされるはずです。

f:id:kossy-web-engineer:20211113205257p:plain

ログインした状態で /users/saml/sign_in にアクセスすると以下の表示になります。

f:id:kossy-web-engineer:20211113205422p:plain

既にログイン済みである旨のフラッシュメッセージが表示されました。

まとめ

メールアドレス + パスワードでのログインとSAMLによるSSOを共存させることを比較的簡単に行えました。

本来はUserモデルに紐づく形でSAMLの設定を保存するモデルを追加するのが筋だと思いますが、今回は「まずは動かす」ところに重点を置いてみました。

近いうちにコードもGem内部のコードも読んでみようと思います。


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

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

devise_saml_authenticatable/README.md at master · apokalipto/devise_saml_authenticatable · GitHub
翻訳:Ruby on RailsでDevise・SAML認証(LINE WORKS) - Qiita