1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/server/ProxyAuthRequestHandler.java,v 1.1.2.2 2004/02/22 18:21:18 olegk Exp $
3    * $Revision: 1.1.2.2 $
4    * $Date: 2004/02/22 18:21:18 $
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.auth.AuthenticationException;
39  import org.apache.commons.httpclient.auth.BasicScheme;
40  import org.apache.commons.httpclient.auth.HttpAuthenticator;
41  import org.apache.commons.httpclient.auth.MalformedChallengeException;
42  
43  /***
44   * This request handler guards access to a proxy when used in a 
45   * request handler chain. It checks the headers for valid credentials
46   * and performs the authentication handshake if necessary.
47   * 
48   * @author Ortwin Glueck
49   */
50  public class ProxyAuthRequestHandler implements HttpRequestHandler {
51  	private Credentials credentials;
52  	
53  	/***
54  	 * TODO replace creds parameter with a class specific to an auth scheme encapsulating all required information for a specific scheme
55  	 * @param creds
56  	 */
57  	public ProxyAuthRequestHandler(Credentials creds)  {
58  		if (creds == null) throw new IllegalArgumentException("Credentials can not be null");
59  		this.credentials = creds;
60  	}
61  
62  	public boolean processRequest(SimpleHttpServerConnection conn)
63  		throws IOException {
64  		Header[] headers = conn.getHeaders();
65  		Header clientAuth = findHeader(headers, HttpAuthenticator.PROXY_AUTH_RESP);
66  		if (clientAuth != null) {
67  			boolean ok = checkAuthorization(clientAuth);
68  			if (ok) conn.connectionKeepAlive();
69  			return !ok;
70  		} else {
71  			performHandshake(conn);
72  		}
73  		return true;
74  	}
75  	
76  	/***
77  	 * @param conn
78  	 */
79  	private void performHandshake(SimpleHttpServerConnection conn) throws IOException {
80  		Header challenge = createChallenge();
81  		ResponseWriter out = conn.getWriter();
82  		out.println("HTTP/1.1 407 Proxy Authentication Required");
83  		out.print(challenge.toExternalForm());
84  		out.print(new Header("Proxy-Connection", "Keep-Alive").toExternalForm());
85  		out.print(new Header("Content-Length", "0").toExternalForm());
86  		out.println();
87  		out.flush();
88  		conn.connectionKeepAlive();
89  	}
90  
91  	/***
92  	 * 
93  	 * @return
94  	 */
95  	private Header createChallenge() {
96  		Header header = new Header();
97  		header.setName(HttpAuthenticator.PROXY_AUTH);
98  		//TODO add more auth schemes
99  		String challenge = "basic realm=test";
100 		header.setValue(challenge);
101 		return header;
102 	}
103 
104 	/***
105 	 * Checks if the credentials provided by the client match the required credentials
106 	 * @return true if the client is authorized, false if not.
107 	 * @param clientAuth
108 	 */
109 	private boolean checkAuthorization(Header clientAuth) {
110 		// TODO Auto-generated method stub
111 		BasicScheme scheme;
112 		try {
113 			scheme = new BasicScheme("basic realm=test");
114 			String expectedAuthString = scheme.authenticate(credentials, null, null);
115 			return expectedAuthString.equals(clientAuth.getValue());
116 		} catch (MalformedChallengeException e) {
117 			// TODO Auto-generated catch block
118 			e.printStackTrace();
119 		} catch (AuthenticationException e) {
120 			// TODO Auto-generated catch block
121 			e.printStackTrace();
122 		}
123 		return false;
124 	}
125 
126 	private Header findHeader(Header[] headers, String name) {
127 		for(int i=0; i<headers.length; i++) {
128 			Header header = headers[i];
129 			if (header.getName().equalsIgnoreCase(name)) return header;
130 		}
131 		return null;
132 	}
133 
134 }