Solr6のSearchComponentを自作する

http://qiita.com/aiyi/items/ed56869845333613fa80
以前ManifoldCF2.4 Security SearchComponent pluginという検索時のセキュリティトリミングを実現したプラグインについてご紹介しましたが、こちらのプラグインはActive Directory前提で作られているので、Active Directory使用しない場合は自作したSearchComponentでセキュリティートリミングをチャレンジしてみました。

**1.EclipseでMavenプロジェクト作成**
まずSolrのSearchComponent開発はJAVAなので、Eclipseを使用しましました。ManifoldCF版を参考にし、中を覗いてみるとApache Mavenを使ってるっぽいなので、Mavenプロジェクトの骨格を作成し、SolrのSearchComponentベースクラスとSolrCoreAwareインターフェースを参照するクラスを作成します。
(Ex:com.myhost.solr.mcf.SecuritySearchComponent)

**2.Authoriy Serviceについて**
ManifoldCFを配置したときに「AuthorityServiceBaseURL」に「http://localhost:8345/mcf-authority-service」 のWebServiceが置かれていますよね、これは問い合わせたSamAccountに対してそのアカウント自身と所属するすべての組織また匿名ユーザーのSIDを返しているAPIです。応答は

```
Security Token:
Active Directory SID:S-1-5-21-917266621-1342861121-1792158721-XXX
Active Directory SID:S-1-5-21-917266621-1342861121-1792158721-XXX
...
```
のようにSIDをプレインテキストで返しています。こんなイメージで自身が使うセキュリティートークンを返すAPIが必要です。このAPIはのちSearchComponent（Java）から呼ばれるのでアプリケーションに認証が必要な場合は要注意です。実際の作りはアプリによって違うので、具体的な作りかたは割愛します。

**3.allowとdenyについて**
ここはトークンがどうやって働くかを説明します。
下準備としてドキュメントに設定したアクセストークンをインデックスに投入する必要があります。
Solrのmanaged_schema.xmlに以下のfieldをあらかじめ用意しておいてください。nameは任意ですが、allow、denyは明記したほうがいいでしょう。

```managed_schema.xml
...
<field name="allow_token" type="string" indexed="true" stored="true"
    multiValued="true" required="true" default="__nosecurity__"/>
<field name="deny_token" type="string" indexed="true" stored="true"
    multiValued="true" required="true" default="__nosecurity__"/>
...
```
これでScriptUpdateProcessorを用いアクセストークンを投入できます。以前の記事はこの辺お話しました。
http://qiita.com/aiyi/items/a45d1a6463c0d0c3bf52

今度はJava側で先ほど作ったWebAPIからセキュリティートークンを取得する実装例です、HttpGetを使います。

```SecuritySearchComponent.java
...
HttpGet method = new HttpGet("http://mywebservice:port/my-authority-service/userToken?user=XXXX");
HttpResponse httpResponse = client.execute(method);
InputStream is = httpResponse.getEntity().getContent();
List<string> accessTokens=getAccessToken(is);
...
```

こちらで取得したトークンをそれぞれTermQueryを使い、Allow,Denyのインデックスと照合します。
ただ、アクセストークンはひとつもない場合は、ユーザーに0件で返すわけには行きません。以下のQeuryを使い、allow,deny両方"\__nosecurity__"となっているアイテムは匿名閲覧可能なので探して返すようにしましょう。

```SecuritySearchComponent.java
BooleanQuery.Builder bq = new BooleanQuery.Builder();
Query allowDocument = new TermQuery(new Term("allow_token","__nosecurity__"));
Query denyDocument = new TermQuery(new Term("deny_token","__nosecurity__"));
bq.add(allowDocument);
bq.add(denyDocument);
bq.build();
```

トークンが取得できた場合、allow_tokenに「Should」、deny_tokenに「MUST_NOT」というクエリ条件で実行し論理和をとれば、このユーザがアクセス権のあるドキュメントを割り出すことができまます。
詳しくはここ⇒http://www.kakiro-web.com/lucene/query/query-base.html

```SecuritySearchComponent.java
for (String accessToken : accessTokens)
{
bq.add(new TermQuery(new Term("allow_token",accessToken)),BooleanClause.Occur.SHOULD);
bq.add(new TermQuery(new Term("deny_token",accessToken)),BooleanClause.Occur.MUST_NOT);
}
bq.build();
```

**4.SearchComponentの配置**
ビルドでできたjarファイルは、Solrの側のlibフォルダーに配置し、solrconfig.xmlを以下のように記載

```xml:solrconfig.xml
...
<searchComponent name="MySecuritySearchComponent"
  class="com.myhost.solr.mcf.SecuritySearchComponent">
  <str name="AuthorityServiceBaseURL">http://mywebservice:port/my-authority-service</str>
</searchComponent>
...
<requestHandler name="/select" class="solr.SearchHandler">
...
  <arr name="last-components">
    <str>MySecuritySearchComponent</str>
  </arr>
  ...
</requestHandler>
...
```