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.nio.charset.StandardCharsets;
25  import java.util.Base64;
26  import java.util.Map;
27  
28  import javax.servlet.ServletException;
29  import javax.servlet.ServletRequest;
30  import javax.servlet.ServletResponse;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  
34  import org.eclipse.jetty.proxy.AsyncProxyServlet;
35  import org.eclipse.jetty.proxy.ConnectHandler;
36  import org.eclipse.jetty.server.Server;
37  import org.eclipse.jetty.server.ServerConnector;
38  import org.eclipse.jetty.servlet.ServletContextHandler;
39  import org.eclipse.jetty.servlet.ServletHolder;
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      private ServerConnector serverConnector;
52  
53      /**
54       * @param proxyServlet the wanted auth proxy servlet
55       */
56      public ProxyServer( AuthAsyncProxyServlet proxyServlet )
57      {
58          this( null, 0, proxyServlet );
59      }
60  
61      /**
62       * @param hostName the server name
63       * @param port the server port
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          serverConnector = new ServerConnector( proxyServer );
71          serverConnector.setHost( InetAddress.getLoopbackAddress().getHostName() );
72          serverConnector.setReuseAddress( true );
73          serverConnector.setPort( 0 );
74  
75          proxyServer.addConnector( serverConnector );
76  
77          // Setup proxy handler to handle CONNECT methods
78          ConnectHandler proxy = new ConnectHandler();
79          proxyServer.setHandler(proxy);
80  
81          // Setup proxy servlet
82          ServletContextHandler context = new ServletContextHandler(proxy, "/", true, false);
83          ServletHolder appServletHolder = new ServletHolder(proxyServlet);
84          context.addServlet(appServletHolder, "/*");
85  
86      }
87  
88      /**
89       * @return the host name
90       */
91      public String getHostName()
92      {
93          return serverConnector.getHost() == null ? InetAddress.getLoopbackAddress().getHostName() : serverConnector.getHost();
94      }
95  
96      /**
97       * @return the host port
98       */
99      public int getPort()
100     {
101         return serverConnector.getLocalPort();
102     }
103 
104     /**
105      * @throws Exception if any
106      */
107     public void start()
108         throws Exception
109     {
110         if ( proxyServer != null )
111         {
112             proxyServer.start();
113         }
114     }
115 
116     /**
117      * @throws Exception if any
118      */
119     public void stop()
120         throws Exception
121     {
122         if ( proxyServer != null )
123         {
124             proxyServer.stop();
125         }
126         proxyServer = null;
127     }
128 
129 
130     /**
131      * A proxy servlet with authentication support.
132      */
133     static class AuthAsyncProxyServlet
134         extends AsyncProxyServlet
135     {
136         private Map<String, String> authentications;
137 
138         private long sleepTime = 0;
139 
140         /**
141          * Constructor for non authentication servlet.
142          */
143         public AuthAsyncProxyServlet()
144         {
145             super();
146         }
147 
148         /**
149          * Constructor for authentication servlet.
150          *
151          * @param authentications a map of user/password
152          */
153         public AuthAsyncProxyServlet( Map<String, String> authentications )
154         {
155             this();
156 
157             this.authentications = authentications;
158         }
159 
160         /**
161          * Constructor for authentication servlet.
162          *
163          * @param authentications a map of user/password
164          * @param sleepTime a positive time to sleep the service thread (for timeout)
165          */
166         public AuthAsyncProxyServlet( Map<String, String> authentications, long sleepTime )
167         {
168             this();
169             this.authentications = authentications;
170             this.sleepTime = sleepTime;
171         }
172 
173         /** {@inheritDoc} */
174         @Override
175         public void service( ServletRequest req, ServletResponse res )
176             throws ServletException, IOException
177         {
178             final HttpServletRequest request = (HttpServletRequest) req;
179             final HttpServletResponse response = (HttpServletResponse) res;
180 
181             if ( this.authentications != null && !this.authentications.isEmpty() )
182             {
183                 String proxyAuthorization = request.getHeader( "Proxy-Authorization" );
184                 if ( proxyAuthorization != null && proxyAuthorization.startsWith( "Basic " ) )
185                 {
186                     String proxyAuth = proxyAuthorization.substring("Basic ".length());
187                     String authorization = new String(Base64.getDecoder().decode(proxyAuth), StandardCharsets.UTF_8);
188 
189 
190                     String[] authTokens = authorization.split( ":" );
191                     String user = authTokens[0];
192                     String password = authTokens[1];
193 
194                     if ( this.authentications.get( user ) == null )
195                     {
196                         throw new IllegalArgumentException( user + " not found in the map!" );
197                     }
198 
199                     if ( sleepTime > 0 )
200                     {
201                         try
202                         {
203                             Thread.sleep( sleepTime );
204                         }
205                         catch ( InterruptedException e )
206                         {
207                             // nop
208                         }
209                     }
210                     String authPass = this.authentications.get(user);
211                     if ( password.equals( authPass ) )
212                     {
213                         // could throw exceptions...
214                         super.service( req, res );
215                         return;
216                     }
217                 }
218 
219                 // Proxy-Authenticate Basic realm="CCProxy Authorization"
220                 response.addHeader( "Proxy-Authenticate", "Basic realm=\"Jetty Proxy Authorization\"" );
221                 response.setStatus( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED );
222                 return;
223             }
224 
225             super.service( req, res );
226         }
227     }
228 }