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     */
016    package org.opengion.hayabusa.filter;
017    
018    import org.opengion.hayabusa.common.HybsSystem;
019    
020    import java.io.IOException;
021    import java.io.PrintWriter;
022    
023    import javax.servlet.Filter;
024    import javax.servlet.FilterChain;
025    import javax.servlet.FilterConfig;
026    import javax.servlet.ServletContext;
027    import javax.servlet.ServletException;
028    import javax.servlet.ServletRequest;
029    import javax.servlet.ServletResponse;
030    import javax.servlet.RequestDispatcher;
031    import javax.servlet.http.HttpServletResponse;
032    import javax.servlet.http.HttpServletRequest;
033    
034    import org.opengion.fukurou.security.URLHashMap;
035    import org.opengion.fukurou.util.StringUtil;
036    import org.opengion.fukurou.util.FileString;
037    
038    /**
039     * URLHashFilter は、Filter インターフェースを継承した URLチェ?クラスです?
040     * web.xml で filter 設定することにより、??開始します?
041     * filter 処??、設定レベルとURLの飛?先により処?法が異なります?
042     * こ?フィルターでは、ハ?ュ?暗号化ではなく?アドレスに戻す作業になります?
043     * ?URLの場合?ハッシュ化?外部URLの場合?暗号化に適用されます?
044     *
045     * 基本?は、外部へのURLでエンジンシス?へ飛?す?合?、暗号化になります?
046     * ?へのURLは、基本?、パラメータのみ暗号化を行います?なお?直接画面ID?
047     * ?して飛?す?合を、止めるかど?は、設定レベルに依存します?
048     *
049     * フィルターの設定レベルは、シス?リソースの URL_ACCESS_SECURITY_LEVEL 変数で
050     * 設定します?
051     * なお??ベル共通で、戻し???レベルに関係なく実行されます?
052     *   レベル?:なにも制限?ありません?
053     *   レベル?:Referer チェ?を行います?つまり?URLを直接入力しても動作しません?
054     *             ただし?Refererが付いてさえ?ば、アクセス許可を与えます?
055     *             Referer 無し?場合でも?URLにパラメータが存在しな??また??
056     *             アドレスがハ?ュ?暗号化されて?場合?、アクセスを許可します?
057     *             レベル??場合?ハッシュ戻??化???行います?あくまで、ハ?ュ?
058     *             暗号化されて???合でも?Refererさえあれば、許可すると?ことです?
059     *             (パラメータな?or ハッシュあり or Refererあり の場合?許可)
060     *   レベル?:フィルター処?しては、レベル?と同じです?
061     *             異なる?は、URLのハッシュ?暗号化??、外部URLに対してのみ行います?
062     *             (パラメータな?or ハッシュあり or Refererあり の場合?許可)
063     *   レベル?:URLのパラメータがハ?ュ?暗号化されて??があります?
064     *             レベル?同様?URLにパラメータが存在しな??合?、アクセスを許可します?
065     *             レベル?と異なる?は、パラメータは?ハッシュ化か、暗号化されて?
066     *             ?があると?ことです?(?/外部問わ?
067     *             (パラメータな?or ハッシュあり の場合?許可)
068     *   それ以外:アクセスを停止します?
069     *
070     * フィルターに対してweb.xml でパラメータを設定します?
071     *   ・filename   :停止時メ?ージ表示ファイル??/jsp/custom/refuseAccess.html)
072     *   ・initPage   :??にアクセスされる?期画面アドレス(初期値:/jsp/index.jsp)
073     *   ・debug      :??メ?ージの表示(初期値:false)
074     *
075     * 【WEB-INF/web.xml?
076     *     <filter>
077     *         <filter-name>URLHashFilter</filter-name>
078     *         <filter-class>org.opengion.hayabusa.filter.URLHashFilter</filter-class>
079     *         <init-param>
080     *             <param-name>filename</param-name>
081     *             <param-value>/jsp/custom/refuseAccess.html</param-value>
082     *         </init-param>
083     *          <init-param>
084     *              <param-name>initPage</param-name>
085     *              <param-value>/jsp/index.jsp</param-value>
086     *          </init-param>
087     *          <init-param>
088     *              <param-name>debug</param-name>
089     *              <param-value>false</param-value>
090     *          </init-param>
091     *     </filter>
092     *
093     *     <filter-mapping>
094     *         <filter-name>URLHashFilter</filter-name>
095     *         <url-pattern>*.jsp</url-pattern>
096     *     </filter-mapping>
097     *
098     * @og.group フィルター処?
099     *
100     * @og.rev 5.2.2.0 (2010/11/01) 新規追?
101     *
102     * @version  5.2.2.0 (2010/11/01)
103     * @author   Kazuhiko Hasegawa
104     * @since    JDK1.6,
105     */
106    public final class URLHashFilter implements Filter {
107            private static final String REQ_KEY = HybsSystem.URL_HASH_REQ_KEY ;
108    
109            private static final int ACCS_LVL = HybsSystem.sysInt( "URL_ACCESS_SECURITY_LEVEL" );
110    
111            private String          initPage        = "/jsp/index.jsp";
112    //      private String          filename        = null;                 // アクセス拒否時メ?ージ表示ファイル?
113            private FileString      refuseMsg       = null;                 // アクセス拒否時メ?ージファイルの?(キャ?ュ)
114            private boolean         isDebug         = false;
115    
116            /**
117             * フィルター処?体?メソ?です?
118             *
119             * @og.rev 5.3.0.0 (2010/12/01) ?化け対策として、setCharacterEncoding を実行する?
120             *
121             * @param       request         ServletRequestオブジェク?
122             * @param       response        ServletResponseオブジェク?
123             * @param       chain           FilterChainオブジェク?
124             * @throws IOException , ServletException
125             */
126            public void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain chain ) throws IOException, ServletException {
127                    HttpServletRequest req = (HttpServletRequest)request ;
128                    req.setCharacterEncoding( "UTF-8" );    // 5.3.0.0 (2010/12/01)
129    
130                    if( isValidAccess( req ) ) {
131                            String h_r = req.getParameter( REQ_KEY );
132                            // ハッシュ化キーが存在する?
133                            if( h_r != null ) {
134                                    HttpServletResponse resp = ((HttpServletResponse)response);
135                                    String qu = URLHashMap.getValue( h_r );
136                                    // キーに対する実アドレスが存在する?
137                                    if( qu != null ) {
138                                            String requestURI = req.getRequestURI();                // /gf/jsp/index.jsp など
139                                            String cntxPath   = req.getContextPath();               // /gf など
140                                            // 自??身のコン?ストと同じなので、forward できる?
141                                            if( requestURI.startsWith( cntxPath ) ) {
142                                                    String url = requestURI.substring(cntxPath.length()) + "?" + qu ;
143                                                    RequestDispatcher rd = request.getRequestDispatcher( url );
144                                                    rd.forward( request,response );
145                                            }
146                                            // そうでな??合?リ?レクトする?
147                                            else {
148                                                    String url = resp.encodeRedirectURL( requestURI + "?" + qu );
149                                                    resp.sendRedirect( url );
150                                            }
151                                    }
152                                    // キーに対する実アドレスが存在しな??(行き先無し?ケース)
153                                    else {
154                                            String url = resp.encodeRedirectURL( initPage );
155                                            resp.sendRedirect( url );
156                                    }
157                            }
158                            // ハッシュ化キーが存在しな??
159                            else {
160                                    chain.doFilter(request, response);
161                            }
162                    }
163                    else {
164                            // アクセス拒否を示すメ?ージファイルの?を?力する?
165                            response.setContentType( "text/html; charset=UTF-8" );
166                            PrintWriter out = response.getWriter();
167                            out.println( refuseMsg.getValue() );
168                            out.flush();
169                    }
170            }
171    
172            /**
173             * フィルターの初期処?ソ?です?
174             *
175             * フィルターに対してweb.xml で初期パラメータを設定します?
176             *   ・filename   :停止時メ?ージ表示ファイル?
177             *   ・initPage   :??にアクセスされる?期画面アドレス(初期値:/jsp/index.jsp)
178             *   ・debug      :??メ?ージの表示(初期値:false)
179             *
180             * @param config FilterConfigオブジェク?
181             */
182            public void init( final FilterConfig config ) {
183                    initPage = StringUtil.nval( config.getInitParameter("initPage"), initPage );
184                    isDebug  = StringUtil.nval( config.getInitParameter("debug")   , isDebug  );
185    
186                    ServletContext context = config.getServletContext();
187                    String realPath = context.getRealPath( "/" );
188    
189                    // アクセス拒否を示すメ?ージファイルの?を管??FileString オブジェクトを構築する?
190                    String filename  = realPath + config.getInitParameter("filename");
191                    refuseMsg = new FileString();
192                    refuseMsg.setFilename( filename );
193                    refuseMsg.setEncode( "UTF-8" );
194            }
195    
196            /**
197             * フィルターの終???ソ?です?
198             *
199             */
200            public void destroy() {
201                    // ここでは処?行いません?
202            }
203    
204            /**
205             * フィルターの?状態をチェ?するメソ?です?
206             *
207             * 判定条件は、URL_ACCESS_SECURITY_LEVEL 変数 に応じて異なります?
208             *     レベル?:なにも制限?ありません?
209             *     レベル?:Referer チェ?を行います?つまり?URLを直接入力しても動作しません?
210             *     レベル?:URLのハッシュ?暗号化??、外部URLに対してのみ行います?(チェ?は、レベル?と同?
211             *     レベル?:URLのパラメータがハ?ュ?暗号化されて??があります?
212             *     それ以外:アクセスを停止します?
213             *
214             * @param request HttpServletRequestオブジェク?
215             *
216             * @return      (true:許可  false:拒否)
217             */
218            private boolean isValidAccess( final HttpServletRequest request ) {
219                    if( ACCS_LVL == 0 )      { return true;  }      // レベル?:無条件アクセス
220    
221                    String httpReferer = request.getHeader( "Referer" );
222                    String requestURI  = request.getRequestURI();
223                    String queryString = request.getQueryString();
224                    String hashVal     = request.getParameter( REQ_KEY );
225    
226                    if( isDebug ) {
227                            System.out.println( "URLHashFilter#httpReferer = " + httpReferer );
228                            System.out.println( "URLHashFilter#requestURI  = " + requestURI  );
229                    }
230    
231                    // 基準となる許可?パラメータな?or ハッシュありの場?
232                    boolean flag2 = ( queryString == null || hashVal != null ) ;
233    
234                    // レベル???:パラメータな?or ハッシュあり or Refererあり の場合?許可
235                    if( ACCS_LVL == 1 || ACCS_LVL == 2 ) {
236                            return ( flag2 || httpReferer != null );
237                    }
238    
239                    // レベル?:パラメータな?or ハッシュありの場合?許可
240                    if( ACCS_LVL == 3 ) {
241                            String cntxPath = request.getContextPath();             // /gf など
242                            // 特別処置
243                            return flag2 ||
244                                              requestURI.equalsIgnoreCase( initPage )            ||
245                                              requestURI.startsWith( cntxPath + "/jsp/menu/"   ) ||
246                                              requestURI.startsWith( cntxPath + "/jsp/custom/" ) ||
247                                              requestURI.startsWith( cntxPath + "/jsp/common/" ) ;
248                    }
249    
250                    return false;   // それ以外:無条件拒否
251            }
252    
253            /**
254             * ?状態を??で返します?
255             *
256             * @return      こ?クラスの??表示
257             */
258            @Override
259            public String toString() {
260                    StringBuilder sb = new StringBuilder()
261                            .append( this.getClass().getCanonicalName() ).append( " : ")
262                            .append( "initPage = [" ).append( initPage ).append( "] , ")
263    //                      .append( "filename = [" ).append( filename ).append( "] , ")
264                            .append( "isDebug  = [" ).append( isDebug  ).append( "]");
265                    return (sb.toString());
266            }
267    }