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 java.io.File;                                                    // 5.7.3.2 (2014/02/28) Tomcat8 対?
019    import java.io.BufferedReader;
020    import java.io.FileInputStream;
021    import java.io.IOException;
022    import java.io.InputStreamReader;
023    import java.io.PrintWriter;
024    import java.io.UnsupportedEncodingException;
025    
026    import javax.servlet.Filter;
027    import javax.servlet.FilterChain;
028    import javax.servlet.FilterConfig;
029    import javax.servlet.ServletContext;
030    import javax.servlet.ServletException;
031    import javax.servlet.ServletRequest;
032    import javax.servlet.ServletResponse;
033    import javax.servlet.http.HttpServletRequest;
034    
035    import org.opengion.fukurou.security.HybsCryptography;
036    import org.opengion.fukurou.util.Closer;
037    import org.opengion.fukurou.util.StringUtil;
038    import org.opengion.hayabusa.common.HybsSystem;
039    
040    /**
041     * URLCheckFilter は、Filter インターフェースを継承した URLチェ?クラスです?
042     * web.xml で filter 設定することにより、該当?リソースに対して、og:linkタグで?
043     * useURLCheck="true"が指定されたリンクURL以外を拒否することができます?
044     * また?og:linkタグを経由した場合でも?リンクの有効期限を設定することで?
045     * リンクURLの漏洩に対しても??時間?経過を持って、アクセスを拒否することができます?
046     * また?リンク時にユーザー??も埋め込んで?す?で(初期値は、ログインユーザー)?
047     * リンクアドレスが他?ユーザーに知られた?合でも?アクセスを拒否することができます?
048     * 
049     * シス?リソースの「URL_CHECK_CRYPT」で暗号復号化?キーを指定可能です?
050     * ?しな??合??ォルト?キーが利用されます?
051     * キーの形式?HybsCryptographyに従います?
052     *
053     * フィルターに対してweb.xml でパラメータを設定します?
054     *   ・filename :停止時メ?ージ表示ファイル?
055     *   ・ignoreURL:暗号化されたURLの?空白に置き換える接頭??を指定します?
056     *                      外部からアクセスしたURLがロードバランサで?向けURLに変換されてチェ?が動作しな??場合に
057     *                      利用します?https://wwwX.のように?します?通常は設定しません?
058     *
059     * 【WEB-INF/web.xml?
060     *     <filter>
061     *         <filter-name>URLCheckFilter</filter-name>
062     *         <filter-class>org.opengion.hayabusa.filter.URLCheckFilter</filter-class>
063     *         <init-param>
064     *             <param-name>filename</param-name>
065     *             <param-value>jsp/custom/refuseAccess.html</param-value>
066     *         </init-param>
067     *     </filter>
068     *
069     *     <filter-mapping>
070     *         <filter-name>URLCheckFilter</filter-name>
071     *         <url-pattern>/jsp/*</url-pattern>
072     *     </filter-mapping>
073     *
074     * @og.group フィルター処?
075     *
076     * @version  4.0
077     * @author   Hiroki Nakamura
078     * @since    JDK5.0,
079     */
080    public final class URLCheckFilter implements Filter {
081    
082    //      private static final HybsCryptography HYBS_CRYPTOGRAPHY = new HybsCryptography(); // 4.3.7.0 (2009/06/01)
083            private static final HybsCryptography HYBS_CRYPTOGRAPHY 
084                                                    = new HybsCryptography( HybsSystem.sys( "URL_CHECK_CRYPT" ) ); // 5.8.8.0 (2015/06/05)
085    
086            private String  filename  = null;                       // アクセス拒否時メ?ージ表示ファイル?
087    //      private int             maxInterval = 3600;                     // リンクの有効期限
088            private boolean  isDebug         = false;
089            private boolean  isDecode        = true;                // 5.4.5.0(2012/02/28) URIDecodeするかど?
090            
091            private String          ignoreURL       = null; //5.8.6.1 (2015/04/17) 飛んできたcheckURLから取り除くURL??
092    
093            /**
094             * フィルター処?体?メソ?です?
095             *
096             * @param       request         ServletRequestオブジェク?
097             * @param       response        ServletResponseオブジェク?
098             * @param       chain           FilterChainオブジェク?
099             * @throws ServletException サーブレ?関係?エラーが発生した?合?throw されます?
100             */
101            public void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain chain ) throws IOException, ServletException {
102    
103                    if( !isValidAccess( request ) ) {
104                            BufferedReader in = null ;
105                            try {
106                                    response.setContentType( "text/html; charset=UTF-8" );
107                                    PrintWriter out = response.getWriter();
108                                    in = new BufferedReader( new InputStreamReader(
109                                                                    new FileInputStream( filename ) ,"UTF-8" ) );
110                                    String str ;
111                                    while( (str = in.readLine()) != null ) {
112                                            out.println( str );
113                                    }
114                                    out.flush();
115                            }
116                            catch( UnsupportedEncodingException ex ) {
117                                    String errMsg = "?されたエンコー?ングがサポ?トされて?せん?UTF-8]" ;
118                                    throw new RuntimeException( errMsg,ex );
119                            }
120                            catch( IOException ex ) {
121                                    String errMsg = "ストリー?オープン出来ませんでした?" + filename + "]" ;
122                                    throw new RuntimeException( errMsg,ex );
123                            }
124                            finally {
125                                    Closer.ioClose( in );
126                            }
127                            return;
128                    }
129    
130                    chain.doFilter(request, response);
131            }
132    
133            /**
134             * フィルターの初期処?ソ?です?
135             *
136             * フィルターに対してweb.xml で初期パラメータを設定します?
137             *   ・maxInterval:リンクの有効期限
138             *   ・filename   :停止時メ?ージ表示ファイル?
139             *   ・decode     :URL?ードを行ってチェ?する?初期true)
140             *
141             * @og.rev 5.4.5.0 (2102/02/28)
142             * @og.rev 5.7.3.2 (2014/02/28) Tomcat8 対応?getRealPath( "/" ) の互換性のための修正?
143             * @og.rev 5.8.6.1 (2015/04/17) DMZのURL変換対?
144             *
145             * @param filterConfig FilterConfigオブジェク?
146             */
147            public void init(final FilterConfig filterConfig) {
148                    ServletContext context = filterConfig.getServletContext();
149    //              String realPath = context.getRealPath( "/" );
150                    String realPath = context.getRealPath( "" ) + File.separator;           // 5.7.3.2 (2014/02/28) Tomcat8 対?
151    
152    //              maxInterval = StringUtil.nval( filterConfig.getInitParameter("maxInterval"), maxInterval );
153                    filename  = realPath + filterConfig.getInitParameter("filename");
154                    isDebug = StringUtil.nval( filterConfig.getInitParameter("debug"), false );
155                    isDecode = StringUtil.nval( filterConfig.getInitParameter("decode"), true ); // 5.4.5.0(2012/02/28)
156                    ignoreURL = filterConfig.getInitParameter("ignoreURL"); // 5.8.6.1 (2015/04/17)
157            }
158    
159            /**
160             * フィルターの終???ソ?です?
161             *
162             */
163            public void destroy() {
164                    // ここでは処?行いません?
165            }
166    
167            /**
168             * フィルターの?状態をチェ?するメソ?です?
169             *
170             * @og.rev 5.4.5.0 (2012/02/28) Decode
171             * @og.rev 5.8.8.2 (2015/07/17) マルチバイト対応追?
172             *
173             * @param request ServletRequestオブジェク?
174             *
175             * @return      (true:許可  false:拒否)
176             */
177            private boolean isValidAccess( final ServletRequest request ) {
178                    String checkKey = request.getParameter( HybsSystem.URL_CHECK_KEY );
179                    if( checkKey == null || checkKey.length() == 0 ) {
180                            if( isDebug ) {
181                                    System.out.println( "  check NG [ No Check Key ]" );
182                            }
183                            return false;
184                    }
185    
186                    boolean rtn = false;
187                    try {
188                            checkKey = HYBS_CRYPTOGRAPHY.decrypt( checkKey ).replace( "&", "&" );
189    
190                            if( isDebug ) {
191                                    System.out.println( "checkKey=" + checkKey );
192                            }
193    
194                            String url = checkKey.substring( 0 , checkKey.lastIndexOf( ",time=") );
195                            long time = Long.parseLong( checkKey.substring( checkKey.lastIndexOf( ",time=") + 6, checkKey.lastIndexOf( ",userid=" ) ) );
196                            String userid = checkKey.substring( checkKey.lastIndexOf( ",userid=") + 8 );
197                            // 4.3.8.0 (2009/08/01)
198                            String[] userArr = StringUtil.csv2Array( userid );
199                            
200                            // 5.8.6.1 (2015/04/17)ignoreURL対?
201                            if( ignoreURL!=null && ignoreURL.length()>0 && url.indexOf( ignoreURL ) == 0 ){
202                                    url = url.substring( ignoreURL.length() );
203                            }
204    
205                            if( isDebug ) {
206                                    System.out.println( " [ignoreURL]=" + ignoreURL ); // 2015/04/17 (2015/04/17)
207                                    System.out.println( " [url]    =" + url );
208                                    System.out.println( " [vtime]  =" + time );
209                                    System.out.println( " [userid] =" + userid );
210                            }
211    
212                            String reqStr =  ((HttpServletRequest)request).getRequestURL().toString() + "?" + ((HttpServletRequest)request).getQueryString();
213                            // 5.4.5.0 (2012/02/28) URLDecodeを行う
214                            if(isDecode){
215                                    if( isDebug ) {
216                                            System.out.println( "[BeforeURIDecode]="+reqStr );
217                                    }
218                                    reqStr = StringUtil.urlDecode( reqStr );
219                                    url = StringUtil.urlDecode( url ); // 5.8.8.2 (2015/07/17)
220                            }
221                            reqStr = reqStr.substring( 0, reqStr.lastIndexOf( HybsSystem.URL_CHECK_KEY ) -1 );
222                            //      String reqStr =  ((HttpServletRequest)request).getRequestURL().toString();
223                            String reqUser = ((HttpServletRequest)request).getRemoteUser();
224    
225                            if( isDebug ) {
226                                    System.out.println( " [reqURL] =" + reqStr );
227                                    System.out.println( " [ctime]  =" + System.currentTimeMillis() );
228                                    System.out.println( " [reqUser]=" + reqUser );
229                            }
230    
231                            if( reqStr.endsWith( url )
232    //                                      && System.currentTimeMillis() - time < maxInterval * 1000
233                                            && System.currentTimeMillis() - time < 0
234    //                                      && userid.equals( reqUser ) ) {
235                                            && userArr != null && userArr.length > 0 ) {
236                                    // 4.3.8.0 (2009/08/01)
237                                    for( int i=0; i<userArr.length; i++ ) {
238                                            if( "*".equals( userArr[i] ) || reqUser.equals( userArr[i] ) ) {
239                                                    rtn = true;
240                                                    if( isDebug ) {
241                                                            System.out.println( "  check OK" );
242                                                    }
243                                                    break;
244                                            }
245                                    }
246                            }
247                    }
248                    catch( RuntimeException ex ) {
249                            if( isDebug ) {
250                                    String errMsg = "チェ?エラー?"
251                                                            + " checkKey=" + checkKey
252                                                            + " " + ex.getMessage();                        // 5.1.8.0 (2010/07/01) errMsg 修正
253                                    System.out.println( errMsg );
254                                    ex.printStackTrace();
255                            }
256                            rtn = false;
257                    }
258                    return rtn;
259            }
260    
261            /**
262             * ?状態を??で返します?
263             *
264             * @return      こ?クラスの??表示
265             */
266            @Override
267            public String toString() {
268                    StringBuilder sb = new StringBuilder();
269                    sb.append( "UrlCheckFilter" );
270    //              sb.append( "[" ).append( maxInterval ).append( "],");
271                    sb.append( "[" ).append( filename  ).append( "],");
272                    return (sb.toString());
273            }
274    }