    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.hayabusa.resource;
    017
    018import java.text.MessageFormat;
    019import java.util.List;
    020import java.util.Arrays;                                                                                        // 6.4.7.0 (2016/06/03)
    021
    022import org.opengion.hayabusa.common.HybsSystem;
    023import org.opengion.hayabusa.common.HybsSystemException;
    024import org.opengion.hayabusa.common.SystemManager;
    025import org.opengion.fukurou.system.LogWriter;
    026import org.opengion.fukurou.util.Cleanable;
    027import org.opengion.fukurou.util.StringUtil;
    028import org.opengion.fukurou.db.ApplicationInfo;
    029import org.opengion.fukurou.db.DBUtil;
    030
    031/**
    032 * systemId に対応したユーザー情報を作成するファクトリクラスです。
    033 *
    034 * UserInfoオブジェクトは，キャッシュせずに、要求都度、データベースを検索します。
    035 * これは、ユーザー登録が、他システムより行われる可能性を考慮している為です。
    036 * ユーザーオブジェクトの要求は、基本的にログイン時のみで、その後セッションに
    037 * キープされます。
    038 *
    039 * 検索するカラムには、必ず、USERID,LANG,NAME,ROLES,DROLES がこの順番で含まれており、
    040 * 絞込み条件(?パラメータ)として、SYSTEM_ID,USERID がこの順番で指定される必要があります。
    041 * (カラム名は関係ありません。並び順と意味が重要です。)
    042 * また、検索順(ORDER BY)は、優先順位の低い順に検索してください。使用するのは、一番最後に
    043 * 検索された行を使用します。
    044 * ユーザーリソースは、RESOURCE_USER_DBID で指定のデータベースから取得します。
    045 * 未定義の場合は、RESOURCE_DBID から、それも未定義の場合は デフォルトの接続先を
    046 * 使用します。
    047 *
    048 * SYSTEM_ID='**' は、共通リソースです(ROLESも共通に設定する必要があります。)。
    049 * これは、システム間で共通に使用されるリソース情報を登録しておきます。
    050 * SYSTEM_ID は、指定のシステムIDと**を検索対象にします。**は、全システム共通の
    051 * 指定のシステムIDと**と両方存在する場合は、指定のシステムIDが優先されます。
    052 *
    053 * ver4 では、デフォルトロールという考え方がなくなりましたので、画面のロールに、
    054 * (*)を明示的に追加し、RWMODE を指定する必要があります。
    055 *
    056 * @og.rev 4.0.0.0 (2004/12/31) 新規作成
    057 * @og.group リソース管理
    058 *
    059 * @version  4.0
    060 * @author   Kazuhiko Hasegawa
    061 * @since    JDK5.0,
    062 */
    063public final class UserInfoFactory {
    064
    065        private static final String SYSTEM_ID = HybsSystem.sys( "SYSTEM_ID" );
    066
    067        // ユーザーリソースの接続先を、取得します。
    068        private static String dbid = StringUtil.nval(
    069                                                                HybsSystem.sys( "RESOURCE_USER_DBID" ) ,
    070                                                                HybsSystem.sys( "RESOURCE_DBID" )
    071                                                        ) ;
    072
    073        // ユーザーリソースのキー指定読み込みのクエリー
    074        private static String query                     = HybsSystem.sys( "RESOURCE_USER_SQL" );
    075        private static String queryRole         = HybsSystem.sys( "RESOURCE_USER_ROLE_SQL" );
    076
    077        // 5.2.0.0 (2010/09/01) LDAP対応
    078        private static String srcType           = HybsSystem.sys( "RESOURCE_USER_SRC_TYPE" );
    079        private static String[] ldapClm         = StringUtil.csv2Array( HybsSystem.sys( "RESOURCE_USER_LDAP_CLM" ) );
    080        private static String ldapFilter        = HybsSystem.sys( "RESOURCE_USER_LDAP_FILTER" );
    081        private static String ldapRoleFilter= HybsSystem.sys( "RESOURCE_USER_ROLE_LDAP_FILTER" );
    082
    083        private static String searchScope       = HybsSystem.sys( "LDAP_SEARCH_SCOPE" );
    084        private static String initctx           = HybsSystem.sys( "LDAP_INITIAL_CONTEXT_FACTORY" );
    085        private static String providerURL       = HybsSystem.sys( "LDAP_PROVIDER_URL" );
    086        private static String entrydn           = HybsSystem.sys( "LDAP_ENTRYDN" );
    087        private static String password          = HybsSystem.sys( "LDAP_PASSWORD" );
    088        private static String searchbase        = HybsSystem.sys( "LDAP_SEARCH_BASE" );
    089
    090        private static final Object LOCK = new Object();                                                                                                // 6.4.1.1 (2016/01/16) lock → LOCK  refactoring
    091
    092        /** コネクションにアプリケーション情報を追記するかどうか指定 */
    093        public static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;
    094
    095        // 4.0.0 (2005/01/31) Cleanable インターフェースによる初期化処理
    096        static {
    097                final Cleanable clr = new Cleanable() {
    098                        /**
    099                         * 初期化(クリア)します。
    100                         * 主に、キャッシュクリアで利用します。
    101                         */
    102                        public void clear() {
    103                                UserInfoFactory.clear();
    104                        }
    105                };
    106
    107                SystemManager.addCleanable( clr );
    108        }
    109
    110        /**
    111         *  デフォルトコンストラクターをprivateにして、
    112         *  オブジェクトの生成をさせないようにする。
    113         *
    114         */
    115        private UserInfoFactory() {
    116        }
    117
    118        /**
    119         * UserInfo オブジェクトを取得します。
    120         *
    121         * UserInfoオブジェクトは，キャッシュせずに、要求都度、データベースを検索します。
    122         * これは、ユーザー登録が、他システムより行われる可能性を考慮している為です。
    123         * ユーザーオブジェクトの要求は、基本的にログイン時のみで、その後セッションに
    124         * キープされます。
    125         *
    126         * @og.rev 3.7.0.4 (2005/03/18) ゲストログイン機能追加
    127         * @og.rev 4.0.0.0 (2007/10/31) ロール指定でのログイン機能追加
    128         * @og.rev 4.3.4.0 (2008/12/01) GE20(ユーザー定数)へ登録するかのフラグへの対応
    129         * @og.rev 4.4.0.0 (2009/08/02) データロール対応
    130         * @og.rev 5.2.0.0 (2010/09/01) LDAP対応
    131         * @og.rev 5.3.6.0 (2011/06/01) GE20の読み込みをUserInfo内に移動
    132         *
    133         * @param       userID          ユーザーID
    134         * @param       ipAddress       ログイン端末のIPアドレス
    135         * @param       roles           データロール
    136         *
    137         * @return      UserInfoオブジェクト
    138         */
    139        public static UserInfo newInstance( final String userID,final String ipAddress,final String roles ) {
    140                // 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
    141                ApplicationInfo appInfo = null ;
    142                if( USE_DB_APPLICATION_INFO ) {
    143                        appInfo = new ApplicationInfo();
    144                        // ユーザーID,IPアドレス,ホスト名
    145                        appInfo.setClientInfo( userID,ipAddress,null );
    146                        // 画面ID,操作,プログラムID
    147                        appInfo.setModuleInfo( "UserInfoFactory",null,"newInstance" );
    148                }
    149
    150                String[][] vals;
    151                if( "LDAP".equalsIgnoreCase( srcType ) ) {
    152                        vals = getValsByLdap( userID, roles );
    153                }
    154                else {
    155                        vals = getVals( userID, roles, appInfo );
    156                }
    157
    158                final UserInfo info ;
    159                final int len = vals.length ;   // システムID ** を含む。
    160                if( len >= 1 && vals[0].length >= 5 ) {
    161                        // システムIDでソートされる。SYSTEM_ID="**"は最初に現れるので、最後を取得
    162                        info = new UserInfo(
    163                                                                userID          ,                       // userID
    164                                                                vals[len-1][1]  ,               // lang
    165                                                                vals[len-1][2]  ,               // jname
    166                                                                vals[len-1][3]  ,               // roles
    167                                                                vals[len-1][4]  ,               // droles // 4.4.0.0 (2009/08/02)
    168                                                                SYSTEM_ID               ,               // systemId
    169                                                                ipAddress               ,               // ipAddress
    170                                                                appInfo                 ) ;             // ApplicationInfo
    171                }
    172                else {
    173                        final String errMsg = "UserInfo のデータ(USERID,LANG,NAME,ROLES,DROLES)が取得できません。"
    174                                                + " Key [" + userID + "]"
    175                                                + " SQL [" + query + "]" ;
    176                        LogWriter.log( errMsg );
    177                        throw new HybsSystemException( errMsg );
    178                }
    179
    180                return info ;
    181        }
    182
    183        /**
    184         * UserInfoFactoryをクリアします。
    185         *
    186         * @og.rev 5.2.0.0 (2010/09/01) LDAP対応
    187         *
    188         */
    189        public static void clear() {
    190                synchronized( LOCK ) {
    191                        dbid = StringUtil.nval(
    192                                                                        HybsSystem.sys( "RESOURCE_USER_DBID" ) ,
    193                                                                        HybsSystem.sys( "RESOURCE_DBID" )
    194                                                                ) ;
    195                        query = HybsSystem.sys( "RESOURCE_USER_SQL" );
    196                        queryRole = HybsSystem.sys( "RESOURCE_USER_ROLE_SQL" );
    197
    198                        // 5.2.0.0 (2010/09/01) LDAP対応
    199                        srcType                 = HybsSystem.sys( "RESOURCE_USER_SRC_TYPE" );
    200                        ldapClm                 = StringUtil.csv2Array( HybsSystem.sys( "RESOURCE_USER_LDAP_CLM" ) );
    201                        ldapFilter              = HybsSystem.sys( "RESOURCE_USER_LDAP_FILTER" );
    202                        ldapRoleFilter  = HybsSystem.sys( "RESOURCE_USER_ROLE_LDAP_FILTER" );
    203
    204                        searchScope             = HybsSystem.sys( "LDAP_SEARCH_SCOPE" );
    205                        initctx                 = HybsSystem.sys( "LDAP_INITIAL_CONTEXT_FACTORY" );
    206                        providerURL     = HybsSystem.sys( "LDAP_PROVIDER_URL" );
    207                        entrydn                 = HybsSystem.sys( "LDAP_ENTRYDN" );
    208                        password                = HybsSystem.sys( "LDAP_PASSWORD" );
    209                        searchbase              = HybsSystem.sys( "LDAP_SEARCH_BASE" );
    210                }
    211        }
    212
    213        /**
    214         * DBからユーザーリソースの情報を取得します。
    215         *
    216         * @og.rev 5.2.0.0 (2010/09/01) 新規作成
    217         *
    218         * @param       userId  ユーザーID
    219         * @param       roles   ロール
    220         * @param       appInfo DB接続情報
    221         *
    222         * @return ユーザーリソース情報
    223         */
    224        private static String[][] getVals( final String userId, final String roles, final ApplicationInfo appInfo ) {
    225                String[] args;
    226                String[][] rtn;
    227
    228                if( roles == null || roles.isEmpty() ) {
    229                        args = new String[] { SYSTEM_ID,userId };
    230                        synchronized( LOCK ) {
    231                                rtn = DBUtil.dbExecute( query,args,appInfo,dbid );
    232                        }
    233                }
    234                // 4.0.0.0 (2007/10/31)
    235                else {
    236                        args = new String[] { SYSTEM_ID,userId,roles };
    237                        synchronized( LOCK ) {
    238                                rtn = DBUtil.dbExecute( queryRole,args,appInfo,dbid );
    239                        }
    240                }
    241
    242                return rtn;
    243        }
    244
    245        /**
    246         * LDAPからユーザーリソースの情報を取得します。
    247         *
    248         * @og.rev 5.2.0.0 (2010/09/01) 新規作成
    249         * @og.rev 6.4.7.0 (2016/06/03) IllegalArgumentException が発生した場合に、見えるようにする。
    250         *
    251         * @param       userId  ユーザーID
    252         * @param       roles   ロール
    253         *
    254         * @return ユーザーリソース情報
    255         */
    256        private static String[][] getValsByLdap( final String userId, final String roles ) {
    257                final LDAPSearch serch = new LDAPSearch();
    258                serch.setSearchScope( searchScope ) ;
    259                serch.setInitctx( initctx ) ;
    260                serch.setProviderURL( providerURL ) ;
    261                serch.setSearchbase( searchbase ) ;
    262                if( entrydn != null  ) { serch.setEntrydn( entrydn ) ; }
    263                if( password != null ) { serch.setPassword( password ) ; }
    264                serch.setAttributes( ldapClm ) ;
    265                serch.init();
    266
    267                // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
    268                String filter = roles == null || roles.isEmpty() ? ldapFilter : ldapRoleFilter;
    269                final String[] args = roles == null || roles.isEmpty() ? new String[] { SYSTEM_ID,userId } : new String[] { SYSTEM_ID,userId,roles };
    270
    271                // 6.4.7.0 (2016/06/03) IllegalArgumentException が発生した場合に、見えるようにする。
    272                try {
    273                        filter = MessageFormat.format( filter,(Object[])args );
    274                }
    275                catch( final IllegalArgumentException ex ) {
    276                        final String errMsg = "MessageFormatエラー:"
    277                                                + " Pattern [" + filter + "]"
    278                                                + " Arguments [" + Arrays.toString( (Object[])args ) + "]" ;
    279                        throw new HybsSystemException( errMsg,ex );
    280                }
    281
    282                final List<String[]> list = serch.search( filter );
    283
    284                String[][] rtn = null;
    285                if( !list.isEmpty() ) {                 // 6.1.1.0 (2015/01/17) refactoring
    286                        rtn = new String[1][];
    287                        rtn[0] = list.get( 0 );
    288                        rtn[0][1] = StringUtil.nval( rtn[0][1], "ja" );                 // 言語のデフォルト値は、'ja'
    289                        rtn[0][2] = StringUtil.nval( rtn[0][2], rtn[0][0] );    // 名称のデフォルト値は、ユーザーID
    290                        rtn[0][3] = StringUtil.nval( rtn[0][3], ldapClm[3] );   // ロールズの初期値は、ロールに設定された項目名
    291                        rtn[0][4] = StringUtil.nval( rtn[0][4], "" );
    292                }
    293
    294                return rtn;
    295        }
    296}