SAMLユーザマッピングのジョブを作成する

標準機能では、IdPユーザとintra-martユーザを紐付けるには以下の方法があります。

・SAMLユーザマッピング画面からユーザ毎に登録する。
・SAMLユーザマッピング画面からCSVファイルを利用して、一括登録する

上記いずれの場合も、画面での操作が必要になります。

これを半自動化するために、SAMLユーザマッピングのCSVファイルを取り込み一括登録するジョブを作成します。
定期的にSAMLユーザマッピングのCSVファイルを作成し、ジョブスケジューラを利用してデータを取り込むことが可能です。

サンプルはシンプルなものとなっています。
必要であれば目的によってサンプルを改変して利用してください。

【サンプルの仕様】

ジョブパラメータ
path:CSVファイルパス(パブリックストレージからの相対パス)
prov_id:IdP登録時のID(IdP一覧画面から確認できます)

【サンプルの注意点】

・基本的に新規追加と変更を想定したシンプルなサンプルです。
・既存のデータ間のユーザの入れ替えには対応してません。(別途処理が必要です)
・トランザクション処理は行っていません。一件づつコミットが行われます。

package com.example.saml;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import jp.co.intra_mart.common.platform.log.Logger;
import jp.co.intra_mart.foundation.context.Contexts;
import jp.co.intra_mart.foundation.job_scheduler.Job;
import jp.co.intra_mart.foundation.job_scheduler.JobResult;
import jp.co.intra_mart.foundation.job_scheduler.JobSchedulerContext;
import jp.co.intra_mart.foundation.job_scheduler.annotation.Parameter;
import jp.co.intra_mart.foundation.job_scheduler.annotation.Parameters;
import jp.co.intra_mart.foundation.job_scheduler.exception.JobExecuteException;
import jp.co.intra_mart.foundation.saml.mapping.SAMLMappingManager;
import jp.co.intra_mart.foundation.saml.mapping.entity.ImsamlUserMapping;
import jp.co.intra_mart.foundation.saml.mapping.exception.IdpNotExistException;
import jp.co.intra_mart.foundation.service.client.file.PublicStorage;

public final class SamlMappingImporterJob implements Job {

    private static String PATH_KEY = "path";
    private static String PROV_ID = "prov_id";

    public SamlMappingImporterJob() {
    }

    @Override
    @Parameters({@Parameter(key = "prov_id", value = ""),@Parameter(key = "path", value = "saml_mapping.csv")})
    public JobResult execute() throws JobExecuteException {

        final Logger logger = Logger.getLogger();

        // ジョブスケジューラコンテキスト取得
        final JobSchedulerContext jobSchedulerContext = Contexts.get(JobSchedulerContext.class);

        // パラメータの取得(prov_id)
        String provId = jobSchedulerContext.getParameter(PROV_ID);
        if (null == provId) {
            // 処理結果:異常
            return JobResult.error("prov_id not found.");
        }
        provId = provId.trim();
        if (provId.isEmpty()) {
            // 処理結果:異常
            return JobResult.error("prov_id id Empty.");
        }

        // パラメータの取得(path)
        String path = jobSchedulerContext.getParameter(PATH_KEY);
        if (null == path) {
            // 処理結果:異常
            return JobResult.error("path is not found.");
        }
        path = path.trim();
        if (path.isEmpty()) {
            // 処理結果:異常
            return JobResult.error("path is empty.");
        }

        // ファイルを取得とチェック
        final PublicStorage storage = new PublicStorage(path);
        try {
            if (!storage.exists()) {
                // 処理結果:異常
                return JobResult.error(String.format("File not found.(%s)", path));
            }
        } catch (IOException e) {
            final String errorMessage = String.format("Can not read the file.(%s)", path);
            logger.error(errorMessage, e);
            return JobResult.error(errorMessage);
        }

        // インポート処理
        BufferedReader reader = null;
        int totalCount = 0;
        int insertCount = 0;
        int updateCount = 0;
        int skipCount = 0;

        final SAMLMappingManager manager = new SAMLMappingManager();

        try {
            reader = new BufferedReader(new InputStreamReader(storage.open()));
            String line;
            while ((line = reader.readLine()) != null) {
                try {
                    String[] record = line.split(",", 2);
                    if (record.length == 2) {
                        record[0] = record[0].trim();
                        record[1] = record[1].trim();
                        final ImsamlUserMapping mapping = manager.find(provId, record[0]);
                        if (mapping != null) {
                            // 更新
                            manager.update(provId, record[0], record[1], mapping.getProvUserCd(), mapping.getUserCd());
                            updateCount++;

                        } else {
                            // 新規追加
                            manager.insert(provId, record[0], record[1]);
                            insertCount++;
                        }
                    } else {
                        logger.warn(String.format("Skip for invalid format.(%s)", line));
                        skipCount++;
                    }
                } catch (IdpNotExistException e) {
                    String errorMessage = String.format("prov_id not found.(%s)", provId);
                    logger.error(errorMessage, e);
                    return JobResult.error(errorMessage);
                } catch (Exception e) {
                    String errorMessage = String.format("Skip for import error.(%s)", line);
                    logger.warn(errorMessage, e);
                    skipCount++;
                }

                totalCount++;
            }
        } catch (IOException e) {
            final String errorMessage = String.format("Can not read the file.(%s)", path);
            logger.error(errorMessage, e);
            return JobResult.error(errorMessage);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    final String errorMessage = String.format("Can not close the file.(%s)", path);
                    logger.error(errorMessage, e);
                    return JobResult.error(String.format("Can not close the file.(%s)", path));
                }
            }
        }
        final String message = String.format("Success import.( total:%d / insert:%d / update:%d / skip:%d )",
                totalCount, insertCount, updateCount, skipCount);
        return JobResult.success(message);
    }
}