Bump upstreams to SNAPSHOTs
[netconf.git] / restconf / websocket-client / src / main / java / org / opendaylight / restconf / websocket / client / ApplicationSettings.java
1 /*
2  * Copyright © 2019 FRINX s.r.o. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.websocket.client;
9
10 import com.google.common.base.Preconditions;
11 import java.io.File;
12 import java.io.PrintWriter;
13 import java.io.StringWriter;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Optional;
17 import net.sourceforge.argparse4j.ArgumentParsers;
18 import net.sourceforge.argparse4j.annotation.Arg;
19 import net.sourceforge.argparse4j.helper.HelpScreenException;
20 import net.sourceforge.argparse4j.inf.ArgumentParser;
21 import net.sourceforge.argparse4j.inf.ArgumentParserException;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Holder of the parsed user-input application arguments.
27  */
28 final class ApplicationSettings {
29
30     /**
31      * Credentials used for basic authentication - grouping of username and password.
32      */
33     static final class Credentials {
34         final String userName;
35         final String password;
36
37         private Credentials(final String userName, final String password) {
38             this.userName = userName;
39             this.password = password;
40         }
41
42         private static Credentials extractCredentials(final String basicAuthentication) {
43             final String[] credentials = basicAuthentication.split(":");
44             Preconditions.checkArgument(credentials.length == 2, "Both username and password must be specified in the "
45                     + "format [username]:[password] for basic authentication.");
46             final String userName = credentials[0].trim();
47             final String password = credentials[1].trim();
48             return new Credentials(userName, password);
49         }
50     }
51
52     private static final Logger LOG = LoggerFactory.getLogger(ApplicationSettings.class);
53     private static final ArgumentParser PARSER = ArgumentParsers.newFor("web-socket client test-tool").build();
54
55     static {
56         PARSER.addArgument("-l")
57                 .dest("loggingLevel")
58                 .required(false)
59                 .setDefault("INFO")
60                 .metavar("LEVEL")
61                 .type(String.class)
62                 .help("Logging level threshold used throughout the whole web-socket client.");
63         PARSER.addArgument("-s")
64                 .dest("streams")
65                 .required(true)
66                 .nargs("+")
67                 .help("Web-socket stream paths with ws or wss schemas.")
68                 .metavar("STREAM")
69                 .type(String.class);
70         PARSER.addArgument("-pi")
71                 .dest("pingInterval")
72                 .help("Interval in milliseconds between sending of ping web-socket frames to server. "
73                         + "Value of 0 disables ping process.")
74                 .metavar("INTERVAL")
75                 .setDefault(0)
76                 .type(Integer.class);
77         PARSER.addArgument("-pm")
78                 .dest("pingMessage")
79                 .help("Explicitly set ping message.")
80                 .metavar("MESSAGE")
81                 .setDefault("ping")
82                 .type(String.class);
83         PARSER.addArgument("-t")
84                 .dest("threads")
85                 .help("Explicitly set size of thread-pool used for holding of web-socket handlers and ping processes.")
86                 .metavar("SIZE")
87                 .setDefault(8)
88                 .type(Integer.class);
89         PARSER.addArgument("-r")
90                 .dest("regeneration")
91                 .help("Allowed TLS/SSL session regeneration.")
92                 .metavar("ALLOWED")
93                 .setDefault(false)
94                 .type(Boolean.class);
95         PARSER.addArgument("-kpath")
96                 .dest("keystorePath")
97                 .help("Path to the certificates key-store file.")
98                 .metavar("PATH")
99                 .type(File.class);
100         PARSER.addArgument("-kpass")
101                 .dest("keystorePassword")
102                 .help("Password used for unlocking of the certificates keystore.")
103                 .metavar("SECRET")
104                 .type(String.class);
105         PARSER.addArgument("-tpath")
106                 .dest("truststorePath")
107                 .help("Path to the certificates trust-store file.")
108                 .metavar("PATH")
109                 .type(File.class);
110         PARSER.addArgument("-tpass")
111                 .dest("truststorePassword")
112                 .help("Password used for unlocking of the certificates truststore.")
113                 .metavar("SECRET")
114                 .type(String.class);
115         PARSER.addArgument("-ta")
116                 .dest("trustAll")
117                 .help("All incoming certificates are trusted when both truststore and keystore are not specified.")
118                 .metavar("TRUST")
119                 .setDefault(false)
120                 .type(Boolean.class);
121         PARSER.addArgument("-ip")
122                 .dest("includedProtocols")
123                 .nargs("+")
124                 .help("Explicitly specified list of permitted versions of web-security protocols.")
125                 .metavar("PROTOCOL")
126                 .setDefault("TLSv1.2", "TLSv1.3")
127                 .type(String.class);
128         PARSER.addArgument("-ep")
129                 .dest("excludedProtocols")
130                 .nargs("*")
131                 .help("Explicitly specified list of denied versions of web-security protocols (denied protocols have "
132                         + "the highest priority).")
133                 .metavar("PROTOCOL")
134                 .setDefault("TLSv1", "TLSv1.1", "SSL", "SSLv2", "SSLv2Hello", "SSLv3")
135                 .type(String.class);
136         PARSER.addArgument("-ic")
137                 .dest("includedCipherSuites")
138                 .nargs("+")
139                 .help("Explicitly specified list of permitted cipher suites.")
140                 .metavar("CIPHER")
141                 .setDefault("TLS_ECDHE.*", "TLS_DHE_RSA.*")
142                 .type(String.class);
143         PARSER.addArgument("-ec")
144                 .dest("excludedCipherSuites")
145                 .nargs("*")
146                 .help("Explicitly specified list of denied cipher suites (denied ciphers have the highest priority).")
147                 .metavar("CIPHER")
148                 .setDefault(".*MD5.*", ".*RC4.*", ".*DSS.*", ".*NULL.*", ".*DES.*")
149                 .type(String.class);
150         PARSER.addArgument("-b")
151                 .dest("basicAuthentication")
152                 .help("[username:password] used with basic authentication that can be required on upgrade-request.")
153                 .metavar("[USERNAME]:[PASSWORD]")
154                 .type(String.class);
155     }
156
157     @Arg(dest = "loggingLevel")
158     private String loggingLevel;
159     @Arg(dest = "streams")
160     private List<String> streams;
161     @Arg(dest = "pingInterval")
162     private int pingInterval;
163     @Arg(dest = "pingMessage")
164     private String pingMessage;
165     @Arg(dest = "threads")
166     private int threadPoolSize;
167     @Arg(dest = "regeneration")
168     private boolean regenerationAllowed;
169     @Arg(dest = "keystorePath")
170     private File keystorePath;
171     @Arg(dest = "keystorePassword")
172     private String keystorePassword;
173     @Arg(dest = "truststorePath")
174     private File truststorePath;
175     @Arg(dest = "truststorePassword")
176     private String truststorePassword;
177     @Arg(dest = "trustAll")
178     private boolean trustAll;
179     @Arg(dest = "includedProtocols")
180     private List<String> includedProtocols;
181     @Arg(dest = "excludedProtocols")
182     private List<String> excludedProtocols;
183     @Arg(dest = "includedCipherSuites")
184     private List<String> includedCipherSuites;
185     @Arg(dest = "excludedCipherSuites")
186     private List<String> excludedCipherSuites;
187     @Arg(dest = "basicAuthentication")
188     private String basicAuthentication;
189
190     private Credentials credentials;
191
192     private ApplicationSettings() {
193     }
194
195     /**
196      * Creation of application settings object using input command-line arguments (factory method).
197      *
198      * @param arguments Raw program arguments.
199      * @return Parsed arguments wrapped in {@link Optional} or {@link Optional#empty()} if only help is going
200      *     to be invoked.
201      */
202     static Optional<ApplicationSettings> parseApplicationSettings(final String[] arguments) {
203         final ApplicationSettings applicationSettings = new ApplicationSettings();
204         try {
205             PARSER.parseArgs(arguments, applicationSettings);
206             applicationSettings.verifyParsedArguments();
207             if (applicationSettings.basicAuthentication == null) {
208                 applicationSettings.credentials = null;
209             } else {
210                 applicationSettings.credentials = Credentials.extractCredentials(
211                     applicationSettings.basicAuthentication);
212             }
213         } catch (final ArgumentParserException | IllegalArgumentException e) {
214             if (e instanceof HelpScreenException) {
215                 return Optional.empty();
216             } else {
217                 final StringWriter helpWriter = new StringWriter();
218                 final PrintWriter helpPrintWriter = new PrintWriter(helpWriter);
219                 PARSER.printHelp(helpPrintWriter);
220                 LOG.error("Cannot parse input arguments {}.", arguments, e);
221                 LOG.info("Help: {}", helpWriter.toString());
222                 throw new IllegalArgumentException("Cannot parse input arguments", e);
223             }
224         }
225         LOG.info("Application settings {} have been parsed successfully.", (Object) arguments);
226         return Optional.of(applicationSettings);
227     }
228
229     private void verifyParsedArguments() {
230         Preconditions.checkArgument(pingInterval >= 0, "Ping interval must be set to value higher than 0 (enabled) or "
231                 + "to 0 (disabled).");
232         Preconditions.checkArgument(threadPoolSize > 0, "Thread pool must have capacity of at least 1 thread.");
233         Preconditions.checkArgument((keystorePath == null && keystorePassword == null) || (keystorePath != null
234                 && keystorePassword != null), "Both keystore path and keystore password must be configured at once.");
235         Preconditions.checkArgument((truststorePath == null && truststorePassword == null) || (truststorePath != null
236                 && truststorePassword != null), "Both truststore path and truststore password must be configured");
237     }
238
239     String getLoggingLevel() {
240         return loggingLevel;
241     }
242
243     List<String> getStreams() {
244         return new ArrayList<>(streams);
245     }
246
247     int getPingInterval() {
248         return pingInterval;
249     }
250
251     String getPingMessage() {
252         return pingMessage;
253     }
254
255     File getKeystorePath() {
256         return keystorePath;
257     }
258
259     String getKeystorePassword() {
260         return keystorePassword;
261     }
262
263     File getTruststorePath() {
264         return truststorePath;
265     }
266
267     String getTruststorePassword() {
268         return truststorePassword;
269     }
270
271     List<String> getIncludedProtocols() {
272         return new ArrayList<>(includedProtocols);
273     }
274
275     List<String> getExcludedProtocols() {
276         return new ArrayList<>(excludedProtocols);
277     }
278
279     List<String> getIncludedCipherSuites() {
280         return new ArrayList<>(includedCipherSuites);
281     }
282
283     List<String> getExcludedCipherSuites() {
284         return new ArrayList<>(excludedCipherSuites);
285     }
286
287     boolean isTrustAll() {
288         return trustAll;
289     }
290
291     boolean isRegenerationAllowed() {
292         return regenerationAllowed;
293     }
294
295     int getThreadPoolSize() {
296         return threadPoolSize;
297     }
298
299     Credentials getCredentials() {
300         return credentials;
301     }
302 }