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.filter;
017
018import jakarta.servlet.ServletRequest;
019import jakarta.servlet.http.HttpServletRequest;
020import jakarta.servlet.ServletResponse;
021import jakarta.servlet.ServletException;
022import jakarta.servlet.Filter;
023import jakarta.servlet.FilterChain;
024import jakarta.servlet.FilterConfig;
025
026import java.io.File;                                                                                            // 5.7.3.2 (2014/02/28) Tomcat8 対応
027import java.io.PrintWriter;
028import java.io.BufferedReader;
029import java.io.IOException;
030import java.io.UnsupportedEncodingException;
031import java.nio.charset.CharacterCodingException;                                       // 6.3.1.0 (2015/06/28)
032
033import org.opengion.fukurou.system.OgRuntimeException ;                         // 6.4.2.0 (2016/01/29)
034import org.opengion.fukurou.system.OgCharacterException ;                       // 6.5.0.1 (2016/10/21)
035import org.opengion.fukurou.system.DateSet;                                                     // 6.4.2.0 (2016/01/29)
036import org.opengion.fukurou.system.Closer;
037import org.opengion.fukurou.util.FileUtil;                                                      // 6.2.0.0 (2015/02/27)
038import org.opengion.fukurou.util.StringUtil;                                            // 6.3.8.0 (2015/09/11)
039import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
040import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.3.1.0 (2015/06/28)
041import org.opengion.hayabusa.common.HybsSystem;                                         // 6.2.4.1 (2015/05/22)
042
043/**
044 * AccessStopFilter は、Filter インターフェースを継承した アクセス制御クラスです。
045 * web.xml で filter 設定することにより、Webアプリケーションへのアクセスを制御できます。
046 * また、SYSTEM ユーザーは、このフィルターを常に通過します。
047 *
048 * フィルターに対してweb.xml でパラメータを設定します。
049 *   ・startTime:停止開始時刻 (初期値:230000)
050 *   ・stopTime :停止終了時刻 (初期値:070000)
051 *   ・filename :停止時メッセージ表示ファイル名 (初期値:jsp/custom/stopFile.html)
052 *   ・passUsers:停止中でもアクセス可能なユーザーID (初期値:SYSTEM,ADMIN)
053 *   ・addUsers :停止中でもアクセス可能な追加ユーザーID (初期値:null)
054 *
055 * 【WEB-INF/web.xml】
056 *     <filter>
057 *         <filter-name>AccessStopFilter</filter-name>
058 *         <filter-class>org.opengion.hayabusa.filter.AccessStopFilter</filter-class>
059 *         <init-param>
060 *             <param-name>startTime</param-name>
061 *             <param-value>070000</param-value>
062 *         </init-param>
063 *         <init-param>
064 *             <param-name>stopTime</param-name>
065 *             <param-value>070000</param-value>
066 *         </init-param>
067 *         <init-param>
068 *             <param-name>filename</param-name>
069 *             <param-value>jsp/custom/stopFile.html</param-value>
070 *         </init-param>
071 *     </filter>
072 *
073 *     <filter-mapping>
074 *         <filter-name>AccessStopFilter</filter-name>
075 *         <url-pattern>/jsp/*</url-pattern>
076 *     </filter-mapping>
077 *
078 * @og.group フィルター処理
079 *
080 * @version  4.0
081 * @author   Kazuhiko Hasegawa
082 * @since    JDK5.0,
083 */
084public final class AccessStopFilter implements Filter {
085
086        private static boolean useFilter = true ;               // 6.3.8.3 (2015/10/03)
087
088        private String startTime        = "230000";             // 停止開始時刻
089        private String stopTime         = "070000";             // 停止終了時刻
090        private String filename         = "jsp/custom/stopFile.html";   // 6.3.8.0 (2015/09/11) 停止時メッセージ表示ファイル名
091        private String passUsers        = "SYSTEM,admin";                               // 6.3.8.0 (2015/09/11) 停止中でもアクセス可能なユーザーID
092        private int    startStop        ;
093
094        private static final String  USERID_HEADER = HybsSystem.sys( "USERID_HEADER_NAME" ); // 5.10.18.0 (2019/11/29)
095
096        /**
097         * フィルター処理本体のメソッドです。
098         *
099         * @og.rev 3.1.3.0 (2003/04/10) UTF-8 決め打ちで、stopFile.html を返送する。
100         * @og.rev 3.1.8.0 (2003/05/16) 文字エンコードが、UTF-8 になっていないのを修正。
101         * @og.rev 6.2.0.0 (2015/02/27) new BufferedReader … を、FileUtil.getBufferedReader … に変更。
102         * @og.rev 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。
103         * @og.rev 6.3.8.3 (2015/10/03) フィルターの停止処理。
104         * @og.rev 6.5.0.1 (2016/10/21) CharacterCodingException は、OgCharacterException に変換する。
105         *
106         * @param       request         ServletRequestオブジェクト
107         * @param       response        ServletResponseオブジェクト
108         * @param       chain           FilterChainオブジェクト
109         * @throws IOException 入出力エラーが発生した場合、throw されます。
110         * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。
111         */
112        public void doFilter( final ServletRequest request,
113                                                        final ServletResponse response,
114                                                        final FilterChain chain) throws IOException, ServletException {
115
116                if( useFilter && isStop( request ) ) {                          // 6.3.8.3 (2015/10/03) フィルターの停止処理
117                        BufferedReader in = null ;
118                        try {
119                                response.setContentType( "text/html; charset=UTF-8" );
120                                final PrintWriter out = response.getWriter();
121                                in = FileUtil.getBufferedReader( new File( filename ), "UTF-8" );               // 6.2.0.0 (2015/02/27)
122                                String str ;
123                                while( (str = in.readLine()) != null ) {
124                                        out.println( str );
125                                }
126                                out.flush();
127                        }
128                        catch( final UnsupportedEncodingException ex ) {
129                                final String errMsg = "指定されたエンコーディングがサポートされていません。[UTF-8]" ;
130                                throw new OgRuntimeException( errMsg,ex );
131                        }
132                        // 6.3.1.0 (2015/06/28) nioを使用すると UTF-8とShuft-JISで、エラーになる。
133                        catch( final CharacterCodingException ex ) {
134                                final String errMsg = "文字のエンコード・エラーが発生しました。" + CR
135                                                                        +       "  ファイルのエンコードが指定のエンコードと異なります。" + CR
136                                                                        +       " [" + filename + "] , Encode=[UTF-8]" ;
137                                throw new OgCharacterException( errMsg,ex );    // 6.5.0.1 (2016/10/21)
138                        }
139                        catch( final IOException ex ) {
140                                final String errMsg = "ストリームがオープン出来ませんでした。[" + filename + "]" ;
141                                throw new OgRuntimeException( errMsg,ex );
142                        }
143                        finally {
144                                Closer.ioClose( in );
145                        }
146                        return;
147                }
148
149                chain.doFilter(request, response);
150        }
151
152        /**
153         * フィルターの初期処理メソッドです。
154         *
155         * フィルターに対してweb.xml で初期パラメータを設定します。
156         *   ・startTime:停止開始時刻 (初期値:230000)
157         *   ・stopTime :停止終了時刻 (初期値:070000)
158         *   ・filename :停止時メッセージ表示ファイル名 (初期値:jsp/custom/stopFile.html)
159         *   ・passUsers:停止中でもアクセス可能なユーザーID (初期値:SYSTEM,admin)
160         *   ・addUsers :停止中でもアクセス可能な追加ユーザーID (初期値:null)
161         *
162         * @og.rev 5.7.3.2 (2014/02/28) Tomcat8 対応。getRealPath( "/" ) の互換性のための修正。
163         * @og.rev 6.2.4.1 (2015/05/22) REAL_PATH 対応。realPath は、HybsSystem経由で、取得する。
164         * @og.rev 6.3.8.0 (2015/09/11) パラメータの初期値設定と、passUsers、addUsers 属性追加
165         * @og.rev 7.1.0.0 (2020/01/27) フィルターが実行されているかどうかを、System.setProperty で設定しておきます。
166         *
167         * @param       filterConfig    FilterConfigオブジェクト
168         */
169        public void init( final FilterConfig filterConfig ) {
170                // 6.3.8.0 (2015/09/11) パラメータの初期値設定と、passUsers、addUsers 属性追加
171                startTime = StringUtil.nval( filterConfig.getInitParameter( "startTime" ) , startTime );
172                stopTime  = StringUtil.nval( filterConfig.getInitParameter( "stopTime"  ) , stopTime  );
173                filename  = HybsSystem.getRealPath()
174                                                + StringUtil.nval( filterConfig.getInitParameter( "filename" ) , filename );
175                passUsers = StringUtil.nval( filterConfig.getInitParameter( "passUsers"  ) , passUsers  )       // 6.3.8.0 (2015/09/11) 新規
176                                                + ',' + filterConfig.getInitParameter( "addUsers" ) ;
177
178                if( startTime == null || stopTime == null ) {
179                        startStop = 0;
180                }
181                else {
182                        startStop = startTime.compareTo( stopTime );
183                }
184
185                // 7.1.0.0 (2020/01/27) フィルターが実行されているかどうかを、System.setProperty で設定しておきます。
186                System.setProperty( "AccessStopFilter" , "true" );
187        }
188
189        /**
190         * フィルターの終了処理メソッドです。
191         *
192         */
193        public void destroy() {
194                // ここでは処理を行いません。
195        }
196
197        /**
198         * フィルターの内部状態をチェックするメソッドです。
199         * 内部のフラグをもとに、停止/許可を求めます。
200         *
201         * @og.rev 3.1.8.0 (2003/05/16) 開始時刻と終了時刻を同一にしていると、画面からの制御が効かないバグを修正。
202         * @og.rev 5.5.3.2 (2012/06/08) 通過させるユーザーに、admin を追加します。
203         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
204         * @og.rev 6.3.8.0 (2015/09/11) パラメータの初期値設定と、passUsers、addUsers 属性追加
205         * @og.rev 6.3.8.3 (2015/10/03) フィルターの停止処理。判定をdoFilterメソッドに移動。
206         * @og.rev 5.10.18.0 (2019/11/29) ヘッダ認証
207         *
208         * @param request ServletRequestオブジェクト
209         *
210         * @return      (true:停止  false:実行許可)
211         */
212        private boolean isStop( final ServletRequest request ) {
213//              final String userID = ((HttpServletRequest)request).getRemoteUser() ;
214                String userID = ((HttpServletRequest)request).getRemoteUser() ;
215
216                // 5.10.18.0 (2019/11/29) ヘッダ認証
217                if( USERID_HEADER != null && USERID_HEADER.length() > 0 && ( userID == null || userID.length() == 0) ) {
218                        userID = ((HttpServletRequest)request).getHeader( USERID_HEADER );
219                }
220
221                // 5.5.3.2 (2012/06/08) 通過させるユーザーに、admin を追加
222                // 6.3.8.0 (2015/09/11) パラメータの初期値設定と、passUsers、addUsers 属性追加
223                if( passUsers.contains( userID ) ) { return false; }
224
225                // 4.0.0 (2005/01/31)
226                final String time = DateSet.getDate( "HHmmss" );                // 5.5.7.2 (2012/10/09) HybsDateUtil を利用
227
228                return  startStop < 0 && startTime.compareTo( time ) < 0 && time.compareTo( stopTime ) < 0 ||
229                                startStop > 0 && ( startTime.compareTo( time ) < 0 || time.compareTo( stopTime ) < 0 ) ;
230
231 //             boolean rtnFlag = stopFilter;
232 //             if( startStop < 0 ) {
233 //                     if( startTime.compareTo( time ) < 0 &&
234 //                             time.compareTo( stopTime )  < 0 ) {
235 //                                     rtnFlag = true;
236 //                     }
237 //             }
238 //             else if( startStop > 0 ) {
239 //                     if( startTime.compareTo( time ) < 0 ||
240 //                             time.compareTo( stopTime )  < 0 ) {
241 //                                     rtnFlag = true;
242 //                             }
243 //             }
244 //             return rtnFlag;
245        }
246
247        /**
248         * フィルターの実行/停止を設定するメソッドです。
249         *
250         * 初期値は、true:実行 です。
251         *
252         * @og.rev 4.0.0.0 (2005/01/31) synchronized の廃止
253         * @og.rev 6.3.8.3 (2015/10/03) フィルターの停止処理。メソッド名変更、引数の意味反転。
254         *
255         * @param flag (true:実行  false:停止)
256         */
257        public static void setUseFilter( final boolean flag ) {
258                useFilter = flag;
259        }
260
261        /**
262         * フィルターの内部状態(強制停止/解除)を取得するメソッドです。
263         * これは、現在、アクセス制限がどうなっているかという状態ではなく、
264         * 強制停止されているかどうかの確認メソッドです。
265         *
266         * @og.rev 4.0.0.0 (2007/11/29) getStopFilter() ⇒ isStopFilter() に変更
267         * @og.rev 6.3.8.3 (2015/10/03) フィルターの停止処理。メソッド名変更、戻り値の意味反転。
268         *
269         * @return      (true:実行  false:停止)
270         */
271        public static boolean isUseFilter() {
272                return useFilter;
273        }
274
275        /**
276         * 内部状態を文字列で返します。
277         *
278         * @return      このクラスの文字列表示
279         * @og.rtnNotNull
280         */
281        @Override
282        public String toString() {
283                final StringBuilder sb = new StringBuilder( BUFFER_MIDDLE )
284                        .append( "AccessStopFilter" )
285                        .append( '[' ).append( startTime ).append( "],")                // 6.0.2.5 (2014/10/31) char を append する。
286                        .append( '[' ).append( stopTime  ).append( "],")
287                        .append( '[' ).append( filename  ).append( "],");
288                return sb.toString();
289        }
290}