Mediawiki 1.35でLdapAuthenticationからLDAPAuthentication2に移行した時のメモ

# はじめに

MediaWiki LTS版を1.27から1.31と使ってきて、そろそろ1.35に移行するべき時期がやってきました。

Extensionsの互換性を確認したのですが、1.35で互換性が確認されていない、推奨されていないものが増えてきて継続使用を諦めたものがほとんどという状況です。

その中でもLDAP認証への対応は必須なので、1.35では推奨されていないLdapAuthenticationから、LDAPAuthentication2に移行しようと思います。

その作業の顛末をメモとして残しておくことにします。

## 環境

* MediaWiki 1.35.x Server - VMware Workstation Pro 16上のUbuntu 20.04.2 64bit版に配置
* LDAP Server#1 - Synology NASのLDAPサーバー上に作成したアカウントが対象
* LDAP Server#2 - OpenLDAPで構成されている基幹LDAPサーバー

2つのLDAPサーバーが存在するのは、そもそもSynologyで基幹LDAPサーバーを利用したかったのですが、Synology側のLDAP連携ではActiveDirectory(AD)は考慮されていましたが、一般的なLDAPサーバーの様々な設定に対応するような柔軟性がなかったことに起因します。結果としてSynology上でLDAPサーバーを動かし、SynologyのNAS機能と少人数で共有するサービスで利用してきた経緯があります。

Mediawikiでは、その必要なメンバーだけが利用してきたSynology NAS上のLDAPサーバーを参照することで、認証されたユーザーは全てMediawikiの利用が承認される設定で運用してきました。そのためグループ管理の機能は、ほぼほぼ利用してきませんでした。

本来は基幹LDAPのみを利用するべきで、多く登録されているIDの中から特定のグループ認証ができるのであれば、こちらを利用するのが管理上良いわけで、最終的には#2の基幹LDAPサーバーを利用することがゴールとなります。

本番サーバーはPC Engines社製APU2上で稼動しているUbuntu 20.04 LTS (amd64版)で稼動しています。
この記事はテスト環境であるVMware Workstation上で行なった作業結果についてまとめています。

## 参考資料

1.35をサポートしているLDAPAuthentication2側でもLdapAuthenticaionからの移行については意識していて、ドキュメントは揃っています。設定値をどのように変換するのは丁寧にドキュメントを読めば、ある程度は理解できると思います。

* [LDAP hub](https://www.mediawiki.org/wiki/LDAP_hub)
* [LDAP hub/Migration from extension LDAPAuthentication](https://www.mediawiki.org/wiki/LDAP_hub/Migration_from_extension_LDAPAuthentication)
* [LDAP hub/Config conversion](https://www.mediawiki.org/wiki/LDAP_hub/Migration_from_extension_LDAPAuthentication/Config_conversion)

利用を検討した機能拡張へのリンクは下にまとめています。(全て利用したわけではありません)

* [LdapAuthentication](https://www.mediawiki.org/wiki/Extension:LDAP_Authentication) (未使用)
* [LDAPAutnentication2](https://www.mediawiki.org/wiki/Extension:LDAPAuthentication2)
* [LDAPProvider](https://www.mediawiki.org/wiki/Extension:LDAPProvider)
* [PluggableAuth](https://www.mediawiki.org/wiki/Extension:PluggableAuth)
* [LDAPAuthorization](https://www.mediawiki.org/wiki/Extension:LDAPAuthorization) 
* [LDAPUserInfo](https://www.mediawiki.org/wiki/Extension:LDAPUserInfo)
* [LDAPGroups](https://www.mediawiki.org/wiki/Extension:LDAPGroups) (未使用)
 
この他に自分で作成したAnsible Playbookのroleをテスト環境構築のために利用しています。

* https://github.com/YasuhiroABE/ansible-mediawiki-restoredb

ここではVMware Workstation Pro 16上のVMにansible-playbookを利用して環境を構築してテストした結果を掲載しています。

# 必要なExtensionsについて

これまではLdapAuthenticaionのtar.gzファイルをextensionsで展開すれば利用できましたが、LDAPAuthentication2はLDAPProviderとPluggableAuthの2つのextensionsが必要と書かれています。

またLDAP hubのページを確認すると、認証(Authentication)後の承認(Authorization)処理でグループを利用する場合は、LDAPAuthorizationが必要と書かれていますが、これはLDAPAuthentication2のページには書かれていません。

情報が分散しているので全体像が見えにくいですが、LDAPを利用したい場合には、LDAP Hubのページをまず確認するのが良いと思います。
このページにある図が全体像を良く表現していると思います。(LDAP Stack Flow: https://www.mediawiki.org/wiki/LDAP_hub#/media/File:LDAPStack.svg)

LdapAuthenticationからの移行では、ダウンロードするextensionsの数が増えたり、設定する内容が分散する結果になり、控え目にいっても面倒の度合いは増えたと思います。

## 使用したextensionsのバージョン

今回はMediaWiki 1.35に対応した次のファイルをダウンロードしてテストしています。

* LDAPAuthentication2-REL1_35-771b91e.tar.gz
* PluggableAuth-REL1_35-2a465ae.tar.gz
* LDAPProvider-REL1_35-ca854c1.tar.gz
* LDAPAuthorization-REL1_35-e037664.tar.gz
* LDAPGroups-REL1_35-97e04b2.tar.gz
* LDAPUserInfo-REL1_35-39cca83.tar.gz

※ LDAPAuthentication2は1.35.2がリリースされたタイミングで新しいバージョン(LDAPAuthentication2-REL1_35-771b91e.tar.gz)がリリースされています。Extensionsは更新作業などの際に最新版が存在するか確認してください。

> 【2021/8/23 追記】1.35.3に更新するタイミングで確認したところ、これらのextensionsのバージョンは全て更新されていましたのでご注意ください。

# 基本的な設定方法

参考資料に挙げている、Ldap hubのLdapAuthorizationからの移行についてのドキュメントを読むと、設定を全てLocalSettings.phpに書き込む方法と、LDAPサーバー関連の情報をjsonファイルに保存する方法の2つが例として挙げられています。

## 設定ファイル変換ツールの利用

Config conversionのページには、LdapAuthenticationでの設定をどこに反映させれば良いかのヒントがまとめられています。また、LdapAuthentication用の設定を、変換してJSONファイルを出力するツールについても記載があります。

単純にLDAPProviderモジュールを有効にしただけではエラーになります。

```bash:そのままではちゃんと動かせない
$ sudo php extensions/LDAPProvider/maintenance/ConvertLdapAuthenticationConfig.php --output /ext/mediawiki/ldapprovider.json

Could not access configuration file '/etc/mediawiki/ldapprovider.json'!

Please set up a domain configuration file for the LDAPProvider extension.

Backtrace:  ...
```

LocalSettings.phpにLDAPProvider用の設定をしないと、このようにデフォルトの/etc/mediawiki/ldapprovider.jsonを読み込もうとしてエラーになります。

このスクリプトを試すために、以前のLocalSettings.phpファイルをmediawiki-1.35.0.tar.gzを展開したディレクトリに配置(/var/www/html/mediawiki/LocalSettings.php)し、次のような設定のみを加えました。(古いLdapAuthenticationの設定もそのままです)

```php:LocalSettings.phpに追記した内容
wfLoadExtensions( [
  'LDAPProvider'
] );
$LDAPProviderDomainConfigs = "/tmp/mediawiki-ldapprovider.json";
```
ここに設定した```/tmp/mediawiki-ldapprovider.json```ファイルは空で良いのですが、配置しておく必要があります。

```bash:空の設定ファイルを配置する
$ touch /tmp/mediawiki-ldapprovider.json
```

この後で次のように/tmp/以下に変換されたLDAPAuthentication2用のJSONファイルを出力するようにコマンドを実行しています。

```bash:
$ cd /var/www/html/mediawiki/
$ sudo php extensions/LDAPProvider/maintenance/ConvertLdapAuthenticationConfig.php --output /tmp/ldapprovider.json
```

この結果、/tmp/ldapprovider.jsonファイルが出力されました。

```json:/tmp/ldapprovidler.json
{
    "MYLDAP": {
        "connection": {
            "server": "ldap.example.com",
            "port": 636,
            "enctype": "clear",
            "basedn": "dc=ldap,dc=example,dc=com",
            "userbasedn": "cn=users,dc=ldap,dc=example,dc=com",
            "userdnsearchattribute": "uid"
        },
        "userinfo": {
            "attributes-map": {
                "email": "mail"
            }
        },
        "authorization": {
            "rules": {
                "groups": {
                    "required": [
                        "cn=users,cn=groups,dc=ldap,dc=example,dc=com"
                    ]
                }
            }
        }
    }
}
```

このままではうまく動かないので、設定を変更していきます。

## 具体的な設定

出力されたldapprovider.jsonファイルは参考にしつつも、古い設定を消し、次のような設定で試しています。

```json:ldapprovider.jsonファイル全体
{
    "MYLDAP": {
        "connection": {
            "server": "ldap.example.com",
            "port": 636,
            "enctype": "ssl",
            "basedn": "dc=ldap,dc=example,dc=com",
            "userbasedn": "cn=users,dc=ldap,dc=example,dc=com",
            "userdnsearchattribute": "uid",
            "usernameattribute": "uid",
            "realnameattribute": "gecos",
            "emailattribute": "mail",
            "searchattribute": "uid"
        },
        "userinfo": {
            "attributes-map": {
                "email": "mail",
                "nickname": "uid",
                "realname": "gecos"
            }
        }
    }
}
```

```php:LocalSettings.phpの該当部分のみ抜粋
## for LDAPAuthentication2
wfLoadExtensions( [
  'PluggableAuth',
  'LDAPProvider',
  'LDAPAuthentication2',
#  'LDAPAuthorization',
#  'LDAPGroups',
#  'LDAPUserInfo'
] );

## -- Setting of LDAPProvider --
$myLdapJsonFile = "$IP/ldapprovider.json";
$LDAPProviderDomainConfigProvider = "\\MediaWiki\\Extension\\LDAPProvider\\DomainConfigProvider\\LocalJSONFile::ne
wInstance";
$LDAPProviderDomainConfigs = $myLdapJsonFile;
$LDAPProviderDefaultDomain = "LDAP";

## -- Setting of PluggableAuth --
$wgPluggableAuth_EnableAutoLogin = true; ## default: false

## -- Setting of LDAPAuthentication2 --
$LDAPAuthentication2UsernameNormalizer = 'strtolower';
$LDAPAuthentication2AllowLocalLogin = false;
```

## ldapprovider.jsonファイルの編集

### TLS vs SSL

ここでのTLSとSSLはプロトコルのバージョンというよりは、通信方式を指しています。

自動的に変換された設定ファイルでは、636ポートを使っているのに、```"enctype": "clear",```が指定されています。
このためTLS接続に失敗します。なお具体的な設定では"ssl"を指定しています。

```extensions/LDAPProvider/docs/mediawiki.ldap.json-sample``` のサンプルでは、AD用のサンプルで"tls"を設定していますがADは試していません。後述するようにADでは389ポートに接続した上でTLS認証ができる場合はTLSで経路を確保した上で、ldap://プロトコロルを利用します。今回は、ldaps://を利用する必要があります。

試しにenctypeに"tls"を指定した状況で、LDAP hubに掲載されているデバッグ用スクリプトを起動します。
後述するデバッグ設定で/tmp/LDAP.logにログを出力するよう設定しています。


```bash:LDAPサーバーへの接続テスト
$ sudo php extensions/LDAPProvider/maintenance/ShowUserInfo.php --domain MY_IDS --username user01
PHP Warning:  ldap_start_tls(): Unable to start TLS: Can't contact LDAP server in /var/www/html/mediawiki/extensions/LDAPProvider/src/PlatformFunctionWrapper.php on line 121

Warning: ldap_start_tls(): Unable to start TLS: Can't contact LDAP server in /var/www/html/mediawiki/extensions/LDAPProvider/src/PlatformFunctionWrapper.php on line 121
...
$
```

接続に失敗するのですが、この時の状況をログファイルで確認します。

```text:/tmp/LDAP.logファイルから抜粋
2021-03-06 03:05:28 mediawiki wikidb: ldap_connect( $hostname = 'ldap://openldap.example.org:636', $port = 389 );
PHP Warning:  ldap_start_tls(): Unable to start TLS: Can't contact LDAP server in /var/www/html/mediawiki/extensions/LDAPProvider/src/PlatformFunctionWrapper.php on line 121
...
```

このようにldap_connect()が呼ばれる際に、"ldaps://"ではなく、"ldap://"プロトコルが使用されています。

enctypeをsslにすると次のような結果になります。

```bash:
$ cd /var/www/html/mediawiki
$ sudo vi ldapprovider.json
$ grep enctype ldapprovider.json
            "enctype": "ssl",
$ $ sudo php extensions/LDAPProvider/maintenance/ShowUserInfo.php --domain MYLDAP --username user01
uid => user01
uidnumber => 1001
gidnumber => 1001
...
```

この時の/tmp/LDAP.logの記述は次のようになっています。

```text:/tmp/LDAP.logファイルからの抜粋
2021-03-09 01:33:20 mediawiki wikidb: ldap_connect( $hostname = 'ldaps://openldap.example.org:636', $port = 389 );
2021-03-09 01:33:20 mediawiki wikidb: # __METHOD__ returns Resource id #751
...
```

ここら辺は、LDAPProvider/src/EncType.phpの中で、SSL,TLS等が定義され、実際に利用するケースでは、LDAPProvider/src/Serverlist.phpの中でEncType::SSLとEncType::LDAPIのみが参照されていてプロトコル(ldaps:とldapi:)の選択に利用されています。EncType::TLSを指定した場合はLDAPProvider/src/Client.phpの中でstartTLSから、phpのldap_start_tls()が呼ばれる関係になっているので、このPHPマニュアル( https://www.php.net/manual/ja/function.ldap-start-tls.php )に記載があります。

> PHPマニュアルからの抜粋
Please note there is a difference between ldaps and start-TLS for ldap.  start-TLS uses port 389, while ldaps uses port 636.  ldaps has been deprecated in favour of start-TLS for ldap.  Both encrypted (start-TLS ldap)  and unencrypted ldap (ldap) run on port 389 concurrently.


なので https://www.openldap.org/faq/data/cache/605.html にも記述されているとおり、今後は389ポートを利用してStart-TLSによる暗号化通信を行なう方法が主流になっていくかもしれません。

いずれにしても"enctype"に"clear"を設定するのは、どうかなとは思いますし、環境に合わせて変更する必要があります。

## LocalSettings.phpファイルの編集

### グループ権限の編集

LDAP認証のみを利用したい場合、デフォルトの設定では、認証には成功するもののエラーメッセージが表示されてしまします。

```text:LDAP認証後のエラーメッセージ
ja: ローカルアカウントの自動作成が失敗しました: アカウントの自動作成は許可されていません。
en: Auto-creation of a local account failed: Automatic account creation is not allowed.
```

$wgGroupPermissionsの設定が十分ではないためで、LocalSettings.phpを次のように編集します。

```diff:LocalSettings.phpファイルの差分
--- LocalSettings.php.default   2021-03-09 12:03:03.853917428 +0900
+++ LocalSettings.php   2021-03-09 12:03:16.338025735 +0900
@@ -123,6 +123,7 @@
 
 # The following permissions were set based on your choice in the installer
 $wgGroupPermissions['*']['createaccount'] = false;
+$wgGroupPermissions['*']['autocreateaccount'] = true;
 $wgGroupPermissions['*']['edit'] = false;
 $wgGroupPermissions['*']['read'] = false;
```

必ずプロセスの再起動が必要です。

```bash
$ sudo systemctl restart apache2
```

## LocalSettings.phpの1.31.10から1.35.1への移行

テスト中に1.35.1がリリースされたので、最終的にこれまで利用してきたLocalSettings.phpを1.35.1で生成されたファイルをベースにしたものに移行しようとしています。

diffの差分に注目しながら、削除した項目、変更した項目、追加した項目に分けて対象となった設定値をメモしておきます。

### 削除した項目 (ベースとなる1.35のLocalSettings.phpには記載がないのため転記しない項目)

* $wgScriptExtension
* $wgDBmysql5
* $wgResourceLoaderMaxQueryLength
* $wgDefaultSkin
* $wgDefaultUserOptions[...]
* $wgSyntaxHighlightDefaultLang

### 変更した項目 (ベースとなる1.35のLocalSettings.phpの値を変更するもの)

テスト環境と本番環境での違いなども含まれます。

* $wgSitename
* $wgMetaNamespace
* $wgServer
* $wgLogos
* $wgEmergencyContact
* $wgPasswordSender
* $wgDBname
* $wgDBuser
* $wgDBpassword
* $wgDBTableOptions
* $wgEnableUploads
* $wgShellLocale
* $wgSecretKey 
* $wgUpgradeKey


### 追加した設定項目 (ベースとなる1.35のLocalSettings.phpに記載されていないが追記するもの)

末尾に追加するLDAPProvider,LDAPAuthentication2関連の設定は別に記載しているため省略している。

* $wgGroupPermissions['*']['autocreateaccount'] 


# その他、作業中に気がついたことなど

なにかしら作業中に気がついた事は、このセクションにつらつらと残していくことにします。

## 設定値が実際どのように使われているか探索する

例に挙げられている設定の変数がどのような意味を持つのか、各extensionのWebページ等でパラメータを確認するか、直接tar.gzを展開し、中のコードを眺めることができます。

設定例の中に、"LDAPAuthorizationAutoAuthRemoteUserStringParser" というやたら長い設定項目があって、気になったのですが、結論からいうとこの変数はどこからも参照されていないようです。

```bash:/var/www/html/mediawiki/extensions/以下を検索する例
$ cd /var/www/html/mediawiki/extensions/
$ find . -type f -exec grep -i AutoAuthRemoteUserStringParser {} \; -print
                "AutoAuthRemoteUserStringParserRegistry": {
                "AutoAuthRemoteUserStringParser": {
./LDAPAuthorization/extension.json
                $remoteUserStringParserKey = $this->config->get( 'AutoAuthRemoteUserStringParser' );
                $remoteUserStringParserReg = $this->config->get( 'AutoAuthRemoteUserStringParserRegistry' );
./LDAPAuthorization/src/Hook/AuthRemoteuserFilterUserName.php
```

これはLDAP HubのExample 1の中で使われているLDAPAuthorizationAutoAuthRemoteUserStringParser変数から違和感を感じたので調査した時の出力を掲載しています。このような変数はなく、LDAPAuthorizationの変数リストをみても、AutoAuthRemoteUserStringParser が定義されているだけなので、以前使われていたか、おそらくtypoと思われます。

状況によって、コードを確認し設定値がどのように使われるか、あるいは定義されているか、確認するのが良いでしょう。

## デバッグ環境の設定

LDAP Hubのページにデバッグ方法について言及があります。実際に使用した設定は以下のとおりです。

```php:LocalSettings.phpから抜粋(先頭と最下部に追記しているコード)
<?php
error_reporting( -1 );
ini_set( 'display_errors', 1 );
$wgDebugDumpSql = true;
$wgDebugLogFile = "/tmp/debug-{$wgDBname}.log";
$wgDebugComments = true;
$wgShowExceptionDetails = true;
...

$wgDebugLogGroups['PluggableAuth'] = 
$wgDebugLogGroups['LDAP'] = 
$wgDebugLogGroups['MediaWiki\\Extension\\LDAPProvider\\Client'] = 
$wgDebugLogGroups['LDAPGroups'] = 
$wgDebugLogGroups['LDAPUserInfo'] = 
$wgDebugLogGroups['LDAPAuthentication2'] = 
$wgDebugLogGroups['LDAPAuthorization'] = '/tmp/LDAP.log';
```

この設定はLocalSettings.phpやldapprovider.jsonファイルを調整する際に利用していました。

## 内部エラーとなって正常に表示されない

設定を確認する作業で動くと思って挿入した設定が間違っていたのか、うまく動かない状況になりました。

```text:トップページにアクセスした時に表示されたメッセージ
[6696afa2f755ab158f63f5ee] /mediawiki/index.php Error from line 35 of /var/www/html/mediawiki/extensions/LDAPAuthentication2/src/Setup.php: Call to a member function isSpecial() on null

Backtrace:
...
```

例えば、```wfLoadExtension( 'LDAPAuthorization' );```のような設定を有効にしているのに、ldapprovider.jsonなどのファイルに"authorization"エントリがないと同様のエラーになりました。

とりあえずモジュールのロードは最小限のセットから徐々に増やしていくことで解決しています。

## Synology NASのLDAPサーバー(#1)との連携

SynologyのNASにはLDAPサーバー機能が組み込まれていて、統合ログインなどの機能を提供しています。
ここでは少人数で利用しているLDAPサーバーとの連携を試しています。

Synology NAS上のLDAPサーバーに対するldapsearchの結果は以下のとおりです。

```bash:Synology上のLDAPサーバー上のDirectoryの状態
$ ldapsearch -x -H ldaps://synas.example.com:636 -b cn=users,dc=synas,dc=example,dc=com 'uid=user01'
# extended LDIF
#
# LDAPv3
# base <cn=users,dc=synas,dc=example,dc=com> with scope subtree
# filter: uid=user01
# requesting: ALL
#

# user01, users, synas.example.com
dn: uid=user01,cn=users,dc=synas,dc=example,dc=com
objectClass: top
objectClass: posixAccount
objectClass: shadowAccount
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: apple-user
objectClass: sambaSamAccount
objectClass: sambaIdmapEntry
objectClass: extensibleObject
cn: user01
uid: user01
uidNumber: 1000003
gidNumber: 1000001
loginShell: /bin/sh
homeDirectory: /home/user01
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
shadowExpire: -1
shadowInactive: 0
shadowFlag: 0
sn: user01
mail: user01@synas.example.com
authAuthority: ;basic;
sambaSID: S-1-5-21-3786949212-3348748899-2943954552-1008
sambaPasswordHistory: 00000000000000000000000000000000000000000000000000000000
 00000000
sambaAcctFlags: [xxxxxxxxxxxx]
displayName: user01
memberOf: cn=users,cn=groups,dc=synas,dc=example,dc=com
telephoneNumber: xxxx
gecos: User01 Admin
apple-generateduid: 4EEA5A3A-9942-43A3-9733-73F698D3736A

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
```

ディレクトリの構造はposixAccountとinetOrgPersonの他にも様々なschemaに対応しているので、一般的なLDAPサーバーに対応しているアプリケーションでも利用できると思います。SynologyのNASにはTLS接続ができるように秘密鍵を設定しているので、ldapsで接続するようになっています。

Mediawikiではldapprovider.jsonの接続先を変更するだけで利用できるようになりました。小規模な環境では多用途NASサーバーに管理を集中するのもありかもしれません。

## 基幹OpenLDAPサーバー(#2)との連携時の問題点

LDAPサーバーを利用しているといっても、そのディレクトリ構成は様々です。
ActiveDirectory(AD)ではユーザーディレクトリに所属グループのリストを含まれていますが、OpenLDAPの場合はmemberOf overlayを利用する必要があり一般的ではない印象です。

ActiveDirectory(AD)を前提としている構成では、このユーザーのディレクトリ情報に所属グループが含まれていることを前提とする場合が多い印象があり、LDAPプロトコルを利用していながら、AD以外には対応できない製品が存在する残念な状況を生み出しています。

このように多様なディレクトリ構造に対応することは難易度が高くなるため、設定も複雑になる傾向があります。

基幹サーバーはOpenLDAPとしては一般的な構成です。しかしADやSynologyのLDAPサーバーとも構成が違うためそれなりの設定を行う必要がありました。

### LDAPグループのMediawiki内部での取り扱い

MediawikiのLDAPProviderの"grouprequest"パラメータのデフォルト設定ではGroupUniqueMember.php が指定されています。この中ではfilterに指定するattribute名がuniqueMemberに固定されています。

```php:extensions/LDAPProvider/src/UserGroupsRequest/GroupUniqueMember.php抜粋
$groups = $this->ldapClient->search(
     "(&(objectclass=groupOfUniqueNames)(uniqueMember=$userDN))",
     $baseDN, [ $dn ]
);
```

そのため、この"grouprequest"パラメータは利用するLDAPサーバーの構造に合わせて適宜変更する必要があります。
今回利用しているのは、objectClass: groupOfNames なので、このままでは動作しません。

https://www.mediawiki.org/wiki/Topic:Vcpn9bycm7fyyq23 で指摘されているように、"grouprequest"の指定を変更することで、この挙動を変更させることができます。

```json:ldapprovider.jsonの抜粋
    "grouprequest": "MediaWiki\\Extension\\LDAPProvider\\UserGroupsRequest\\Configurable::factory",
    "groupbasedn": "ou=MailGroup,ou=proxy,dc=example,dc=com",
    "groupobjectclass": "*",
    "groupattribute": "member"
```

最初から Configurable.php で良いと思いますが、設定可能なパラメータについては LDAPProvider のページに書いてあります。例えば、"groupattribute"はConfigurable.php が指定された時にのみ有効なことが記載されています。

## ログインした後にユーザーの本名が適切に設定されない

ldapprovider.jsonに設定している項目については、ドキュメントに様々な設定方法が分散しています。
最新の設定方法はWikiのExtensionの各ページを参照する必要があります。

例えば、"userinfo"について、次のような設定が掲載されています。

```json:LDAPAuthorizationに掲載されているPHP形式の設定をJSONに変更したもの
   ...
   "userinfo": {
      "email": "mail",
      "realname": "cn",
      "properties.gender": "gender"
   },
   ...
```

似たような記述は他でも見ることができます。LDAPUserInfoの設定では変数名に"userinfo.attributes-map"という記述があるため、意図した動作をさせるためには次のように記述する必要があります。

```json:LDAPUserInfo拡張を利用するための設定方法
   ...
   "userinfo": {
      "attributes-map": {
          "email": "mail",
          "realname": "cn",
          "properties.gender": "gender"
      }
   },
   ...
```

LDAPProviderのdocs/ldapprovider.jsonのサンプルにも同様に正しい設定が掲載されているので、設定方法については最新のモジュールのサンプルを確認するのが良いでしょう。

### ユーザー名の先頭が大文字になってしまう

これはMediawikiの仕様で変更することはできません。
詳細は https://www.mediawiki.org/wiki/Topic:R97c76vpuokaqby9 で述べられているとおりです。

$wgCapitalLinkOverridesを使えばできるはず、などの情報はありますが、https://www.mediawiki.org/wiki/Manual:$wgCapitalLinkOverrides にあるように、UserのNamespaceでは利用できないと注釈で述べられています。

リクエストはあるものの、現状では副作用が多くて実現できないようです。

## LDAPドメイン名を変更すると接続できなくなる

例えば、これまで ```$wgLDAPDomainNames = array('LDAP_ID' );``` をLdapAuthenticationで利用していた場合で、今回から、```$LDAPProviderDefaultDomain = 'LDAP'``` ドメイン名を変更した場合に、次のようなメッセージが表示されて、ログインできない場合がありました。

```text:エラーメッセージ
DomainConfigFactory.php: No configuration available for domain mediawiki: "LDAP_ID"
```

どこにも設定されていない "LDAP_ID" が表示されて、ちょっとした悪夢ですが、MySQLのldap_domainsテーブルにこの値が格納されていて参照されているのが原因でした。

```text:ldap_domainsテーブルの内容
mysql> select * from ldap_domains;
+-----------+---------+---------+
| domain_id | domain  | user_id |
+-----------+---------+---------+
|         1 | LDAP_ID |       4 |
+-----------+---------+---------+
1 row in set (0.00 sec)
```

この現象は、設定ファイル(ldapprovider.json)のドメイン名を変更して、さらに、同じユーザーIDを引き続き利用している場合に発生することになります。今回は接続先のLDAPサーバーは変更したものの、ユーザーIDは他に合わせて同じものを利用していたので、設定ファイル中のdomainを引き継げば良かったのですが、サーバーが異なることから律儀に変更した事で、この現象が引き起されました。

このテーブルへの参照は extensions/LDAPProvider/src/UserDomainStore.php で行なわれていて、ldap_domainsテーブルにuser_idに対応するドメインが定義されている場合は、これ(LDAP_ID)をまず返し、該当する情報がない場合は、設定ファイルのデフォルト・ドメイン(LDAP)を返す実装になっています。

複数のLDAPサーバー定義が、ldapprovider.jsonにある場合で、同一のログイン用IDが定義されている場合(あるいは後からもう一方のLDAPサーバー上に同一ログイン用ID名を作成した場合)、なりすましを防ぐため最初にログインしたユーザー名を正とする仕様になっているようです。

とりあえず、このテーブルの情報を削除するか、domain名を変更するか、をすればログインできるようになりますが、削除してしまうと、userテーブルに存在しないIDでログインする最初のタイミングでしか、このテーブルの情報は更新されないようなので、セキュリティを向上させるという点では、domainの値をLDAP_IDからLDAPに変更する方法が良さそうです。

```sql:一括で旧ドメイン名を新ドメイン名に更新するSQL文
mysql> update ldap_domains set domain = 'LDAP' where domain = 'LDAP_ID';
```

# さいごに

Mediawikiはファイル共有のような用途では必ずしも便利とはいえませんが、LDAPなどで利用者を適切に管理すれば、情報共有の場所としては良く出来ていると思います。

バージョンアップはある程度の頻度で行なう必要はありますが、きちんとメンテナンスされていて、たまに使えなくなりますが拡張機能も豊富にあるので、環境を改善するためのツールとしてもっと普及してくれれば良いなと思っています。

以上