001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.ui; 020 021import java.io.IOException; 022import java.io.PrintWriter; 023 024import javax.servlet.*; 025import javax.servlet.http.HttpServletRequest; 026import javax.servlet.http.HttpServletRequestWrapper; 027 028import org.apache.log4j.Logger; 029import org.apache.log4j.NDC; 030 031import org.apache.wiki.WikiContext; 032import org.apache.wiki.WikiEngine; 033import org.apache.wiki.WikiSession; 034import org.apache.wiki.auth.SessionMonitor; 035import org.apache.wiki.auth.WikiSecurityException; 036import org.apache.wiki.tags.WikiTagBase; 037 038/** 039 * Filter that verifies that the {@link org.apache.wiki.WikiEngine} is running, and 040 * sets the authentication status for the user's WikiSession. Each HTTP request 041 * processed by this filter is wrapped by a {@link WikiRequestWrapper}. The wrapper's 042 * primary responsibility is to return the correct <code>userPrincipal</code> and 043 * <code>remoteUser</code> for authenticated JSPWiki users (whether 044 * authenticated by container or by JSPWiki's custom system). 045 * The wrapper's other responsibility is to incorporate JSPWiki built-in roles 046 * into the role-checking algorithm for {@link HttpServletRequest#isUserInRole(String)}. 047 * Just before the request is wrapped, the method {@link org.apache.wiki.auth.AuthenticationManager#login(HttpServletRequest)} executes; 048 * this method contains all of the logic needed to grab any user login credentials set 049 * by the container or by cookies. 050 * 051 * 052 */ 053public class WikiServletFilter implements Filter 054{ 055 protected static final Logger log = Logger.getLogger( WikiServletFilter.class ); 056 protected WikiEngine m_engine = null; 057 058 /** 059 * Creates a Wiki Servlet Filter. 060 */ 061 public WikiServletFilter() 062 { 063 super(); 064 } 065 066 /** 067 * Initializes the WikiServletFilter. 068 * 069 * @param config The FilterConfig. 070 * @throws ServletException If a WikiEngine cannot be started. 071 */ 072 public void init( FilterConfig config ) throws ServletException 073 { 074 ServletContext context = config.getServletContext(); 075 076 // TODO REMOVEME when resolving JSPWIKI-129 077 if( System.getSecurityManager() != null ) 078 { 079 context.log( "== JSPWIKI WARNING == : This container is running with a security manager. JSPWiki does not yet really support that right now. See issue JSPWIKI-129 for details and information on how to proceed." ); 080 } 081 082 m_engine = WikiEngine.getInstance( context, null ); 083 } 084 085 /** 086 * Destroys the WikiServletFilter. 087 */ 088 public void destroy() 089 { 090 } 091 092 /** 093 * Checks that the WikiEngine is running ok, wraps the current 094 * HTTP request, and sets the correct authentication state for the users's 095 * WikiSession. First, the method {@link org.apache.wiki.auth.AuthenticationManager#login(HttpServletRequest)} 096 * executes, which sets the authentication state. Then, the request is wrapped with a 097 * {@link WikiRequestWrapper}. 098 * @param request the current HTTP request object 099 * @param response the current HTTP response object 100 * @param chain The Filter chain passed down. 101 * @throws ServletException if {@link org.apache.wiki.auth.AuthenticationManager#login(HttpServletRequest)} fails for any reason 102 * @throws IOException If writing to the servlet response fails. 103 */ 104 public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException 105 { 106 // 107 // Sanity check; it might be true in some conditions, but we need to know where. 108 // 109 if( chain == null ) 110 { 111 throw new ServletException("FilterChain is null, even if it should not be. Please report this to the jspwiki development team."); 112 } 113 114 if( m_engine == null ) 115 { 116 PrintWriter out = response.getWriter(); 117 out.print("<!DOCTYPE html><html lang=\"en\"><head><title>Fatal problem with JSPWiki</title></head>"); 118 out.print("<body>"); 119 out.print("<h1>JSPWiki has not been started</h1>"); 120 out.print("<p>JSPWiki is not running. This is probably due to a configuration error in your jspwiki.properties file, "); 121 out.print("or a problem with your servlet container. Please double-check everything before issuing a bug report "); 122 out.print("at jspwiki.apache.org.</p>"); 123 out.print("<p>We apologize for the inconvenience. No, really, we do. We're trying to "); 124 out.print("JSPWiki as easy as we can, but there is only so much we have time to test "); 125 out.print("platforms.</p>"); 126 out.print( "<p>Please go to the <a href='Install.jsp'>installer</a> to continue.</p>" ); 127 out.print("</body></html>"); 128 return; 129 } 130 131 // If we haven't done so, wrap the request 132 HttpServletRequest httpRequest = (HttpServletRequest) request; 133 134 // Set the character encoding 135 httpRequest.setCharacterEncoding( m_engine.getContentEncoding() ); 136 137 if ( !isWrapped( request ) ) 138 { 139 // Prepare the WikiSession 140 try 141 { 142 m_engine.getAuthenticationManager().login( httpRequest ); 143 WikiSession wikiSession = SessionMonitor.getInstance( m_engine ).find( httpRequest.getSession() ); 144 httpRequest = new WikiRequestWrapper( m_engine, httpRequest ); 145 if ( log.isDebugEnabled() ) 146 { 147 log.debug( "Executed security filters for user=" + wikiSession.getLoginPrincipal().getName() + ", path=" + httpRequest.getRequestURI() ); 148 } 149 } 150 catch ( WikiSecurityException e ) 151 { 152 throw new ServletException( e ); 153 } 154 } 155 156 try 157 { 158 NDC.push( m_engine.getApplicationName()+":"+httpRequest.getRequestURL() ); 159 160 chain.doFilter( httpRequest, response ); 161 } 162 finally 163 { 164 NDC.pop(); 165 NDC.remove(); 166 } 167 168 } 169 170 /** 171 * Figures out the wiki context from the request. This method does not create the 172 * context if it does not exist. 173 * 174 * @param request The request to examine 175 * @return A valid WikiContext value (or null, if the context could not be located). 176 */ 177 protected WikiContext getWikiContext( ServletRequest request ) 178 { 179 HttpServletRequest httpRequest = (HttpServletRequest) request; 180 181 WikiContext ctx = (WikiContext) httpRequest.getAttribute( WikiTagBase.ATTR_CONTEXT ); 182 183 return ctx; 184 } 185 186 /** 187 * Determines whether the request has been previously wrapped with a WikiRequestWrapper. 188 * We find the wrapper by recursively unwrapping successive request wrappers, if they have been supplied. 189 * @param request the current HTTP request 190 * @return <code>true</code> if the request has previously been wrapped; 191 * <code>false</code> otherwise 192 */ 193 private boolean isWrapped( ServletRequest request ) 194 { 195 while ( !(request instanceof WikiRequestWrapper ) 196 && request != null 197 && request instanceof HttpServletRequestWrapper ) 198 { 199 request = ((HttpServletRequestWrapper) request).getRequest(); 200 } 201 return request instanceof WikiRequestWrapper ? true : false; 202 } 203 204}