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