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