/*********************************************************************
 * All Rights reserved,Copyright (c) K-Opticom
 **********************************************************************
 *＜プログラム内容＞
 *   システム名      ：eo顧客基幹システム
 *   モジュール名    ：JFUCheckAuthTwoStepInfo
 *   ソースファイル名：JFUCheckAuthTwoStepInfo.java
 *   作成者          ：富士通
 *   日付            ：2021年08月30日
 *＜機能概要＞
 *   2段階認証設定チェック部品です。
 *＜修正履歴＞
 *   バージョン  修正日       修正者      修正内容
 *   v54.00      2021/08/30   FJ）西川  新規作成【ANK-4132-00-00】高リスク情報表示Web画面の2段階認証チェック機能追加
 *   v57.00      2022/02/21   FJ）西川  変更【ANK-4200-00-00】高リスク情報表示Web画面のチェック条件変更
 *   v62.00      2022/11/24   FJ）行武  変更【ANK-4332-00-00】【eo】生体認証パスワードレス認証導入対応（12月末リリース分）
 *   v66.00      2023/05/23   FJ）行武  変更【ANK-4407-00-00】【eo】パスキー導入対応
 *   
**********************************************************************/
package eo.web.webview.common;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.fujitsu.futurity.web.x00.JCCBusinessException;
import com.fujitsu.futurity.web.x00.JCCWebServiceException;
import com.fujitsu.futurity.web.x31.X31BWebBusinessLogic;
import com.fujitsu.futurity.web.x31.X31CWebConst;
import com.fujitsu.futurity.web.x31.X31SDataBeanAccess;
import com.fujitsu.futurity.web.x31.X31SDataBeanAccessArray;
import com.fujitsu.futurity.web.x31.X31SWebLog;
import com.fujitsu.futurity.web.x33.HttpDispatchContext;
import com.fujitsu.futurity.web.x33.X33CUtil;
import com.fujitsu.futurity.web.x33.X33WSessionController;

import eo.common.constant.JFUStrConst;
import eo.common.constant.JPCModelConstant;
import eo.web.webview.CommonInfoCF.CommonInfoCFConst;

/**
 * 2段階認証設定チェック部品です。
 * <br>
 * @author 富士通
 */
public class JFUCheckAuthTwoStepInfo
{

	/** 2段階認証設定取得コモンコンポーネント部品マップキー名 */
	private static final String CC_TITLE_FUSV034901 = "FUSV034901CC";

	/** サービスID */
	private static final String SVC_ID_FUSV0349 = "FUSV0349";

	/** 機能コード */
	private static final String FUNC_CODE = "func_code";

	/** サービスのINPUT項目 SYSID */
	private static final String KEY_SYSID = "key_sysid";

	/** サービスのOUTPUT項目 SYSID */
	private static final String SYSID = "sysid";

	/** 認証レベル */
	private static final String AUTHENTICATION_LEVEL = "authentication_level";

	/** 2段階認証エラー画面（CMP） */
	private static final String AUTHSTEP_ERROR_URL = "AUTHSTEP_ERROR_URL";

	/** 認証方法取得用のHTTPヘッダーキー名 */
	private static final String HEADER_ACR_KEY = "OIDC_CLAIM_acr";

	/** 認証方法を認証済として検索する文字列 */
	private static final String HEADER_ACR_SEARCH_WORD = "two-factor";

	/** テストモード取得用キー**/
	private static final String MODE_KEY = "AXM_TEST_MODE";

	/**
	 * 2段階認証設定チェック処理を行います。
	 * <br>
	 * @param bl 実行中のVIEWロジックインスタンス
	 */
	public static boolean isSetAuthTwoStep(X31BWebBusinessLogic bl)
	{
		X31SWebLog.DEBUG_LOG.debug("■■■■■☆☆☆2段階認証設定チェック処理実行開始！☆☆☆■■■■■");

		boolean isOkAuthTwoStep = false;
		try
		{
			isOkAuthTwoStep = JFUCheckAuthTwoStepInfo.callService(bl);
			X31SWebLog.DEBUG_LOG.debug("■■■■■☆☆☆2段階認証設定チェック処理実行終了！☆☆☆■■■■■");
		}
		catch (JCCWebServiceException jwse)
		{
			// 上記以外は混雑中エラー
			X31SWebLog.DEBUG_LOG.debug("2段階認証設定チェック【混雑中エラー】");
			throw new JCCBusinessException(JFUStrConst.ERROR_CODE_0004);
		}

		return isOkAuthTwoStep;
	}

	/**
	 * 2段階認証設定チェック処理を行います。
	 * サービス層にて、サービス判定チェックを行います。
	 * <br>
	 * @param bl 実行中のVIEWロジックインスタンス
	 */
	private static boolean callService(X31BWebBusinessLogic bl)
	{
		X31SDataBeanAccess commonInfoBean = bl.getCommonInfoBean();

		// ANK-4332-00-00 HTTPリクエストヘッダから認証方式を取得
		String session_id = bl.getSession().getViewParamId().getSessionID();
		X33WSessionController session_controller = X33CUtil.getSession(session_id);
		HttpServletRequest request = session_controller.getServletRequest();

		String requestAcr = request.getHeader(HEADER_ACR_KEY);

		// テストモード設定の取得
		String testMode = JCCWebCommon.getApplicationConst(MODE_KEY);
		if (null != testMode && "ON".equals(testMode.toUpperCase()))
		{
			// テストモード時の認証方式取得
			requestAcr = request.getParameter(HEADER_ACR_KEY);
		}

		if (!JFUWebCommon.isNull(requestAcr))
		{
			// 認証方法に所定の文字列を含む場合は認証済とし、「true」を返却
			if (requestAcr.contains(HEADER_ACR_SEARCH_WORD))
			{
				X31SWebLog.DEBUG_LOG.debug("2段階認証設定チェック([認証済の認証方法]" + HEADER_ACR_KEY + ":" + requestAcr + ""+")");
				return true;
			}
		}

		HashMap<String, Object> parentMap = new HashMap<String, Object>();

		// ■SYSID
		String sysId = null;
		// 共有フォームBean.ＷＥＢ新規情報
		X31SDataBeanAccessArray webNewInfoBeanArray = commonInfoBean.getDataBeanArray(CommonInfoCFConst.WEB_NEW_INFO);
		if (webNewInfoBeanArray != null)
		{
			X31SDataBeanAccess webNewInfoBean = webNewInfoBeanArray.getDataBean(JFUStrConst.I_ZERO);
			// 共有フォームBean.ＷＥＢ新規情報.ｓｙｓＩＤ
			sysId = webNewInfoBean.sendMessageString(CommonInfoCFConst.SYSID_06, X31CWebConst.DATABEAN_GET_VALUE);
		}

		if (isNullOrEmpty(sysId))
		{
			// 共有フォームBean.ＷＥＢ変更情報. ＳＳＯ情報. ＳＹＳＩＤ
			sysId = JFUWebCommon.getDataBeanItemByPath(commonInfoBean, JFUWebCommon.SSO_INFO + JFUWebCommon.SEP_0 + CommonInfoCFConst.SYSID_21);
		}

		if (isNullOrEmpty(sysId))
		{
			// SYSID未取得は後続処理を実行せずに処理を抜ける。
			X31SWebLog.DEBUG_LOG.debug("2段階認証設定チェック(SYSID取得不可)【チェック対象外】");
			throw new JCCBusinessException(JFUStrConst.ERROR_CODE_0002);
		}

		// 機能コード
		parentMap.put(FUNC_CODE, JPCModelConstant.FUNC_CD_1);
		// SYSID
		parentMap.put(KEY_SYSID, sysId);

		HashMap<String, Object> inputMap = new HashMap<String, Object>();
		HashMap<Object, Object> outputMap = new HashMap<Object, Object>();

		inputMap.put(CC_TITLE_FUSV034901, parentMap);

		// サービスIDをparamにセット
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put(X31CWebConst.TELEGRAM_INFO_USECASE_ID, SVC_ID_FUSV0349);

		// サービス呼び出し
		bl.invokeService(paramMap, inputMap, outputMap);

		if (outputMap.containsKey(CC_TITLE_FUSV034901))
		{
			HashMap returnMap = (HashMap)outputMap.get(CC_TITLE_FUSV034901);

			if (returnMap == null || !returnMap.containsKey(SYSID))
			{
				throw new JCCBusinessException(JFUStrConst.ERROR_CODE_0004);
			}

			if (returnMap.containsKey(SYSID))
			{
				String sysid = (String)returnMap.get(SYSID);
				if (sysid == null || JFUStrConst.EMPTY.equals(sysid))
				{
					throw new JCCBusinessException(JFUStrConst.ERROR_CODE_0004);
				}
			}

			if (returnMap.containsKey(AUTHENTICATION_LEVEL))
			{
				// 認証レベル
				Object authenticationLevel = returnMap.get(AUTHENTICATION_LEVEL);
				if ("0".equals(authenticationLevel) || "2".equals(authenticationLevel))
				{
					// 認証レベルが以下の場合に2段階認証設定チェックスキップ、または2段階認証設定済として「true」を返却。
					//「0：2段階認証なし・認証項目追加判定なし（eoID/パスワードのみ）」
					//「2：2段階認証」

					return true;
				}
			}
		}

		// HttpServletResponseオブジェクトの取得
		String sessionId = bl.getSession().getViewParamId().getSessionID();
		X33WSessionController sc = X33CUtil.getSession(sessionId);
		String authTwoStepUrl = JCCWebCommon.getApplicationConst(AUTHSTEP_ERROR_URL);
		HttpServletResponse res = ((HttpDispatchContext)sc.getContext()).getServletResponse();
		res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
		res.setHeader("Location", authTwoStepUrl);

		return false;
	}

	/**
	 * 値が設定されているか判定を行います。
	 * @param value 判定値
	 * @return true:未設定、false:設定
	 */
	private static boolean isNullOrEmpty(String value)
	{
		if (value == null || JFUStrConst.EMPTY.equals(value))
		{
			return true;
		}
		return false;
	}
}
