View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.example.proxy;
21  
22  import java.net.InetSocketAddress;
23  import java.net.URL;
24  import java.security.Security;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.List;
28  
29  import org.apache.mina.core.RuntimeIoException;
30  import org.apache.mina.core.future.ConnectFuture;
31  import org.apache.mina.core.session.IdleStatus;
32  import org.apache.mina.core.session.IoSession;
33  import org.apache.mina.filter.logging.LoggingFilter;
34  import org.apache.mina.proxy.ProxyConnector;
35  import org.apache.mina.proxy.handlers.ProxyRequest;
36  import org.apache.mina.proxy.handlers.http.HttpAuthenticationMethods;
37  import org.apache.mina.proxy.handlers.http.HttpProxyConstants;
38  import org.apache.mina.proxy.handlers.http.HttpProxyRequest;
39  import org.apache.mina.proxy.handlers.socks.SocksProxyConstants;
40  import org.apache.mina.proxy.handlers.socks.SocksProxyRequest;
41  import org.apache.mina.proxy.session.ProxyIoSession;
42  import org.apache.mina.proxy.utils.MD4Provider;
43  import org.apache.mina.transport.socket.nio.NioSocketConnector;
44  
45  /**
46   * ProxyTestClient.java - Base test class for mina proxy
47   * 
48   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
49   * @since MINA 2.0.0-M3
50   */
51  public class ProxyTestClient {
52      
53      /**
54       * The global variables used when creating the HTTP proxy connection.
55       */
56      
57      /**
58       * The user login.
59       */
60      public final static String USER = "TED_KODS";
61  
62      /**
63       * The user password.
64       */
65      public final static String PWD = "EDOUARD";
66  
67      /**
68       * The domain name. (used in NTLM connections)
69       */
70      public final static String DOMAIN = "MYDOMAIN";
71  
72      /**
73       * The workstation name. (used in NTLM connections)
74       */    
75      public final static String WORKSTATION = "MYWORKSTATION";
76  
77      /**
78       * Set this variable to true in order to generate HTTP/1.1 requests.
79       */
80      private final static boolean USE_HTTP_1_1 = false;
81  
82      /**
83       * NTLM proxy authentication needs a JCE provider that handles MD4 hashing.
84       */
85      static {
86          if (Security.getProvider("MINA") == null) {
87              Security.addProvider(new MD4Provider());
88          }
89      }
90  
91      /**
92       * Creates a connection to the endpoint through a proxy server using the specified
93       * authentication method.
94       * 
95       * Command line arguments: 
96       *       ProxyTestClient <proxy-hostname> <proxy-port> <url> <proxy-method> 
97       *       
98       * Note that <proxy-method> is OPTIONNAL a HTTP proxy connection will be used if not 
99       * specified.
100      * 
101      * Examples:
102      *          ProxyTestClient myproxy 8080 http://mina.apache.org SOCKS4
103      *          ProxyTestClient squidsrv 3128 http://mina.apache.org:80
104      *       
105      * @param args parse arguments to get proxy hostaname, proxy port, the url to connect to 
106      * and optionnaly the proxy authentication method 
107      * @throws Exception
108      */
109     public ProxyTestClient(String[] args) throws Exception {
110         if (args.length < 3) {
111             System.out
112                     .println(ProxyTestClient.class.getName()
113                             + " <proxy-hostname> <proxy-port> <url> <proxy-method> (<proxy-method> is OPTIONNAL)");
114             return;
115         }
116 
117         // Create proxy connector.
118         NioSocketConnector socketConnector = new NioSocketConnector(Runtime
119                 .getRuntime().availableProcessors() + 1);
120 
121         ProxyConnector connector = new ProxyConnector(socketConnector);
122 
123         // Set connect timeout.
124         connector.setConnectTimeoutMillis(5000);
125 
126         URL url = new URL(args[2]);
127         int port = url.getPort() == -1 ? url.getDefaultPort() : url.getPort();
128 
129         ProxyRequest req = null;
130 
131         if (args.length == 4) {
132             if ("SOCKS4".equals(args[3])) {
133                 req = new SocksProxyRequest(
134                         SocksProxyConstants.SOCKS_VERSION_4,
135                         SocksProxyConstants.ESTABLISH_TCPIP_STREAM,
136                         new InetSocketAddress(url.getHost(), port), USER);
137             } else if ("SOCKS4a".equals(args[3])) {
138                 req = new SocksProxyRequest(
139                         SocksProxyConstants.ESTABLISH_TCPIP_STREAM, url
140                                 .getHost(), port, USER);
141             } else if ("SOCKS5".equals(args[3])) {
142                 req = new SocksProxyRequest(
143                         SocksProxyConstants.SOCKS_VERSION_5,
144                         SocksProxyConstants.ESTABLISH_TCPIP_STREAM,
145                         new InetSocketAddress(url.getHost(), port), USER);
146                 ((SocksProxyRequest) req).setPassword(PWD);
147                 ((SocksProxyRequest) req)
148                         .setServiceKerberosName(Socks5GSSAPITestServer.SERVICE_NAME);
149             } else {
150                 req = createHttpProxyRequest(args[2]);
151             }
152         } else {
153             req = createHttpProxyRequest(args[2]);
154         }
155 
156         ProxyIoSession proxyIoSession = new ProxyIoSession(
157                 new InetSocketAddress(args[0], Integer.parseInt(args[1])), req);
158 
159         // Tests modifying authentication order preferences. First algorithm in list available on server 
160         // will be used for authentication.
161         List<HttpAuthenticationMethods> l = new ArrayList<HttpAuthenticationMethods>();
162         l.add(HttpAuthenticationMethods.DIGEST);
163         l.add(HttpAuthenticationMethods.BASIC);
164         proxyIoSession.setPreferedOrder(l);
165 
166         connector.setProxyIoSession(proxyIoSession);
167 
168         socketConnector.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 5);
169 
170         connector.getFilterChain().addLast("logger", new LoggingFilter());
171 
172         // This command is sent when using a socks proxy to request a page from the web server.
173         String cmd = "GET " + url.toExternalForm() + " HTTP/1.0"
174                 + HttpProxyConstants.CRLF + HttpProxyConstants.CRLF;
175 
176         connector.setHandler(new ClientSessionHandler(cmd));
177 
178         IoSession session;
179         for (;;) {
180             try {
181                 ConnectFuture future = connector.connect();
182                 future.awaitUninterruptibly();
183                 session = future.getSession();
184                 break;
185             } catch (RuntimeIoException e) {
186                 System.err.println("Failed to connect. Retrying in 5 secs ...");
187                 Thread.sleep(5000);
188             }
189         }
190 
191         // Wait until done
192         if (session != null) {
193             session.getCloseFuture().awaitUninterruptibly();
194         }
195         connector.dispose();
196         System.exit(0);
197     }
198 
199     /**
200      * Creates a {@link HttpProxyRequest} from the provided <i>uri</i> parameter.
201      * It uses the global variables defined at the top of the class to fill the 
202      * connection properties of the request. If the global variable <i>useHttp1_1</i> 
203      * is set to true, it will create a HTTP/1.1 request.
204      * 
205      * @param uri the requested uri to connect to through the HTTP proxy
206      * @return the fully initialized {@link HttpProxyRequest} object
207      */
208     private HttpProxyRequest createHttpProxyRequest(String uri) {
209         HttpProxyRequest req = new HttpProxyRequest(uri);
210         HashMap<String, String> props = new HashMap<String, String>();
211         props.put(HttpProxyConstants.USER_PROPERTY, USER);
212         props.put(HttpProxyConstants.PWD_PROPERTY, PWD);
213         props.put(HttpProxyConstants.DOMAIN_PROPERTY, DOMAIN);
214         props.put(HttpProxyConstants.WORKSTATION_PROPERTY, WORKSTATION);
215 
216         req.setProperties(props);
217         if (USE_HTTP_1_1) {
218             req.setHttpVersion(HttpProxyConstants.HTTP_1_1);
219         }
220 
221         return req;
222     }
223 
224     /**
225      * {@inheritDoc}
226      */
227     public static void main(String[] args) throws Exception {
228         new ProxyTestClient(args);
229     }
230 }