Fessの管理画面の全般設定で設定可能な項目を拡充 

Fessの管理画面にある「全般」設定ページで設定できる項目を大幅に増やしました。これまでsystem.propertiesファイルを直接編集する必要があった設定を、管理画面から変更できるようにしています。

背景

Fessでは、system.propertiesで多くの設定項目を管理していますが、すべてが管理画面から設定できるわけではありませんでした。設定を変更するためにサーバー上のファイルを直接編集する必要があり、運用の手間が発生していました。今回、管理画面の全般設定に45項目を追加し、ほぼすべての設定をブラウザから変更できるようにしました。

追加した設定項目

各セクションに追加した項目は以下の通りです。

システム設定

  • 検索ファイルプロキシ: ファイルプロキシの有効/無効
  • ブラウザロケール使用: 検索時にブラウザのロケールを使用するかどうか
  • SSOタイプ: SSO認証方式の選択(none、oic、saml、spnego、entraid)

クローラー設定

  • User Agent: クローリング時に使用するユーザーエージェント文字列

LDAP設定

  • Security Authentication: LDAP認証タイプ
  • Initial Context Factory: LDAPコンテキストファクトリのクラス名

通知設定

  • 詳細検索ページ通知: 詳細検索ページに表示する通知メッセージ
  • Slack Webhook URL: Slack通知用のWebhook URL
  • Google Chat Webhook URL: Google Chat通知用のWebhook URL

OpenID Connect設定(新規セクション)

クライアントID、クライアントシークレット、認証サーバーURL、トークンサーバーURL、リダイレクトURL、スコープ、ベースURL、デフォルトグループ、デフォルトロールの9項目を設定できます。

SAML設定(新規セクション)

SPベースURL、グループ属性名、ロール属性名、デフォルトグループ、デフォルトロールの5項目を設定できます。

SPNEGO設定(新規セクション)

Kerberos設定ファイルパス、ログイン設定ファイルパス、クライアント/サーバーモジュール名、事前認証のユーザー名/パスワード、Basic認証やNTLMプロンプトの有効/無効、localhost許可、委任許可、除外ディレクトリの12項目を設定できます。

Entra ID設定(新規セクション)

クライアントID、クライアントシークレット、テナントID、Authority URL、Reply URL、State TTL、デフォルトグループ、デフォルトロール、パーミッションフィールド、ドメインサービス利用の10項目を設定できます。

セキュリティへの配慮

クライアントシークレットやパスワードなどの機密情報は、管理画面上ではマスク表示(**********)されます。値が設定済みかどうかは確認でき、新しい値を入力して更新することも可能ですが、現在の値がそのまま表示されることはありません。

まとめ

今回の変更により、SSO関連の設定を含む45項目が管理画面から設定可能になりました。サーバー上のファイルを直接編集する必要がなくなるため、運用の効率化が期待できます。

関連リンク

Fessの管理画面でアクセス拒否時の監査ログを出力する 

Fessの管理画面で権限のないコンテンツにアクセスした際、これまではログが出力されずにリダイレクトされるだけだった。セキュリティ監査の観点から、アクセス拒否時にも監査ログを記録するようにした。

背景

Fessの管理画面では、ユーザーのロールに基づいてアクセス制御が行われている。権限のないページにアクセスするとUserRoleLoginExceptionが発生し、トップページへリダイレクトされる。しかし、この時点で監査ログが出力されていなかったため、不正アクセスの試行を検知・追跡できなかった。

変更内容

FessAdminActionでのアクセス拒否ログ出力

FessAdminAction.godHandPrologue()UserRoleLoginExceptionをキャッチした際に、activityHelper.accessDenied()を呼び出してログを記録するようにした。

@Override
public ActionResponse godHandPrologue(final ActionRuntime runtime) {
    try {
        return superGodHandPrologue(runtime);
    } catch (final UserRoleLoginException e) {
        activityHelper.accessDenied(getUserBean(), runtime.getRequestPath());
        return redirect(e.getActionClass());
    }
}

テスタビリティのため、super.godHandPrologue()の呼び出しをsuperGodHandPrologue()メソッドに抽出している。

ActivityHelperにACCESS_DENIEDアクションを追加

ActivityHelperaccessDenied()メソッドとACCESS_DENIED列挙値を追加した。ユーザー情報とリクエストパスをログに記録する。

public void accessDenied(final OptionalThing<FessUserBean> user, final String path) {
    final Map<String, String> valueMap = new LinkedHashMap<>();
    valueMap.put("action", Action.ACCESS_DENIED.name());
    valueMap.put("user", user.map(FessUserBean::getUserId).orElse("-"));
    valueMap.put("path", path);
    log(valueMap);
}

ログ出力例

通常フォーマットの場合:

action:ACCESS_DENIED    user:testuser   path:/admin/user/

ECSフォーマットの場合:

{
  "labels.action": "ACCESS_DENIED",
  "labels.user": "testuser",
  "labels.path": "/admin/user/"
}

ユーザーが未認証の場合はuser-として記録される。

まとめ

この変更により、管理画面への不正アクセス試行を監査ログから検知できるようになった。誰が、どのパスにアクセスしようとして拒否されたかが記録されるため、セキュリティインシデントの調査に活用できる。

FessのAI検索モードで会話履歴の最適化

FessのAI検索モードでは、セッション内の会話履歴をLLMに渡すことで文脈を維持した回答を生成しています。しかし、会話が長くなるとアシスタントの応答が大きくなり、コンテキストウィンドウを圧迫するという課題がありました。そこで、会話履歴のコンテキストの扱いを見直し、smart_summaryモードの導入やターンベースの履歴パッキングなどの改善を行いました。今後も調整していく可能性はありますが、現時点での変更内容を紹介します。

背景

AI検索モードでは、ユーザーとアシスタントの過去のやり取りを会話履歴としてLLMに渡しています。これにより「さっきの検索結果について詳しく教えて」といった文脈依存の質問に対応できます。

従来は、アシスタントの応答を履歴に含める際のデフォルトモードとしてsource_titles(参照したドキュメントのタイトルのみを残す)を使用していました。しかし、タイトルだけでは前の応答の内容を十分に把握できず、文脈が途切れるケースがありました。

smart_summaryモードの導入

新しいデフォルトモードとしてsmart_summaryを導入しました。このモードでは、長いアシスタント応答の先頭60%(直接的な回答部分)と末尾40%(まとめ部分)を保持し、中間部分を省略します。

[先頭60%: 直接的な回答]
...[omitted]...
[末尾40%: まとめ・結論]
[Referenced documents: ドキュメントタイトル1, タイトル2]

LLMの応答は一般的に、冒頭に質問への直接的な回答があり、末尾にまとめや結論が来る構成になっています。中間部分は詳細な説明や補足情報であることが多いため、省略しても文脈の維持に必要な情報は残りやすいという考え方です。

なお、応答が短い場合はそのまま全文が保持されます。

ターンベースの履歴パッキング

履歴をLLMに渡す際の詰め込み方式も改善しました。従来はメッセージ単位で個別に予算に収まるかを判定していたため、ユーザーの質問だけが入ってアシスタントの応答が入らない、といった不自然な切れ方が起きる可能性がありました。

新しい方式では、ユーザーメッセージとアシスタント応答をペア(ターン)として扱い、ターン単位で予算内に収まるかを判定します。これにより、質問と回答の対応関係が維持されます。

履歴設定のLlmClientへの移動

これまでfess_config.propertiesで静的に設定していた履歴関連のパラメータを、LlmClientインターフェースのメソッドに移動しました。

パラメータ説明デフォルト値
getHistoryAssistantMaxChars()アシスタントメッセージの最大文字数800
getHistoryAssistantSummaryMaxChars()サマリーの最大文字数800
getIntentHistoryMaxMessages()インテント検出用の最大メッセージ数6
getIntentHistoryMaxChars()インテント検出用の最大文字数3000

これにより、fess-llm-openai、fess-llm-ollama、fess-llm-geminiなどのLLMプラグインが、それぞれのモデルの特性に合わせてパラメータをオーバーライドできるようになりました。

その他の変更

  • 会話履歴の最大メッセージ数のデフォルトを20から30に増加
  • インテント検出用の履歴メッセージ数のデフォルトを4から6に増加し、文字数による予算制御も追加
  • 削除された設定プロパティ: rag.chat.history.max.charsrag.chat.history.assistant.max.charsrag.chat.history.assistant.summary.max.charsrag.chat.intent.history.max.messages

まとめ

今回の変更により、AI検索モードでの会話履歴の扱いがより効率的になりました。smart_summaryモードによって、限られたコンテキストウィンドウの中でも会話の文脈を維持しやすくなっています。また、LLMプラグインごとにパラメータを調整できるようにしたことで、モデルの特性に合わせた最適化が可能になりました。今後も実際の利用状況を見ながら調整を続けていく予定です。

詳細はPR #3084を参照してください。