0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Rails 7 on Windows で devise を用いた ActiveDirectory 認証のテスト

Last updated at Posted at 2023-05-17

環境

  • Windows Server 2022 Standard
  • Windows 10 Pro
  • Ruby 3.0.4[x64-migw32]
  • Rails 7.0.4.3
  • Devise 4.9.2
  • Devise_ldap_authenticatable 0.8.7

その1:ActiveDirectoryドメイン構築

前提

  • Windows 10 Pro(22H2)上の Hyper-V 環境(ホスト環境)

手順

  1. 「Windows Server 2022 Standard」の評価版をダウンロードして、ホスト環境にインストールする(ホスト環境のスペック次第だが、少なくとも2CPU、RAM 8G 以上にするのがよい。以下同じ)。ホスト名を「dc1」とする。
  2. 「Windows 10 Enterprise」の評価版をダウンロードして、ホスト環境にインストールする。ホスト名を「client1」とする。
  3. 「dc1」上にActiveDirecotry環境を構築する。サーバマネージャで役割として「ActiveDirectoryドメインサービス」を追加した後、ドメインコントローラに昇格させる。新規フォレストを「home.example.jp」とする。同一ネットワーク内に委任可能なDNSはないため、DNSもインストールされる。
  4. 「client1」のDNSに「dc1.home.example.jp」のIPアドレスを設定する。今回はドメインには参加させたが、参加させなくてもよいかもしれない。

参考

その2:Rails 環境構築

Rails の開発環境を構築する。CランタイムがUCRTでなくMSVCRTであるRubyの最新版を使う。

前提

  • 上記で構築したWindows 10 Enterprise 評価版「client1」

手順

  1. ブラウザで github の「winget-cli」のサイトに行く。
  2. 右側の「Releases」の「Latest」の「Windows Package Manager...」を選択する。
  3. 一番下の「Assets」からファイル名末尾が「.msixbundle」のファイルをダウンロードしてインストールする。
  4. 管理者権限でPowerShellを起動して、wingetの動作確認後、Ruby3.0環境を構築する1
    winget
    winget install git.git
    winget install RubyInstallerTeam.RubyWithDevKit.3.0
    winget install sqlite.sqlite
    winget install microsoft.visualstudiocode
    
  5. ソースにCを含むgemをコンパイルできるように「MSYS2」「MINGW」をセットアップする。管理者権限でコマンドプロンプトを起動してridk installを実行する。デフォルトの[1,3]の選択のまま、Enterでインストールを実行する。
    C:\Windows\system32>ridk install
     _____       _           _____           _        _ _         ___
    |  __ \     | |         |_   _|         | |      | | |       |__ \
    | |__) |   _| |__  _   _  | |  _ __  ___| |_ __ _| | | ___ _ __ ) |
    |  _  / | | | '_ \| | | | | | | '_ \/ __| __/ _` | | |/ _ \ '__/ /
    | | \ \ |_| | |_) | |_| |_| |_| | | \__ \ || (_| | | |  __/ | / /_
    |_|  \_\__,_|_.__/ \__, |_____|_| |_|___/\__\__,_|_|_|\___|_||____|
                        __/ |           _
                       |___/          _|_ _  __   | | o __  _| _     _
                                       | (_) |    |^| | | |(_|(_)\^/_>
    
       1 - MSYS2 base installation
       2 - MSYS2 system update (optional)
       3 - MSYS2 and MINGW development toolchain
    
    Which components shall be installed? If unsure press ENTER [1,3]
    
  6. 環境変数反映のため、新しくPowerShellを起動する。gemの実行を確認後、Railsをバージョンを確認してインストールする。ここで想定しているのは Rails 7.0系なので、最新版が7.0系でない場合は、バージョンを指定する。ドキュメントはインストールしない。
    gem
    gem search \Arails\z -a
    gem install rails -N
    rails
    
  7. 「Railsをはじめよう」のチュートリアル「blog」の2つめのモデル追加前まで作成したアプリを作成して、起動する。直接関係しないが、Visual Studio では、$home\source\repos がデフォルトのソース置き場になるので、それに倣う。Railsは、minimalオプションで最小構成にする。
    cd $home
    mkdir source\repos
    cd source\repos
    rails new blog --minimal
    cd blog
    rails g scaffold Article title:string body:text
    rails db:migrate
    (Get-Content .\config\routes.rb)|%{$_ -replace '# root','root'}|Set-Content .\config\routes.rb
    'Article.create(title: "Hello Rails", body: "I am on Rails!")'|Add-Content .\db\seeds.rb
    rails db:seed
    rails s
    
  8. ブラウザで「http://localhost:3000」 にアクセスし、CRUDの挙動を確認する。

参考

その3:Devise による認証機能の追加

ここは先人の記録に感謝。参考にあげたサイトを参照しなければ、実現できたとは思えない。

前提

  • 上記で構築したRailsアプリ「blog」

手順

  1. Gem のインストール
    Gemfile
    gem 'devise'
    gem 'devise_ldap_authenticatable'
    
    bundle install
    
  2. 設定ファイルの初期化、ユーザーモデルの作成と修正
    ここではモデル名として「User」を指定している。
    rails g devise:install
    rails g devise User
    rails g devise_ldap_authenticatable:install
    
    app/model/user.rb を修正、有効にする機能だけを残す
    class User < ApplicationRecord
      # Include default devise modules. Others available are:
      # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
    -  devise :ldap_authenticatable, :registerable,
    -         :recoverable, :rememberable, :validatable
    +   devise :ldap_authenticatable, :rememberable, :trackable
    end
    
    db/migrate/yyyyMMddhhmmss_devise_create_users.rb を修正、デフォルトが emailログインなので修正する
    class DeviseCreateUsers < ActiveRecord::Migration[7.0]
      def change
        create_table :users do |t|
    +     ## LDAP authenticatable
    +     t.string :login, null: false, default: "", unique: true
          ## Database authenticatable
    -      t.string :email,              null: false, default: ""
    -      t.string :encrypted_password, null: false, default: ""
    
          ## Recoverable
    -      t.string   :reset_password_token
    -      t.datetime :reset_password_sent_at
    
          ## Rememberable
          t.datetime :remember_created_at
    
          ## Trackable
    -      # t.integer  :sign_in_count, default: 0, null: false
    +      t.integer  :sign_in_count, default: 0, null: false
    -      # t.datetime :current_sign_in_at
    +      t.datetime :current_sign_in_at
    -      # t.datetime :last_sign_in_at
    +      t.datetime :last_sign_in_at
    -      # t.string   :current_sign_in_ip
    +      t.string   :current_sign_in_ip
    -      # t.string   :last_sign_in_ip
    +      t.string   :last_sign_in_ip
    
          t.timestamps null: false
        end
    
    +    add_index :users, :login,                unique: true
    -    add_index :users, :email,                unique: true
    -    add_index :users, :reset_password_token, unique: true
        # add_index :users, :confirmation_token,   unique: true
        # add_index :users, :unlock_token,         unique: true
      end
    end
    
    マイグレーション
    rails db:migrate
    
  3. 認証設定
    config/initializers/devise.rb を修正(修正箇所を抜粋。使用したバージョンではログアウト処理でエラーになるので、HTTPメソッドを修正)
    # ==> LDAP Configuration
    # config.ldap_logger = true
    -# config.ldap_create_user = false
    +config.ldap_create_user = true
    -# config.ldap_update_password = true
    +config.ldap_update_password = false
    # config.ldap_config = "#{Rails.root}/config/ldap.yml"
    # config.ldap_check_group_membership = false
    # config.ldap_check_group_membership_without_admin = false
    # config.ldap_check_attributes = false
    # config.ldap_check_attributes_presence = false
    -# config.ldap_use_admin_to_bind = false
    +config.ldap_use_admin_to_bind = true
    # config.ldap_ad_group_check = false
    
    -# config.authentication_keys = [:email]
    +config.authentication_keys = [:login]
    
    # The default HTTP method used to sign out a resource. Default is :delete.
    -config.sign_out_via = :delete
    +config.sign_out_via = :get
    
    sAMAccountName は ユーザーログオン名(Windows2000より前)。base は補足の方法での確認を推奨。admin_user はLDAPアクセス用のドメインユーザーを作成して使用する。ドメイン管理者「Administrator」だとうまくいかないかも?
    config/ldap.yml を修正
    development:
    -  host: localhost
    +  host: dc1.home.example.jp
      port: 389
    -  attribute: cn
    +  attribute: sAMAccountName
    -  base: ou=people,dc=test,dc=com
    +  base: CN=Users,DC=home,DC=example,DC=jp
    -  admin_user: cn=admin,dc=test,dc=com
    +  admin_user: "user_for_ldap"
    -  admin_password: admin_password
    +  admin_password: "user_for_ldap_password"
      ssl: false
      # <<: *AUTHORIZATIONS
    
  4. ログイン用のviewを作成
    rails g devise:views
    
    app/views/devise/session/new.html.erb を修正
    <div class="field">
    -  <%= f.label :email %><br />
    +  <%= f.label :login %><br />
    -  <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
    +  <%= f.text_field :login, autofocus: true %>
    </div>
    
    <div class="field">
      <%= f.label :password %><br />
    -  <%= f.password_field :password, autocomplete: "current-password" %>
    +  <%= f.password_field :password, autocomplete: "off" %>
    </div>
    
  5. ルーティング修正、確認
    config/routes.rb を修正
    Rails.application.routes.draw do
    -  devise_for :users
    +  devise_for :users, only:[:sessions]
      resources :articles
      # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
    
      # Defines the root path route ("/")
      root "articles#index"
    end
    
    ルーティング確認、/users で始まるURIは、new_user_session, user_session, destroy_user_session のみ
    rails routes
    
  6. 記事の更新操作はログインユーザーのみに設定
    app/conftollers/article_controller.rb を修正
    class ArticlesController < ApplicationController
      before_action :set_article, only: %i[ show edit update destroy ]
    +  before_action :authenticate_user!, only: %i[new create edit update destory]
    
  7. ログアウトのリンクをレイアウトに追加。ログインしているときのみ有効。
    layout.html.erbなど
    <%= link_to_if user_signed_in?, "Logout", destroy_user_session_path, method: :delete %>
    
  8. サーバを起動して、新規作成、更新、削除時には、ログインが要求されること、ログイン情報の入力で編集画面に遷移できることを確認
    rails s
    

参考

その4:認証を組み込んだテスト

手順

  1. テスト用dbの作成
    rails db:migate RAILS_ENV=test
    
  2. テストを実行してみる。Scaffoldで作成されていたテストがあり、エラーになる。test開始時にロードされるuserのfixtureがユニークでないため。ユーザー情報はfixtureからロードしないので、削除。
    rails t
    
    test/fixture/user.yml を修正
    -one: {}
    -two: {}
    
  3. テストを再度実行してみる。認証を必要と設定した、new, edit, update, create が失敗する。
    rails t
    
  4. ヘルパーを追加した上で、認証を必要とする操作のまえにログインするようにテストを修正する。なお「sign_in」しても、認証サーバにログイン要求が飛ぶのではなく、Devise上でログイン済みの扱いにしているだけの模様。
    test/controllers/articles_controller_test.rb を修正
    class ArticlesControllerTest < ActionDispatch::IntegrationTest
    +  include Devise::Test::IntegrationHelpers    
      setup do
        @article = articles(:one)
    +    @user = User.create(login:'alice', password:'inwonderland')
      end
    
      test "should get index" do
        get articles_url
        assert_response :success
      end
    
      test "should get new" do
    +   sign_in @user
        get new_article_url
        assert_response :success
    +   sign_out @user
      end
    
      test "should create article" do
    +   sign_in @user
        assert_difference("Article.count") do
          post articles_url, params: { article: { body: @article.body, title: @article.title } }
        end
    +   sign_out @user
    
        assert_redirected_to article_url(Article.last)
      end
    
      test "should show article" do
        get article_url(@article)
        assert_response :success
      end
    
      test "should get edit" do
    +   sign_in @user
        get edit_article_url(@article)
        assert_response :success
    +   sign_out @user
      end
    
      test "should update article" do
    +   sign_in @user
        patch article_url(@article), params: { article: { body: @article.body, title: @article.title } }
        assert_redirected_to article_url(@article)
    +   sign_out @user
      end
    
      test "should destroy article" do
    +   sign_in @user
        assert_difference("Article.count", -1) do
          delete article_url(@article)
        end
    +   sign_out @user
    
        assert_redirected_to articles_url
      end
    end
    
  5. テストを再度実行する。failuresとerrorsがゼロになっていることを確認する。
    rails t
    

参考

補足:設定する認証情報の確認方法

ドメインコントローラ上で確認

  1. 「Active Directory ユーザーとコンピュータ」を起動
  2. メニューの表示から「拡張機能」を有効にする
  3. オブジェクトのプロパティを表示すると、タブに「属性エディタ―」があり、「distinguishedName」、「sAMAccountName」等が確認できる

ドメインに参加した Windows 10上で PowerShellで確認

  1. 設定 -> オプション機能 -> 機能の追加、から「RSAT: Active Directory Domain Services 及びライトウェイトディレクトリサービスツール」をインストールする
  2. PowerShellで、Import-Module ActiryDirecotry した後、Get-ADUserが使えるようになる。「DistinguishedName」、「SamAccountName」等が確認できる。

参考

  1. PowerShellが文字化けする場合は、英文フォントに強制変更されているためなので、ウィンドウ枠の右クリックプロパティから、フォントを「MSゴシック」等に変更する。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?