devise_ldap_authenticatable でグループ制限したい人生だった (Rails 4)
とあるアプリ (でLDAP認証を実現するために、 cschiewek/devise_ldap_authenticatable · GitHub を使っていて幸せに暮らしていたけど、ある日突然○○グループのみ認証を通したくなったので、設定ファイルをいじったら簡単にできるやろって思ったらできなかったので、ちょこっと頑張ったお話。
devise_ldap_authenticatable でグループ認証したい人向けのお話です
先に結論から
で完了
gemのバージョンたち
net-ldap (0.5.1)
devise (3.1.1)
devise_ldap_authenticatable (0.8.1) # 現時点で rubygems 的に最新のgemのバージョン
モンキーパッチを当てる
config/initializers/devise_ldap_authenticatable_customizer.rb
module DeviseLdapAuthenticatableCustomizer
begin
class Railtie < ::Rails::Railtie
config.after_initialize do
Devise::LDAP::Connection.class_eval do
def initialize(params = {})
ldap_config = YAML.load(ERB.new(File.read(::Devise.ldap_config || "#{Rails.root}/config/ldap.yml")).result)[Rails.env]
ldap_options = params
ldap_config["ssl"] = :simple_tls if ldap_config["ssl"] === true
ldap_options[:encryption] = ldap_config["ssl"].to_sym if ldap_config["ssl"]
@ldap = Net::LDAP.new(ldap_options)
@ldap.host = ldap_config["host"]
@ldap.port = ldap_config["port"]
@ldap.base = ldap_config["base"]
@attribute = ldap_config["attribute"]
@ldap_auth_username_builder = params[:ldap_auth_username_builder]
@group_base = ldap_config["group_base"]
@check_group_membership = ldap_config.has_key?("check_group_membership") ? ldap_config["check_group_membership"] : ::Devise.ldap_check_group_membership
# この行を追加
@check_group_membership_without_admin = ldap_config.has_key?("check_group_membership_without_admin") ? ldap_config["check_group_membership_without_admin"] : ::Devise.ldap_check_group_membership_without_admin
@required_groups = ldap_config["required_groups"]
@required_attributes = ldap_config["require_attribute"]
@ldap.auth ldap_config["admin_user"], ldap_config["admin_password"] if params[:admin]
@login = params[:login]
@password = params[:password]
@new_password = params[:new_password]
end
def in_group?(group_name, group_attribute = LDAP::DEFAULT_GROUP_UNIQUE_MEMBER_LIST_KEY)
in_group = false
if @check_group_membership_without_admin
group_checking_ldap = @ldap
else
group_checking_ldap = Connection.admin
end
unless ::Devise.ldap_ad_group_check
group_checking_ldap.search(:base => group_name, :scope => Net::LDAP::SearchScope_BaseObject) do |entry|
#元のコード
#if entry[group_attribute].include? dn
if entry[group_attribute].include? dn.gsub(/uid=([^,]+),.*$/,'\1')
in_group = true
DeviseLdapAuthenticatable::Logger.send("User #{dn} IS included in group: #{group_name}")
end
end
else
# AD optimization - extension will recursively check sub-groups with one query
# "(memberof:1.2.840.113556.1.4.1941:=group_name)"
search_result = group_checking_ldap.search(:base => dn,
:filter => Net::LDAP::Filter.ex("memberof:1.2.840.113556.1.4.1941", group_name),
:scope => Net::LDAP::SearchScope_BaseObject)
# Will return the user entry if belongs to group otherwise nothing
if search_result.length == 1 && search_result[0].dn.eql?(dn)
in_group = true
DeviseLdapAuthenticatable::Logger.send("User #{dn} IS included in group: #{group_name}")
end
end
unless in_group
DeviseLdapAuthenticatable::Logger.send("User #{dn} is not in group: #{group_name}")
end
return in_group
end
end
end
end
rescue Exception(err_msg)
puts (" --- error => #{err_msg} --- ")
end
end
LDAP設定ファイル
config/ldap.yml グループとかLDAPのホストとかは適宜変えてください
## Authorizations
# Uncomment out the merging for each environment that you'd like to include.
# You can also just copy and paste the tree (do not include the "authorizations") to each
# environment if you need something different per enviornment.
authorizations: &AUTHORIZATIONS
group_base: ou=groups,dc=test,dc=com
## Requires config.ldap_check_group_membership in devise.rb be true
# Can have multiple values, must match all to be authorized
required_groups:
# If only a group name is given, membership will be checked against "uniqueMember"
- cn=admins,ou=groups,dc=test,dc=com
- cn=users,ou=groups,dc=test,dc=com
# If an array is given, the first element will be the attribute to check against, the second the group name
- ["moreMembers", "cn=users,ou=groups,dc=test,dc=com"]
## Requires config.ldap_check_attributes in devise.rb to be true
## Can have multiple attributes and values, must match all to be authorized
require_attribute:
objectClass: inetOrgPerson
authorizationRole: postsAdmin
## Environment
development:
host: ldap.network.kani.dc
port: 389
attribute: uid
base: ou=users,dc=kani,dc=co,dc=jp
ssl: false
group_base: ou=groups,dc=kani,dc=co,dc=jp
check_group_membership: true
check_group_membership_without_admin: true
required_groups:
- ["memberuid", "cn=hogegroup,ou=groups,dc=kani,dc=co,dc=jp"]
test:
host: ldap.network.kani.dc
port: 389
attribute: uid
base: ou=users,dc=kani,dc=co,dc=jp
ssl: false
production:
host: ldap.network.kani.dc
port: 389
attribute: uid
base: ou=users,dc=kani,dc=co,dc=jp
ssl: false
group_base: ou=groups,dc=kani,dc=co,dc=jp
check_group_membership: true
check_group_membership_without_admin: true
required_groups:
- ["memberuid", "cn=hogegroup,ou=groups,dc=kani,dc=co,dc=jp"]
解説
LDAP認証の流れ
- 個人アカウントでLDAP認証してオブジェクト取得
- そのオブジェクトを使ってグループ認証
ざっくりこんな感じ
2 を行う際、ldap.yml に check_group_membership_without_admin がないと、グループ認証する際に、入力されたユーザーではなく admin のアカウントとパスワードでバインドしてしまうので、invalid bind みたいな怒られ方をします。
そんな設定なかった
で、config に書くんですが、rubygemsから落とせる最新版 (0.8.1) にはその設定がなく、githubのmasterブランチ (0.8.3) にはありました。
ただ、認証系のgemをmasterから取ってくるのはイヤだったので、0.8.1にモンキーパッチを当てることにしました。
ポイントは2か所
Devise::LDAP::Connection の initialize で ldap.yml の設定を読んでいたので、check_group_membership_without_admin を読ませる
グループに属しているかチェックしている in_group? メソッドで、uid で認証して欲しかったので、正規表現で切り取って認証
手を加えたのは Devise::LDAP::Connection の中の2行だけ
これでグループ認証があなたのもとへ、やったね!
カニでもわかるWindows 7新規インストール
windows機のHDDが突然お亡くなりになったので、新規HDDにwindows DSP版を入れて若干四苦八苦したところをメモる。
環境
マシン
ThinkPad Edge E420
HDD
壊れたHDD
ST9750420AS
http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=6324326
調べたら非AFTらしい。
AFTってなんじゃい
このへんを見ました。
http://www.pc-master.jp/jisaku/aft-hdd.html
なる、ほ、ど。。。
わからんが、AFTのものを買った方が良さそう。それに合わせてwindows7 SP1 適応済みにしたほうがよさげ
新しく買ったHDD
WD7500BPVX
http://shop.tsukumo.co.jp/goods/4515479660908/
これはちょっと調べるのに苦労したけど、AFTっぽい
OS
Microsoft Windows7 Home Premium 64bit Service Pack 1 日本語 DSP版 DVD LCP 【紙パッケージ版】
http://www.amazon.co.jp/gp/product/B00HSC9E78/ref=oh_details_o00_s00_i00?ie=UTF8&psc=1
なんかよくわかんないけど、一番安そうなやつ買いました
インストール
インストール自体は何の問題もなく、ディスクを入れて電源を入れたら勝手にインストール画面になったので、キーボードとか色々設定をポチポチしていくだけ
ここからが本当の地獄だ...
さてとりあえず chrome 入れるかと思って IE 立ち上げたらネットつながんねーわ
ディスプレイも外部ディスプレイ検出しねーわ
Bluetooth ヘッドセットも接続できねーわ etc...
なんか色々できない!
デバイスドライバを見ると、とりあえずネットワークアダプターねーじゃんよ
まずはインターネットから
ぐぐってたらレノボのサポートサイトから必要なデバイスドライバーを入れてみることに
http://support.lenovo.com/ja_JP/research/hints-or-tips/detail.page?DocID=HT037710
幸いメインPCはMacさんなのでそっちからネットワークドライバーさんを落として、USBメモリからwin機に入れたらインターネットできました、素敵!!
ディスプレイ
ディスプレイもドライバー入れたら検出してくれました
最後の難関 Bluetooth ヘッドセット
これはほぼ自分用
MW600 を使ってるんですが、PCと接続しようとするとデバイス認証するところまではできた。
でも接続はできない
なぜだ
ぐぐったり、製品のQ&Aを見に行ったりして悶絶してたら、電源ボタン+電話マークのボタン (何て言うんだこれ) 同時長押しで何かがリセットされたっぽくて、接続できるようになりました。
というわけで、ちょっと悶絶しましたが無事 windows 使えるようになりました
カニでもわかるRails 3 (nginx + unicorn) 開発環境構築
今まで Rails 1系だけ触った事があったのですが、Rails 3系をやる機会があったので、開発環境構築手順をまとめました。
手順として、
という感じでいきます。
rvm インストール
ちなみにサーバーは Debian (squeeze) です。
今回は開発環境なので、自分だけ使う前提で自分のアカウントでrvmをインストールします。
curl -L get.rvm.io | bash -s stable
# パスを通す
source ~/.rvm/scripts/rvm
# ruby インストール
rvm install 1.9.3
# gemset 作成
rvm gemset create kanipan_rails
# kanipan_rails gemset を使う
rvm gemset use kanipan_rails
gemset use してgem installすると、
/home/kanipan/.rvm/gems/ruby-(version)@(gemset名)/gems/
以下にgemが入ります。
Rails インストール
今回は最新版 (3.2) をインストールします。
gem install rails
#バージョン確認
rails -v
Rails 3.2.11
# rails プロジェクト作成 databaseをmysqlに指定
rails new kanipan_project --database=mysql
unicornのインストールと設定
vim Gemfile
Gemfileに以下を追加
gem 'unicorn'
Gemfile保存後、
bundle install
# unicornの設定ファイル作成
vim config/unicorn.rb
サンプルとして
listen "/tmp/unicorn.sock" pid "/tmp/unicorn.pid" worker_processes 1 preload_app true if ENV['RAILS_ENV'] == 'production' shared_path = "/var/www/shared" stderr_path = "#{shared_path}/log/unicorn.stderr.log" stdout_path = "#{shared_path}/log/unicorn.stdout.log" end # ログ stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) preload_app true before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{ server.config[:pid] }.oldbin" unless old_pid == server.pid begin Process.kill :QUIT, File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end
unicornを起動します。
# -D : デーモンとして動かす, -E : Railsの環境, -c : unicorn設定ファイルのパス
unicorn_rails -D -E development -c config/unicorn.rb
unicornはmasterプロセスと複数のwokerプロセスから成り立っています。 unicornを停止するにはmasterのプロセスを止めます。
pidはunicorn.rbにパスを指定しているので、
kill -9 `cat /tmp/unicorn.pid`
nginx インストールと設定
sudo apt-get install nginx
sudo vim /etc/nginx/ngin
# kanipan_project用の設定ファイル
sudo vim /etc/nginx/sites-available/kanipan_project
以下サンプル
# statements for each of your virtual hosts upstream kanipan_project{ server unix:/tmp/unicorn.sock; } server { listen 80; server_name localhost; access_log /var/log/nginx/kanipan_project/access.log combined2; error_log /var/log/nginx/kanipan_project/error.log warn; root /var/www/kanipan_project/current/public; #rails params用 proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; proxy_temp_file_write_size 256k; location / { proxy_pass http://kanipan_project; }
kanipan_project用設定へのシンボリックリンクを sites-enabled以下に置きます。
sudo ln -s /etc/nginx/sites-available/kanipan_project /etc/nginx/sites-enabled/kanipan_project
ドキュメントルートにkanipan_projectのpublicフォルダへのシンボリックリンクを置きます。
# /var/wwwにシンボリックリンクをはる
sudo ln -s kanipan_project/public /var/www/current/kanipan_project
これで準備完了!