鯖防人は忘れる。

機械音痴の鯖防人が忘れないように…

Samba Active DirectoryへのLDAPによるユーザ追加

こんにちは。
機械音痴の鯖防人です。


先日、自身が所属する研究室のメンバーを管理する、ADをSambaを使って立てました。
今回はそのことについて、ちょっとお話ししようかと思います。

以前はOpenLDAPを使っていたのですが、RADIUS連携する際にパスワードの扱いにちょっと困ってしまったので
研究室の認証基盤の不調を機に、構築し直すことにしました。

OpenLDAPの構築事例を見ると、SSHAを使っている場合が多いのですが
SSHAはハッシュなので、RADIUSとかで使うときに困ります。(困りました)

そのため、以前は、アカウント登録の際に、LDAPRADIUSRDBバックエンド)両方に登録を行うという
非常~に頭の弱いやり方を採用していました。。

RADIUSを前提としたOpenLDAPの構築事例は無いのかと探してみれば、
LDAPにパスワードを平文で登録していて「おいおい…」となりました。

この辺実運用ではどうやってるんですかね…
(まぁ社内システムとかでOpenLDAP&FreeRADIUS使ってるなんてことは無いか…)


と、いうわけで
これを解決するために、Active Directoryを構築することにしました。

SambaでADを構築すれば、タダです。

なお、Samba Active Directoryの構築・設定の仕方は、ここでは説明しません。

このページなどを参考にしてもらえればいいと思います。
www.rem-system.com


それでは本題。

Samba Active Directoryを扱っている事例はそこそこあったのですが、
LDAPでユーザ追加する方法を紹介しているサイトがあまりなかったので
備忘録的に書いておきます。

通常、LDAPは、認証などはTLSを使わずに行うことが多いのですが
Sambaの場合、LDAPS強制でした。
(ここを、面倒だと思うか、安全で良いと思うか)

ですので、Samba ADにLDAPで接続するときは、LDAPSを使います。

ldaps://hogehoge で大丈夫です。

次に、ユーザアカウントの属性ですが、
基本Windows Serverに従っているので、それを参考にしたら良いんだと思いますが
docs.microsoft.com
今回は、以下のような属性にしました。


属性名



objectClass

top

objectClass

person

objectClass

organizationalPerson

objectClass

user

sn

Doe(苗字)

cn

10001(コモンネーム(社員番号など))

instanceType

4

objectCategory

CN=Person,CN=Schema,CN=Configuration,DC=test,DC=local

displayName

John Doe(表示名(氏名など))

sAMAccountName

10001(cnと同じ)

userPrincipalName

10001@test.local

userAccountControl

512 ※1

distinguishedName

CN=10001,CN=Users,DC=test,DC=local

uid

10001

homeDirectory

/home/10001

loginShell

/bin/bash

uidNumber

10001

gidNumber

10001

unicodePwd

※2
※1
基本的に512を指定します。512は一般的なアカウントを示します。
https://support.microsoft.com/ja-jp/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties
※2
パスワードをダブルクォーテーションで括った文字列を、UTF-16LEでエンコードしたものです。
[MS-ADTS]: unicodePwd | Microsoft Docs

実運用の場合でも、だいたいこれくらいの属性情報になるのではないかと思います。

そして、ユーザ追加のフォームですが
phpで以下のように書いてみました。
良かったら参考にしてみてください。

<?php

if(!empty($_POST['submit'])) {
  $ds = ldap_connect("ldaps://localhost");
  if($ds) {
      ldap_set_option($ds,LDAP_OPT_PROTOCOL_VERSION,3);
      $r = ldap_bind($ds,"cn=Administrator,cn=Users,dc=test,dc=local","ぱすわーど");
      $dn = "cn=" . $_POST['uid'] . ",cn=Users,dc=test,dc=local";
      $info["objectClass"][0] = "top";
      $info["objectClass"][1] = "person";
      $info["objectClass"][2] = "organizationalPerson";
      $info["objectClass"][3] = "user";
      $info["sn"] = $_POST['sn'];
      $info["cn"] = $_POST['uid'];
      $info["instanceType"] = "4";
      $info["objectCategory"] = "CN=Person,CN=Schema,CN=Configuration,DC=test,DC=local";
      $info["uid"] = $_POST['uid'];
      $info["displayName"] = $_POST['cn'];
      $info["sAMAccountName"] = $_POST['uid'];
      $info["userPrincipalName"] = $_POST['uid'] . "@test.local";
      $info["userAccountControl"] = "512";
      $info["distinguishedName"] = $dn;
      $info["homeDirectory"] = "/home/".$info["uid"];
      $info["loginShell"] = "/bin/bash";
      exec("ldapsearch -x -H ldaps://localhost -D cn=Administrator,cn=Users,dc=test,dc=local -w ぱすわーど -b cn=Users,dc=test,dc=local -LLL | grep uidNumber: | cut -f 2 -d ' ' | sort -nr | head -n 1",$uidNum,$res);
      $uid = ++$uidNum[0]; if($uid <= 1000) {
        $uid = 1001;
      }
      $info["uidNumber"] = $uid;
      $info["gidNumber"] = $uid;
      $info["unicodePwd"] = mb_convert_encoding("\"" . $_POST['password'] . "\"", "UTF-16LE");
      $r = ldap_add($ds,$dn,$info);
      if($r === FALSE) {
        echo "LDAPサーバへの登録に失敗しました<BR>";
      }
      else {
        echo "LDAPサーバへの登録完了しました<BR>";
      }
      ldap_close($ds);
  }
  else {
      echo "LDAPサーバへの接続に失敗しました";
  }
}

?>

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>ADアカウント登録</title>
</head>
<body>
  <h2>ADアカウント登録</h2>
  <form method="post" action="">
    <table>
      <tr>
        <th>社員番号</th>
        <td><input type="text" name="uid"></td>
      </tr>
      <tr>
        <th>Family Name</th>
        <td><input type="text" name="sn"></td>
      </tr>
      <tr>
        <th>Name(例:John Doe)</th>
        <td><input type="text" name="cn"></td>
      </tr>
      <tr>
        <th>Password</th>
        <td><input type="password" name="password"></td>
      </tr>
      <tr>
        <td><input type="submit" name="submit" value="送信"></td>
      </tr>
    </table>
  </form>
</body>
</html>

以上です。

ほかにも、ADからデータ取ってきてRADIUSに渡して無線LANの認証したり、
いろいろやったんですが

気が向いたら、鯖防人が忘れないように、書いておくかもしれません。



では。