翻訳：Ruby on RailsでDevise・SAML認証（LINE WORKS)

# はじめに

Thank you very much, Rawat. I appreciated that you allow me to share your post in Japanese. I’m sure this should come in useful for developers. 
この記事は、Alok Rawat氏による「[Devise and SAML Authentication with Ruby On Rails(Line Works)](https://qiita.com/alokrawat050/items/98a40c414d06a6e679ca)」という投稿の日本語訳になります。ご本人より日本語への翻訳とその文書の掲載について許可をいただきました。
この記事は、Ruby On Railsのアプリケーションの認証をLINE WORKSで行うための実装方法を紹介しています。

実は私自身は英語は得意ではなくRubyも書いたことがないのですが、、この記事を是非LINE WORKS Developersに紹介したいという思いから書いています。自作のアプリケーションの認証をLINE WORKSで行ってみたいという方は是非試してみてください！
訳に間違いや改善点があればご指摘頂ければ幸いですm(_ _)m

以下、翻訳文となります。

# 認証と認可（LINE WORKS)

![Screen Shot 2018-02-07 at 23.22.32.png](https://qiita-image-store.s3.amazonaws.com/0/117479/c63bccb0-594f-88cd-1b43-1849f57e9fa3.png)

**■SAMLとは何か？**
Security Assertion Markup Language (SAML)は、サービスプロバイダー（以後、SP）とアイデンティティプロバイダー（以後、Idp）の2つのエンティティ間で認証と認可を行うためのXMLベースのフレームワークです。SPは、ユーザーを認証するIdpを信頼し同意します。引き換えに、Idpはユーザーが認証済みであることを示す認証アサーションを生成します。

SAMLは標準のシングルサインオン（SSO）形式です。認証情報は、デジタル署名されたXML文書を通して交換されます。複雑なシングルサインオン（以後、SSO）設定は、主にビジネスとエンタープライズの間でシームレスな認証を有効にするのです。
SAMLでは、認証資格情報の入力やパスワードをリセットすることを心配する必要がなくなります。

**■SAML認証のメリットは何か？**
以下が、SAML認証のメリットとなります。

**● 標準化:** SAMLは、設定に依存せず、複数のシステム間でシームレスな相互運用ができる標準フォーマットです。ベンダー、プラットフォーム特有のアーキテクチャ、実装に関係する共通の問題等から解放されます。

**● ユーザーエクスペリエンスの改善:** ユーザーはたった１回のログインのみで、追加認証なしに複数のSPにアクセスすることができ、各SPでのエクスペリエンスもとても早く良くなります。これでパスワードのリセットや復元といった問題は無くなります。

**● セキュリティ強化:** セキュリティはソフトウェア開発のキーとなる部分であり、エンタープライズのアプリケーションでは非常に重要になります。SAMLは安全なIdpでシングルポイントでの認証を実施します。そしてSAMLは資格情報をSPへ送ります。この認証方式は、資格情報はFW内から出ないことを保証しています。

**● ディレクトリの疎結合:** SAMLはユーザー情報の管理やディレクトリ間での同期を必要としません。

**● SPのコスト削減:** SAMLを使うと、複数のサービスのアカウント情報をメンテする必要がありません。Idpがこの責任を担います。

**■なぜ組織はSAMLを使うのか？**
全ての種類の組織はインフラ、サービス、データをクラウドに移行するとき、SAMLは、拡大するプラットフォーム基盤、デジタル接点、端末を通してユーザーを認証・認可する安全な方法を提供します。顧客のWebアプリケーションへより簡単にアクセスすることによって、SAMLはより堅牢性の高いシステムを実現します。

SAMLは、Idp（ユーザー資格情報を保持する）とSP（サービスプロバイダー）との間でIdpファイアーウォール内で行われるトークンベースの認証交換を有効化することによって、複数のWebアプリケーションパスワードを排除します。”SP-initiated” SAMLトランザクションでは、ユーザーがアプリケーションに対しアクセスを要求した時、SPは自動的にIdpへリダイレクトし、ユーザーは個人情報をSPのシステムへ入力することなく認証されます。

SAMLは、シングルサインオン（SSO）の機能性の有効化により、キーチャレンジを解決します：登録やログインすることをユーザーに許可し、一定時間有効な認証情報のシングルセットで複数のプロパティを通して認可されます。SAMLはシングルサインアウトするという機能もあり、1つのサイトからユーザーがサインアウトする時に、自動的に会社が所有している全ての他のSPからログアウトさせられます。

**■SAML認証はどのように動作するか?**
SAML SSOは1つの場所（Idp）からもう一方の場所（SP）へユーザー識別情報を渡すことによって動作します。これは、デジタルに署名されたXML文書を交換を通して行われます。


例えば、ユーザーがあるIdpとして動作するシステムにログインしているとします。そのユーザーはSmart-Flowアプリケーション（SP）のようなリモートアプリケーションへログインしたい。この場合、下記のようになります：

● ユーザーは[Smart Flowのアプリ](https://smartflow.vebuin.com)へアクセスします。
● アプリケーションは、そのユーザーの身元（アプリケーションサブドメイン、ユーザーIPアドレス等から）を特定し、Idpへリダイレクトし、認証のため問い合わせを行います。これは認証リクエストとなります。
● ユーザーは既にあるIdpの有効なブラウザーのセッションを保持するか、Idpへログインしセッションを確立します。
● Idpはユーザーのユーザー名やメールアドレスを含んだXML文書の形の認証レスポンスを生成します。
● 既にIdpを知っていてフィンガープリント証明書を持っているSPは、認証情報を復元しフィンガープリント証明書を使って妥当性を検証します。
● ユーザーの識別情報が生成され、アプリへのアクセスが可能となります。

**■SAML SSO フロー**
![SAMLflow.png](https://qiita-image-store.s3.amazonaws.com/0/135983/e7c77e6f-8a68-e583-f09f-c5687010835e.png)

**■SAML vs OAuth:**
OAuthは2006年からGoogleとTwitterによって共同で開発されたSAMLより新しい標準規格です。SAMLのモバイルプラットフォーム上の欠点を補うために部分的に開発されたものであり、またXMLというよりもむしろJSONに基づいています。

SAMLのいまいちなモバイルサポート以外で、この2つにはどういった違いがあるのでしょうか？見て頂いた通り、SAML標準は、どのように認証と認可の両方を提供できるかを定義しています。一方でOAuthは認可のみ扱っています。

**■何をする必要があるか?**
SAML機能をあなたのRailsアプリに実装するためには、Idpが必要です。現在、私はLINE WORKSとoktaがあります。
これはLINE WORKSの例です。
もし、LINE WORKSのアカウントを持っていない場合は、Oktaでも同様に行うことができます。

> https://www.okta.com/
> http://blog.cloud66.com/adding-sso-to-your-rails-application-with-saml/

Devise gemについて知っていて、あなたのアプリに実装したことがあると思います。
もし、まだ実装したことがない場合は、以下のリンクを参照してください。
> https://qiita.com/alokrawat050/items/5267e6ab0e274ad1188a
> https://medium.com/@alokrawat050/devise-gem-tutorial-authenticate-a-user-by-user-id-and-email-ruby-on-rails-e25ae60ca437

**■SAMLの設定をやってみましょう**
まず最初に、DeviseでSAMLを実装します。

**1)** Devise SAML 認証用の GemをGemfileに追加します。

```rb
gem 'devise_saml_authenticatable'
```

> 参照： https://github.com/apokalipto/devise_saml_authenticatable

**2)** saml_authenticatableをユーザーモデルファイル user.rbへ追加します。

```rb
class User < ApplicationRecord
  devise :saml_authenticatable, :database_authenticatable, :registerable,
        :recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]

  attr_accessor :login

  def login=(login)
   @login = login
  end

  def login
   @login || self.user_id || self.email
  end

  def self.find_for_database_authentication(warden_conditions)
   conditions = warden_conditions.dup
   if login = conditions.delete(:login)
     where(conditions.to_h).where(["user_id = :value OR email = :value", { :value => login.downcase }]).first
   else
     where(conditions.to_h).first
   end
  end

  def send_devise_notification(notification, *args)
   devise_mailer.send(notification, self, *args).deliver_later
  end
end
```

何故、attr_accessor :loginを使うのでしょうか？
それは、ユーザーはemailと同じuser_idでログインできるからです。しかし、もし必要がなければ無視してください。アプリケーションで必ずしも使う必要はありません。

**3)** 以下をconfig/initializers/devise.rbファイルに追加します：

```rb
Devise.setup do |config|
……
……

Devise.setup do |config| 
     config.saml_create_user = false
     config.saml_update_user = true
     config.saml_default_user_key = :email
     config.saml_session_index_key = :session_index
     config.saml_use_subject = true
     config.idp_settings_adapter = nil
     config.saml_configure do |settings|
       settings.assertion_consumer_service_url     = "<your url>/users/saml/auth"
     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                             = "<your url>/users/saml/metadata"
     settings.authn_context                      = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
     settings.idp_slo_target_url                 = ""
    
     #line configuration
     settings.idp_sso_target_url                 = "<your SSO auth url>"
     settings.idp_cert_fingerprint               = '<your fingerprint of the certificate>'
     settings.idp_cert_fingerprint_algorithm     = 'http://www.w3.org/2000/09/xmldsig#sha256'
     end
   end
end
```

以下のように設定を変更する必要があります：

`<your url>: http://localhost:3000`  #開発用にlocalhostを指定していますが、開発環境によって設定してください。
`<your SSO auth url>`: #Step 4.2を参照してください

`<your fingerprint of the certificate>` フィンガープリントをどのように生成するかはStep8を参照してください

**routes.rb**ファイルは下記のようになります。

```rb
Rails.application.routes.draw do
  root 'home#index' 
  devise_for :users, skip: :saml_authenticatable, controllers: {
   registrations: "user/registrations",
   sessions: "user/sessions",
   passwords: "user/passwords"
  }

  # opt-in saml_authenticatable
  devise_scope :user do
   scope "users", controller: 'saml_sessions' do
     get :new, path: "saml/sign_in", as: :new_user_sso_session
     post :create, path: "saml/auth", as: :user_sso_session
     get :destroy, path: "sign_out", as: :destroy_user_sso_session
     get :metadata, path: "saml/metadata", as: :metadata_user_sso_session
     match :idp_sign_out, path: "saml/idp_sign_out", via: [:get, :post]
   end
  end
end
```

**4)** LINE WORKSのアカウントを持っている必要があります。
https://developers.worksmobile.com/
Developer Consoleをクリックします。以下がセットアップ手順です。

**4.1** LINE WORKSのDeveloper Consoleへのログインが成功したら、[Apps]-[SAML Apps]へいきます。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/117479/f6f07468-b9d7-e824-b398-5c35d8e2a193.png)

**4.2** アプリを作成します、追加するボタンをクリックし、以下のように設定を行い、次へのボタンをクリックします。
**[Application情報]欄**

```
・Application Name:
・Description:
```

**[Service Provider情報]欄**

```
・ACS URL: http://localhost:3000/users/saml/auth
・SP issuer(Entity Id): http://localhost:3000/users/saml/metadata
```
![2.png](https://qiita-image-store.s3.amazonaws.com/0/117479/1eac6ccb-b70d-c516-527c-0bc74df6c8fb.png)

**4.3 アプリケーションを有効化します。[変更]ボタンをクリックし、「有効」を選択します。

- 1
![3.png](https://qiita-image-store.s3.amazonaws.com/0/117479/ec9d022f-7899-e20b-8cfc-76d6809ed289.png)

- 2
![4.png](https://qiita-image-store.s3.amazonaws.com/0/117479/5d186e93-8438-616d-3886-609247c17ea8.png)

- 3
![5.png](https://qiita-image-store.s3.amazonaws.com/0/117479/bebb1975-1cdb-682c-c008-7370cbfc845f.png)


**5)** もし開発環境で動かしている場合は、例えば、
http://localhost:3000
(私は、Railsのデフォルトのポート番号3000を使っていますが、環境に合わせて変更してください）となります。
本番環境の場合は、httpsを使っているか確認し、アプリやサーバーをセットアップします。

**6)** SSO URL（Idpのシングルサインオン用のURL）をコピーし、**devise.rb**の**idp_sso_target_url**のところに値を貼り付けてください。

**7)** [Certificate]欄の[ダウンロード]ボタンをクリックし、証明書を保存します。
![6.png](https://qiita-image-store.s3.amazonaws.com/0/117479/521610ca-39fe-b5b8-645f-df3054d9dd4e.png)

**8)** 以下のコマンドを実行し証明書のフィンガープリントを取得します。

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

`これで~/Downloads/<ファイル名>に証明書が保存されたと思います。`
SHA256 Fingerprint=と書かれている最後の行をコピーします。コピーした値を、devise.rbファイルの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`

**9)** アプリの構成ディレクトリで、attribute-map.ymlと呼ばれるファイルを作成し、以下の内容を追記します。

```yaml
   "urn:mace:dir:attribute-def:uid": “login”
   "urn:mace:dir:attribute-def:email": "email"
```

ここでは、Devise SAMLに対し、IdpからUserモデルのどの属性値を何の属性値にマッピングして返すか、を記述しています。

**10)**. テストする準備ができました、**/users/saml/sign_in**へアクセスするとLINE WORKSのログインページへリダイレクトされ、認証後にあなたのアプリに戻ってきます。

以上です！👏👏👏👏

貴重な時間を使って読んでくださりありがとうございます。

コーディングを楽しみましょう！:grinning: :grinning:

**Thanks & Best Regards,
Alok Rawat**