前回はiDempiereの画面から実装したプロセスを起動する方法を紹介しました。
今回は、iDempiereの検証を進める中で気になっていた認証関連の調査結果をお伝えします。
認証サーバーとしてOpenLDAPを利用しましたので、その内容を共有させていただきます。
Ⅰ.OpenLDAPを認証サーバとして動作させた結果
一部のソースコードを修正し、iDempiereの設定を行った結果、OpenLDAPとの認証ができました。
もちろん、OpenLDAP認証を実現するためには他にも適切な方法があるかもしれませんが、この記事は参考情報としてご覧いただければと思います。
課題については、当記事「LDAP認証と運用時の課題」に記載しました。
LDAP認証を実際に導入する過程でさまざまな課題が浮かび上がりましたが、それらの詳細な解決策やベストプラクティスについては今後の課題となります。その一環として、LDAP認証の導入手順について以下で詳細に紹介いたします。
Ⅱ.事前知識と準備
Javaソースコードの修正とiDempiereの画面を用いて設定を行います。
iDempiereの開発環境を構築し、JPiereのプラグインが動作できるようにしておきます。
iDempiereの環境構築と開発環境の準備はこちらをそれぞれ参照ください。
その他、必要となるスキル面は以下です。
- Eclipse
- iDempiere(JPiere)
- OpenLDAP (Ver3ベースです)
- php LDAP admin (OpenLDAPのアカウント登録時に使用します)
※ OpenLDAP 公式サイトはこちらから
Ⅲ.iDempiereとLDAP連携の参考記事
接続情報に関する点は、こちらを参考にさせていただきました。
Ⅳ.LDAP認証機能の検証のながれ
今回は以下のながれで動作検証を行いました。
以下の内容を次章以降から紹介します。

Ⅴ.OpenLDAPの環境構築
Dockerを使用した環境構築には、こちらを参考にさせていただきました。ありがとうございました。
以下の内容から、phpLDAPadminを用いた環境構築およびLDAPのユーザ登録方法を把握することができます。
1) LDAP環境の起動
当検証において以下の内容でOpenLDAPサーバを利用します。
- LDAPサーバのDocker定義情報
 以下の内容をdocker-compose.ymlファイルに記述します。
version: '3'
services:
  ldap-server:
    image: osixia/openldap:latest
    restart: always
    container_name: ldap-host
    environment:
      LDAP_ORGANISATION: "erp"
      LDAP_DOMAIN: "erp.work"
      LDAP_ADMIN_PASSWORD: "password"
    networks:
      - webnet
  ldap-admin:
    image: osixia/phpldapadmin:latest
    restart: always
    container_name: ldap-admin
    environment:
      PHPLDAPADMIN_LDAP_HOSTS: "ldap"
      PHPLDAPADMIN_HTTPS: "false"
    ports:
      - "8081:80"
    links:
      - "ldap-server:ldap"
    networks:
      - webnet
networks:
  webnet:
- LDAPサーバの起動
 DOSプロンプトからdocker-compose up -dコマンドを実装しLDAPサーバーを起動します。
補足)登録結果
次章以降の手順に沿って登録した結果、以下の状態になります。
※ phpLDAPadminにより確認

ユーザを登録する所属DNをdc=erp,dc=workとし、ou=usersに属するcn=ldapuser1アカウントを登録した結果です。
またユーザ情報(ObjectClass)として、inetOrgPersonが適用されています。
今回検証したiDempiereの認証機能では、以下のRDN識別子を使用します。
dc:ユーザの所属するtopのDomain Component名(erp.workの2階層で表現)
ou: ユーザの所属するOrganization Unit名(usersとして定義)
cn: ユーザーのcommonName名(iDempiereではこの名称がログインIDとなります)
userPassword: ユーザーのログインパスワード(iDempiereではこのパスワードがログインパスワードになります)
2) ログイン
iDempiereからログインするユーザをOpenLDAPに登録します。
ブラウザを起動しlocalhost:8081を入力しphp LDAP adminページにアクセスします。
LDAPサーバへログインします。
Login DN: cn=admin,dc=erp,dc=work
Password: password
※ docker-compose.ymlのLDAP_ADMIN_PASSWORD: "password"で指定したパスワードを入力します。
3) 各RDN識別子の登録
1. 最初にouを追加します。
左メニューのdc=erp,dc=workをクリックし、つづいて、Create a child entryをクリックします。

2. objectClassを指定する画面が表示されます。
Generic: Organisational Unitをクリックします。

3. Organisational Unit入力画面が表示されます。
usersを入力しCreate Objectボタンをクリックします。
4. LDAP Entryの登録確認画面が表示されます。
Commitボタンをクリックします。

以上でouのRDN識別子登録は完了です。
ou=usersにて当階層にアクセスすることができます。
続いて、ou=usersの下にユーザを追加します。
5. ユーザを登録します。
左メニューのツリーを展開し、ou=users欄をクリックし、つづいて、Create a child entryをクリックします。

6. objectClassを指定する画面が表示されます。
Kolab: User Entryをクリックします。

LDAPにユーザを登録する場合、数多くのobjectClassを使用することができます。
ツールおよびご利用のユーザ管理方法に沿って適切なobjectClassを指定します。
今回の検証では、登録ユーザのcnおよびpasswordが必要になるため、Kolabを指定しました。
7. ユーザ情報の登録画面が表示されます。
各項目を入力します。
Common Name、Emailは後続の手順でiDempiereに登録します。
Common Nameは、姓名の間にスペースが付加されるためldapuser1として入力しなおします。
また、Passwordを登録する際にはclearを指定します。
なお、ここでのPasswordは、user1passwordとします。

Passwordを登録する際にclearを指定することによりパスワードがLDAP内に平文で保存されます。
iDempiereと連携してログインする場合、clear以外を指定すると正常にログインすることができませんでした。
また、iDempiereにおけるパスワード管理方法はデフォルトでは平文で保持(PostgreSQLのAD_Userテーブルに平文で保存されている)する設定になっています。
iDempiere側の設定に依存していると思われますが、まだ検証はできていません。
今回の検証では、iDempiereおよびLDAPに平文でパスワードを保持する設定を前提に進めます。
入力後、画面をスクロールしCreate Objectボタンをクリックします。

8. LDAP Entryの登録確認画面が表示されます。
Commitボタンをクリックします。

以上でユーザ登録は完了です。
続いて、iDempiereの設定を行います。
Ⅵ.iDempiere設定
iDempiere側で以下の点の設定、登録をします。
ログインユーザ、ロールを切り替えながら設定を進めます。
iDempiereサービスを起動していない場合は、こちらを参考にサービスを起動します。
PostgreSQLサーバも起動しておきます。
- LDAPのDN定義の追加
- LDAP認証にOpenLDAP形式を使用する設定の追加
- LDAP認証するユーザの登録
- メールアドレスによる認証の無効化
1) LDAPのDN定義の追加
1. iDempiereにログインします。
ブラウザのURLにhttps://127.0.0.1:8443/webuiを入力しログインします。
ユーザ情報は以下を入力します。
- EMail: superuser@oss-erp.co.jp
- Password: System
ロール情報は以下を入力します。
- Tenant: System
- Role: System Administrator
2. System画面を開きます。
検索欄にSysを入力するとSystemが表示されます。
Systemをクリックします。

3. System画面が表示されます。
LDAPのサーバー情報およびDN情報を入力します。
LDAPのDN定義の登録は以上です。
続いて、OpenLDAP形式を使用する定義を追加します。
2) LDAP認証にOpenLDAP形式を使用する設定の追加
1. System Configurator画面(新規登録)を開きます。
検索欄にSysを入力するとSystem Configuratorが表示されます。
System Configurator行の新規ボタンをクリックします。

2. LDAP_TYPEを追加します。
以下の欄を入力および選択します。
- Name: LDAP_TYPE
- Configured Value: openldap
- Entity Type: iDempiere
- 
Configuration Level: System
 入力したら保存ボタンをクリックします。
   
以上で、OpenLDAP形式を使用する設定は完了です。
つづいて、LDAP認証するユーザを登録します。
3) LDAP認証するユーザの登録
LDAP認証するユーザ情報を、iDempiereにも登録します。
株式会社OSS ERP Solutionsに属するユーザとして追加します。
1. 現在ログインしているSystem:System Administratorを株式会社OSS ERP Solutions:Admin Roleに切り替えます。
画面上部のChange Roleをクリックします。

2. テナントおよりロールの指定画面が表示されます。
以下のロールを指定します。
3. User画面(新規登録)を開きます。
検索欄にuserを入力するとUserが表示されます。
User行の新規ボタンをクリックします。

4. ユーザ情報の新規登録画面が表示されます。
それぞれの項目を入力します。
最初にUser Contact情報を入力します。
- Name: LDAP User1
- EMail Address: ldapuser1@yourdomain.com.com
- Password: dummy
- 
LDAP User Name: ldapuser1
 ※ LDAP User Nameには、上記のLDAP登録したCN名と一致させます。
LDAP認証を使用する際も、EMail AddressおよびPasswordを入力する必要があります。
5. つづいてに権限情報を入力します。
画面下のDetail Recordエリアを開きます。

新規ボタンをクリックし、虫眼鏡ボタンをクリック後、所属するロールを選択します。

虫眼鏡ボタンをクリック後、ログインユーザのロールが表示されます。
Name欄のテキストを削除し、再表示ボタンをクリックすると登録されているロールが全て表示されます。

ロールの設定と同様に、つづいて、Org AccessタブをクリックしOrgを登録します。

同エリアにLDAP Accessというタブがありますが、登録は特に行いません。
以上でユーザ登録の作業は完了です。
つづいて、最後の設定です。
メールアドレスによる認証を無効にし、ユーザIDでログインできるようにします。
4) メールアドレスによるログインの無効化
ログイン方法を変更するにあたり、再度ロールを切り替えて設定します。
1. ロールを切り替えます。
上記の手順同様に、画面上部Chainge Roleをクリックし、以下のロールに切り替えます。
ロール情報は以下を入力します。
- Tenant: System
- Role: System Administrator
2. メールアドレスログインを無効化します。
検索欄にsysを入力するとSystem Configuratorが表示されます。
System Configurator行をクリックします。

3. 検索画面が表示されます。
Name欄にUSE_EMAIL_FOR_LOGINを入力し、検索します。

4. USE_EMAIL_FOR_LOGINの設定内容が表示されます。
Configured ValueをNにします。
変更したら保存ボタンをクリックします。

以上でメールアドレスによるログインの無効化の設定は完了です。
iDempiere画面からの設定は全て完了しました。
つづいて、Eclipseを開きソースコードを一部修正します。
Ⅶ.iDempiereのソースコード改修点
修正点は、RDN識別子名称の変更です。
デフォルトのuidがログイン関数による検証でどうしてもエラーになります。
RDN識別子でcnを使用するようにします。
1) RDN識別子の変更
- 対象のパッケージ: org.compiere.db
- 修正クラス: LDAP
- 修正ソースファイル: org.adempiere.base/src/org/compiere/db/LDAP.java
validateメソッド内の以下の点を修正します。
	public static boolean validate (String ldapURL, String domain, String userName, String password)
	{
		Hashtable<String,String> env = new Hashtable<String,String>();
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		//	ldap://dc.compiere.org
		env.put(Context.PROVIDER_URL, ldapURL);
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
		StringBuilder principal;
		if ("openldap".equals(MSysConfig.getValue(MSysConfig.LDAP_TYPE))) {
-			principal = new StringBuilder("uid=").append(userName).append(",").append(domain);
+            principal = new StringBuilder("CN=").append(userName).append(",").append(domain);
		} else {
			principal = new StringBuilder(userName).append("@").append(domain);
		}
		env.put(Context.SECURITY_PRINCIPAL, principal.toString());
		env.put(Context.SECURITY_CREDENTIALS, password);
		//
		try
		{
			// Create the initial context
			InitialLdapContext ctx = new InitialLdapContext(env, null);
		//	DirContext ctx = new InitialDirContext(env);
			
			//	Test - Get the attributes
			ctx.getAttributes("");
		    // Print the answer
		    //if (false)
		    // dump (answer);
		}
		catch (AuthenticationException e)
		{
			if (log.isLoggable(Level.INFO)) log.info("Error: " + principal + " - " + e.getLocalizedMessage());
			return false;
		}
		catch (Exception e) 
		{
			log.log (Level.SEVERE, ldapURL + " - " + principal, e);
		    return false;
		}
		if (log.isLoggable(Level.INFO)) log.info("OK: " + principal);
		return true;
	}	//	validate
Javaコードの修正は以上です。
以上で、LDAP認証の準備は全て整いました。
実際に動作をします。
ソースコードを修正しているので、iDempiereサービスを再起動します。
Ⅷ.動作確認
LDAP認証によるログインの確認です。
電子メールによる認証からユーザIDによる認証に変更しましたので、先ほどまで入力していた欄がEMailからUserに変わっています。
画面のログイン画面にLDAPに登録したユーザldapuser1を入力し、パスワードにuser1passwordを入力します。

テナント・Role画面が表示されれば、LDAP認証処理は成功です。
ldapuser1ユーザに定義したロール情報が表示されますので、選択してOKボタンによりログインします。

Ⅸ.LDAP認証と運用時の課題
LDAP認証とその運用における課題についてです。今回はOpenLDAPを用いた認証機能を検証しましたが、いくつかの課題が浮かび上がりました。もしかすると設定等で回避することができるかもしれませんが、以下にそれらの課題をいくつか紹介いたします。
1. LDAPサーバのDN名が固定(ouの指定を含む)
iDempiereのLDAPサーバ参照時のDN(LDAP Domain)の定義が1つしかなく、ユーザ認証のために使用するou=users,dc=erp,dc=workの定義を固定で設定する必要がありました。
2. ログインユーザのロールに応じたLDAP内のouの定義がiDempiereの仕様上難しい(階層状の定義など)
ログインするユーザのロール階層に基づいてLDAPの階層を一致させることができませんでした。実際の運用では、LDAP上の定義として課部署など階層状に登録することが想定されますが、ログイン時の認証認可の制御については、認証(課部署情報を含まない)にはLDAPを使用し、認可についてはiDempiereの設定に依存する形になりました。
3. ソースコードの改修が必要
OpenLDAPで認証する際、標準の実装ではRDN識別子としてuidが記述されており、InitialLdapContextメソッドによる認証の検証処理が正常に行えませんでした。OpenLDAPにユーザを登録する際に適用するObjectClassによっては、uidが存在しているものの、認証処理でエラーが発生しました。posixAccountの適用や個別にuidを追加したユーザを登録しても、認証エラーによりログインができませんでした。
Ⅹ.次回は
今回は、認証機能の第1弾としてOpenLDAP認証について動作確認を行いました。
次回も他の認証機能を用いたユーザ認証処理について調査を進めたいと思います。











