1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/server/ProxyAuthRequestHandler.java,v 1.9 2004/02/27 19:01:34 olegk Exp $
3    * $Revision: 1.9 $
4    * $Date: 2004/02/27 19:01:34 $
5    *
6    * ====================================================================
7    *
8    *  Copyright 1999-2004 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
27   *
28   * [Additional notices, if required by prior licensing conditions]
29   *
30   */
31  
32  package org.apache.commons.httpclient.server;
33  
34  import java.io.IOException;
35  
36  import org.apache.commons.httpclient.Credentials;
37  import org.apache.commons.httpclient.Header;
38  import org.apache.commons.httpclient.UsernamePasswordCredentials;
39  import org.apache.commons.httpclient.auth.BasicScheme;
40  
41  /***
42   * This request handler guards access to a proxy when used in a request handler
43   * chain. It checks the headers for valid credentials and performs the
44   * authentication handshake if necessary.
45   * 
46   * @author Ortwin Glueck
47   * @author Oleg Kalnichevski
48   */
49  public class ProxyAuthRequestHandler implements HttpRequestHandler {
50      private Credentials credentials;
51  
52      /***
53       * The proxy authenticate challange header.
54       */
55      public static final String PROXY_AUTH = "Proxy-Authenticate";
56  
57      /***
58       * The proxy authenticate response header.
59       */
60      public static final String PROXY_AUTH_RESP = "Proxy-Authorization";
61  
62      /***
63       * TODO replace creds parameter with a class specific to an auth scheme
64       * encapsulating all required information for a specific scheme
65       * 
66       * @param creds
67       */
68      public ProxyAuthRequestHandler(Credentials creds) {
69          if (creds == null)
70              throw new IllegalArgumentException("Credentials can not be null");
71          this.credentials = creds;
72      }
73  
74      public boolean processRequest(
75          final SimpleHttpServerConnection conn,
76          final SimpleRequest request) throws IOException
77      {
78          Header clientAuth = request.getFirstHeader(PROXY_AUTH_RESP);
79          if (clientAuth != null) {
80              boolean ok = checkAuthorization(clientAuth);
81              if (ok)
82                  conn.connectionKeepAlive();
83              return !ok;
84          } else {
85              performHandshake(conn);
86          }
87          return true;
88      }
89  
90      /***
91       * @param conn
92       */
93      private void performHandshake(SimpleHttpServerConnection conn) throws IOException {
94          Header challenge = createChallenge();
95          ResponseWriter out = conn.getWriter();
96          out.println("HTTP/1.1 407 Proxy Authentication Required");
97          out.print(challenge.toExternalForm());
98          out.print(new Header("Proxy-Connection", "Keep-Alive").toExternalForm());
99          out.print(new Header("Content-Length", "0").toExternalForm());
100         out.println();
101         out.flush();
102         conn.connectionKeepAlive();
103     }
104 
105     /***
106      * @return
107      */
108     private Header createChallenge() {
109         Header header = new Header();
110         header.setName(PROXY_AUTH);
111         //TODO add more auth schemes
112         String challenge = "basic realm=test";
113         header.setValue(challenge);
114         return header;
115     }
116 
117     /***
118      * Checks if the credentials provided by the client match the required
119      * credentials
120      * 
121      * @return true if the client is authorized, false if not.
122      * @param clientAuth
123      */
124     private boolean checkAuthorization(Header clientAuth) {
125         String expectedAuthString = BasicScheme.authenticate(
126             (UsernamePasswordCredentials)credentials,
127             "ISO-8859-1");
128         return expectedAuthString.equals(clientAuth.getValue());
129     }
130 
131 }