View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.openr66.proxy.protocol.http.adminssl;
21  
22  import io.netty.buffer.ByteBuf;
23  import io.netty.channel.ChannelHandlerContext;
24  import io.netty.handler.codec.http.FullHttpRequest;
25  import io.netty.handler.codec.http.HttpMethod;
26  import io.netty.handler.codec.http.QueryStringDecoder;
27  import io.netty.handler.codec.http.cookie.DefaultCookie;
28  import io.netty.handler.traffic.TrafficCounter;
29  import org.waarp.common.exception.FileTransferException;
30  import org.waarp.common.logging.WaarpLogLevel;
31  import org.waarp.common.logging.WaarpLogger;
32  import org.waarp.common.logging.WaarpLoggerFactory;
33  import org.waarp.common.utility.ParametersChecker;
34  import org.waarp.common.utility.Version;
35  import org.waarp.common.utility.WaarpShutdownHook;
36  import org.waarp.common.utility.WaarpStringUtils;
37  import org.waarp.gateway.kernel.http.HttpWriteCacheEnable;
38  import org.waarp.openr66.context.R66Session;
39  import org.waarp.openr66.protocol.configuration.Messages;
40  import org.waarp.openr66.protocol.http.adminssl.HttpSslHandler;
41  
42  import java.util.Arrays;
43  import java.util.List;
44  import java.util.Locale;
45  
46  import static org.waarp.openr66.protocol.configuration.Configuration.*;
47  
48  /**
49   *
50   */
51  public class HttpSslHandlerProxyR66 extends HttpSslHandler {
52    private static final String XXXLEVEL4XXX2 = "XXXLEVEL4XXX";
53    private static final String XXXLEVEL3XXX2 = "XXXLEVEL3XXX";
54    private static final String XXXLEVEL2XXX2 = "XXXLEVEL2XXX";
55    private static final String XXXLEVEL1XXX2 = "XXXLEVEL1XXX";
56    private static final String CHECKED2 = "checked";
57    /**
58     * Internal Logger
59     */
60    private static final WaarpLogger logger =
61        WaarpLoggerFactory.getLogger(HttpSslHandlerProxyR66.class);
62  
63    private enum REQUEST {
64      Logon("Logon.html"), index("index.html"), error("error.html"),
65      System("System.html");
66  
67      private final String header;
68  
69      /**
70       * Constructor for a unique file
71       *
72       * @param uniquefile
73       */
74      REQUEST(final String uniquefile) {
75        header = uniquefile;
76      }
77  
78      /**
79       * Reader for a unique file
80       *
81       * @return the content of the unique file
82       */
83      public final String readFileUnique(final HttpSslHandlerProxyR66 handler) {
84        return handler.readFileHeaderInternal(
85            configuration.getHttpBasePath() + header);
86      }
87    }
88  
89    private String readFileHeaderInternal(final String filename) {
90      final String value;
91      try {
92        value = WaarpStringUtils.readFileException(filename);
93      } catch (final FileTransferException e) {
94        logger.error("Error while trying to read: " + filename, e);
95        return "";
96      }
97      final StringBuilder builder = new StringBuilder(value);
98      WaarpStringUtils.replace(builder, REPLACEMENT.XXXLOCALXXX.toString(),
99                               configuration.getLocalTransaction()
100                                           .getNumberLocalChannel() + " " +
101                              Thread.activeCount());
102     WaarpStringUtils.replace(builder, REPLACEMENT.XXXNETWORKXXX.toString(),
103                              Integer.toString(
104                                  configuration.getLocalTransaction()
105                                               .getNumberLocalChannel()));
106     WaarpStringUtils.replace(builder, REPLACEMENT.XXXHOSTIDXXX.toString(),
107                              configuration.getHostId());
108     if (authentHttp.isAuthenticated()) {
109       WaarpStringUtils.replace(builder, REPLACEMENT.XXXADMINXXX.toString(),
110                                Messages.getString(
111                                    "HttpSslHandler.1")); //$NON-NLS-1$
112     } else {
113       WaarpStringUtils.replace(builder, REPLACEMENT.XXXADMINXXX.toString(),
114                                Messages.getString(
115                                    "HttpSslHandler.0")); //$NON-NLS-1$
116     }
117     final TrafficCounter trafficCounter =
118         configuration.getGlobalTrafficShapingHandler().trafficCounter();
119     WaarpStringUtils.replace(builder, REPLACEMENT.XXXBANDWIDTHXXX.toString(),
120                              Messages.getString("HttpSslHandler.IN") +
121                              (trafficCounter.lastReadThroughput() >> 20) +
122                              //$NON-NLS-1$
123                              Messages.getString("HttpSslHandler.MOPS") +
124                              //$NON-NLS-1$
125                              Messages.getString("HttpSslHandler.OUT") +
126                              //$NON-NLS-1$
127                              (trafficCounter.lastWriteThroughput() >> 20) +
128                              Messages.getString(
129                                  "HttpSslHandler.MOPS")); //$NON-NLS-1$
130     WaarpStringUtils.replace(builder, REPLACEMENT.XXXLANGXXX.toString(), lang);
131     return builder.toString();
132   }
133 
134   private String indexProxy() {
135     final String index = REQUEST.index.readFileUnique(this);
136     final StringBuilder builder = new StringBuilder(index);
137     WaarpStringUtils.replaceAll(builder, REPLACEMENT.XXXHOSTIDXXX.toString(),
138                                 configuration.getHostId());
139     WaarpStringUtils.replaceAll(builder, REPLACEMENT.XXXADMINXXX.toString(),
140                                 "Administrator Connected");
141     WaarpStringUtils.replace(builder, REPLACEMENT.XXXVERSIONXXX.toString(),
142                              Version.fullIdentifier());
143     return builder.toString();
144   }
145 
146   /**
147    * @param builder
148    */
149   private void replaceStringSystem(final StringBuilder builder) {
150     WaarpStringUtils.replace(builder,
151                              REPLACEMENT.XXXXSESSIONLIMITWXXX.toString(),
152                              Long.toString(
153                                  configuration.getServerChannelWriteLimit()));
154     WaarpStringUtils.replace(builder,
155                              REPLACEMENT.XXXXSESSIONLIMITRXXX.toString(),
156                              Long.toString(
157                                  configuration.getServerChannelReadLimit()));
158     WaarpStringUtils.replace(builder, REPLACEMENT.XXXXDELAYCOMMDXXX.toString(),
159                              Long.toString(configuration.getDelayCommander()));
160     WaarpStringUtils.replace(builder, REPLACEMENT.XXXXDELAYRETRYXXX.toString(),
161                              Long.toString(configuration.getDelayRetry()));
162     WaarpStringUtils.replace(builder,
163                              REPLACEMENT.XXXXCHANNELLIMITWXXX.toString(),
164                              Long.toString(
165                                  configuration.getServerGlobalWriteLimit()));
166     WaarpStringUtils.replace(builder,
167                              REPLACEMENT.XXXXCHANNELLIMITRXXX.toString(),
168                              Long.toString(
169                                  configuration.getServerGlobalReadLimit()));
170     WaarpStringUtils.replace(builder, "XXXBLOCKXXX",
171                              configuration.isShutdown()? CHECKED2 : "");
172     switch (WaarpLoggerFactory.getLogLevel()) {
173       case DEBUG:
174         WaarpStringUtils.replace(builder, XXXLEVEL1XXX2, CHECKED2);
175         WaarpStringUtils.replace(builder, XXXLEVEL2XXX2, "");
176         WaarpStringUtils.replace(builder, XXXLEVEL3XXX2, "");
177         WaarpStringUtils.replace(builder, XXXLEVEL4XXX2, "");
178         break;
179       case INFO:
180         WaarpStringUtils.replace(builder, XXXLEVEL1XXX2, "");
181         WaarpStringUtils.replace(builder, XXXLEVEL2XXX2, CHECKED2);
182         WaarpStringUtils.replace(builder, XXXLEVEL3XXX2, "");
183         WaarpStringUtils.replace(builder, XXXLEVEL4XXX2, "");
184         break;
185       case WARN:
186         WaarpStringUtils.replace(builder, XXXLEVEL1XXX2, "");
187         WaarpStringUtils.replace(builder, XXXLEVEL2XXX2, "");
188         WaarpStringUtils.replace(builder, XXXLEVEL3XXX2, CHECKED2);
189         WaarpStringUtils.replace(builder, XXXLEVEL4XXX2, "");
190         break;
191       case ERROR:
192         WaarpStringUtils.replace(builder, XXXLEVEL1XXX2, "");
193         WaarpStringUtils.replace(builder, XXXLEVEL2XXX2, "");
194         WaarpStringUtils.replace(builder, XXXLEVEL3XXX2, "");
195         WaarpStringUtils.replace(builder, XXXLEVEL4XXX2, CHECKED2);
196         break;
197       default:
198         WaarpStringUtils.replace(builder, XXXLEVEL1XXX2, "");
199         WaarpStringUtils.replace(builder, XXXLEVEL2XXX2, "");
200         WaarpStringUtils.replace(builder, XXXLEVEL3XXX2, "");
201         WaarpStringUtils.replace(builder, XXXLEVEL4XXX2, "");
202         break;
203 
204     }
205   }
206 
207   private String System() {
208     getParamsProxy();
209     if (params == null) {
210       final String system = REQUEST.System.readFileUnique(this);
211       final StringBuilder builder = new StringBuilder(system);
212       replaceStringSystem(builder);
213       langHandle(builder);
214       return builder.toString();
215     }
216     String extraInformation = null;
217     if (params.containsKey("ACTION")) {
218       final List<String> action = params.get("ACTION");
219       for (final String act : action) {
220         if ("Language".equalsIgnoreCase(act)) {
221           lang = getTrimValue("change");
222           final String sys = getTrimValue("changesys");
223           Messages.init(new Locale(sys));
224           extraInformation =
225               Messages.getString("HttpSslHandler.LangIs") + "Web: " + lang +
226               " OpenR66: " //$NON-NLS-1$
227               + Messages.getSlocale();
228         } else if ("Level".equalsIgnoreCase(act)) {
229           final String loglevel = getTrimValue("loglevel");
230           WaarpLogLevel level = WaarpLogLevel.WARN;
231           if ("debug".equalsIgnoreCase(loglevel)) {
232             level = WaarpLogLevel.DEBUG;
233           } else if ("info".equalsIgnoreCase(loglevel)) {
234             level = WaarpLogLevel.INFO;
235           } else if ("warn".equalsIgnoreCase(loglevel)) {
236             level = WaarpLogLevel.WARN;
237           } else if ("error".equalsIgnoreCase(loglevel)) {
238             level = WaarpLogLevel.ERROR;
239           }
240           WaarpLoggerFactory.setLogLevel(level);
241           extraInformation = Messages.getString("HttpSslHandler.LangIs") +
242                              level.name(); //$NON-NLS-1$
243         } else if ("Disconnect".equalsIgnoreCase(act)) {
244           String logon = logon();
245           logon = logon.replaceAll(REPLACEMENT.XXXERRORMESGXXX.toString(),
246                                    Messages.getString(
247                                        "HttpSslHandler.DisActive"));
248           newSession = true;
249           clearSession();
250           forceClose = true;
251           return logon;
252         } else if ("Shutdown".equalsIgnoreCase(act)) {
253           final String error;
254           if (configuration.getShutdownConfiguration().serviceFuture != null) {
255             error =
256                 error(Messages.getString("HttpSslHandler.38")); //$NON-NLS-1$
257           } else {
258             error =
259                 error(Messages.getString("HttpSslHandler.37")); //$NON-NLS-1$
260           }
261           WaarpShutdownHook.setRestart(false);
262           newSession = true;
263           clearSession();
264           forceClose = true;
265           shutdown = true;
266           return error;
267         } else if ("Restart".equalsIgnoreCase(act)) {
268           String error;
269           if (configuration.getShutdownConfiguration().serviceFuture != null) {
270             error =
271                 error(Messages.getString("HttpSslHandler.38")); //$NON-NLS-1$
272           } else {
273             error = error(Messages.getString("HttpSslHandler.39")
274                           //$NON-NLS-1$
275                           + configuration.getTimeoutCon() * 2 / 1000 +
276                           Messages.getString(
277                               "HttpSslHandler.40")); //$NON-NLS-1$
278           }
279           error = error.replace("XXXRELOADHTTPXXX",
280                                 "HTTP-EQUIV=\"refresh\" CONTENT=\"" +
281                                 configuration.getTimeoutCon() * 2 / 1000 + '"');
282           WaarpShutdownHook.setRestart(true);
283           newSession = true;
284           clearSession();
285           forceClose = true;
286           shutdown = true;
287           return error;
288         } else if ("Validate".equalsIgnoreCase(act)) {
289           final String bsessionr = getTrimValue("BSESSR");
290           long lsessionr = configuration.getServerChannelReadLimit();
291           long lglobalr;
292           long lsessionw;
293           long lglobalw;
294           try {
295             if (bsessionr != null) {
296               lsessionr = (Long.parseLong(bsessionr) / 10) * 10;
297             }
298             final String bglobalr = getTrimValue("BGLOBR");
299             lglobalr = configuration.getServerGlobalReadLimit();
300             if (bglobalr != null) {
301               lglobalr = (Long.parseLong(bglobalr) / 10) * 10;
302             }
303             final String bsessionw = getTrimValue("BSESSW");
304             lsessionw = configuration.getServerChannelWriteLimit();
305             if (bsessionw != null) {
306               lsessionw = (Long.parseLong(bsessionw) / 10) * 10;
307             }
308             final String bglobalw = getTrimValue("BGLOBW");
309             lglobalw = configuration.getServerGlobalWriteLimit();
310             if (bglobalw != null) {
311               lglobalw = (Long.parseLong(bglobalw) / 10) * 10;
312             }
313             configuration.changeNetworkLimit(lglobalw, lglobalr, lsessionw,
314                                              lsessionr,
315                                              configuration.getDelayLimit());
316             final String dcomm = getTrimValue("DCOM");
317             if (dcomm != null) {
318               configuration.setDelayCommander(Long.parseLong(dcomm));
319               if (configuration.getDelayCommander() <= 100) {
320                 configuration.setDelayCommander(100);
321               }
322               configuration.reloadCommanderDelay();
323             }
324             final String dret = getTrimValue("DRET");
325             if (dret != null) {
326               configuration.setDelayRetry(Long.parseLong(dret));
327               if (configuration.getDelayRetry() <= 1000) {
328                 configuration.setDelayRetry(1000);
329               }
330             }
331             extraInformation =
332                 Messages.getString("HttpSslHandler.41"); //$NON-NLS-1$
333           } catch (final NumberFormatException e) {
334             extraInformation =
335                 Messages.getString("HttpSslHandler.42"); //$NON-NLS-1$
336           }
337         }
338       }
339     }
340     final String system = REQUEST.System.readFileUnique(this);
341     final StringBuilder builder = new StringBuilder(system);
342     replaceStringSystem(builder);
343     langHandle(builder);
344     if (extraInformation != null) {
345       builder.append(extraInformation);
346     }
347     return builder.toString();
348   }
349 
350   private void getParamsProxy() {
351     if (request.method() == HttpMethod.GET) {
352       params = null;
353     } else if (request.method() == HttpMethod.POST) {
354       final ByteBuf content = request.content();
355       if (content.isReadable()) {
356         final String param = content.toString(WaarpStringUtils.UTF8);
357         final QueryStringDecoder queryStringDecoder2 =
358             new QueryStringDecoder("/?" + param);
359         params = queryStringDecoder2.parameters();
360       } else {
361         params = null;
362       }
363     }
364   }
365 
366   @Override
367   protected final void clearSession() {
368     if (admin != null) {
369       final R66Session lsession = sessions.remove(admin.value());
370       admin = null;
371       if (lsession != null) {
372         lsession.setStatus(75);
373         lsession.clear();
374       }
375     }
376   }
377 
378   private void checkAuthentProxy(final ChannelHandlerContext ctx) {
379     newSession = true;
380     if (request.method() == HttpMethod.GET) {
381       String logon = logon();
382       logon = logon.replaceAll(REPLACEMENT.XXXERRORMESGXXX.toString(), "");
383       responseContent.append(logon);
384       clearSession();
385       writeResponse(ctx);
386       return;
387     } else if (request.method() == HttpMethod.POST) {
388       getParamsProxy();
389       if (params == null) {
390         String logon = logon();
391         logon = logon.replaceAll(REPLACEMENT.XXXERRORMESGXXX.toString(),
392                                  Messages.getString(
393                                      "HttpSslHandler.EmptyLogin"));
394         responseContent.append(logon);
395         clearSession();
396         writeResponse(ctx);
397         return;
398       }
399     }
400     boolean getMenu = false;
401     if (params != null && params.containsKey("Logon")) {
402       String name = null;
403       String password = null;
404       List<String> values;
405       if (!params.isEmpty()) {
406         // get values
407         if (params.containsKey("name")) {
408           values = params.get("name");
409           if (values != null) {
410             name = values.get(0);
411             if (ParametersChecker.isEmpty(name)) {
412               getMenu = true;
413             }
414           }
415         } else {
416           getMenu = true;
417         }
418         // search the nb param
419         if (!getMenu && params.containsKey("passwd")) {
420           values = params.get("passwd");
421           if (values != null) {
422             password = values.get(0);
423             getMenu = ParametersChecker.isEmpty(password);
424           } else {
425             getMenu = true;
426           }
427         } else {
428           getMenu = true;
429         }
430       } else {
431         getMenu = true;
432       }
433       if (!getMenu && name != null) {
434         if (logger.isDebugEnabled()) {
435           logger.debug("Name={} vs {} Passwd vs ", name,
436                        name.equals(configuration.getAdminName()),
437                        Arrays.equals(password.getBytes(WaarpStringUtils.UTF8),
438                                      configuration.getServerAdminKey()));
439         }
440         if (name.equals(configuration.getAdminName()) &&
441             Arrays.equals(password.getBytes(WaarpStringUtils.UTF8),
442                           configuration.getServerAdminKey())) {
443           authentHttp.getAuth()
444                      .specialNoSessionAuth(true, configuration.getHostId());
445           authentHttp.setStatus(70);
446         } else {
447           getMenu = true;
448         }
449         if (!authentHttp.isAuthenticated()) {
450           authentHttp.setStatus(71);
451           logger.info("Still not authenticated: {}", authentHttp);
452           getMenu = true;
453         }
454       }
455     } else {
456       getMenu = true;
457     }
458     if (getMenu) {
459       String logon = logon();
460       logon = logon.replaceAll(REPLACEMENT.XXXERRORMESGXXX.toString(),
461                                Messages.getString("HttpSslHandler.BadLogin"));
462       responseContent.append(logon);
463       clearSession();
464     } else {
465       final String index = indexProxy();
466       responseContent.append(index);
467       clearSession();
468       admin = new DefaultCookie(R66SESSION + configuration.getHostId(),
469                                 configuration.getHostId() +
470                                 Long.toHexString(RANDOM.nextLong()));
471       sessions.put(admin.value(), authentHttp);
472       authentHttp.setStatus(72);
473       logger.debug("CreateSession: {}:{}", uriRequest, admin);
474     }
475     writeResponse(ctx);
476   }
477 
478   @Override
479   protected void channelRead0(final ChannelHandlerContext ctx,
480                               final FullHttpRequest msg) {
481     final FullHttpRequest request = this.request = msg;
482     final QueryStringDecoder queryStringDecoder =
483         new QueryStringDecoder(request.uri());
484     uriRequest = queryStringDecoder.path();
485     logger.debug("Msg: {}", uriRequest);
486     if (uriRequest.contains("gre/") || uriRequest.contains("img/") ||
487         uriRequest.contains("res/") || uriRequest.contains("favicon.ico")) {
488       HttpWriteCacheEnable.writeFile(request, ctx,
489                                      configuration.getHttpBasePath() +
490                                      uriRequest,
491                                      R66SESSION + configuration.getHostId());
492       ctx.flush();
493       return;
494     }
495     checkSession(ctx.channel());
496     try {
497       if (!authentHttp.isAuthenticated()) {
498         logger.debug("Not Authent: {}:{}", uriRequest, authentHttp);
499         checkAuthentProxy(ctx);
500         return;
501       }
502       String find = uriRequest;
503       if (uriRequest.charAt(0) == '/') {
504         find = uriRequest.substring(1);
505       }
506       REQUEST req = REQUEST.index;
507       if (find.length() != 0) {
508         find = find.substring(0, find.indexOf('.'));
509         try {
510           req = REQUEST.valueOf(find);
511         } catch (final IllegalArgumentException e1) {
512           req = REQUEST.index;
513           logger.info("NotFound: {}:{}", find, uriRequest);
514         }
515       }
516       if (req == REQUEST.System) {
517         responseContent.append(System());
518       } else {
519         responseContent.append(indexProxy());
520       }
521       writeResponse(ctx);
522     } finally {
523       closeConnection();
524     }
525   }
526 }