2015年9月23日 星期三

[RoR]使用者登入與LDAP認証

devise在Ruby on Rails是使用率很高的使用者登入管理的gem,網路上相關的devise使用教學很多,本文就不在贅述,而是把重點放在用來做LDAP認証的devise_ldap_authenticatable上。兩者互相搭配透過AD來完成Single Sign On的功能。本文主要是參考devise+LDAP認証 完成的心得。



系統實作

在Gamfile中新增後,在Command line執行bundle install
gem 'devise'
gem 'devise_ldap_authenticatable'
安裝devise
rails g devise:install
rails g devise User
rails g devise_ldap_authenticatable:install
修改app/models/user.rb,刪除devise安裝時給的預設值:registerable、:recoverable、:validatable

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :ldap_authenticatable, :rememberable, :trackable
end
修改db/migrate/YYYYMMDDhhmmss_devise_create_users.rb,新增login欄位,並把預設將建立的email、encrypted_password、reset_password_token、reset_password_sent_at刪除或註解,與email、reset_password_token的add_index刪除或是註解。存檔後執行rake db:migrate建立DB Object。
class DeviseCreateUsers < ActiveRecord::Migration
  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.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      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
修改config/initializers/devise.rb設定檔,使devise啟用LDAP認証

  config.ldap_logger = true
  config.ldap_create_user = true   #預設false表示要先建立user才可以用ldap認証,true則是只要是AD帳號皆可連線
  config.ldap_update_password = false  #預設true表示當密碼改變時會反寫AD中的密碼,但此設定需要再yml中註冊有足夠權限的帳號 
  config.ldap_use_admin_to_bind = true #預設false表示允許匿名登入LDAP Server,但公司AD目前不允許匿名登入
  config.authentication_keys = [ :login ] 
編輯LDAP連線資訊config/ldap.yml,其中的attribute預設是cn,但必須改成sAMAccountName(AD帳號名),另外由於AD不接受匿名登入,所以必須填入帳號/密碼,另外base跟admin_user的架構可以直接參考AD的屬性資料來填寫會比較正確。
development:
  host: 10.40.10.1
  port: 389
  attribute: sAMAccountName
  base: ou=user,ou=mail,dc=example,dc=com,dc=tw
  admin_user: cn=Administrator,cn=Users,dc=example,dc=com,dc=tw
  admin_password: [admin password]
  ssl: false
產生devise views

rails g devise:views
修改app/views/devise/session/new.html.haml,把原預設的email欄位刪除,新增login輸入欄位

Sign in

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.label :login %> <%= f.text_field :login, autofocus: true %>
<%= f.label :password %> <%= f.password_field :password, autocomplete: "off" %>
<% if devise_mapping.rememberable? -%>
<%= f.check_box :remember_me %> <%= f.label :remember_me %>
<% end -%>
<%= f.submit "Sign in" %>
<% end %> <%= render "devise/shared/links" %>
修改/config/routes.rb,使單一帳號無法被重複登入使用
devise_for :users, only: [:sessions]
執行rake routes來確認路由是否正確








讓所有的頁面都需要身份認証,修改/app/controllers/application_controller.rb
before_action :authenticate_user!
在適當處增加登出的連結
<%= link_to "登出", destroy_user_session_path, method: :delete, :class => 'navbar-link'  %>

實作成果

從Server Log中可以看出有成功從AD Server把相關屬性資料抓出,首次登入系統時會做兩件事,分別是寫入Users跟更新Users相關使用者資訊與統計資訊。





沒有留言: