001/* 002 003 Licensed to the Apache Software Foundation (ASF) under one 004 or more contributor license agreements. See the NOTICE file 005 distributed with this work for additional information 006 regarding copyright ownership. The ASF licenses this file 007 to you under the Apache License, Version 2.0 (the 008 "License"); you may not use this file except in compliance 009 with the License. You may obtain a copy of the License at 010 011 http://www.apache.org/licenses/LICENSE-2.0 012 013 Unless required by applicable law or agreed to in writing, 014 software distributed under the License is distributed on an 015 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 KIND, either express or implied. See the License for the 017 specific language governing permissions and limitations 018 under the License. 019 */ 020package org.apache.wiki.ajax; 021 022import org.apache.commons.lang3.StringUtils; 023import org.apache.log4j.Logger; 024import org.apache.wiki.WikiEngine; 025import org.apache.wiki.WikiSession; 026import org.apache.wiki.auth.AuthorizationManager; 027import org.apache.wiki.auth.permissions.PagePermission; 028import org.apache.wiki.util.TextUtil; 029 030import javax.servlet.ServletConfig; 031import javax.servlet.ServletException; 032import javax.servlet.http.HttpServlet; 033import javax.servlet.http.HttpServletRequest; 034import javax.servlet.http.HttpServletResponse; 035import java.io.IOException; 036import java.security.Permission; 037import java.util.ArrayList; 038import java.util.Arrays; 039import java.util.HashMap; 040import java.util.List; 041import java.util.Map; 042 043/** 044 * This provides a simple ajax servlet for handling /ajax/<ClassName> requests. 045 * HttpServlet classes need to be registered using {@link WikiAjaxDispatcherServlet#registerServlet(WikiAjaxServlet)} 046 * 047 * @since 2.10.2-svn12 048 */ 049public class WikiAjaxDispatcherServlet extends HttpServlet { 050 private static final long serialVersionUID = 1L; 051 private static Map<String,AjaxServletContainer> ajaxServlets = new HashMap<String,AjaxServletContainer>(); 052 static final Logger log = Logger.getLogger(WikiAjaxDispatcherServlet.class.getName()); 053 private String PATH_AJAX = "/ajax/"; 054 private WikiEngine m_engine; 055 056 /** 057 * {@inheritDoc} 058 * 059 * This sets the AjaxPath to "/ajax/" as configured in "jspwiki.ajax.url.prefix". 060 * Note: Do not change this without also changing the web.xml file. 061 */ 062 @Override 063 public void init(ServletConfig config) 064 throws ServletException { 065 super.init(config); 066 m_engine = WikiEngine.getInstance(config); 067 PATH_AJAX = "/"+TextUtil.getStringProperty(m_engine.getWikiProperties(), "jspwiki.ajax.url.prefix", "ajax")+"/"; 068 log.info("WikiAjaxDispatcherServlet initialized."); 069 } 070 071 /** 072 * Register a {@link WikiAjaxServlet} using the servlet mapping as the alias 073 */ 074 public static void registerServlet(WikiAjaxServlet servlet) { 075 registerServlet(servlet.getServletMapping(),servlet); 076 } 077 078 /** 079 * Register a {@link WikiAjaxServlet} with a specific alias, and default permission {@link PagePermission#VIEW}. 080 */ 081 public static void registerServlet(String alias, WikiAjaxServlet servlet) { 082 registerServlet(alias, servlet, PagePermission.VIEW); 083 } 084 085 /** 086 * Regster a {@link WikiAjaxServlet} given an alias, the servlet, and the permission. 087 * This creates a temporary bundle object called {@link WikiAjaxDispatcherServlet.AjaxServletContainer} 088 * @param alias the uri link to this servlet 089 * @param servlet the servlet being registered 090 * @param perm the permission required to execute the servlet. 091 */ 092 public static void registerServlet(String alias, WikiAjaxServlet servlet, Permission perm) { 093 log.info("WikiAjaxDispatcherServlet registering "+alias+"="+servlet+" perm="+perm); 094 ajaxServlets.put(alias,new AjaxServletContainer(alias, servlet, perm)); 095 } 096 097 /** 098 * Calls {@link #performAction} 099 */ 100 @Override 101 public void doPost(HttpServletRequest req, HttpServletResponse res) 102 throws IOException, ServletException { 103 performAction(req,res); 104 } 105 106 /** 107 * Calls {@link #performAction} 108 */ 109 @Override 110 public void doGet(HttpServletRequest req, HttpServletResponse res) 111 throws IOException, ServletException { 112 performAction(req,res); 113 } 114 115 /** 116 * The main method which get the requestURI "/ajax/<ServletName>", gets the 117 * {@link #getServletName} and finds the servlet using {@link #findServletByName}. 118 * It then calls {@link WikiAjaxServlet#service} method. 119 * @param req the inbound request 120 * @param res the outbound response 121 * @throws IOException 122 * @throws ServletException if no registered servlet can be found 123 */ 124 private void performAction( final HttpServletRequest req, final HttpServletResponse res ) throws IOException, ServletException { 125 final String path = req.getRequestURI(); 126 final String servletName = getServletName(path); 127 if (servletName!=null) { 128 final AjaxServletContainer container = findServletContainer(servletName); 129 if (container != null) { 130 final WikiAjaxServlet servlet = container.servlet; 131 if ( validatePermission(req,container) ) { 132 req.setCharacterEncoding(m_engine.getContentEncoding().displayName()); 133 res.setCharacterEncoding(m_engine.getContentEncoding().displayName()); 134 final String actionName = AjaxUtil.getNextPathPart(req.getRequestURI(), servlet.getServletMapping()); 135 log.debug("actionName="+actionName); 136 final Object params = req.getParameter("params"); 137 log.debug("params="+params); 138 List<String> paramValues = new ArrayList<String>(); 139 if (params instanceof String) { 140 final String paramString = (String)params; 141 if (StringUtils.isNotBlank(paramString)) { 142 paramValues = Arrays.asList(paramString.trim().split(",")); 143 } 144 } 145 servlet.service(req, res, actionName, paramValues); 146 } else { 147 log.warn("Servlet container "+container+" not authorised. Permission required."); 148 } 149 } else { 150 log.error("No registered class for servletName=" + servletName + " in path=" + path); 151 throw new ServletException("No registered class for servletName=" + servletName); 152 } 153 } 154 } 155 156 /** 157 * Validate the permission of the {@link WikiAjaxServlet} using the {@link AuthorizationManager#checkPermission} 158 * 159 * @param req the servlet request 160 * @param container the container info of the servlet 161 * @return true if permission is valid 162 */ 163 private boolean validatePermission(HttpServletRequest req, AjaxServletContainer container) { 164 final WikiEngine e = WikiEngine.getInstance(req.getSession().getServletContext(), null); 165 boolean valid = false; 166 if (container != null) { 167 valid = e.getAuthorizationManager().checkPermission(WikiSession.getWikiSession(e, req), container.permission); 168 } 169 return valid; 170 } 171 172 /** 173 * Get the ServletName from the requestURI "/ajax/<ServletName>", using {@link AjaxUtil#getNextPathPart}. 174 * 175 * @param path The requestURI, which must contains "/ajax/<ServletName>" in the path 176 * @return The ServletName for the requestURI, or null 177 * @throws ServletException if the path is invalid 178 */ 179 public String getServletName(String path) throws ServletException { 180 return AjaxUtil.getNextPathPart(path, PATH_AJAX); 181 } 182 183 /** 184 * Find the {@link AjaxServletContainer} as registered in {@link #registerServlet}. 185 * 186 * @param servletAlias the name of the servlet from {@link #getServletName} 187 * @return The first servlet found, or null. 188 */ 189 private AjaxServletContainer findServletContainer(String servletAlias) { 190 return ajaxServlets.get(servletAlias); 191 } 192 193 /** 194 * Find the {@link WikiAjaxServlet} given the servletAlias that it was registered with. 195 * 196 * @param servletAlias the value provided to {@link #registerServlet} 197 * @return the {@link WikiAjaxServlet} given the servletAlias that it was registered with. 198 */ 199 public WikiAjaxServlet findServletByName(String servletAlias) { 200 final AjaxServletContainer container = ajaxServlets.get(servletAlias); 201 if (container != null) { 202 return container.servlet; 203 } 204 return null; 205 } 206 207 private static class AjaxServletContainer { 208 String alias; 209 WikiAjaxServlet servlet; 210 Permission permission; 211 212 public AjaxServletContainer(String alias, WikiAjaxServlet servlet, Permission permission) { 213 this.alias = alias; 214 this.servlet = servlet; 215 this.permission = permission; 216 } 217 218 @Override 219 public String toString() { 220 return getClass().getSimpleName()+" "+alias+"="+servlet.getClass().getSimpleName()+" permission="+permission; 221 } 222 } 223 224}