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