001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * 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, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.geronimo.tomcat; 019 020 import java.beans.PropertyChangeListener; 021 import java.io.IOException; 022 import java.util.Iterator; 023 import java.util.List; 024 import java.util.Map; 025 026 import javax.naming.NamingException; 027 import javax.security.auth.Subject; 028 import javax.security.jacc.PolicyContext; 029 import javax.servlet.Servlet; 030 import javax.servlet.ServletException; 031 032 import org.apache.catalina.Container; 033 import org.apache.catalina.LifecycleException; 034 import org.apache.catalina.Loader; 035 import org.apache.catalina.Manager; 036 import org.apache.catalina.Valve; 037 import org.apache.catalina.Wrapper; 038 import org.apache.catalina.cluster.CatalinaCluster; 039 import org.apache.catalina.connector.Request; 040 import org.apache.catalina.connector.Response; 041 import org.apache.catalina.core.StandardContext; 042 import org.apache.catalina.valves.ValveBase; 043 import org.apache.commons.logging.Log; 044 import org.apache.commons.logging.LogFactory; 045 import org.apache.geronimo.common.DeploymentException; 046 import org.apache.geronimo.naming.enc.EnterpriseNamingContext; 047 import org.apache.geronimo.security.ContextManager; 048 import org.apache.geronimo.security.IdentificationPrincipal; 049 import org.apache.geronimo.security.SubjectId; 050 import org.apache.geronimo.security.deploy.DefaultPrincipal; 051 import org.apache.geronimo.security.util.ConfigurationUtil; 052 import org.apache.geronimo.tomcat.interceptor.BeforeAfter; 053 import org.apache.geronimo.tomcat.interceptor.ComponentContextBeforeAfter; 054 import org.apache.geronimo.tomcat.interceptor.InstanceContextBeforeAfter; 055 import org.apache.geronimo.tomcat.interceptor.PolicyContextBeforeAfter; 056 import org.apache.geronimo.tomcat.util.SecurityHolder; 057 import org.apache.geronimo.tomcat.valve.DefaultSubjectValve; 058 import org.apache.geronimo.tomcat.valve.GeronimoBeforeAfterValve; 059 import org.apache.geronimo.webservices.POJOWebServiceServlet; 060 import org.apache.geronimo.webservices.WebServiceContainer; 061 import org.apache.geronimo.webservices.WebServiceContainerInvoker; 062 063 064 public class GeronimoStandardContext extends StandardContext { 065 066 private static final Log log = LogFactory.getLog(GeronimoStandardContext.class); 067 068 private static final long serialVersionUID = 3834587716552831032L; 069 070 private Subject defaultSubject = null; 071 072 private Map webServiceMap = null; 073 074 private boolean pipelineInitialized; 075 076 private BeforeAfter beforeAfter = null; 077 private int contextCount = 0; 078 079 public void setContextProperties(TomcatContext ctx) throws DeploymentException { 080 //try to make sure this mbean properties match those of the TomcatWebAppContext 081 if (ctx instanceof TomcatWebAppContext) { 082 TomcatWebAppContext tctx = (TomcatWebAppContext) ctx; 083 setJavaVMs(tctx.getJavaVMs()); 084 setServer(tctx.getServer()); 085 setJ2EEApplication(tctx.getJ2EEApplication()); 086 setJ2EEServer(tctx.getJ2EEServer()); 087 } 088 // Create ReadOnlyContext 089 javax.naming.Context enc = null; 090 Map componentContext = ctx.getComponentContext(); 091 try { 092 if (componentContext != null) { 093 enc = EnterpriseNamingContext.createEnterpriseNamingContext(componentContext, ctx.getUserTransaction(), ctx.getKernel(), ctx.getClassLoader()); 094 } 095 } catch (NamingException ne) { 096 log.error(ne); 097 } 098 099 int index = 0; 100 BeforeAfter interceptor = new InstanceContextBeforeAfter(null, index++, 101 ctx.getUnshareableResources(), 102 ctx.getApplicationManagedSecurityResources(), 103 ctx.getTrackedConnectionAssociator()); 104 105 // Set ComponentContext BeforeAfter 106 if (enc != null) { 107 interceptor = new ComponentContextBeforeAfter(interceptor, index++, enc); 108 } 109 110 //Set a PolicyContext BeforeAfter 111 SecurityHolder securityHolder = ctx.getSecurityHolder(); 112 if (securityHolder != null) { 113 if (securityHolder.getPolicyContextID() != null) { 114 115 PolicyContext.setContextID(securityHolder.getPolicyContextID()); 116 117 /** 118 * Register our default subject with the ContextManager 119 */ 120 DefaultPrincipal defaultPrincipal = securityHolder.getDefaultPrincipal(); 121 if (defaultPrincipal != null) { 122 defaultSubject = ConfigurationUtil.generateDefaultSubject(defaultPrincipal, ctx.getClassLoader()); 123 ContextManager.registerSubject(defaultSubject); 124 SubjectId id = ContextManager.getSubjectId(defaultSubject); 125 defaultSubject.getPrincipals().add(new IdentificationPrincipal(id)); 126 } 127 128 interceptor = new PolicyContextBeforeAfter(interceptor, index++, index++, securityHolder.getPolicyContextID()); 129 } 130 } 131 132 //Set the BeforeAfters as a valve 133 GeronimoBeforeAfterValve geronimoBAValve = new GeronimoBeforeAfterValve(interceptor, index); 134 addValve(geronimoBAValve); 135 beforeAfter = interceptor; 136 contextCount = index; 137 138 //Not clear if user defined valves should be involved in init processing. Probably not since 139 //request and response are null. 140 141 addValve(new SystemMethodValve()); 142 143 // Add User Defined Valves 144 List valveChain = ctx.getValveChain(); 145 if (valveChain != null) { 146 Iterator iterator = valveChain.iterator(); 147 while (iterator.hasNext()) { 148 Valve valve = (Valve) iterator.next(); 149 addValve(valve); 150 } 151 } 152 153 CatalinaCluster cluster = ctx.getCluster(); 154 if (cluster != null) 155 this.setCluster(cluster); 156 157 Manager manager = ctx.getManager(); 158 if (manager != null) 159 this.setManager(manager); 160 161 pipelineInitialized = true; 162 this.webServiceMap = ctx.getWebServices(); 163 164 this.setCrossContext(ctx.isCrossContext()); 165 166 this.setCookies(!ctx.isDisableCookies()); 167 168 //Set the Dispatch listener 169 this.addInstanceListener("org.apache.geronimo.tomcat.listener.DispatchListener"); 170 } 171 172 public synchronized void start() throws LifecycleException { 173 if (pipelineInitialized) { 174 try { 175 Valve valve = getFirst(); 176 valve.invoke(null, null); 177 //Install the DefaultSubjectValve after the authentication valve so the default subject is supplied 178 //only if no real subject is authenticated. 179 180 Valve defaultSubjectValve = new DefaultSubjectValve(defaultSubject); 181 addValve(defaultSubjectValve); 182 } catch (IOException e) { 183 if (e.getCause() instanceof LifecycleException) { 184 throw (LifecycleException) e.getCause(); 185 } 186 throw new LifecycleException(e); 187 } catch (ServletException e) { 188 throw new LifecycleException(e); 189 } 190 } else 191 super.start(); 192 } 193 194 public synchronized void stop() throws LifecycleException { 195 // Remove the defaultSubject 196 if (defaultSubject != null) { 197 ContextManager.unregisterSubject(defaultSubject); 198 } 199 200 super.stop(); 201 } 202 203 public void addChild(Container child) { 204 Wrapper wrapper = (Wrapper) child; 205 206 String servletClassName = wrapper.getServletClass(); 207 if (servletClassName == null) { 208 super.addChild(child); 209 return; 210 } 211 212 ClassLoader cl = this.getParentClassLoader(); 213 214 Class baseServletClass; 215 Class servletClass; 216 try { 217 baseServletClass = cl.loadClass(Servlet.class.getName()); 218 servletClass = cl.loadClass(servletClassName); 219 //Check if the servlet is of type Servlet class 220 if (!baseServletClass.isAssignableFrom(servletClass)) { 221 //Nope - its probably a webservice, so lets see... 222 if (webServiceMap != null) { 223 WebServiceContainer webServiceContainer = (WebServiceContainer) webServiceMap.get(wrapper.getName()); 224 225 if (webServiceContainer != null) { 226 //Yep its a web service 227 //So swap it out with a POJOWebServiceServlet 228 wrapper.setServletClass("org.apache.geronimo.webservices.POJOWebServiceServlet"); 229 230 //Set the WebServiceContainer stuff 231 String webServicecontainerID = wrapper.getName() + WebServiceContainerInvoker.WEBSERVICE_CONTAINER + webServiceContainer.hashCode(); 232 getServletContext().setAttribute(webServicecontainerID, webServiceContainer); 233 wrapper.addInitParameter(WebServiceContainerInvoker.WEBSERVICE_CONTAINER, webServicecontainerID); 234 235 //Set the SEI Class in the attribute 236 String pojoClassID = wrapper.getName() + POJOWebServiceServlet.POJO_CLASS + servletClass.hashCode(); 237 getServletContext().setAttribute(pojoClassID, servletClass); 238 wrapper.addInitParameter(POJOWebServiceServlet.POJO_CLASS, pojoClassID); 239 } 240 } 241 } 242 } catch (ClassNotFoundException e) { 243 throw new RuntimeException(e.getMessage(), e); 244 } 245 246 super.addChild(child); 247 } 248 249 public synchronized void setLoader(final Loader delegate) { 250 Loader loader = new Loader() { 251 252 public void backgroundProcess() { 253 delegate.backgroundProcess(); 254 } 255 256 public ClassLoader getClassLoader() { 257 // Implementation Note: the actual CL to be used by this 258 // context is the Geronimo one and not the Tomcat one. 259 return parentClassLoader; 260 } 261 262 public Container getContainer() { 263 return delegate.getContainer(); 264 } 265 266 public void setContainer(Container container) { 267 delegate.setContainer(container); 268 } 269 270 public boolean getDelegate() { 271 return delegate.getDelegate(); 272 } 273 274 public void setDelegate(boolean delegateBoolean) { 275 delegate.setDelegate(delegateBoolean); 276 } 277 278 public String getInfo() { 279 return delegate.getInfo(); 280 } 281 282 public boolean getReloadable() { 283 return false; 284 } 285 286 public void setReloadable(boolean reloadable) { 287 if (reloadable) { 288 throw new UnsupportedOperationException("Reloadable context is not supported."); 289 } 290 } 291 292 public void addPropertyChangeListener(PropertyChangeListener listener) { 293 delegate.addPropertyChangeListener(listener); 294 } 295 296 public void addRepository(String repository) { 297 delegate.addRepository(repository); 298 } 299 300 public String[] findRepositories() { 301 return delegate.findRepositories(); 302 } 303 304 public boolean modified() { 305 return delegate.modified(); 306 } 307 308 public void removePropertyChangeListener(PropertyChangeListener listener) { 309 delegate.removePropertyChangeListener(listener); 310 } 311 }; 312 313 super.setLoader(loader); 314 } 315 316 private class SystemMethodValve extends ValveBase { 317 318 public void invoke(Request request, Response response) throws IOException, ServletException { 319 if (request == null && response == null) { 320 try { 321 GeronimoStandardContext.super.start(); 322 } catch (LifecycleException e) { 323 throw (IOException) new IOException("wrapping lifecycle exception").initCause(e); 324 } 325 } else { 326 getNext().invoke(request, response); 327 } 328 329 } 330 } 331 332 333 public BeforeAfter getBeforeAfter() { 334 return beforeAfter; 335 } 336 337 public int getContextCount() { 338 return contextCount; 339 } 340 341 }