LDAP設定
From LimeSurvey Manual
概要
この機能を利用するには、config.phpでLDAPサポートを有効にし、config/ldap.phpでLDAPパラメータを設定する必要があります。
config.phpでLDAPを有効にする
- $enableLdap: LimeSurveyでLDAP機能を使用する場合は、このパラメータをtrueに設定する必要があります(既定ではfalseに設定されています)。
'config'=>array( 'debug'=>0, 'debugsql'=>0, 'enableLdap'=>true, )
LDAPサーバーを定義する
まず、 "application/config/ldap.php"にLDAPサーバー接続オプションを定義します。各サーバーには、次のオプションがあります。
- $serverId: このLDAPサーバーを識別する整数。クエリ定義でサーバーを特定のクエリにバインドするために使用されます。
- $ldap_server[$serverId]['server']: LDAPサーバーのIPアドレスまたはDNS名。SSLで保護された接続(LDAPsまたはLDAP+Start-TLS)を使用する場合、この名前はサーバーのCertificate CN(またはSubjectAlternativeName)に対応する必要があります。
- $ldap_server[$serverId]['protoversion']: あなたのサーバーでサポートされているプロトコルに応じて、 'ldapv2'または 'ldapv3'にします。'ldapv3'が推奨プロトコルです。ただし、暗号化された接続を使用する場合、LDAPsは'ldapv2'モードでサポートされ、Start-TLSは'ldapv3'の暗号化方式であることに注意してください。
- $ldap_server[$serverId]['encrypt']: 使用される暗号化方法を定義します。'ldaps'は 'ldav2'サーバーでサポートされ、'start-tls'は'ldapv3'サーバーでサポートされます。'none'キーワードは、クリアテキストでLDAP通信するときに使用されます。
- 'ldaps'または'start-tls'による暗号化においては、ウェブサーバーはLDAPサーバーの証明書を確認できなければならないことを忘れないでください。したがって、openldapライブラリーに認証局を定義する必要があります(通常、これはlinuxの/etc/openldap/ldap.confファイルで行います)。
- $ldap_server[$serverId]['referrals']: 紹介(referral)に従うかどうかを定義するブール型パラメータです(ActiveDirectoryではfalseを使用します)。
- $ldap_server[$serverId]['encoding']: これは、LDAPディレクトリーが文字列を格納するために使用するエンコーディングを指定するオプションのパラメータです。通常、このパラメータを設定する必要はありません。既定のエンコーディングである'utf-8'は、LDAPディレクトリーの標準エンコーディングです。ただし、Active Directoryを使用していて特殊な文字を含む文字列をインポートできない場合は、このパラメータをあなたの地域で使用されているエンコーディングに設定してください(たとえば、西ヨーロッパの場合は'cp850')。CSVファイルからのトークンインポートのGUIにある"ファイルの文字セット"のドロップダウンリストには、サポートされるエンコーディングがすべて掲載されており、それを参照できます。
次に、ディレクトリーへのアクセスに必要な認証を定義する必要があります。'匿名'アクセスが許可されている場合は、次の2つのパラメータを設定しないでください。そうでない場合は、次の通り設定してください。
- $ldap_server[$serverId]['binddn']: ディレクトリーを読み取ることができる 'LDAP'ユーザーのDN。
- $ldap_server[$serverId]['bindpw']: 上記のLDAPユーザーのパスワード。
他のLDAPサーバーを定義する必要がある場合は、次の行を追加してserverIDを増やし、新しいパラメーターを定義します。
- $serverId++
config/ldap.phpでクエリーを定義する
注意: これらのパラメーターのいずれかでLDAP属性名が必要な場合は、小文字のみの名称を使用してください(例えば、displaynameとし、displayNameとはしない) 。
設定のサンプルが記載されているconfig/ldap.phpファイルを参照してください。
シンプルなクエリー
シンプルなクエリーから始めましょう。 これらのクエリーは、属性と場所に基づいてLDAPエントリーフィルタリングするだけです。ActiveDirectoryを照会するなら、通常はこれで十分です。
- $query_id: LDAPクエリーのIDです。
- $ldap_queries[$query_id]['ldapServerId']: クエリーを特定のサーバーにバインドします。
- $ldap_queries[$query_id]['name']: クエリを説明する文字列。GUIに表示されます。
- $ldap_queries[$query_id]['userbase']: ユーザーの検索に使用するルートDN。
- $ldap_queries[$query_id]['userfilter']: 検索対象となるユーザーのエントリーを選択するためのフィルタです。 かっこで囲む必要があります。
- $ldap_queries[$query_id]['userscope']: ユーザのLDAP検索のスコープです('base'、'one'、'sub')。
- $ldap_queries[$query_id]['firstname_attr']: トークンエントリーの名(Firstname)フィールドにマップされるLDAP属性。
- $ldap_queries[$query_id]['lastname_attr']: トークンエントリの姓(Lastname)フィールドにマップされるLDAP属性。
- $ldap_queries[$query_id]['email_attr']: トークンエントリの電子メールアドレスフィールドにマップされるLDAP属性。
必要に応じて、ディレクトリーからさらに情報を取得できます。
- $ldap_queries[$query_id]['token_attr']: トークンコードにマップされるLDAP属性。
- $ldap_queries[$query_id]['language']: ユーザー言語コードにマップされるLDAP属性。
- $ldap_queries[$query_id]['attr1']: attribute_1フィールドにマップされるLDAP属性。
- $ldap_queries[$query_id]['attr2']: attribute_2フィールドにマップされるLDAP属性。
DNメンバーとグループクエリーの結合
より複雑なクエリーを定義する方法を見てみましょう。
次のクエリは、LDAPグループを探す最初のLDAP検索を使用しています。LDAPグループとは、以下の形式でユーザーのエントリーへの参照を含むLDAPエントリです。
- ユーザーID(例: posixGroups) ==> 次のセクションを参照
- ユーザーDN(例: groupofnames、groupofuniquenames) ==> 下記参照
ここでは、ユーザーDNを含むグループを扱います。
- 上記で説明した$query_id、$ldap_queries[$query_id]['ldapServerId']、$ldap_queries[$query_id]['name']を定義します。
次に、グループフィルターパラメーターを定義します。
- $ldap_queries[$query_id]['groupbase']: グループエントリーの検索を開始するルートDN。
- $ldap_queries[$query_id]['groupfilter']: 検索対象となるグループエントリーを選択するLDAPフィルタ。
- $ldap_queries[$query_id]['groupscope']: グループのLDAP検索のスコープです('base'、'one'、'sub')。
- $ldap_queries[$query_id]['groupmemberattr']: ユーザーのエントリーへの参照を含むグループエントリー内のLDAP属性の名前。
- $ldap_queries[$query_id]['groupmemberisdn']: TRUE
この時点で、最初のLDAP検索で選択したグループに対応するユーザーが検索されるよう設定されています。ただし、これらの"ユーザー候補"のどれを選択するかは、別のフィルターを適用することで制限できます。これはもちろんオプションです。
- $ldap_queries[$query_id]['userbase']: ユーザーのLDAP検索のベースDNが選択されます(このベースに一致するユーザーのみとなる)。
- $ldap_queries[$query_id]['userscope']: ユーザーLDAP検索のスコープが選択されます(ユーザベース+スコープに一致するユーザのみとなる)。
- $ldap_queries[$query_id]['userfilter']: さらに選択するため、各ユーザ候補エントリーに適用されるフィルタです(その属性によって選択される)。
UIDメンバーとグループクエリーの結合
グループメンバーがユーザーのUIDで、ユーザーのDNではない場合、結合されたグループクエリーを定義する方法を見てみましょう。
DNメンバーを持つグループクエリーの場合、まずLDAPグループエントリーを探し、メンバーを取得します。得られたメンバーは、ユーザー検索フィルターで使用され、対応するエントリーを検索します。したがって、グループ内のメンバーUIDと一致するユーザーエントリーのユーザー属性を定義する別のパラメーターを設定する必要があります。
必要なパラメータを確認しましょう。
- 上記のように$query_id、$ldap_queries[$query_id]['ldapServerId']、$ldap_queries[$query_id]['name']を定義します。
次に、グループフィルターパラメーターを定義します。
- $ldap_queries[$query_id]['groupbase']: グループエントリーの検索を開始するルートDN。
- $ldap_queries[$query_id]['groupfilter']: 検索対象となるグループエントリーを選択するLDAPフィルタ。
- $ldap_queries[$query_id]['groupscope']: グループのLDAP検索のスコープです('base'、'one'、'sub')。
- $ldap_queries[$query_id]['groupmemberattr']: ユーザーのエントリーへの参照を含むグループエントリー内のLDAP属性の名前。
- $ldap_queries[$query_id]['groupmemberisdn']: FALSE;
- $ldap_queries[$query_id]['useridattr']: グループメンバーにあるUIDと一致しなければならないユーザー属性の名前。
この時点で、最初のLDAP検索で選択されたグループに対応するユーザーUIDを検索できるようにすべてが設定され、ユーザー検索フィルターに自動的にセットされます。
ただし、これらの「ユーザー候補」のどれを選択するかは、メンバーUIDから計算される自動ユーザーフィルターを適用することによって制限することができます。 これはもちろん、オプションです。
- $ldap_queries[$query_id]['userbase']: ユーザーのLDAP検索のベースDNが選択されます(このベースに一致するユーザーのみとなる)。
- $ldap_queries[$query_id]['userscope']: ユーザーLDAP検索のスコープが選択されます(ユーザベース+スコープに一致するユーザのみとなる)。
- $ldap_queries[$query_id]['userfilter']: さらに選択するため、各ユーザ候補エントリーに適用されるフィルタです(その属性によって選択される)。
Active Directoryではどうなるか?
Active Directory(AD)は、LDAPプロトコルを使用して照会できるMicrosoftのレジストリーです。
LimeSurveyトークンクエリにそのコンテンツを使用することは可能ですが、これにはADの構成方法に関する知識が必要です。
- LDAPルートベースは、dc=my_windows_domain_name,dc=dns_suffix2,dc=dns_suffix1です。
==> たとえば、あなたの会社が、DNSドメイン'my-company.com'を所有し、Windowsドメインが'employees'である場合、ルートベースは、dc=employees,dc=my-company,dc=com となります。
- ユーザーおよびユーザーグループは、cn=Users,dc=my_windows_domain_name,dc=dns_suffix2,dc=dns_suffix1 の下に格納されます(ou=usersではありません)
- Active Directoryグループ:
- グループオブジェクトには、'member'属性にメンバーのDNが含まれています。
- グループメンバーシップは、各ユーザーエントリーのmemberOf属性にも格納されます。この属性には、ユーザーが所属するグループのDNが含まれます。
- いくつかのグループでは、CN=Builtin,dc=my_windows_domain_name,dc=dns_suffix2,dc=dns_suffix1 にあります。
- 例: cn=Administrator,CN=Builtin,dc=my_windows_domain_name,dc=dns_suffix2,dc=dns_suffix1
場合によっては、Active Directoryを照会するのは簡単ではないので、Active Directoryの情報を得るための設定例を以下に示します。
//Active Directoryサーバーへの接続
$serverId=0;
$ldap_server[$serverId]['server'] = "10.10.10.10";
$ldap_server[$serverId]['port'] = "389";
$ldap_server[$serverId]['protoversion'] = "ldapv2";
$ldap_server[$serverId]['encrypt'] = "none"; // ほとんどのAD LDAPサーバーでは、デフォルトで暗号化が設定されていません
$ldap_server[$serverId]['referrals'] = false;
$ldap_server[$serverId]['binddn'] = "domain\\user";
$ldap_server[$serverId]['bindpw'] = "userpassword";
//$ldap_server[$serverId]['binddn'] = "CN=user,OU=user_group,DC=xxx,DC=yyy"; これはActive Directoryでは動作しません。そのため、"domain\\user"を使用する必要があります
//次に、Active Directoryのすべてのアクティブなユーザを取得するためのサンプルクエリを示します。
$query_id=0;
$ldap_queries[$query_id]['ldapServerId'] = 0;
$ldap_queries[$query_id]['name'] = 'Staff with an enabled account';
$ldap_queries[$query_id]['userbase'] = 'OU=USER_GROUP,DC=xxx,DC=yyy';
$ldap_queries[$query_id]['userfilter'] = '(&(objectClass=user)(!(userAccountControl=514)))';
//(!(userAccountControl=514)) Active Directoryにアクティブユーザーを照会することはできませんが、アクティブでないユーザーを照会することはできます
$ldap_queries[$query_id]['userscope'] = 'sub';
$ldap_queries[$query_id]['firstname_attr'] = 'givenname';
$ldap_queries[$query_id]['lastname_attr'] = 'sn';
$ldap_queries[$query_id]['email_attr'] = 'mail';
$ldap_queries[$query_id]['token_attr'] = ''; // phpsvによる自動トークン生成のために空のままにする
$ldap_queries[$query_id]['language'] = '';
$ldap_queries[$query_id]['attr1'] = '';
$ldap_queries[$query_id]['attr2'] = '';
//Active Directoryではグループフィルタリングができないので、ユーザーのmemberOf属性を追加する必要があります。Active Directory内のグループ"samplegroup"のメンバーであるすべてのアクティブユーザーを取得するサンプルクエリを次に示します。
$query_id++;
$ldap_queries[$query_id]['ldapServerId'] = 0;
$ldap_queries[$query_id]['name'] = 'All members of samplegroup';
$ldap_queries[$query_id]['userbase'] = 'OU=USER_GROUP,DC=xxx,DC=yyy';
$ldap_queries[$query_id]['userfilter'] = '(&(objectClass=user)(memberOf=CN=samplegroup,OU=Group Global,OU=USER_GROUP,DC=xxx,DC=yyy)(!(userAccountControl=514)))';
$ldap_queries[$query_id]['userscope'] = 'sub';
$ldap_queries[$query_id]['firstname_attr'] = 'givenname';
$ldap_queries[$query_id]['lastname_attr'] = 'sn';
$ldap_queries[$query_id]['email_attr'] = 'mail';
$ldap_queries[$query_id]['token_attr'] = ''; // phpsvによる自動トークン生成のために空のままにする
$ldap_queries[$query_id]['language'] = '';
$ldap_queries[$query_id]['attr1'] = '';
$ldap_queries[$query_id]['attr2'] = '';
ユーザークエリーのもう1つの例:
$ldap_queries[$query_id]['userfilter'] = '(&('''objectCategory=Person''')(objectClass='''user''')(!('''userAccountControl=514''')))'; // ADは通常の方法では有効なアカウントを認識できないため、代わりにユーザーが無効になっていないことを確認します
- 設定ファイルで示唆されているように、電子メールアドレスのないユーザを無視するよう、ユーザフィルタに (!(email=*)) を追加することを検討してください。
グループクエリーの例:
$ldap_queries[$query_id]['groupfilter'] = '(&(objectClass='''group''')(cn=Domain Admins))'; // ADはグループに標準の属性名を使用しないので、代わりにこの例を使用してください。
Creating one query per Active Directory group automatically
If you keep the groups for your survey participants in one organizational unit (OU), you do not have to write a query for each group. The following code lists all groups in that OU and creates one query per group. The query includes all enabled members of the group, including members of nested groups.
Add the code to config/ldap.php after your server and query definitions and before the line //DO NOT CHANGE BELOW HERE. Then set the four variables at the top:
- $groupServerId: the $serverId of the server to use;
- $groupContainer: the DN of the OU that holds the groups. Only groups directly in this OU are listed, not groups in sub-OUs;
- $groupUserBase: the root DN under which the group members are searched;
- $groupNameAttr: the group attribute (in lower case) used as the query name in the GUI, for instance 'info' (the "Notes" field in "Active Directory Users and Computers") or 'description'. If a group has no value in this attribute, its cn is used.
$groupServerId = 0;
$groupContainer = 'OU=Survey groups,DC=xxx,DC=yyy';
$groupUserBase = 'DC=xxx,DC=yyy';
$groupNameAttr = 'info';
</div>
<div lang="en" dir="ltr" class="mw-content-ltr">
$srv = $ldap_server[$groupServerId];
$ds = ldap_connect(($srv['encrypt'] == 'ldaps' ? 'ldaps://' : 'ldap://') . $srv['server'] . ':' . $srv['port']);
if ($ds) {
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $srv['protoversion'] == 'ldapv3' ? 3 : 2);
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
// Never send the bind password if Start-TLS was requested but failed
$secure = $srv['encrypt'] != 'start-tls' || @ldap_start_tls($ds);
$bound = $secure && (empty($srv['binddn']) ? @ldap_bind($ds) : @ldap_bind($ds, $srv['binddn'], $srv['bindpw']));
$result = $bound ? @ldap_list($ds, $groupContainer, '(objectCategory=group)', array('cn', $groupNameAttr)) : false;
$groups = $result ? ldap_get_entries($ds, $result) : array('count' => 0);
for ($i = 0; $i < $groups['count']; $i++) {
$query_id++;
$ldap_queries[$query_id]['ldapServerId'] = $groupServerId;
$ldap_queries[$query_id]['name'] = isset($groups[$i][$groupNameAttr][0]) ? $groups[$i][$groupNameAttr][0] : $groups[$i]['cn'][0];
$ldap_queries[$query_id]['userbase'] = $groupUserBase;
// Enabled users with an email address that are members of the group, directly or through nested groups
$ldap_queries[$query_id]['userfilter'] = '(&(objectCategory=person)(objectClass=user)(mail=*)'
. '(!(userAccountControl:1.2.840.113556.1.4.803:=2))'
. '(memberOf:1.2.840.113556.1.4.1941:=' . ldap_escape($groups[$i]['dn'], '', LDAP_ESCAPE_FILTER) . '))';
$ldap_queries[$query_id]['userscope'] = 'sub';
$ldap_queries[$query_id]['firstname_attr'] = 'givenname';
$ldap_queries[$query_id]['lastname_attr'] = 'sn';
$ldap_queries[$query_id]['email_attr'] = 'mail';
$ldap_queries[$query_id]['token_attr'] = '';
$ldap_queries[$query_id]['language'] = '';
$ldap_queries[$query_id]['attr1'] = '';
$ldap_queries[$query_id]['attr2'] = '';
}
ldap_unbind($ds);
}
Things to keep in mind:
- The code connects to the directory each time the "Import participants from LDAP" page is opened or submitted, so new groups appear without changing the configuration. If the connection or the bind fails, the page only shows the queries you defined by hand.
- The matching rule 1.2.840.113556.1.4.1941 (LDAP_MATCHING_RULE_IN_CHAIN) resolves nested groups. It only exists in Active Directory, so this example does not work with other LDAP servers. On those, use a combined group query for each group instead.
- To also list groups in sub-OUs of $groupContainer, replace ldap_list with ldap_search.
- To list groups from more than one OU, repeat the code with other values for the four variables.
Active Directory LDAP構造の詳細については、Active DirectoryのアーキテクチャーとActive Directoryの技術仕様を参照してください。