1515 * limitations under the License.
1616 */
1717
18-
1918package org .apache .ignite .internal .commandline ;
2019
2120import java .lang .reflect .Field ;
2221import java .util .ArrayDeque ;
2322import java .util .ArrayList ;
2423import java .util .Deque ;
25- import java .util .HashSet ;
2624import java .util .Iterator ;
2725import java .util .List ;
26+ import java .util .ListIterator ;
2827import java .util .Set ;
2928import java .util .function .BiConsumer ;
3029import java .util .function .BiFunction ;
4241import org .apache .ignite .internal .management .api .CommandUtils ;
4342import org .apache .ignite .internal .management .api .CommandsRegistry ;
4443import org .apache .ignite .internal .management .api .Positional ;
44+ import org .apache .ignite .internal .util .typedef .internal .SB ;
4545import org .apache .ignite .internal .util .typedef .internal .U ;
4646import org .apache .ignite .lang .IgniteExperimental ;
47- import org .apache .ignite .ssl .SslContextFactory ;
4847
4948import static org .apache .ignite .IgniteSystemProperties .IGNITE_ENABLE_EXPERIMENTAL_COMMAND ;
5049import static org .apache .ignite .internal .commandline .CommandHandler .DFLT_HOST ;
5150import static org .apache .ignite .internal .commandline .CommandHandler .DFLT_PORT ;
5251import static org .apache .ignite .internal .commandline .CommandHandler .UTILITY_NAME ;
53- import static org .apache .ignite .internal .commandline .argument .parser .CLIArgument .optionalArg ;
52+ import static org .apache .ignite .internal .commandline .argument .parser .CLIArgument .CLIArgumentBuilder .argument ;
53+ import static org .apache .ignite .internal .commandline .argument .parser .CLIArgument .CLIArgumentBuilder .optionalArgument ;
54+ import static org .apache .ignite .internal .commandline .argument .parser .CLIArgumentParser .readNextValueToken ;
5455import static org .apache .ignite .internal .management .api .CommandUtils .CMD_WORDS_DELIM ;
5556import static org .apache .ignite .internal .management .api .CommandUtils .NAME_PREFIX ;
5657import static org .apache .ignite .internal .management .api .CommandUtils .PARAM_WORDS_DELIM ;
6263import static org .apache .ignite .internal .management .api .CommandUtils .toFormattedCommandName ;
6364import static org .apache .ignite .internal .management .api .CommandUtils .toFormattedFieldName ;
6465import static org .apache .ignite .internal .management .api .CommandUtils .visitCommandParams ;
66+ import static org .apache .ignite .ssl .SslContextFactory .DFLT_KEY_ALGORITHM ;
6567import static org .apache .ignite .ssl .SslContextFactory .DFLT_SSL_PROTOCOL ;
68+ import static org .apache .ignite .ssl .SslContextFactory .DFLT_STORE_TYPE ;
6669
6770/**
6871 * Argument parser.
@@ -131,9 +134,6 @@ public class ArgumentParser {
131134 /** */
132135 static final String CMD_SSL_FACTORY = "--ssl-factory" ;
133136
134- /** Set of sensitive arguments */
135- private static final Set <String > SENSITIVE_ARGUMENTS = new HashSet <>();
136-
137137 /** */
138138 private static final BiConsumer <String , Integer > PORT_VALIDATOR = (name , val ) -> {
139139 if (val <= 0 || val > 65535 )
@@ -143,64 +143,46 @@ public class ArgumentParser {
143143 /** */
144144 private final List <CLIArgument <?>> common = new ArrayList <>();
145145
146- static {
147- SENSITIVE_ARGUMENTS .add (CMD_PASSWORD );
148- SENSITIVE_ARGUMENTS .add (CMD_KEYSTORE_PASSWORD );
149- SENSITIVE_ARGUMENTS .add (CMD_TRUSTSTORE_PASSWORD );
150- }
151-
152- /**
153- * @param arg To check.
154- * @return True if provided argument is among sensitive one and not should be displayed.
155- */
156- public static boolean isSensitiveArgument (String arg ) {
157- return SENSITIVE_ARGUMENTS .contains (arg );
158- }
146+ /** Console instance. */
147+ protected final GridConsole console ;
159148
160149 /**
161150 * @param log Logger.
162151 * @param registry Supported commands.
152+ * @param console Console.
163153 */
164- public ArgumentParser (IgniteLogger log , IgniteCommandRegistry registry ) {
154+ public ArgumentParser (IgniteLogger log , IgniteCommandRegistry registry , GridConsole console ) {
165155 this .log = log ;
166156 this .registry = registry ;
167-
168- BiConsumer <String , ?> securityWarn = (name , val ) -> log .info (String .format ("Warning: %s is insecure. " +
169- "Whenever possible, use interactive prompt for password (just discard %s option)." , name , name ));
170-
171- arg (CMD_HOST , "HOST_OR_IP" , String .class , DFLT_HOST );
172- arg (CMD_PORT , "PORT" , Integer .class , DFLT_PORT , PORT_VALIDATOR );
173- arg (CMD_USER , "USER" , String .class , null );
174- arg (CMD_PASSWORD , "PASSWORD" , String .class , null , (BiConsumer <String , String >)securityWarn );
175- arg (CMD_VERBOSE , CMD_VERBOSE , boolean .class , false );
176- arg (CMD_SSL_PROTOCOL , "SSL_PROTOCOL[, SSL_PROTOCOL_2, ..., SSL_PROTOCOL_N]" , String [].class , new String [] {DFLT_SSL_PROTOCOL });
177- arg (CMD_SSL_CIPHER_SUITES , "SSL_CIPHER_1[, SSL_CIPHER_2, ..., SSL_CIPHER_N]" , String [].class , null );
178- arg (CMD_SSL_KEY_ALGORITHM , "SSL_KEY_ALGORITHM" , String .class , SslContextFactory .DFLT_KEY_ALGORITHM );
179- arg (CMD_SSL_FACTORY , "SSL_FACTORY_PATH" , String .class , null );
180- arg (CMD_KEYSTORE_TYPE , "KEYSTORE_TYPE" , String .class , SslContextFactory .DFLT_STORE_TYPE );
181- arg (CMD_KEYSTORE , "KEYSTORE_PATH" , String .class , null );
182- arg (CMD_KEYSTORE_PASSWORD , "KEYSTORE_PASSWORD" , char [].class , null , (BiConsumer <String , char []>)securityWarn );
183- arg (CMD_TRUSTSTORE_TYPE , "TRUSTSTORE_TYPE" , String .class , SslContextFactory .DFLT_STORE_TYPE );
184- arg (CMD_TRUSTSTORE , "TRUSTSTORE_PATH" , String .class , null );
185- arg (CMD_TRUSTSTORE_PASSWORD , "TRUSTSTORE_PASSWORD" , char [].class , null , (BiConsumer <String , char []>)securityWarn );
186- arg (CMD_AUTO_CONFIRMATION , CMD_AUTO_CONFIRMATION , boolean .class , false );
187- arg (
188- CMD_ENABLE_EXPERIMENTAL ,
189- CMD_ENABLE_EXPERIMENTAL , Boolean .class ,
190- IgniteSystemProperties .getBoolean (IGNITE_ENABLE_EXPERIMENTAL_COMMAND )
157+ this .console = console ;
158+
159+ common .addAll (List .of (
160+ optionalArgument (CMD_HOST , String .class ).withUsage ("HOST_OR_IP" ).withDefault (DFLT_HOST ).build (),
161+ optionalArgument (CMD_PORT , Integer .class ).withUsage ("PORT" ).withDefault (DFLT_PORT ).withValidator (PORT_VALIDATOR ).build (),
162+ optionalArgument (CMD_USER , String .class ).withUsage ("USER" ).build (),
163+ optionalArgument (CMD_PASSWORD , String .class ).withUsage ("PASSWORD" ).markSensitive ().build (),
164+ optionalArgument (CMD_VERBOSE , boolean .class ).withUsage (CMD_VERBOSE ).withDefault (false ).build (),
165+ optionalArgument (CMD_SSL_PROTOCOL , String [].class )
166+ .withUsage ("SSL_PROTOCOL[, SSL_PROTOCOL_2, ..., SSL_PROTOCOL_N]" )
167+ .withDefault (t -> new String [] {DFLT_SSL_PROTOCOL })
168+ .build (),
169+ optionalArgument (CMD_SSL_CIPHER_SUITES , String [].class ).withUsage ("SSL_CIPHER_1[, SSL_CIPHER_2, ..., SSL_CIPHER_N]" ).build (),
170+ optionalArgument (CMD_SSL_KEY_ALGORITHM , String .class ).withUsage ("SSL_KEY_ALGORITHM" ).withDefault (DFLT_KEY_ALGORITHM ).build (),
171+ optionalArgument (CMD_SSL_FACTORY , String .class ).withUsage ("SSL_FACTORY_PATH" ).build (),
172+ optionalArgument (CMD_KEYSTORE_TYPE , String .class ).withUsage ("KEYSTORE_TYPE" ).withDefault (DFLT_STORE_TYPE ).build (),
173+ optionalArgument (CMD_KEYSTORE , String .class ).withUsage ("KEYSTORE_PATH" ).build (),
174+ optionalArgument (CMD_KEYSTORE_PASSWORD , char [].class ).withUsage ("KEYSTORE_PASSWORD" ).markSensitive ().build (),
175+ optionalArgument (CMD_TRUSTSTORE_TYPE , String .class ).withUsage ("TRUSTSTORE_TYPE" ).withDefault (DFLT_STORE_TYPE ).build (),
176+ optionalArgument (CMD_TRUSTSTORE , String .class ).withUsage ("TRUSTSTORE_PATH" ).build (),
177+ optionalArgument (CMD_TRUSTSTORE_PASSWORD , char [].class ).withUsage ("TRUSTSTORE_PASSWORD" ).markSensitive ().build (),
178+ optionalArgument (CMD_AUTO_CONFIRMATION , boolean .class ).withUsage (CMD_AUTO_CONFIRMATION ).withDefault (false ).build (),
179+ optionalArgument (CMD_ENABLE_EXPERIMENTAL , Boolean .class )
180+ .withUsage (CMD_ENABLE_EXPERIMENTAL )
181+ .withDefault (t -> IgniteSystemProperties .getBoolean (IGNITE_ENABLE_EXPERIMENTAL_COMMAND ))
182+ .build ())
191183 );
192184 }
193185
194- /** */
195- private <T > void arg (String name , String usage , Class <T > type , T dflt , BiConsumer <String , T > validator ) {
196- common .add (optionalArg (name , usage , type , t -> dflt , validator ));
197- }
198-
199- /** */
200- private <T > void arg (String name , String usage , Class <T > type , T dflt ) {
201- common .add (optionalArg (name , usage , type , () -> dflt ));
202- }
203-
204186 /**
205187 * Creates list of common utility options.
206188 *
@@ -236,7 +218,9 @@ public <A extends IgniteDataTransferObject> ConnectionAndSslParameters<A> parseA
236218
237219 CLIArgumentParser parser = createArgumentParser ();
238220
239- parser .parse (args .iterator ());
221+ parser .parse (args .listIterator ());
222+
223+ String safeCmd = buildSafeCommandString (raw .listIterator (), parser );
240224
241225 A arg = (A )argument (
242226 cmdPath .peek ().argClass (),
@@ -253,7 +237,7 @@ public <A extends IgniteDataTransferObject> ConnectionAndSslParameters<A> parseA
253237 throw new IllegalArgumentException ("Experimental commands disabled" );
254238 }
255239
256- return new ConnectionAndSslParameters <>(cmdPath , arg , parser );
240+ return new ConnectionAndSslParameters <>(cmdPath , arg , parser , safeCmd );
257241 }
258242
259243 /**
@@ -323,14 +307,11 @@ private CLIArgumentParser createArgumentParser() {
323307 List <CLIArgument <?>> positionalArgs = new ArrayList <>();
324308 List <CLIArgument <?>> namedArgs = new ArrayList <>();
325309
326- BiFunction <Field , Boolean , CLIArgument <?>> toArg = (fld , optional ) -> new CLIArgument <>(
327- toFormattedFieldName (fld ).toLowerCase (),
328- null ,
329- optional ,
330- fld .getType (),
331- null ,
332- (name , val ) -> {}
333- );
310+ BiFunction <Field , Boolean , CLIArgument <?>> toArg =
311+ (fld , optional ) -> argument (toFormattedFieldName (fld ).toLowerCase (), fld .getType ())
312+ .withOptional (optional )
313+ .withSensitive (fld .getAnnotation (Argument .class ).sensitive ())
314+ .build ();
334315
335316 List <Set <String >> grpdFlds = CommandUtils .argumentGroupsValues (cmdPath .peek ().argClass ());
336317
@@ -339,14 +320,10 @@ private CLIArgumentParser createArgumentParser() {
339320 || fld .getAnnotation (Argument .class ).optional ())
340321 );
341322
342- Consumer <Field > positionalArgCb = fld -> positionalArgs .add (new CLIArgument <>(
343- fld .getName ().toLowerCase (),
344- null ,
345- fld .getAnnotation (Argument .class ).optional (),
346- fld .getType (),
347- null ,
348- (name , val ) -> {}
349- ));
323+ Consumer <Field > positionalArgCb = fld -> positionalArgs .add (argument (fld .getName ().toLowerCase (), fld .getType ())
324+ .withOptional (fld .getAnnotation (Argument .class ).optional ())
325+ .build ()
326+ );
350327
351328 BiConsumer <ArgumentGroup , List <Field >> argGrpCb = (argGrp0 , flds ) -> flds .forEach (fld -> {
352329 if (fld .isAnnotationPresent (Positional .class ))
@@ -359,6 +336,37 @@ private CLIArgumentParser createArgumentParser() {
359336
360337 namedArgs .addAll (common );
361338
362- return new CLIArgumentParser (positionalArgs , namedArgs );
339+ return new CLIArgumentParser (positionalArgs , namedArgs , console );
340+ }
341+
342+ /** @return String representation of command with hidden values of sensitive arguments. */
343+ private String buildSafeCommandString (ListIterator <String > rawIter , CLIArgumentParser parser ) {
344+ SB res = new SB ();
345+
346+ while (rawIter .hasNext ()) {
347+ String arg = rawIter .next ();
348+
349+ CLIArgument <?> argDesc = parser .getArgumentDescriptor (arg .toLowerCase ());
350+
351+ res .a (arg ).a (' ' );
352+
353+ if (argDesc == null || argDesc .isFlag ())
354+ continue ;
355+
356+ String argVal = readNextValueToken (rawIter );
357+
358+ if (argVal != null ) {
359+ if (!argDesc .isSensitive ())
360+ res .a (argVal ).a (' ' );
361+ else {
362+ res .a ("***** " );
363+
364+ log .info (String .format ("Warning: %s is insecure. Whenever possible, use interactive prompt for " +
365+ "password (just omit the argument value)." , argDesc .name ()));
366+ }
367+ }
368+ }
369+
370+ return res .toString ();
363371 }
364372}
0 commit comments