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 */
019 package org.apache.wiki.ui;
020
021 import java.io.IOException;
022 import java.io.PrintWriter;
023
024 import javax.servlet.*;
025 import javax.servlet.http.HttpServletRequest;
026 import javax.servlet.http.HttpServletRequestWrapper;
027
028 import org.apache.log4j.Logger;
029 import org.apache.log4j.NDC;
030
031 import org.apache.wiki.WikiContext;
032 import org.apache.wiki.WikiEngine;
033 import org.apache.wiki.WikiSession;
034 import org.apache.wiki.auth.SessionMonitor;
035 import org.apache.wiki.auth.WikiSecurityException;
036 import 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 */
053 public 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("<html><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( m_engine.getBaseURL().length() == 0 && !httpRequest.getRequestURI().endsWith("Install.jsp") )
138 {
139 PrintWriter out = response.getWriter();
140
141 out.print( "<html><head><title>JSPWiki installation start</title></head>" );
142 out.print( "<body>" );
143 out.print( "<h1>JSPWiki installation</h1>" );
144 out.print( "<p>Hello! It appears that this is your first jspwiki installation." );
145 out.print( "(Or, you have removed jspwiki.baseURL from your property file.) " );
146 out.print( "Therefore, you will need to start the installation process. " );
147 out.print( "Please <a href='Install.jsp'>continue to the installer</a>." );
148 out.print( "</p>");
149 out.print( "<p>If you just used the installer, then please restart your servlet container to get rid of this message.</p>" );
150 out.print("</body></html>");
151 return;
152 }
153
154 if ( !isWrapped( request ) )
155 {
156 // Prepare the WikiSession
157 try
158 {
159 m_engine.getAuthenticationManager().login( httpRequest );
160 WikiSession wikiSession = SessionMonitor.getInstance( m_engine ).find( httpRequest.getSession() );
161 httpRequest = new WikiRequestWrapper( m_engine, httpRequest );
162 if ( log.isDebugEnabled() )
163 {
164 log.debug( "Executed security filters for user=" + wikiSession.getLoginPrincipal().getName() + ", path=" + httpRequest.getRequestURI() );
165 }
166 }
167 catch ( WikiSecurityException e )
168 {
169 throw new ServletException( e );
170 }
171 }
172
173 try
174 {
175 NDC.push( m_engine.getApplicationName()+":"+httpRequest.getRequestURL() );
176
177 chain.doFilter( httpRequest, response );
178 }
179 finally
180 {
181 NDC.pop();
182 NDC.remove();
183 }
184
185 }
186
187 /**
188 * Figures out the wiki context from the request. This method does not create the
189 * context if it does not exist.
190 *
191 * @param request The request to examine
192 * @return A valid WikiContext value (or null, if the context could not be located).
193 */
194 protected WikiContext getWikiContext( ServletRequest request )
195 {
196 HttpServletRequest httpRequest = (HttpServletRequest) request;
197
198 WikiContext ctx = (WikiContext) httpRequest.getAttribute( WikiTagBase.ATTR_CONTEXT );
199
200 return ctx;
201 }
202
203 /**
204 * Determines whether the request has been previously wrapped with a WikiRequestWrapper.
205 * We find the wrapper by recursively unwrapping successive request wrappers, if they have been supplied.
206 * @param request the current HTTP request
207 * @return <code>true</code> if the request has previously been wrapped;
208 * <code>false</code> otherwise
209 */
210 private boolean isWrapped( ServletRequest request )
211 {
212 while ( !(request instanceof WikiRequestWrapper )
213 && request != null
214 && request instanceof HttpServletRequestWrapper )
215 {
216 request = ((HttpServletRequestWrapper) request).getRequest();
217 }
218 return request instanceof WikiRequestWrapper ? true : false;
219 }
220
221 }