20
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

エムスリーAdvent Calendar 2016

Day 6

よく知らないままに ldapjs を使ってみる

Last updated at Posted at 2016-12-06

概要

この記事はエムスリーアドベントカレンダーの6日目の記事です。普段の仕事ではコードらしいコードを書かないで仕事をしているのですが、アドベントカレンダーを覗いてみたら絶妙に空いているところがあったのでエントリーしてみた次第です。
Node.js は初めて触れているので試しながら行きたいと思います。

アジェンダ

  • ldapjs の環境を構築する
  • ldapjs を軽く使ってみる
  • こんな使い方が出来るんじゃないかというポエムコーナー

環境構築

AmazonのVPSサービス[Amazon Lightsail](https://amazonlightsail.com/,Amazon Lightsail)が発表されたのでさくっと環境構築します。

instance image Node.js を選択して、
スクリーンショット 2016-12-05 21.35.22.png
instance planを選択して create するだけでもう出来ています。
スクリーンショット 2016-12-05 21.35.35.png

事前にkey pairをアップロードしておくと仮想マシンへのSSH接続に利用可能です。

次にldapjsをインストールします。

$ sudo npm install -g ldapjs

# ldapjs を試してみる

サーバを立ち上げる

var ldap = require('ldapjs');
var server = ldap.createServer();
server.listen(1389, function() {
  console.log(server.url);
});
$ node server.js
ldap://0.0.0.0:1389

この状態だと検索したりすることはできないのですが。LDAPサーバを立ち上げるだけならこれだけです。

バインド

LDAPを操作する上でDN(識別名)を認証する操作をバインドと呼ぶようです。

server.bind('cn=root', function(req, res, next) {
  if (req.dn.toString() !== 'cn=root' || req.credentials !== 'secret')
    return next(new ldap.InvalidCredentialsError());

  res.end();
  return next();
});

サンプルのままですが、cn=rootもしくはパスワードがsecretでないときはエラーとなるような定義です。

認可(権限設定)

function authorize(req, res, next) {
  if (!req.connection.ldap.bindDN.equals('cn=root'))
    return next(new ldap.InsufficientAccessRightsError());

  return next();
}

authorizeのための関数を定義します。cn=rootでないとエラーになるような定義です。

## 検索用関数の定義
検索用の関数を定義します。サーバ上の/etc/passwd の中身をattributeとして定義しています。


function loadPasswdFile(req, res, next) {
  fs.readFile('/etc/passwd', 'utf8', function(err, data) {
    if (err)
      return next(new ldap.OperationsError(err.message));

    req.users = {};

    var lines = data.split('\n');
    for (var i = 0; i < lines.length; i++) {
      if (!lines[i] || /^#/.test(lines[i]))
        continue;

      var record = lines[i].split(':');
      if (!record || !record.length)
        continue;

      req.users[record[0]] = {
        dn: 'cn=' + record[0] + ', ou=users, o=myhost',
        attributes: {
          cn: record[0],
          uid: record[2],
          gid: record[3],
          description: record[4],
          homedirectory: record[5],
          shell: record[6] || '',
          objectclass: 'unixUser'
        }
      };
    }

    return next();
  });
}

検索

最後にauthorizeと検索用の関数を紐付けてサーバに検索機能を実装します。

var pre = [authorize, loadPasswdFile];

server.search('o=myhost', pre, function(req, res, next) {
  Object.keys(req.users).forEach(function(k) {
    if (req.filter.matches(req.users[k].attributes))
      res.send(req.users[k]);
  });

  res.end();
  return next();
});

実際に検索してみた結果はいかのようになります。

entry: {"dn":"cn=root, ou=users, o=myhost","controls":[],"cn":"root"}
entry: {"dn":"cn=bin, ou=users, o=myhost","controls":[],"cn":"bin"}
entry: {"dn":"cn=daemon, ou=users, o=myhost","controls":[],"cn":"daemon"}
entry: {"dn":"cn=adm, ou=users, o=myhost","controls":[],"cn":"adm"}
entry: {"dn":"cn=lp, ou=users, o=myhost","controls":[],"cn":"lp"}

クライアント

クライアントも同じように実装可能です。

var ldap = require('ldapjs');
var assert = require('assert');
var client = ldap.createClient({
  url: 'ldap://localhost:1389'
});

client.bind('cn=root', 'secret', function(err) {
  assert.ifError(err);
});

var opts = {
  filter: '(objectclass=*)',
  scope: 'sub',
  attributes: ['dn', 'sn', 'cn']
};

client.search('o=myhost', opts, function(err, res) {
  assert.ifError(err);

  res.on('searchEntry', function(entry) {
    console.log('entry: ' + JSON.stringify(entry.object));
  });
  res.on('searchReference', function(referral) {
    console.log('referral: ' + referral.uris.join());
  });
  res.on('error', function(err) {
    console.error('error: ' + err.message);
  });
  res.on('end', function(result) {
    console.log('status: ' + result.status);
  });
});

まとめ

  • ldapjsを使うことでLDAPサーバ/クライアントを簡単に実装できる
  • DBサーバなどをバックエンドにしたLDAPサーバを実装してみると便利そうですね。
  • 普段やってないことに突然挑戦してみても出来ることがなさ過ぎて悲しい結果になります。

それでも調べてみたことで疑問や興味がわいてきたし良かったんじゃないかと思います(ポエム)。

20
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?