環境
- 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 環境(ホスト環境)
手順
- 「Windows Server 2022 Standard」の評価版をダウンロードして、ホスト環境にインストールする(ホスト環境のスペック次第だが、少なくとも2CPU、RAM 8G 以上にするのがよい。以下同じ)。ホスト名を「dc1」とする。
- 「Windows 10 Enterprise」の評価版をダウンロードして、ホスト環境にインストールする。ホスト名を「client1」とする。
- 「dc1」上にActiveDirecotry環境を構築する。サーバマネージャで役割として「ActiveDirectoryドメインサービス」を追加した後、ドメインコントローラに昇格させる。新規フォレストを「home.example.jp」とする。同一ネットワーク内に委任可能なDNSはないため、DNSもインストールされる。
- 「client1」のDNSに「dc1.home.example.jp」のIPアドレスを設定する。今回はドメインには参加させたが、参加させなくてもよいかもしれない。
参考
- Windows Server 2022 - Microsoft Evaluation Center
- Windows 10 Enterprise - Microsoft Evaluation Center
- 【仮想環境】評価版 Windows Server 2022 のインストール【番外編】 – たまテク
- Windows Server 2022でActive Directoryを構築する (新規ドメイン) - ITなんでも屋さん
その2:Rails 環境構築
Rails の開発環境を構築する。CランタイムがUCRTでなくMSVCRTであるRubyの最新版を使う。
前提
- 上記で構築したWindows 10 Enterprise 評価版「client1」
手順
- ブラウザで github の「winget-cli」のサイトに行く。
- 右側の「Releases」の「Latest」の「Windows Package Manager...」を選択する。
- 一番下の「Assets」からファイル名末尾が「.msixbundle」のファイルをダウンロードしてインストールする。
- 管理者権限でPowerShellを起動して、wingetの動作確認後、Ruby3.0環境を構築する1。
winget winget install git.git winget install RubyInstallerTeam.RubyWithDevKit.3.0 winget install sqlite.sqlite winget install microsoft.visualstudiocode
- ソースに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]
- 環境変数反映のため、新しくPowerShellを起動する。gemの実行を確認後、Railsをバージョンを確認してインストールする。ここで想定しているのは Rails 7.0系なので、最新版が7.0系でない場合は、バージョンを指定する。ドキュメントはインストールしない。
gem gem search \Arails\z -a gem install rails -N rails
- 「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
- ブラウザで「http://localhost:3000」 にアクセスし、CRUDの挙動を確認する。
参考
- GitHub - microsoft-winget-cli- Windows Package Manager CLI (aka winget)
- winget を用いて,Windows での主要なソフトウェアのインストールと設定(winget を使用)(Windows 上)
- Getting Started with Rails — Ruby on Rails Guides
- Rails をはじめよう - Railsガイド
その3:Devise による認証機能の追加
ここは先人の記録に感謝。参考にあげたサイトを参照しなければ、実現できたとは思えない。
前提
- 上記で構築したRailsアプリ「blog」
手順
- Gem のインストール
Gemfile
gem 'devise' gem 'devise_ldap_authenticatable'
bundle install
- 設定ファイルの初期化、ユーザーモデルの作成と修正
ここではモデル名として「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
- 認証設定
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
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
- ログイン用の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>
- ルーティング修正、確認
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
- 記事の更新操作はログインユーザーのみに設定
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]
- ログアウトのリンクをレイアウトに追加。ログインしているときのみ有効。
layout.html.erbなど
<%= link_to_if user_signed_in?, "Logout", destroy_user_session_path, method: :delete %>
- サーバを起動して、新規作成、更新、削除時には、ログインが要求されること、ログイン情報の入力で編集画面に遷移できることを確認
rails s
参考
- GitHub - cschiewek-devise_ldap_authenticatable- Devise Module for LDAP
- devise+ActiveDirectory(LDAP)認証 - JunkBoxWiki
- devise で ActiveDirectory 認証 - Qiita
- [Rails]No route matches [GET] --users-sign_out”の対処法 - Qiita
その4:認証を組み込んだテスト
手順
- テスト用dbの作成
rails db:migate RAILS_ENV=test
- テストを実行してみる。Scaffoldで作成されていたテストがあり、エラーになる。test開始時にロードされるuserのfixtureがユニークでないため。ユーザー情報はfixtureからロードしないので、削除。
rails t
test/fixture/user.yml を修正-one: {} -two: {}
- テストを再度実行してみる。認証を必要と設定した、new, edit, update, create が失敗する。
rails t
- ヘルパーを追加した上で、認証を必要とする操作のまえにログインするようにテストを修正する。なお「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
- テストを再度実行する。failuresとerrorsがゼロになっていることを確認する。
rails t
参考
補足:設定する認証情報の確認方法
ドメインコントローラ上で確認
- 「Active Directory ユーザーとコンピュータ」を起動
- メニューの表示から「拡張機能」を有効にする
- オブジェクトのプロパティを表示すると、タブに「属性エディタ―」があり、「distinguishedName」、「sAMAccountName」等が確認できる
ドメインに参加した Windows 10上で PowerShellで確認
- 設定 -> オプション機能 -> 機能の追加、から「RSAT: Active Directory Domain Services 及びライトウェイトディレクトリサービスツール」をインストールする
- PowerShellで、
Import-Module ActiryDirecotry
した後、Get-ADUser
が使えるようになる。「DistinguishedName」、「SamAccountName」等が確認できる。
参考
- 【Active Directory】様々な属性を表示・編集できる「属性エディター」タブを表示する - なべりうむ
- リモート サーバー管理ツール - Windows Server - Microsoft Learn
-
PowerShellが文字化けする場合は、英文フォントに強制変更されているためなので、ウィンドウ枠の右クリックプロパティから、フォントを「MSゴシック」等に変更する。 ↩