001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.context.rmi;
017:
018: import org.acegisecurity.context.SecurityContext;
019: import org.acegisecurity.context.SecurityContextHolder;
020:
021: import org.aopalliance.intercept.MethodInvocation;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: import org.springframework.remoting.support.RemoteInvocation;
027:
028: import java.lang.reflect.InvocationTargetException;
029:
030: /**
031: * The actual <code>RemoteInvocation</code> that is passed from the client to the server, which contains the
032: * contents of {@link SecurityContextHolder}, being a {@link SecurityContext} object.<p>When constructed on the
033: * client via {@link org.acegisecurity.context.rmi.ContextPropagatingRemoteInvocationFactory}, the contents of the
034: * <code>SecurityContext</code> are stored inside the object. The object is then passed to the server that is
035: * processing the remote invocation. Upon the server invoking the remote invocation, it will retrieve the passed
036: * contents of the <code>SecurityContextHolder</code> and set them to the server-side
037: * <code>SecurityContextHolder</code> whilst the target object is invoked. When the target invocation has been
038: * completed, the server-side <code>SecurityContextHolder</code> will be reset to a new instance of
039: * <code>SecurityContextImpl</code>.</p>
040: *
041: * @author James Monaghan
042: * @author Ben Alex
043: * @version $Id: ContextPropagatingRemoteInvocation.java 1496 2006-05-23 13:38:33Z benalex $
044: */
045: public class ContextPropagatingRemoteInvocation extends
046: RemoteInvocation {
047: //~ Static fields/initializers =====================================================================================
048:
049: private static final Log logger = LogFactory
050: .getLog(ContextPropagatingRemoteInvocation.class);
051:
052: //~ Instance fields ================================================================================================
053:
054: private SecurityContext securityContext;
055:
056: //~ Constructors ===================================================================================================
057:
058: /**
059: * Constructs the object, storing the value of the client-side
060: * <code>SecurityContextHolder</code> inside the object.
061: *
062: * @param methodInvocation the method to invoke
063: */
064: public ContextPropagatingRemoteInvocation(
065: MethodInvocation methodInvocation) {
066: super (methodInvocation);
067: securityContext = SecurityContextHolder.getContext();
068:
069: if (logger.isDebugEnabled()) {
070: logger.debug("RemoteInvocation now has SecurityContext: "
071: + securityContext);
072: }
073: }
074:
075: //~ Methods ========================================================================================================
076:
077: /**
078: * Invoked on the server-side as described in the class JavaDocs.<p>Invocations will always have their
079: * {@link org.acegisecurity.Authentication#setAuthenticated(boolean)} set to <code>false</code>, which is
080: * guaranteed to always be accepted by <code>Authentication</code> implementations. This ensures that even
081: * remotely authenticated <code>Authentication</code>s will be untrusted by the server-side, which is an
082: * appropriate security measure.</p>
083: *
084: * @param targetObject the target object to apply the invocation to
085: *
086: * @return the invocation result
087: *
088: * @throws NoSuchMethodException if the method name could not be resolved
089: * @throws IllegalAccessException if the method could not be accessed
090: * @throws InvocationTargetException if the method invocation resulted in an exception
091: */
092: public Object invoke(Object targetObject)
093: throws NoSuchMethodException, IllegalAccessException,
094: InvocationTargetException {
095: SecurityContextHolder.setContext(securityContext);
096:
097: if ((SecurityContextHolder.getContext() != null)
098: && (SecurityContextHolder.getContext()
099: .getAuthentication() != null)) {
100: SecurityContextHolder.getContext().getAuthentication()
101: .setAuthenticated(false);
102: }
103:
104: if (logger.isDebugEnabled()) {
105: logger.debug("Set SecurityContextHolder to contain: "
106: + securityContext);
107: }
108:
109: try {
110: return super .invoke(targetObject);
111: } finally {
112: SecurityContextHolder.clearContext();
113:
114: if (logger.isDebugEnabled()) {
115: logger
116: .debug("Set SecurityContext to new instance of SecurityContextImpl");
117: }
118: }
119: }
120: }
|