A Day In The Boy's Life -27ページ目

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

IDやパスワードを一元管理するために、Active Directoryと連携したいというケースがあったりしますが、ADへ認証やパスワード変更などをPHPから行うためのメモです。


LDAPを通して簡単に認証やパスワードなどの属性値変更が行えます。
PHPは5.3系を使っています。

Windows側はWindows2008およびWindows2012で動作確認しています。



Active Directoryへ認証するPHPプログラム


これは特に難しいことなく、PHPのldap_bind を使えば認証が行えます。


<?php

$host = "ldaps://192.168.0.100";
$ldapConn = ldap_connect($host);

// userprincipalnameを指定
$userId = "username@testdomain.test";
$userPass = "HogeHoge12";

ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);
if (ldap_bind($ldapConn, $userId, $passwd)) {
    echo "ログイン成功" . PHP_EOL;
} else {
    echo "ログイン失敗" . PHP_EOL;
}
ldap_close($ldapConn);

ポイントとしては、ユーザー名にはuserprincipalnameを指定すること(dnを指定してもできますが)ぐらいで後は認証するldap_bindに引数を渡して結果がTRUE/FALSEで返ってきます。



Active Directoryのパスワードを変更するPHPプログラム


お次はAD上のパスワードを変更する方法ですが、前提としてパスワード変更する際にはAD上にSSL証明書を用意し、LDAPSで接続する必要があります。

SSL証明書は正規のものではなく自己証明書でもかまいませんが、その場合は接続するサーバー側で証明書の検証を無効にするように設定しておく必要があります。


TLS_REQCERT never

上記の設定を、/etc/openldap/ldap.confあたり(環境によっては複数あったりしますが)に記載しておきます。


パスワード変更するための具体的なプログラムは下記の通りです。


<?php

$host      = "ldaps://192.168.0.100";
// 管理権限を持つユーザー名
$adminId   = "administrator@testdomain.test";
// 上記ユーザーのパスワード
$adminPass = "adminpassword";

// パスワード変更対象のユーザー名
$userId   = "username@testdomain.test";
// 変更するパスワード
$userPass = "HogeHoge12345";

// 管理者権限を持つユーザーでADへ接続
$ldapConn = ldap_connect($host);
ldap_set_option($ldapConn, LDAP_OPT_PROTOCOL_VERSION, 3);
if (!ldap_bind($ldapConn, $adminId, $adminPass)) {
    echo "ログイン失敗" . PHP_EOL;
    exit;
}

// ユーザーのDNを取得する
$baseDn = "OU=Employee,OU=Users,DC=testdomain,DC=test";
$filter   = array("dn");
$ls       = ldap_search($ldapConn, $baseDn, "userprincipalname=$userId", $filter);
$userInfo = ldap_get_entries($ldapConn, $ls);

// 設定するパスワードはダブルクォートで括ったものをUTF-16に変換する
// unicodePwdはパスワードを格納しているエントリ名
$entry["unicodePwd"] = mb_convert_encoding("\"" . $userPass . "\"", "UTF-16LE");

if (ldap_mod_replace($ldapConn, $userInfo[0]['dn'], $entry)) {
    echo "変更成功" . PHP_EOL;
} else {
    echo "変更失敗" . PHP_EOL;
}
ldap_close($ldapConn);

パスワードを変更するプログラムは、少し複雑にはなりますが予約すると下記の流れで組んでいます。

(その他の属性の変更も基本同じ流れでいけるはず)


1. パスワードを変更できる管理権限を持つユーザー(ここではadministrator)でADへ接続
2. 変更したいユーザーのDNを取得するためにADを検索
3. 変更したいパスワードをダブルクォーテーションで囲ったものをUTF-16LEで変換
4. 変更したいユーザーのパスワード属性(unicodePwd)に2.のパスワードを変更


2.の処理でDNを検索するのは回りくどいように思えますが、ldap_mod_replace(またはldap_modify)で変更したいユーザー属性やオブジェクトを変更したい場合、DNを指定する必要があるためにそうしています(ldap_bindはuserprincipalnameの指定でもいけるのに何故・・・)


3.の処理はWindows側の仕様のようで、本来であればダブルクォーテーションで囲った平文パスワードをUTF-16LEに変更し、それをBase64エンコードすることになるのですが、Base64へのエンコードはLDAP関数側で自動的にやってくれるので省略可能です(逆にBase64にエンコードしてしまうと二重にエンコードされます)。
この辺の話は、下記に情報があります。


Active Directory: AD LDS における unicodePwd 属性値の謎


また、実運用するならエラーハンドリングをきちんと書いたほうが良いと思いますし、LDAPに渡すフィルタの値などはエスケープ処理をきちんとしておいたほうがよさそうです。

PHPにはldap_escape という関数ができているようですが、PHP5.6以上じゃないと使えません。
これ以下のバージョンを使っている場合は自前で用意するしかなさそうです。


下記のRFCの要約を見る限りは、「* ( ) \ NULL」は円マークでエスケープしたあとにASCII値に変更しろって書いていますので、その辺の処理を組み込む必要がありそうです。


付録 A:RFC2254 - LDAP 検索フィルタ


あと、余談の余談にはなりますけど、PHPのldap_mod_replace のマニュアルを見ていると、設定するパスワードの最後に「\000」をつけていたりしていて、これなんだろうとか思ってましたがどうもNULL文字つけて文字の区切りをはっきりさせているのでしょうか。


$newPassword = "MyPassword";
$newPassword = "\"" . $newPassword . "\"";
$len = strlen($newPassword);
for ($i = 0; $i < $len; $i++)
        $newPassw .= "{$newPassword{$i}}\000";
$newPassword = $newPassw;

この処理はいるのだろうか(無くても動く)と思ったり。





周りから「ストレス耐性があるよね」なんて言われるんですよ。

でも、実際ストレスに強いわけではなく結構ガラスのハートの持ち主だったりするわけですよ。

で、ストレス耐性ってものが本当にあるのかって言われたらそんなものないと思うわけです。



ストレスからは逃げるしかない


自分的にストレス耐性があるって思われているのは、


1. 寝たら忘れられる都合のよい性格

2. 人の話を適度にスルーできる

3. 面倒がありそうなところに突っ込んでいかない無関心さ

4. ストレスを共有できる気があう仲間の存在

5. 逃げられない環境を作らないための空気口


のようなものがあって、要はストレスを溜め込まないようにしているわけです。

1.の性格は結構都合のよいものだったりもするのですが、この辺は人によって何日も引きづったり、怒りを維持したまま眠って、そのままのテンションで次の日に怒る人もいたりするものですからあんまり参考にならなかったりするのですが、2.3.なんかは要はスルー力みたいなところで、ストレスを受け止めるのではなく流したり、あんまり面倒くさそうなところには関わらないことでストレスの発生源を少なくするというように、ストレスを溜め込まないためには必要だったりするんじゃなかろうかと思うわけです。

もちろん、悪いところもあって人の話を聞いていないとか怒られたり、無関心さから人間関係が希薄になったり、冷たい奴って思われたりするんですが、情報があふれる現代においては自分が嫌だと思う情報は適度にスルーしたり、SNSなど気軽にコミュニケーションが取れる今だからこそ返ってSNS疲れなんかを起さないような適度な無関心さっているんじゃないかとも思ったりします。


4.の話は、気の合う仲間と愚痴をぶつけるために飲みに行ったりしても、似た状況で共通のストレス発生源があればぶつけ合うことで互いに外に追い出すことはできるでしょうが、片方の愚痴を延々と聞かさせるだけだったりしてそれが何日も続いてしまうと、聞いているほうのストレスが溜まってしまって、さらに別の人にそのストレスをぶつけるといった悪循環に陥ったりもします。

ですので、こういう仲間というのは同じ職場の人であったり、職種であったり、立場であったり、結婚しているとか似たような状況下にあるもの同士のほうがよいのではないかと思います。

単に愚痴の聞いてくれる都合のよい人という捉え方をしてしまうと、その人にストレスを押し付けているだけでいつか関係性が壊れてしまうかもしれませんし。


5.の話は、例えば家庭であったり職場であったり、どうしてもストレスを受けざるを得ない環境ってあったりするわけで、気軽に逃げるという選択肢が取れない場合に対して、その受けてしまったストレスをうまく逃がすための自分なりの空気口をちゃんと用意しておいた方がよいかと思っています。

例えば、ストレスを発散できる趣味があったりとか、家庭内でも一人の時間をもてるとか、運動して汗をかくとか、この辺は人それぞれ違ってくるでしょうけど、どうしても受けてしまうストレスに対しては、それを抜くための空気口ってちゃんと用意しておいて、自分であけることができるようにしておいたほうがよいと思ったりします。



精神論を振りかざす


人っていたりするわけですけど、そういう人ってきっと適当な人なんだろうなって思ったりします。

適当というのは、「○○は甘え」というような自分の意見を押し通していて、そうではないという人の話を聞かなかったりするので、ある意味その人はストレスを受けづらい人なんだと思います。

人の話をスルーでき、相手の立場を棚に上げることができるので、言い返したところで聞いてないし、ポジショントークを繰り広げられます。


過去の体験をベースに話したりする人もいますが、その時と今の時代の状況の違いを理解してなかったり(または、それを棚に上げておいたり)、昔の状況がより不利であったかのように話してきたりもするのですが、結局のところその優劣を判断することは誰もできませんし、今の時代の方が全てにおいて優れているとも限りません。

情報を捨てるセンス 選ぶ技術 」という本(まだ、全部読んでないですが)の中に、現代において人が1日に下す決断の数は約1万件、消費した情報量は50年前に比べて3倍になっているそうです。

都合のよい捉え方をすれば、それだけ豊富な情報があるのに何で仕事ができないんだ見たいな事を言えるかもしれませんが、実際それだけの情報に埋もれ、その目にする情報によって素早い判断を求められ、得たくも無い情報を耳にしたりすることでストレス量も増加します。


また、こういうことを言う人って、立場的に上だったりするもんですからそもそもストレスを受けにくい環境下にいたりします。

ストレスが無い立場なんで、ストレスを受ける側の立場を理解できなかったりしますし、その上下関係の有意性からストレートに発する言葉に、受け手はストレスを感じたりするわけです。

立場が上であるが故に、ストレスを逃がすための空気口はいつでも自分で作れますから、状況がまずくなったら逆ギレして強制させたり、あとは適当にやっといてと丸投げしてくるのではないかと思います。

何れにせよ、こういう人が今の自分と同じ立場でやったら我慢してできるのだろうかとか思ったりすることもありますが、これはその人と同じ考えに染まることになるわけなので、そういった考えをするよりはそういう人にはなるべく近づかないで済むように考えた方がストレスが溜まらなくてよいかもしれません。


結局、ストレスなんて誰しもまともに受け続けていたら自分の中に蓄積されていきいつかつぶれてしまうもので、受け流すまたはストレスから逃げる・遠ざかる術を身につけるしかないのかなと思っています。





2006年から開始したこのブログもこの8月で8年が経過したことになりました。

当初はあまり技術ログとしてスタートするつもりは無かったのですが、ここ最近はプログラミングなどのネタの方が中心となって、更新頻度も生活リズムの変化とともに変わり、当初のやろうとしていたことから随分とかけ離れてしまったかなと思ったりしています。



ネットに住まう難しさ


じゃあ、当初何をしたかったのかというと、プログラミングやライブラリの使い方などの技術ログを残すというよりは、IT業界の話題や仕事の上での考え方などのまとめて、同じ業界で仕事しているエンジニアのブログとかとのつながりが持てたらいいなと思ってました。

まぁ、ブログ界隈で少しは有名人になればいいなとかの野心も少し持っていましたが、如何せんそんなに凄いネタを提供できるほどの情報力も文章力も知識量もないものなので単なる日記としての足跡ぐらいしか残せていないのですが。


当時は、トラックバックの機能もまだ比較的使われていましたし、個人がやっているまとめサイトなども数多くあって、ブログとブログがつながっている印象を凄く感じていたのですが、時代の流れとともに情報発信もTwitterやFacebookに流れていったり、ブログ同士のつながりというものも薄くなってしまったように思えます。

これは当然色んなサービスが出ては消えていく時代の流れの中でのことなので仕方が無いことですが、自分的にはこのブログを始めた当初はネットにおけるホームのような位置づけだったりして、それを発展させたいという思いを強く持っていました。


ただ、ホームは作ったもののそこに時間をかけるのはそれなりの労力が当然かかるわけで、一方でその労力が目に見えて報われるほどの大きなリターンというのは当時すぐに得られるわけも無く、なかなかモチベーションを維持し続けることが難しいと思うようにもなり、それを専門でやっているようなブロガーのネットに住んでいる感って半端ないんだなと感じたりもします。

それを感じとったぐらいから自分がネットに住まうというのは難しいとも思うようになって、自分のペースというものを見出し、ある意味その諦めからブログというものを長く続けられているのかもしれません。



技術ネタに逃げたのは反応が得やすいから


年々技術的な話題のエントリって増えていったりしているのですが、それはある意味ネタとして書きやすいからだったりします。

自分が調べ上げたことの結果を、スタートからゴールまで単に羅列していけば済むので。


ただ、入社当時の上司の言い分で「ネットで調べてみたら自分と同じ状況で困っている奴は1人はいるから調べろ」って言われたことがあって、その困っている人を助けられる1人に今度は自分がなれたらいいなとかって思いはあったりもします。

まぁ、それは自分への備忘録のついでという意味もあったりするのですが、現にこういうエントリって今でも数年前のものがそれなりに読まれていたりして、技術ログって反応が継続的にあってわかりやすかったりします。


もう1つ、技術ネタを中心に書いていた効能としてはエンジニアとしてのモチベーションが上がったんですね。

他の人の技術ネタのエントリを読んでみたらこれは凄いと思えるようになりますし、そのネタを試してみたいとも思いますし、そんなネタを自分でも書いてみたいとも思うようになったりします。

最初から技術ネタだけを扱うブログとしてスタートできなかったのは、当時の自分にはたいした技術的な知識ってあんまり持ってなかったからというのが正直なところなんですが、ブログでプログラミングネタとかを書いていってその反応が見て取れたからこそ、今でもエンジニアとしてのモチベーションが維持できているのかなと思ったりします。


ただ、技術系のエントリはそもそも書くのにはかなりの時間がかかってしまいます。

エンジニアとしてのモチベーションはあっても、実際の仕事としてプログラマとして第一線にいるかといわれたら、やっぱり経験とともに他の仕事も押し付けられたりしてなかなかそうはいかないので、ネタとしても幾つも出てこなかったりもするわけです。

なので、現場では下の子がやっているテクニックや使っているツールなどをみては吸収できることは無いかなという見方をしてたりもして、そういう技術的なことに対する興味が尽きないのはブログをやっていたおかげなのかもしれません。


まぁ、それでもエンジニアブロガーとして結果を出すということにこだわるのであれば、技術ネタをどんどん書くよりは、小規模なものでもいいので使えるサービスというものを産み落とすことをした方が説得力もありますし、周りからも受け入れやすいと思う今日この頃ではありますが。

ということで、自分のペースを維持しつつ、このブログ運営を今後も継続できるようになんとかがんばっていきたいと思います。