View Javadoc
1   package org.apache.maven.plugins.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   * @since 2.6
46   */
47  class ProxyServer
48  {
49      private Server proxyServer;
50  
51      /**
52       * @param proxyServlet the wanted auth proxy servlet
53       */
54      public ProxyServer( AuthAsyncProxyServlet proxyServlet )
55      {
56          this( null, 0, proxyServlet );
57      }
58  
59      /**
60       * @param hostName the server name
61       * @param port the server port
62       * @param debug true to display System.err, false otherwise.
63       * @param proxyServlet the wanted auth proxy servlet
64       */
65      public ProxyServer( String hostName, int port, AuthAsyncProxyServlet proxyServlet )
66      {
67          proxyServer = new Server();
68  
69          proxyServer.addConnector( getDefaultConnector( hostName, port ) );
70  
71          Context context = new Context( proxyServer, "/", 0 );
72  
73          context.addServlet( new ServletHolder( proxyServlet ), "/" );
74      }
75  
76      /**
77       * @return the host name
78       */
79      public String getHostName()
80      {
81          Connector connector = proxyServer.getConnectors()[0];
82          return connector.getHost();
83      }
84  
85      /**
86       * @return the host port
87       */
88      public int getPort()
89      {
90          Connector connector = proxyServer.getConnectors()[0];
91          return ( connector.getLocalPort() <= 0 ? connector.getPort() : connector.getLocalPort() );
92      }
93  
94      /**
95       * @throws Exception if any
96       */
97      public void start()
98          throws Exception
99      {
100         if ( proxyServer != null )
101         {
102             proxyServer.start();
103         }
104     }
105 
106     /**
107      * @throws Exception if any
108      */
109     public void stop()
110         throws Exception
111     {
112         if ( proxyServer != null )
113         {
114             proxyServer.stop();
115         }
116         proxyServer = null;
117     }
118 
119     private Connector getDefaultConnector( String hostName, int port )
120     {
121         Connector connector = new SocketConnector();
122         if ( hostName != null )
123         {
124             connector.setHost( hostName );
125         }
126         else
127         {
128             try
129             {
130                 connector.setHost( InetAddress.getLocalHost().getCanonicalHostName() );
131             }
132             catch ( UnknownHostException e )
133             {
134                 // nop
135             }
136         }
137         if ( port > 0 )
138         {
139             connector.setPort( port );
140         }
141 
142         return connector;
143     }
144 
145     /**
146      * A proxy servlet with authentication support.
147      */
148     static class AuthAsyncProxyServlet
149         extends AsyncProxyServlet
150     {
151         private Map<String, String> authentications;
152 
153         private long sleepTime = 0;
154 
155         /**
156          * Constructor for non authentication servlet.
157          */
158         public AuthAsyncProxyServlet()
159         {
160             super();
161         }
162 
163         /**
164          * Constructor for authentication servlet.
165          *
166          * @param authentications a map of user/password
167          */
168         public AuthAsyncProxyServlet( Map<String, String> authentications )
169         {
170             this();
171 
172             this.authentications = authentications;
173         }
174 
175         /**
176          * Constructor for authentication servlet.
177          *
178          * @param authentications a map of user/password
179          * @param sleepTime a positive time to sleep the service thread (for timeout)
180          */
181         public AuthAsyncProxyServlet( Map<String, String> authentications, long sleepTime )
182         {
183             this();
184 
185             this.authentications = authentications;
186             this.sleepTime = sleepTime;
187         }
188 
189         /** {@inheritDoc} */
190         @Override
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);
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 }