/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.web.server;
import com.sun.enterprise.container.common.spi.util.InjectionException;
import com.sun.enterprise.container.common.spi.util.InjectionManager;
import com.sun.enterprise.security.integration.AppServSecurityContext;
import com.sun.enterprise.security.integration.RealmInitializer;
import com.sun.enterprise.security.integration.SecurityConstants;
import com.sun.enterprise.transaction.api.JavaEETransactionManager;
import com.sun.enterprise.web.WebComponentInvocation;
import com.sun.enterprise.web.WebModule;
import org.apache.catalina.*;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.servlets.DefaultServlet;
import org.apache.jasper.servlet.JspServlet;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.api.ServerContext;
import org.glassfish.logging.annotation.LogMessageInfo;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestWrapper;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.String;
import java.security.*;
import java.text.MessageFormat;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
//END OF IASRI 4660742
/**
* This class implements the Tomcat InstanceListener interface and
* handles the INIT,DESTROY and SERVICE, FILTER events.
* @author Vivek Nagar
* @author Tony Ng
*/
public final class J2EEInstanceListener implements InstanceListener {
private static final Logger _logger = com.sun.enterprise.web.WebContainer.logger;
private static final ResourceBundle _rb = _logger.getResourceBundle();
@LogMessageInfo(
message = "*** InstanceEvent: {0}",
level = "FINEST")
public static final String INSTANCE_EVENT = "AS-WEB-GLUE-00265";
@LogMessageInfo(
message = "Obtained securityContext implementation class {0}",
level = "FINE")
public static final String SECURITY_CONTEXT_OBTAINED = "AS-WEB-GLUE-00266";
@LogMessageInfo(
message = "Failed to obtain securityContext implementation class",
level = "FINE")
public static final String SECURITY_CONTEXT_FAILED = "AS-WEB-GLUE-00267";
@LogMessageInfo(
message = "Exception during processing of event of type {0} for web module {1}",
level = "SEVERE",
cause = "An exception occurred during processing event type",
action = "Check the exception for the error")
public static final String EXCEPTION_DURING_HANDLE_EVENT = "AS-WEB-GLUE-00268";
@LogMessageInfo(
message = "No ServerContext in WebModule [{0}]",
level = "WARNING")
public static final String NO_SERVER_CONTEXT = "AS-WEB-GLUE-00269";
private InvocationManager im;
private JavaEETransactionManager tm;
private InjectionManager injectionMgr;
private boolean initialized = false;
private AppServSecurityContext securityContext;
public J2EEInstanceListener() {
}
public void instanceEvent(InstanceEvent event) {
Context context = (Context) event.getWrapper().getParent();
if (!(context instanceof WebModule)) {
return;
}
WebModule wm = (WebModule)context;
init(wm);
InstanceEvent.EventType eventType = event.getType();
if(_logger.isLoggable(Level.FINEST)) {
_logger.log(Level.FINEST, INSTANCE_EVENT, eventType);
}
if (eventType.isBefore) {
handleBeforeEvent(event, eventType);
} else {
handleAfterEvent(event, eventType);
}
}
private synchronized void init(WebModule wm) {
if (initialized) {
return;
}
ServerContext serverContext = wm.getServerContext();
if (serverContext == null) {
String msg = _rb.getString(NO_SERVER_CONTEXT);
msg = MessageFormat.format(msg, wm.getName());
throw new IllegalStateException(msg);
}
ServiceLocator services = serverContext.getDefaultServices();
im = services.getService(InvocationManager.class);
tm = getJavaEETransactionManager(services);
injectionMgr = services.getService(InjectionManager.class);
initialized = true;
securityContext = serverContext.getDefaultServices().getService(AppServSecurityContext.class);
if (securityContext != null) {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, SECURITY_CONTEXT_OBTAINED, securityContext);
}
} else {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, SECURITY_CONTEXT_FAILED);
}
}
}
private void handleBeforeEvent(InstanceEvent event, InstanceEvent.EventType eventType) {
Context context = (Context) event.getWrapper().getParent();
if (!(context instanceof WebModule)) {
return;
}
WebModule wm = (WebModule)context;
Object instance;
if (eventType == InstanceEvent.EventType.BEFORE_FILTER_EVENT) {
instance = event.getFilter();
} else {
instance = event.getServlet();
}
// set security context
// BEGIN IAfSRI 4688449
//try {
Realm ra = context.getRealm();
/** IASRI 4713234
if (ra != null) {
HttpServletRequest request =
(HttpServletRequest) event.getRequest();
if (request != null && request.getUserPrincipal() != null) {
WebPrincipal prin =
(WebPrincipal) request.getUserPrincipal();
// ra.authenticate(prin);
// It is inefficient to call authenticate just to set
// sec.ctx. Instead, WebPrincipal modified to keep the
// previously created secctx, and set it here directly.
SecurityContext.setCurrent(prin.getSecurityContext());
}
}
**/
// START OF IASRI 4713234
if (ra != null) {
ServletRequest request = event.getRequest();
if (request != null && request instanceof HttpServletRequest) {
HttpServletRequest hreq = (HttpServletRequest)request;
HttpServletRequest base = hreq;
Principal prin = hreq.getUserPrincipal();
Principal basePrincipal = prin;
boolean wrapped = false;
while (prin != null) {
if (base instanceof ServletRequestWrapper) {
// unwarp any wrappers to find the base object
ServletRequest sr =
((ServletRequestWrapper) base).getRequest();
if (sr instanceof HttpServletRequest) {
base = (HttpServletRequest) sr;
wrapped = true;
continue;
}
}
if (wrapped) {
basePrincipal = base.getUserPrincipal();
}
else if (base instanceof RequestFacade) {
// try to avoid the getUnWrappedCoyoteRequest call
// when we can identify see we have the texact class.
if (base.getClass() != RequestFacade.class) {
basePrincipal = ((RequestFacade)base).
getUnwrappedCoyoteRequest().getUserPrincipal();
}
} else {
basePrincipal = base.getUserPrincipal();
}
break;
}
if (prin != null && prin == basePrincipal &&
prin.getClass().getName().equals(SecurityConstants.WEB_PRINCIPAL_CLASS)) {
securityContext.setSecurityContextWithPrincipal(prin);
} else if (prin != basePrincipal) {
// the wrapper has overridden getUserPrincipal
// reject the request if the wrapper does not have
// the necessary permission.
checkObjectForDoAsPermission(hreq);
securityContext.setSecurityContextWithPrincipal(prin);
}
}
}
// END OF IASRI 4713234
// END IASRI 4688449
ComponentInvocation inv;
if (eventType == InstanceEvent.EventType.BEFORE_INIT_EVENT) {
// The servletName is not avaiable from servlet instance before servlet init.
// We have to pass the servletName to ComponentInvocation so it can be retrieved
// in RealmAdapter.getServletName().
inv = new WebComponentInvocation(wm, instance, event.getWrapper().getName());
} else {
inv = new WebComponentInvocation(wm, instance);
}
try {
im.preInvoke(inv);
if (eventType == InstanceEvent.EventType.BEFORE_SERVICE_EVENT) {
// Emit monitoring probe event
wm.beforeServiceEvent(event.getWrapper().getName());
// enlist resources with TM for service method
if (tm != null) {
tm.enlistComponentResources();
}
}
} catch (Exception ex) {
im.postInvoke(inv); // See CR 6920895
String msg = _rb.getString(EXCEPTION_DURING_HANDLE_EVENT);
msg = MessageFormat.format(msg, new Object[] { eventType, wm });
throw new RuntimeException(msg, ex);
}
}
private static javax.security.auth.AuthPermission doAsPrivilegedPerm =
new javax.security.auth.AuthPermission("doAsPrivileged");
private static void checkObjectForDoAsPermission(final Object o)
throws AccessControlException{
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ProtectionDomain pD = o.getClass().getProtectionDomain();
Policy p = Policy.getPolicy();
if (!p.implies(pD,doAsPrivilegedPerm)) {
throw new AccessControlException
("permission required to override getUserPrincipal",
doAsPrivilegedPerm);
}
return null;
}
});
}
}
private void handleAfterEvent(InstanceEvent event,
InstanceEvent.EventType eventType) {
Wrapper wrapper = event.getWrapper();
Context context = (Context) wrapper.getParent();
if (!(context instanceof WebModule)) {
return;
}
WebModule wm = (WebModule)context;
Object instance;
if (eventType == InstanceEvent.EventType.AFTER_FILTER_EVENT) {
instance = event.getFilter();
} else {
instance = event.getServlet();
}
if (instance == null) {
return;
}
// Emit monitoring probe event
if (instance instanceof Servlet) {
if (eventType == InstanceEvent.EventType.AFTER_INIT_EVENT) {
wm.servletInitializedEvent(wrapper.getName());
} else if (eventType == InstanceEvent.EventType.AFTER_DESTROY_EVENT) {
wm.servletDestroyedEvent(wrapper.getName());
}
}
// Must call InjectionManager#destroyManagedObject WITHIN
// EE invocation context
try {
if (eventType == InstanceEvent.EventType.AFTER_DESTROY_EVENT &&
!DefaultServlet.class.equals(instance.getClass()) &&
!JspServlet.class.equals(instance.getClass())) {
injectionMgr.destroyManagedObject(instance, false);
}
} catch (InjectionException ie) {
String msg = _rb.getString(EXCEPTION_DURING_HANDLE_EVENT);
msg = MessageFormat.format(msg, new Object[] { eventType, wm });
_logger.log(Level.SEVERE, msg, ie);
}
ComponentInvocation inv = new WebComponentInvocation(wm, instance);
try {
im.postInvoke(inv);
} catch (Exception ex) {
String msg = _rb.getString(EXCEPTION_DURING_HANDLE_EVENT);
msg = MessageFormat.format(msg, new Object[] { eventType, wm });
throw new RuntimeException(msg, ex);
} finally {
if (eventType == InstanceEvent.EventType.AFTER_DESTROY_EVENT) {
if (tm != null) {
tm.componentDestroyed(instance, inv);
}
} else if (eventType == InstanceEvent.EventType.AFTER_FILTER_EVENT ||
eventType == InstanceEvent.EventType.AFTER_SERVICE_EVENT) {
// Emit monitoring probe event
if (eventType == InstanceEvent.EventType.AFTER_SERVICE_EVENT) {
ServletResponse response = event.getResponse();
int status = -1;
if (response != null &&
response instanceof HttpServletResponse) {
status = ((HttpServletResponse) response).getStatus();
}
wm.afterServiceEvent(wrapper.getName(), status);
}
// check it's top level invocation
// BEGIN IASRI# 4646060
if (im.getCurrentInvocation() == null) {
// END IASRI# 4646060
try {
// clear security context
Realm ra = context.getRealm();
if (ra != null && (ra instanceof RealmInitializer)) {
//cleanup not only securitycontext but also PolicyContext
((RealmInitializer)ra).logout();
}
} catch (Exception ex) {
String msg = _rb.getString(EXCEPTION_DURING_HANDLE_EVENT);
msg = MessageFormat.format(msg, new Object[] { eventType, wm });
_logger.log(Level.SEVERE, msg, ex);
}
if (tm != null) {
try {
if (tm.getTransaction() != null) {
tm.rollback();
}
tm.cleanTxnTimeout();
} catch (Exception ex) {}
}
}
if (tm != null) {
tm.componentDestroyed(instance, inv);
}
}
}
}
private JavaEETransactionManager getJavaEETransactionManager(ServiceLocator services) {
JavaEETransactionManager tm = null;
ServiceHandle<JavaEETransactionManager> inhabitant = services.getServiceHandle(JavaEETransactionManager.class);
if (inhabitant != null && inhabitant.isActive()) {
tm = inhabitant.getService();
}
return tm;
}
}