View Javadoc

1   /* Copyright 2004, 2005, 2006 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.httpinvoker;
17  
18  import org.acegisecurity.Authentication;
19  import org.acegisecurity.AuthenticationCredentialsNotFoundException;
20  
21  import org.acegisecurity.context.SecurityContextHolder;
22  
23  import org.apache.commons.codec.binary.Base64;
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  
27  import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;
28  
29  import java.io.IOException;
30  
31  import java.net.HttpURLConnection;
32  
33  
34  /**
35   * Adds BASIC authentication support to <code>SimpleHttpInvokerRequestExecutor</code>.
36   *
37   * @author Ben Alex
38   * @version $Id: AuthenticationSimpleHttpInvokerRequestExecutor.java 1784 2007-02-24 21:00:24Z luke_t $
39   */
40  public class AuthenticationSimpleHttpInvokerRequestExecutor extends SimpleHttpInvokerRequestExecutor {
41      //~ Static fields/initializers =====================================================================================
42  
43      private static final Log logger = LogFactory.getLog(AuthenticationSimpleHttpInvokerRequestExecutor.class);
44  
45      //~ Methods ========================================================================================================
46  
47      /**
48       * Provided so subclasses can perform additional configuration if required (eg set additional request
49       * headers for non-security related information etc).
50       *
51       * @param con the HTTP connection to prepare
52       * @param contentLength the length of the content to send
53       *
54       * @throws IOException if thrown by HttpURLConnection methods
55       */
56      protected void doPrepareConnection(HttpURLConnection con, int contentLength)
57          throws IOException {}
58  
59      /**
60       * Called every time a HTTP invocation is made.<p>Simply allows the parent to setup the connection, and
61       * then adds an <code>Authorization</code> HTTP header property that will be used for BASIC authentication.</p>
62       *  <p>The <code>SecurityContextHolder</code> is used to obtain the relevant principal and credentials.</p>
63       *
64       * @param con the HTTP connection to prepare
65       * @param contentLength the length of the content to send
66       *
67       * @throws IOException if thrown by HttpURLConnection methods
68       * @throws AuthenticationCredentialsNotFoundException if the <code>SecurityContextHolder</code> does not contain a
69       *         valid <code>Authentication</code> with both its <code>principal</code> and <code>credentials</code> not
70       *         <code>null</code>
71       */
72      protected void prepareConnection(HttpURLConnection con, int contentLength)
73          throws IOException, AuthenticationCredentialsNotFoundException {
74          super.prepareConnection(con, contentLength);
75  
76          Authentication auth = SecurityContextHolder.getContext().getAuthentication();
77  
78          if ((auth != null) && (auth.getName() != null) && (auth.getCredentials() != null)) {
79              String base64 = auth.getName() + ":" + auth.getCredentials().toString();
80              con.setRequestProperty("Authorization", "Basic " + new String(Base64.encodeBase64(base64.getBytes())));
81  
82              if (logger.isDebugEnabled()) {
83                  logger.debug("HttpInvocation now presenting via BASIC authentication SecurityContextHolder-derived: "
84                      + auth.toString());
85              }
86          } else {
87              if (logger.isDebugEnabled()) {
88                  logger.debug("Unable to set BASIC authentication header as SecurityContext did not provide "
89                          + "valid Authentication: " + auth);
90              }
91          }
92  
93          doPrepareConnection(con, contentLength);
94      }
95  }