View Javadoc

1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.acegisecurity.context.rmi;
17  
18  import org.acegisecurity.context.SecurityContext;
19  import org.acegisecurity.context.SecurityContextHolder;
20  import org.acegisecurity.context.SecurityContextImpl;
21  
22  import org.aopalliance.intercept.MethodInvocation;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import org.springframework.remoting.support.RemoteInvocation;
28  
29  import java.lang.reflect.InvocationTargetException;
30  
31  
32  /***
33   * The actual <code>RemoteInvocation</code> that is passed from the client to
34   * the server, which contains the contents of {@link SecurityContextHolder},
35   * being a {@link SecurityContext} object.
36   * 
37   * <p>
38   * When constructed on the client via {@link
39   * org.acegisecurity.context.rmi.ContextPropagatingRemoteInvocationFactory},
40   * the contents of the <code>SecurityContext</code> are stored inside the
41   * object. The object is then passed to the server that is processing the
42   * remote invocation. Upon the server invoking the remote invocation, it will
43   * retrieve the passed contents of the <code>SecurityContextHolder</code> and
44   * set them to the server-side <code>SecurityContextHolder</code> whilst the
45   * target object is invoked. When the target invocation has been completed,
46   * the server-side <code>SecurityContextHolder</code> will be reset to a new
47   * instance of <code>SecurityContextImpl</code>.
48   * </p>
49   *
50   * @author James Monaghan
51   * @author Ben Alex
52   * @version $Id: ContextPropagatingRemoteInvocation.java,v 1.7 2005/11/23 16:09:44 luke_t Exp $
53   */
54  public class ContextPropagatingRemoteInvocation extends RemoteInvocation {
55      //~ Static fields/initializers =============================================
56  
57      private static final Log logger = LogFactory.getLog(ContextPropagatingRemoteInvocation.class);
58  
59      //~ Instance fields ========================================================
60  
61      private SecurityContext securityContext;
62  
63      //~ Constructors ===========================================================
64  
65      /***
66       * Constructs the object, storing the value of the client-side
67       * <code>SecurityContextHolder</code> inside the object.
68       *
69       * @param methodInvocation the method to invoke
70       */
71      public ContextPropagatingRemoteInvocation(MethodInvocation methodInvocation) {
72          super(methodInvocation);
73          securityContext = SecurityContextHolder.getContext();
74  
75          if (logger.isDebugEnabled()) {
76              logger.debug("RemoteInvocation now has SecurityContext: "
77                  + securityContext);
78          }
79      }
80  
81      //~ Methods ================================================================
82  
83      /***
84       * Invoked on the server-side as described in the class JavaDocs.
85       * 
86       * <p>
87       * Invocations will always have their {@link
88       * org.acegisecurity.Authentication#setAuthenticated(boolean)} set to
89       * <code>false</code>, which is guaranteed to always be accepted by
90       * <code>Authentication</code> implementations. This ensures that even
91       * remotely authenticated <code>Authentication</code>s will be untrusted
92       * by the server-side, which is an appropriate security measure.
93       * </p>
94       *
95       * @param targetObject the target object to apply the invocation to
96       *
97       * @return the invocation result
98       *
99       * @throws NoSuchMethodException if the method name could not be resolved
100      * @throws IllegalAccessException if the method could not be accessed
101      * @throws InvocationTargetException if the method invocation resulted in
102      *         an exception
103      */
104     public Object invoke(Object targetObject)
105         throws NoSuchMethodException, IllegalAccessException, 
106             InvocationTargetException {
107         SecurityContextHolder.setContext(securityContext);
108 
109         if ((SecurityContextHolder.getContext() != null)
110             && (SecurityContextHolder.getContext().getAuthentication() != null)) {
111             SecurityContextHolder.getContext().getAuthentication()
112                                  .setAuthenticated(false);
113         }
114 
115         if (logger.isDebugEnabled()) {
116             logger.debug("Set SecurityContextHolder to contain: "
117                 + securityContext);
118         }
119 
120         try {
121 
122             return super.invoke(targetObject);
123 
124         } finally {
125 
126             SecurityContextHolder.setContext(new SecurityContextImpl());
127 
128             if (logger.isDebugEnabled()) {
129                 logger.debug(
130                     "Set SecurityContext to new instance of SecurityContextImpl");
131             }
132         }
133     }
134 }