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