1   package org.apache.maven.plugin.javadoc;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.IOException;
23  import java.net.InetAddress;
24  import java.net.UnknownHostException;
25  import java.util.Map;
26  
27  import javax.servlet.ServletException;
28  import javax.servlet.ServletRequest;
29  import javax.servlet.ServletResponse;
30  import javax.servlet.http.HttpServletRequest;
31  import javax.servlet.http.HttpServletResponse;
32  
33  import org.mortbay.jetty.Connector;
34  import org.mortbay.jetty.Server;
35  import org.mortbay.jetty.bio.SocketConnector;
36  import org.mortbay.jetty.security.B64Code;
37  import org.mortbay.jetty.servlet.Context;
38  import org.mortbay.jetty.servlet.ServletHolder;
39  import org.mortbay.proxy.AsyncProxyServlet;
40  
41  /**
42   * A Proxy server.
43   *
44   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
45   * @version $Id: ProxyServer.html 829392 2012-08-19 17:29:37Z hboutemy $
46   * @since 2.6
47   */
48  class ProxyServer
49  {
50      private Server proxyServer;
51  
52      /**
53       * @param proxyServlet the wanted auth proxy servlet
54       */
55      public ProxyServer( AuthAsyncProxyServlet proxyServlet )
56      {
57          this( null, 0, proxyServlet );
58      }
59  
60      /**
61       * @param hostName the server name
62       * @param port the server port
63       * @param debug true to display System.err, false otherwise.
64       * @param proxyServlet the wanted auth proxy servlet
65       */
66      public ProxyServer( String hostName, int port, AuthAsyncProxyServlet proxyServlet )
67      {
68          proxyServer = new Server();
69  
70          proxyServer.addConnector( getDefaultConnector( hostName, port ) );
71  
72          Context context = new Context( proxyServer, "/", 0 );
73  
74          context.addServlet( new ServletHolder( proxyServlet ), "/" );
75      }
76  
77      /**
78       * @return the host name
79       */
80      public String getHostName()
81      {
82          Connector connector = proxyServer.getConnectors()[0];
83          return connector.getHost();
84      }
85  
86      /**
87       * @return the host port
88       */
89      public int getPort()
90      {
91          Connector connector = proxyServer.getConnectors()[0];
92          return ( connector.getLocalPort() <= 0 ? connector.getPort() : connector.getLocalPort() );
93      }
94  
95      /**
96       * @throws Exception if any
97       */
98      public void start()
99          throws Exception
100     {
101         if ( proxyServer != null )
102         {
103             proxyServer.start();
104         }
105     }
106 
107     /**
108      * @throws Exception if any
109      */
110     public void stop()
111         throws Exception
112     {
113         if ( proxyServer != null )
114         {
115             proxyServer.stop();
116         }
117         proxyServer = null;
118     }
119 
120     private Connector getDefaultConnector( String hostName, int port )
121     {
122         Connector connector = new SocketConnector();
123         if ( hostName != null )
124         {
125             connector.setHost( hostName );
126         }
127         else
128         {
129             try
130             {
131                 connector.setHost( InetAddress.getLocalHost().getCanonicalHostName() );
132             }
133             catch ( UnknownHostException e )
134             {
135                 // nop
136             }
137         }
138         if ( port > 0 )
139         {
140             connector.setPort( port );
141         }
142 
143         return connector;
144     }
145 
146     /**
147      * A proxy servlet with authentication support.
148      */
149     static class AuthAsyncProxyServlet
150         extends AsyncProxyServlet
151     {
152         private Map authentications;
153 
154         private long sleepTime = 0;
155 
156         /**
157          * Constructor for non authentication servlet.
158          */
159         public AuthAsyncProxyServlet()
160         {
161             super();
162         }
163 
164         /**
165          * Constructor for authentication servlet.
166          *
167          * @param authentications a map of user/password
168          */
169         public AuthAsyncProxyServlet( Map authentications )
170         {
171             this();
172 
173             this.authentications = authentications;
174         }
175 
176         /**
177          * Constructor for authentication servlet.
178          *
179          * @param authentications a map of user/password
180          * @param sleepTime a positive time to sleep the service thread (for timeout)
181          */
182         public AuthAsyncProxyServlet( Map authentications, long sleepTime )
183         {
184             this();
185 
186             this.authentications = authentications;
187             this.sleepTime = sleepTime;
188         }
189 
190         /** {@inheritDoc} */
191         public void service( ServletRequest req, ServletResponse res )
192             throws ServletException, IOException
193         {
194             final HttpServletRequest request = (HttpServletRequest) req;
195             final HttpServletResponse response = (HttpServletResponse) res;
196 
197             if ( this.authentications != null && !this.authentications.isEmpty() )
198             {
199                 String proxyAuthorization = request.getHeader( "Proxy-Authorization" );
200                 if ( proxyAuthorization != null && proxyAuthorization.startsWith( "Basic " ) )
201                 {
202                     String proxyAuth = proxyAuthorization.substring( 6 );
203                     String authorization = B64Code.decode( proxyAuth );
204                     String[] authTokens = authorization.split( ":" );
205                     String user = authTokens[0];
206                     String password = authTokens[1];
207 
208                     if ( this.authentications.get( user ) == null )
209                     {
210                         throw new IllegalArgumentException( user + " not found in the map!" );
211                     }
212 
213                     if ( sleepTime > 0 )
214                     {
215                         try
216                         {
217                             Thread.sleep( sleepTime );
218                         }
219                         catch ( InterruptedException e )
220                         {
221                             // nop
222                         }
223                     }
224                     String authPass = this.authentications.get( user ).toString();
225                     if ( password.equals( authPass ) )
226                     {
227                         // could throw exceptions...
228                         super.service( req, res );
229                         return;
230                     }
231                 }
232 
233                 // Proxy-Authenticate Basic realm="CCProxy Authorization"
234                 response.addHeader( "Proxy-Authenticate", "Basic realm=\"Jetty Proxy Authorization\"" );
235                 response.setStatus( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED );
236                 return;
237             }
238 
239             super.service( req, res );
240         }
241     }
242 }