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