001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2007-2010 Sun Microsystems, Inc.
015 * Portions Copyright 2011-2016 ForgeRock AS.
016 */
017package org.opends.server.admin.client.cli;
018
019import static com.forgerock.opendj.cli.ReturnCode.*;
020import static com.forgerock.opendj.cli.Utils.*;
021import static com.forgerock.opendj.cli.CommonArguments.*;
022import static org.opends.messages.ToolMessages.*;
023import static org.opends.messages.AdminToolMessages.*;
024
025import java.io.File;
026import java.io.FileInputStream;
027import java.io.IOException;
028import java.net.InetAddress;
029import java.security.KeyStore;
030import java.security.KeyStoreException;
031import java.security.NoSuchAlgorithmException;
032import java.security.cert.CertificateException;
033import java.util.ArrayList;
034import java.util.LinkedHashSet;
035import java.util.List;
036import java.util.Set;
037
038import com.forgerock.opendj.cli.ArgumentParser;
039import org.forgerock.i18n.LocalizableMessage;
040import org.forgerock.i18n.LocalizableMessageBuilder;
041import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1;
042import org.forgerock.i18n.slf4j.LocalizedLogger;
043import org.forgerock.opendj.config.server.ConfigException;
044import org.opends.admin.ads.util.ApplicationTrustManager;
045import org.opends.server.admin.AdministrationConnector;
046import org.opends.server.admin.server.ServerManagementContext;
047import org.opends.server.admin.std.server.AdministrationConnectorCfg;
048import org.opends.server.admin.std.server.FileBasedTrustManagerProviderCfg;
049import org.opends.server.admin.std.server.RootCfg;
050import org.opends.server.admin.std.server.TrustManagerProviderCfg;
051import org.opends.server.core.DirectoryServer;
052
053import com.forgerock.opendj.cli.Argument;
054import com.forgerock.opendj.cli.ArgumentException;
055import com.forgerock.opendj.cli.BooleanArgument;
056import com.forgerock.opendj.cli.CliConstants;
057import com.forgerock.opendj.cli.FileBasedArgument;
058import com.forgerock.opendj.cli.IntegerArgument;
059import com.forgerock.opendj.cli.StringArgument;
060
061/**
062 * This is a commodity class that can be used to check the arguments required to
063 * establish a secure connection in the command line. It can be used to generate
064 * an ApplicationTrustManager object based on the options provided by the user
065 * in the command line.
066 */
067public final class SecureConnectionCliArgs
068{
069  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
070
071  private StringArgument hostNameArg;
072  private IntegerArgument portArg;
073  private StringArgument bindDnArg;
074  private StringArgument adminUidArg;
075  private FileBasedArgument bindPasswordFileArg;
076  private StringArgument bindPasswordArg;
077  private BooleanArgument trustAllArg;
078  private StringArgument trustStorePathArg;
079  private StringArgument trustStorePasswordArg;
080  private FileBasedArgument trustStorePasswordFileArg;
081  private StringArgument keyStorePathArg;
082  private StringArgument keyStorePasswordArg;
083  private FileBasedArgument keyStorePasswordFileArg;
084  private StringArgument certNicknameArg;
085  private BooleanArgument useSSLArg;
086  private BooleanArgument useStartTLSArg;
087  private StringArgument saslOptionArg;
088  private IntegerArgument connectTimeoutArg;
089
090  /** Private container for global arguments. */
091  private Set<Argument> argList;
092
093  /** The trust manager. */
094  private ApplicationTrustManager trustManager;
095
096  private boolean configurationInitialized;
097
098  /** Defines if the CLI always use the SSL connection type. */
099  private boolean alwaysSSL;
100
101  /**
102   * Creates a new instance of secure arguments.
103   *
104   * @param alwaysSSL
105   *          If true, always use the SSL connection type. In this case, the
106   *          arguments useSSL and startTLS are not present.
107   */
108  public SecureConnectionCliArgs(boolean alwaysSSL)
109  {
110    this.alwaysSSL = alwaysSSL;
111  }
112
113  /**
114   * Indicates whether or not any of the arguments are present.
115   *
116   * @return boolean where true indicates that at least one of the arguments is
117   *         present
118   */
119  public boolean argumentsPresent()
120  {
121    if (argList != null)
122    {
123      for (Argument arg : argList)
124      {
125        if (arg.isPresent())
126        {
127          return true;
128        }
129      }
130    }
131    return false;
132  }
133
134  /**
135   * Get the admin UID which has to be used for the command.
136   *
137   * @return The admin UID specified by the command line argument, or the
138   *         default value, if not specified.
139   */
140  public String getAdministratorUID()
141  {
142    if (adminUidArg.isPresent())
143    {
144      return adminUidArg.getValue();
145    }
146    return adminUidArg.getDefaultValue();
147  }
148
149  /**
150   * Get the bindDN which has to be used for the command.
151   *
152   * @return The bindDN specified by the command line argument, or the default
153   *         value, if not specified.
154   */
155  public String getBindDN()
156  {
157    if (bindDnArg.isPresent())
158    {
159      return bindDnArg.getValue();
160    }
161    return bindDnArg.getDefaultValue();
162  }
163
164  /**
165   * Initialize Global option.
166   *
167   * @throws ArgumentException
168   *           If there is a problem with any of the parameters used to create
169   *           this argument.
170   * @return a ArrayList with the options created.
171   */
172  public Set<Argument> createGlobalArguments() throws ArgumentException
173  {
174    argList = new LinkedHashSet<>();
175
176    useSSLArg = useSSLArgument();
177    if (!alwaysSSL)
178    {
179      argList.add(useSSLArg);
180    }
181    else
182    {
183      // simulate that the useSSL arg has been given in the CLI
184      useSSLArg.setPresent(true);
185    }
186
187    useStartTLSArg = startTLSArgument();
188    if (!alwaysSSL)
189    {
190      argList.add(useStartTLSArg);
191    }
192
193    hostNameArg = hostNameArgument(getDefaultHostName());
194    argList.add(hostNameArg);
195
196    portArg = createPortArgument(AdministrationConnector.DEFAULT_ADMINISTRATION_CONNECTOR_PORT);
197    argList.add(portArg);
198
199    bindDnArg = bindDNArgument(CliConstants.DEFAULT_ROOT_USER_DN);
200    argList.add(bindDnArg);
201
202    // Classes that required admin UID to be not hidden must call createVisibleAdminUidArgument(localizedDescription)
203    adminUidArg = adminUidHiddenArgument(INFO_DESCRIPTION_ADMIN_UID.get());
204
205    bindPasswordArg = bindPasswordArgument();
206    argList.add(bindPasswordArg);
207
208    bindPasswordFileArg = bindPasswordFileArgument();
209    argList.add(bindPasswordFileArg);
210
211    saslOptionArg = saslArgument();
212    argList.add(saslOptionArg);
213
214    trustAllArg = trustAllArgument();
215    argList.add(trustAllArg);
216
217    trustStorePathArg = trustStorePathArgument();
218    argList.add(trustStorePathArg);
219
220    trustStorePasswordArg = trustStorePasswordArgument();
221    argList.add(trustStorePasswordArg);
222
223    trustStorePasswordFileArg = trustStorePasswordFileArgument();
224    argList.add(trustStorePasswordFileArg);
225
226    keyStorePathArg = keyStorePathArgument();
227    argList.add(keyStorePathArg);
228
229    keyStorePasswordArg = keyStorePasswordArgument();
230    argList.add(keyStorePasswordArg);
231
232    keyStorePasswordFileArg = keyStorePasswordFileArgument();
233    argList.add(keyStorePasswordFileArg);
234
235    certNicknameArg = certNickNameArgument();
236    argList.add(certNicknameArg);
237
238    connectTimeoutArg = connectTimeOutArgument();
239    argList.add(connectTimeoutArg);
240
241    return argList;
242  }
243
244  /**
245   * Get the host name which has to be used for the command.
246   *
247   * @return The host name specified by the command line argument, or the
248   *         default value, if not specified.
249   */
250  public String getHostName()
251  {
252    if (hostNameArg.isPresent())
253    {
254      return hostNameArg.getValue();
255    }
256    return hostNameArg.getDefaultValue();
257  }
258
259  /**
260   * Returns the current hostname.
261   *
262   * If the hostname resolution fails, this method returns {@literal "localhost"}.
263   * @return the current hostname
264     */
265  public String getDefaultHostName() {
266    try
267    {
268      return InetAddress.getLocalHost().getHostName();
269    }
270    catch (Exception e)
271    {
272      return "localhost";
273    }
274  }
275
276  /**
277   * Get the port which has to be used for the command.
278   *
279   * @return The port specified by the command line argument, or the default
280   *         value, if not specified.
281   */
282  public String getPort()
283  {
284    if (portArg.isPresent())
285    {
286      return portArg.getValue();
287    }
288    return portArg.getDefaultValue();
289  }
290
291  /**
292   * Indication if provided global options are validate.
293   *
294   * @param buf
295   *          the LocalizableMessageBuilder to write the error messages.
296   * @return return code.
297   */
298  public int validateGlobalOptions(LocalizableMessageBuilder buf)
299  {
300    final List<LocalizableMessage> errors = new ArrayList<>();
301    addErrorMessageIfArgumentsConflict(errors, bindPasswordArg, bindPasswordFileArg);
302    addErrorMessageIfArgumentsConflict(errors, trustAllArg, trustStorePathArg);
303    addErrorMessageIfArgumentsConflict(errors, trustAllArg, trustStorePasswordArg);
304    addErrorMessageIfArgumentsConflict(errors, trustAllArg, trustStorePasswordFileArg);
305    addErrorMessageIfArgumentsConflict(errors, trustStorePasswordArg, trustStorePasswordFileArg);
306    addErrorMessageIfArgumentsConflict(errors, useStartTLSArg, useSSLArg);
307
308    checkIfPathArgumentIsReadable(errors, trustStorePathArg, ERR_CANNOT_READ_TRUSTSTORE);
309    checkIfPathArgumentIsReadable(errors, keyStorePathArg, ERR_CANNOT_READ_KEYSTORE);
310
311    if (!errors.isEmpty())
312    {
313      for (LocalizableMessage error : errors)
314      {
315        if (buf.length() > 0)
316        {
317          buf.append(LINE_SEPARATOR);
318        }
319        buf.append(error);
320      }
321      return CONFLICTING_ARGS.get();
322    }
323
324    return SUCCESS.get();
325  }
326
327  private void checkIfPathArgumentIsReadable(List<LocalizableMessage> errors, StringArgument pathArg, Arg1<Object> msg)
328  {
329    if (pathArg.isPresent() && !canRead(pathArg.getValue()))
330    {
331      errors.add(msg.get(pathArg.getValue()));
332    }
333  }
334
335  /**
336   * Indicate if the SSL mode is always used.
337   *
338   * @return True if SSL mode is always used.
339   */
340  public boolean alwaysSSL()
341  {
342    return alwaysSSL;
343  }
344
345  /**
346   * Handle TrustStore.
347   *
348   * @return The trustStore manager to be used for the command.
349   */
350  public ApplicationTrustManager getTrustManager()
351  {
352    if (trustManager == null)
353    {
354      KeyStore truststore = null;
355      if (trustAllArg.isPresent())
356      {
357        // Running a null TrustManager  will force createLdapsContext and
358        // createStartTLSContext to use a bindTrustManager.
359        return null;
360      }
361      else if (trustStorePathArg.isPresent())
362      {
363        try (final FileInputStream fos = new FileInputStream(trustStorePathArg.getValue()))
364        {
365          String trustStorePasswordStringValue = null;
366          if (trustStorePasswordArg.isPresent())
367          {
368            trustStorePasswordStringValue = trustStorePasswordArg.getValue();
369          }
370          else if (trustStorePasswordFileArg.isPresent())
371          {
372            trustStorePasswordStringValue = trustStorePasswordFileArg.getValue();
373          }
374
375          if (trustStorePasswordStringValue != null)
376          {
377            trustStorePasswordStringValue = System.getProperty("javax.net.ssl.trustStorePassword");
378          }
379
380          char[] trustStorePasswordValue = null;
381          if (trustStorePasswordStringValue != null)
382          {
383            trustStorePasswordValue = trustStorePasswordStringValue.toCharArray();
384          }
385
386          truststore = KeyStore.getInstance(KeyStore.getDefaultType());
387          truststore.load(fos, trustStorePasswordValue);
388        }
389        catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e)
390        {
391          // Nothing to do: if this occurs we will systematically refuse the
392          // certificates.  Maybe we should avoid this and be strict, but we
393          // are in a best effort mode.
394          logger.warn(LocalizableMessage.raw("Error with the truststore"), e);
395        }
396      }
397      trustManager = new ApplicationTrustManager(truststore);
398    }
399    return trustManager;
400  }
401
402  /**
403   * Returns {@code true} if we can read on the provided path and {@code false}
404   * otherwise.
405   *
406   * @param path
407   *          the path.
408   * @return {@code true} if we can read on the provided path and {@code false}
409   *         otherwise.
410   */
411  private boolean canRead(String path)
412  {
413    final File file = new File(path);
414    return file.exists() && file.canRead();
415  }
416
417  /**
418   * Returns the absolute path of the trust store file that appears on the
419   * config. Returns {@code null} if the trust store is not defined or it does
420   * not exist.
421   *
422   * @return the absolute path of the trust store file that appears on the
423   *         config.
424   * @throws ConfigException
425   *           if there is an error reading the configuration.
426   */
427  public String getTruststoreFileFromConfig() throws ConfigException
428  {
429    String truststoreFileAbsolute = null;
430    TrustManagerProviderCfg trustManagerCfg = null;
431    AdministrationConnectorCfg administrationConnectorCfg = null;
432
433    boolean couldInitializeConfig = configurationInitialized;
434    // Initialization for admin framework
435    if (!configurationInitialized)
436    {
437      couldInitializeConfig = initializeConfiguration();
438    }
439    if (couldInitializeConfig)
440    {
441      // Get the Directory Server configuration handler and use it.
442      RootCfg root = ServerManagementContext.getInstance().getRootConfiguration();
443      administrationConnectorCfg = root.getAdministrationConnector();
444
445      String trustManagerStr = administrationConnectorCfg.getTrustManagerProvider();
446      trustManagerCfg = root.getTrustManagerProvider(trustManagerStr);
447      if (trustManagerCfg instanceof FileBasedTrustManagerProviderCfg)
448      {
449        FileBasedTrustManagerProviderCfg fileBasedTrustManagerCfg = (FileBasedTrustManagerProviderCfg) trustManagerCfg;
450        String truststoreFile = fileBasedTrustManagerCfg.getTrustStoreFile();
451        // Check the file
452        if (truststoreFile.startsWith(File.separator))
453        {
454          truststoreFileAbsolute = truststoreFile;
455        }
456        else
457        {
458          truststoreFileAbsolute = DirectoryServer.getInstanceRoot() + File.separator + truststoreFile;
459        }
460        File f = new File(truststoreFileAbsolute);
461        if (!f.exists() || !f.canRead() || f.isDirectory())
462        {
463          truststoreFileAbsolute = null;
464        }
465        else
466        {
467          // Try to get the canonical path.
468          try
469          {
470            truststoreFileAbsolute = f.getCanonicalPath();
471          }
472          catch (Throwable t)
473          {
474            // We can ignore this error.
475          }
476        }
477      }
478    }
479    return truststoreFileAbsolute;
480  }
481
482  /**
483   * Returns the admin port from the configuration.
484   *
485   * @return the admin port from the configuration.
486   * @throws ConfigException
487   *           if an error occurs reading the configuration.
488   */
489  public int getAdminPortFromConfig() throws ConfigException
490  {
491    // Initialization for admin framework
492    boolean couldInitializeConfiguration = configurationInitialized;
493    if (!configurationInitialized)
494    {
495      couldInitializeConfiguration = initializeConfiguration();
496    }
497    if (couldInitializeConfiguration)
498    {
499      RootCfg root = ServerManagementContext.getInstance().getRootConfiguration();
500      return root.getAdministrationConnector().getListenPort();
501    }
502    else
503    {
504      return AdministrationConnector.DEFAULT_ADMINISTRATION_CONNECTOR_PORT;
505    }
506  }
507
508  private boolean initializeConfiguration()
509  {
510    // check if the initialization is required
511    try
512    {
513      ServerManagementContext.getInstance().getRootConfiguration().getAdministrationConnector();
514    }
515    catch (java.lang.Throwable th)
516    {
517      try
518      {
519        DirectoryServer.bootstrapClient();
520        DirectoryServer.initializeJMX();
521        DirectoryServer.getInstance().initializeConfiguration();
522      }
523      catch (Exception ex)
524      {
525        // do nothing
526        return false;
527      }
528    }
529    configurationInitialized = true;
530    return true;
531  }
532
533  /**
534   * Returns the port to be used according to the configuration and the
535   * arguments provided by the user. This method should be called after the
536   * arguments have been parsed.
537   *
538   * @return the port to be used according to the configuration and the
539   *         arguments provided by the user.
540   */
541  public int getPortFromConfig()
542  {
543    int portNumber;
544    if (alwaysSSL())
545    {
546      portNumber = AdministrationConnector.DEFAULT_ADMINISTRATION_CONNECTOR_PORT;
547      // Try to get the port from the config file
548      try
549      {
550        portNumber = getAdminPortFromConfig();
551      }
552      catch (ConfigException ex)
553      {
554        // Nothing to do
555      }
556    }
557    else
558    {
559      portNumber = CliConstants.DEFAULT_SSL_PORT;
560    }
561    return portNumber;
562  }
563
564  /**
565   * Updates the default values of the port and the trust store with what is
566   * read in the configuration.
567   *
568   * @param parser
569   *        The argument parser where the secure connection arguments were added.
570   */
571  public void initArgumentsWithConfiguration(final ArgumentParser parser) {
572    try
573    {
574      portArg = createPortArgument(getPortFromConfig());
575      trustStorePathArg = trustStorePathArgument(getTruststoreFileFromConfig());
576      parser.replaceArgument(portArg);
577      parser.replaceArgument(trustStorePathArg);
578    }
579    catch (ConfigException | ArgumentException e)
580    {
581      logger.error(LocalizableMessage.raw(
582              "Internal error while reading arguments of this program from configuration"), e);
583    }
584  }
585
586  /**
587   * Replace the admin UID argument by a non hidden one.
588   *
589   * @param description
590   *         The localized description for the non hidden admin UID argument.
591   */
592  public void createVisibleAdminUidArgument(final LocalizableMessage description)
593  {
594    try
595    {
596      this.adminUidArg = adminUid(description);
597    }
598    catch (final ArgumentException unexpected)
599    {
600      throw new RuntimeException("Unexpected");
601    }
602  }
603
604  private IntegerArgument createPortArgument(final int defaultValue) throws ArgumentException
605  {
606    return portArgument(
607            defaultValue, alwaysSSL ? INFO_DESCRIPTION_ADMIN_PORT.get() : INFO_DESCRIPTION_PORT.get());
608  }
609
610  /**
611   * Return the 'keyStore' global argument.
612   *
613   * @return The 'keyStore' global argument.
614   */
615  public StringArgument getKeyStorePathArg() {
616    return keyStorePathArg;
617  }
618
619  /**
620   * Return the 'hostName' global argument.
621   *
622   * @return The 'hostName' global argument.
623   */
624  public StringArgument getHostNameArg() {
625    return hostNameArg;
626  }
627
628  /**
629   * Return the 'port' global argument.
630   *
631   * @return The 'port' global argument.
632   */
633  public IntegerArgument getPortArg() {
634    return portArg;
635  }
636
637  /**
638   * Return the 'bindDN' global argument.
639   *
640   * @return The 'bindDN' global argument.
641   */
642  public StringArgument getBindDnArg() {
643    return bindDnArg;
644  }
645
646  /**
647   * Return the 'adminUID' global argument.
648   *
649   * @return The 'adminUID' global argument.
650   */
651  public StringArgument getAdminUidArg() {
652    return adminUidArg;
653  }
654
655  /**
656   * Return the 'bindPasswordFile' global argument.
657   *
658   * @return The 'bindPasswordFile' global argument.
659   */
660  public FileBasedArgument getBindPasswordFileArg() {
661    return bindPasswordFileArg;
662  }
663
664  /**
665   * Return the 'bindPassword' global argument.
666   *
667   * @return The 'bindPassword' global argument.
668   */
669  public StringArgument getBindPasswordArg() {
670    return bindPasswordArg;
671  }
672
673  /**
674   * Return the 'trustAllArg' global argument.
675   *
676   * @return The 'trustAllArg' global argument.
677   */
678  public BooleanArgument getTrustAllArg() {
679    return trustAllArg;
680  }
681
682  /**
683   * Return the 'trustStore' global argument.
684   *
685   * @return The 'trustStore' global argument.
686   */
687  public StringArgument getTrustStorePathArg() {
688    return trustStorePathArg;
689  }
690
691  /**
692   * Return the 'trustStorePassword' global argument.
693   *
694   * @return The 'trustStorePassword' global argument.
695   */
696  public StringArgument getTrustStorePasswordArg() {
697    return trustStorePasswordArg;
698  }
699
700  /**
701   * Return the 'trustStorePasswordFile' global argument.
702   *
703   * @return The 'trustStorePasswordFile' global argument.
704   */
705  public FileBasedArgument getTrustStorePasswordFileArg() {
706    return trustStorePasswordFileArg;
707  }
708
709  /**
710   * Return the 'keyStorePassword' global argument.
711   *
712   * @return The 'keyStorePassword' global argument.
713   */
714  public StringArgument getKeyStorePasswordArg() {
715    return keyStorePasswordArg;
716  }
717
718  /**
719   * Return the 'keyStorePasswordFile' global argument.
720   *
721   * @return The 'keyStorePasswordFile' global argument.
722   */
723  public FileBasedArgument getKeyStorePasswordFileArg() {
724    return keyStorePasswordFileArg;
725  }
726
727  /**
728   * Return the 'certNicknameArg' global argument.
729   *
730   * @return The 'certNicknameArg' global argument.
731   */
732  public StringArgument getCertNicknameArg() {
733    return certNicknameArg;
734  }
735
736  /**
737   * Return the 'useSSLArg' global argument.
738   *
739   * @return The 'useSSLArg' global argument.
740   */
741  public BooleanArgument getUseSSLArg() {
742    return useSSLArg;
743  }
744
745  /**
746   * Return the 'useStartTLSArg' global argument.
747   *
748   * @return The 'useStartTLSArg' global argument.
749   */
750  public BooleanArgument getUseStartTLSArg() {
751    return useStartTLSArg;
752  }
753
754  /**
755   * Return the 'saslOption' argument.
756   *
757   * @return the 'saslOption' argument.
758   */
759  public StringArgument getSaslOptionArg() {
760    return saslOptionArg;
761  }
762
763  /**
764   * Return the 'connectTimeout' argument.
765   *
766   * @return the 'connectTimeout' argument.
767   */
768  public IntegerArgument getConnectTimeoutArg() {
769    return connectTimeoutArg;
770  }
771
772  /**
773   * Set the bind DN argument with the provided description.
774   * Note that this method will create a new {@link Argument} instance replacing the current one.
775   *
776   * @param description
777   *         The localized description which will be used in help messages.
778   */
779  public void setBindDnArgDescription(final LocalizableMessage description)
780  {
781    try
782    {
783      this.bindDnArg = bindDNArgument(CliConstants.DEFAULT_ROOT_USER_DN, description);
784    }
785    catch (final ArgumentException unexpected)
786    {
787      throw new RuntimeException("unexpected");
788    }
789  }
790
791  /**
792   * Set the bind password argument.
793   *
794   * @param bindPasswordArg
795   *         The argument which will replace the current one.
796   */
797  public void setBindPasswordArgument(final StringArgument bindPasswordArg)
798  {
799    this.bindPasswordArg = bindPasswordArg;
800  }
801
802  /**
803   * Set the bind password file argument.
804   *
805   * @param bindPasswordFileArg
806   *         The argument which will replace the current one.
807   */
808  public void setBindPasswordFileArgument(final FileBasedArgument bindPasswordFileArg)
809  {
810    this.bindPasswordFileArg = bindPasswordFileArg;
811  }
812}