PageRenderTime 45ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/jtopen-7.8/src/com/ibm/as400/access/AS400.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 1098 lines | 691 code | 88 blank | 319 comment | 150 complexity | eb359a416e21ba440a5e9a376a2f7ac5 MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // JTOpen (IBM Toolbox for Java - OSS version)
  4. //
  5. // Filename: AS400.java
  6. //
  7. // The source code contained herein is licensed under the IBM Public License
  8. // Version 1.0, which has been approved by the Open Source Initiative.
  9. // Copyright (C) 1997-2006 International Business Machines Corporation and
  10. // others. All rights reserved.
  11. //
  12. ///////////////////////////////////////////////////////////////////////////////
  13. package com.ibm.as400.access;
  14. import java.beans.PropertyChangeListener;
  15. import java.beans.PropertyChangeSupport;
  16. import java.beans.PropertyVetoException;
  17. import java.beans.VetoableChangeListener;
  18. import java.beans.VetoableChangeSupport;
  19. import java.io.IOException;
  20. import java.io.ObjectInputStream;
  21. import java.io.Serializable;
  22. import java.io.UnsupportedEncodingException;
  23. import java.net.InetAddress;
  24. import java.net.UnknownHostException;
  25. import java.net.Socket;
  26. import java.net.URL;
  27. import java.util.GregorianCalendar;
  28. import java.util.Hashtable;
  29. import java.util.Locale;
  30. import java.util.StringTokenizer;
  31. import java.util.TimeZone;
  32. import java.util.Vector;
  33. import com.ibm.as400.security.auth.ProfileTokenCredential;
  34. import com.ibm.as400.security.auth.ProfileTokenProvider;
  35. /**
  36. Represents the authentication information and a set of connections to the IBM i host servers.
  37. <p>If running on IBM i or an older version of that operating system, the system name, user ID,
  38. and password do not need to be supplied. These values default to the local system.
  39. For the system name, the keyword <code>localhost</code> can be used to specify the local system.
  40. For the user ID and password, *CURRENT can be used.
  41. <p>If running on another operating system, the system name, user ID, and password need to be supplied.
  42. If not supplied, the first 'open' request associated with this object will trigger a prompt to the
  43. workstation user. Subsequent opens associated with the same object will not prompt the workstation
  44. user. Keywords <code>localhost</code> and *CURRENT will not work when running on another operating
  45. system.
  46. <p>For example:
  47. <pre>
  48. * AS400 system = new AS400();
  49. * system.connectService(AS400.DATAQUEUE); // This causes a password prompt.
  50. * ...
  51. * system.connectService(AS400.FILE); // This does not cause a prompt.
  52. </pre>
  53. **/
  54. public class AS400 implements Serializable
  55. {
  56. private static final String CLASSNAME = "com.ibm.as400.access.AS400";
  57. static boolean jdk14 = false;
  58. static
  59. {
  60. if (Trace.traceOn_) Trace.logLoadPath(CLASSNAME);
  61. jdk14 = JVMInfo.isJDK14();
  62. }
  63. static final long serialVersionUID = 4L;
  64. private static final boolean PASSWORD_TRACE = false;
  65. /**
  66. Constant indicating the File service.
  67. **/
  68. public static final int FILE = 0;
  69. /**
  70. Constant indicating the Print service.
  71. **/
  72. public static final int PRINT = 1;
  73. /**
  74. Constant indicating the Command service.
  75. **/
  76. public static final int COMMAND = 2;
  77. /**
  78. Constant indicating the Dataqueue service.
  79. **/
  80. public static final int DATAQUEUE = 3;
  81. /**
  82. Constant indicating the Database service.
  83. **/
  84. public static final int DATABASE = 4;
  85. /**
  86. Constant indicating the Record Access service.
  87. **/
  88. public static final int RECORDACCESS = 5;
  89. /**
  90. Constant indicating the Central service.
  91. **/
  92. public static final int CENTRAL = 6;
  93. /**
  94. Constant indicating the Sign-on service.
  95. **/
  96. public static final int SIGNON = 7;
  97. // Constants 8-15 reserved for SSL versions of the above services.
  98. /**
  99. Special value indicating the service port should be retrieved from the port mapper server.
  100. **/
  101. public static final int USE_PORT_MAPPER = -1;
  102. /**
  103. Constant indicating the authentication scheme is password.
  104. **/
  105. public static final int AUTHENTICATION_SCHEME_PASSWORD = 0;
  106. /**
  107. Constant indicating the authentication scheme is GSS token.
  108. **/
  109. public static final int AUTHENTICATION_SCHEME_GSS_TOKEN = 1;
  110. /**
  111. Constant indicating the authentication scheme is profile token.
  112. **/
  113. public static final int AUTHENTICATION_SCHEME_PROFILE_TOKEN = 2;
  114. /**
  115. Constant indicating the authentication scheme is identity token.
  116. **/
  117. public static final int AUTHENTICATION_SCHEME_IDENTITY_TOKEN = 3;
  118. /**
  119. Constant indicating that the JGSS framework must be used when no password or authentication token is set. An object set to this option will not attempt to present a sign-on dialog or use the current user profile information. A failure to retrieve the GSS token will result in an exception returned to the user.
  120. **/
  121. public static final int GSS_OPTION_MANDATORY = 0;
  122. /**
  123. Constant indicating that the JGSS framework will be attempted when no password or authentication token is set. An object set to this option will attempt to retrieve a GSS token, if that attempt fails, the object will present a sign-on dialog or use the current user profile information. This option is the default.
  124. **/
  125. public static final int GSS_OPTION_FALLBACK = 1;
  126. /**
  127. Constant indicating that the JGSS framework will not be used when no password or authentication token is set. An object set to this option will only present a sign-on dialog or use the current user profile information.
  128. **/
  129. public static final int GSS_OPTION_NONE = 2;
  130. // Determine if we are running on IBM i.
  131. static boolean onAS400 = false;
  132. // VRM from system property, if we are native.
  133. static ServerVersion nativeVRM = null;
  134. // The static default sign-on handler.
  135. static Class defaultSignonHandlerClass_ = ToolboxSignonHandler.class;
  136. static SignonHandler defaultSignonHandler_;
  137. // Default setting for guiAvailable property.
  138. private static boolean defaultGuiAvailable_ = true;
  139. // Default setting for mustAddLanguageLibrary property.
  140. private static boolean defaultMustAddLanguageLibrary_ = false;
  141. // Default setting for mustUseSockets property.
  142. private static boolean defaultMustUseSockets_ = false;
  143. // Default setting for mustUseNetSockets property.
  144. private static boolean defaultMustUseNetSockets_ = false;
  145. // Default setting for mustUseSuppliedProfile property.
  146. private static boolean defaultMustUseSuppliedProfile_ = false;
  147. // Default setting for threadUsed property.
  148. private static boolean defaultThreadUsed_ = true;
  149. static
  150. {
  151. try
  152. {
  153. String s = System.getProperty("os.name");
  154. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Detected os.name:", s);
  155. if (s != null && s.equalsIgnoreCase("OS/400"))
  156. {
  157. String version = System.getProperty("os.version");
  158. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Detected os.version:", version);
  159. if (version != null)
  160. {
  161. char[] versionChars = version.toCharArray();
  162. if (versionChars.length == 6)
  163. {
  164. int vrm = ((versionChars[1] & 0x000F) << 16) +
  165. ((versionChars[3] & 0x000F) << 8) +
  166. (versionChars[5] & 0x000F);
  167. AS400.nativeVRM = new ServerVersion(vrm);
  168. }
  169. }
  170. AS400.onAS400 = true;
  171. }
  172. }
  173. catch (SecurityException e)
  174. {
  175. Trace.log(Trace.WARNING, "Error retrieving os.name:", e);
  176. }
  177. // Get the "default sign-on handler" property.
  178. {
  179. String propVal = SystemProperties.getProperty(SystemProperties.AS400_SIGNON_HANDLER);
  180. if (propVal != null)
  181. {
  182. try
  183. {
  184. defaultSignonHandlerClass_ = Class.forName(propVal);
  185. }
  186. catch (Exception e)
  187. {
  188. Trace.log(Trace.WARNING, "Error retrieving default sign-on handler (specified by property):", e);
  189. defaultSignonHandlerClass_ = ToolboxSignonHandler.class;
  190. }
  191. }
  192. }
  193. // Get the "GUI available" property.
  194. {
  195. String propVal = SystemProperties.getProperty(SystemProperties.AS400_GUI_AVAILABLE);
  196. if (propVal != null)
  197. {
  198. try
  199. {
  200. defaultGuiAvailable_ = Boolean.valueOf(propVal).booleanValue();
  201. }
  202. catch (Exception e)
  203. {
  204. Trace.log(Trace.WARNING, "Error retrieving guiAvailable property value:", e);
  205. }
  206. }
  207. }
  208. // Get the "must add language library" property.
  209. {
  210. String propVal = SystemProperties.getProperty(SystemProperties.AS400_MUST_ADD_LANGUAGE_LIBRARY);
  211. if (propVal != null)
  212. {
  213. try
  214. {
  215. defaultMustAddLanguageLibrary_ = Boolean.valueOf(propVal).booleanValue();
  216. }
  217. catch (Exception e)
  218. {
  219. Trace.log(Trace.WARNING, "Error retrieving mustAddLanguageLibrary property value:", e);
  220. }
  221. }
  222. }
  223. // Get the "must use sockets" property.
  224. {
  225. String propVal = SystemProperties.getProperty(SystemProperties.AS400_MUST_USE_SOCKETS);
  226. if (propVal != null)
  227. {
  228. try
  229. {
  230. defaultMustUseSockets_ = Boolean.valueOf(propVal).booleanValue();
  231. }
  232. catch (Exception e)
  233. {
  234. Trace.log(Trace.WARNING, "Error retrieving mustUseSockets property value:", e);
  235. }
  236. }
  237. }
  238. // Get the "must use net sockets" property.
  239. {
  240. String propVal = SystemProperties.getProperty(SystemProperties.AS400_MUST_USE_NET_SOCKETS);
  241. if (propVal != null)
  242. {
  243. try
  244. {
  245. defaultMustUseNetSockets_ = Boolean.valueOf(propVal).booleanValue();
  246. }
  247. catch (Exception e)
  248. {
  249. Trace.log(Trace.WARNING, "Error retrieving mustUseNetSockets property value:", e);
  250. }
  251. }
  252. }
  253. // Get the "must use supplied profile" property.
  254. {
  255. String propVal = SystemProperties.getProperty(SystemProperties.AS400_MUST_USE_SUPPLIED_PROFILE);
  256. if (propVal != null)
  257. {
  258. try
  259. {
  260. defaultMustUseSuppliedProfile_ = Boolean.valueOf(propVal).booleanValue();
  261. }
  262. catch (Exception e)
  263. {
  264. Trace.log(Trace.WARNING, "Error retrieving mustUseSuppliedProfile property value:", e);
  265. }
  266. }
  267. }
  268. // Get the "thread used" property.
  269. {
  270. String propVal = SystemProperties.getProperty(SystemProperties.AS400_THREAD_USED);
  271. if (propVal != null)
  272. {
  273. try
  274. {
  275. defaultThreadUsed_ = Boolean.valueOf(propVal).booleanValue();
  276. }
  277. catch (Exception e)
  278. {
  279. Trace.log(Trace.WARNING, "Error retrieving threadUsed property value:", e);
  280. }
  281. }
  282. }
  283. }
  284. // System list: elements are 3 element Object[]: systemName, userId, credential vault
  285. private static Vector systemList = new Vector();
  286. // Default users is a hash from systemName to userId.
  287. private static Hashtable defaultUsers = new Hashtable();
  288. // Number of days previous to password expiration to start to warn user.
  289. private static int expirationWarning = 7;
  290. private static int alreadyCheckedForMultipleVersions_ = 0;
  291. // System name.
  292. private String systemName_ = "";
  293. // Flag indicating if system name refers to local system.
  294. private boolean systemNameLocal_ = false;
  295. // User ID.
  296. private String userId_ = "";
  297. // Credential vault used to store password, GSS token, identity token,
  298. // or profile token. An AS400 object must always have its own copy of
  299. // a credential vault (i.e. there must be a 1-to-1 correlation between
  300. // AS400 objects and CredentialVault objects). Sharing a credential vault
  301. // amongst two different AS400 objects is NEVER allowed.
  302. // If you need to share the credential in the vault with another AS400 object,
  303. // you must provide a copy of the credential vault. This is achieved using
  304. // the clone() method provided by the CredentialVault class.
  305. private transient CredentialVault credVault_; // never null after construction
  306. // GSS Credential object, for Kerberos. Type set to Object to prevent dependency on 1.4 JDK.
  307. private transient Object gssCredential_ = null;
  308. // GSS name string, for Kerberos.
  309. private String gssName_ = "";
  310. // How to use the GSS framework.
  311. int gssOption_ = GSS_OPTION_FALLBACK;
  312. // Proxy server system name.
  313. private transient String proxyServer_ = "";
  314. // Client side proxy connection information.
  315. private transient Object proxyClientConnection_ = null; // Tolerate not having class ProxyClientConnection in the jar.
  316. // This controls the prompting. If set to true, then prompting will occur during sign-on if needed. If set to false, no prompting will occur and all security errors are returned as exceptions.
  317. private boolean guiAvailable_ = defaultGuiAvailable_;
  318. // Use the password cache.
  319. private boolean usePasswordCache_ = true;
  320. // Use the default user.
  321. private boolean useDefaultUser_ = true;
  322. // Show the checkboxes on the password dialog.
  323. private boolean showCheckboxes_ = true;
  324. // Detect/prevent recursion when interacting with sign-on handler.
  325. private boolean signingOn_ = false;
  326. // SSL options, null value indicates SSL is not to be used. Options set in SecureAS400 subclass.
  327. SSLOptions useSSLConnection_ = null;
  328. // Flag that indicates if we must add the secondary language library to the library list.
  329. private boolean mustAddLanguageLibrary_ = defaultMustAddLanguageLibrary_;
  330. // Flag that indicates if we must use the host servers and no native optimizations.
  331. private boolean mustUseSockets_ = defaultMustUseSockets_;
  332. // Flag that indicates if we must use network sockets and not unix domain sockets.
  333. private boolean mustUseNetSockets_ = defaultMustUseNetSockets_;
  334. // Flag that indicates if we must not use the current profile.
  335. private boolean mustUseSuppliedProfile_ = defaultMustUseSuppliedProfile_;
  336. // Flag that indicates if we use threads in communication with the host servers.
  337. private boolean threadUsed_ = defaultThreadUsed_;
  338. // Locale object to use for determining NLV.
  339. private Locale locale_ = Locale.getDefault();
  340. // The NLV set or determined from the locale.
  341. private String nlv_ = ExecutionEnvironment.getNlv(Locale.getDefault());
  342. // The system's default time zone.
  343. private transient TimeZone timezone_;
  344. // Set of socket options to use when creating connections.
  345. private SocketProperties socketProperties_ = new SocketProperties();
  346. // No CCSID to start.
  347. private transient int ccsid_ = 0;
  348. // List of connection event bean listeners.
  349. private transient Vector connectionListeners_ = null; // Set on first add.
  350. // Inner class that connects connection events that occur in the ImplRemote to this class.
  351. private transient ConnectionListener dispatcher_ = null; // Set on first add.
  352. // List of property change event bean listeners.
  353. transient PropertyChangeSupport propertyChangeListeners_ = null; // Set on first add.
  354. // List of vetoable change event bean listeners.
  355. transient VetoableChangeSupport vetoableChangeListeners_ = null; // Set on first add.
  356. // Flag for when object state is allowed to change.
  357. transient boolean propertiesFrozen_ = false;
  358. // Implementation object.
  359. private transient AS400Impl impl_ = null;
  360. // This object is created by the initial sign-on process. It contains the information from the retrieve sign-on information flow with the sign-on server.
  361. private transient SignonInfo signonInfo_ = null;
  362. // The IASP name used for the RECORDACCESS service.
  363. private String ddmRDB_ = null;
  364. // The sign-on handler for this object's instance.
  365. private transient SignonHandler signonHandler_ = null;
  366. private transient boolean handlerCanceled_ = false;
  367. /* forcePrompt_ is a flag that tells AS400 to force prompt by displaying login dialog (actually the sign-on handler) prior to even trying to authenticate.
  368. This is useful in cases where an application sends in incorrect dummy id/password and expects Toolbox to display the logon dialog.
  369. In JDBC, we do some pre-validation of id/password. So JDBC may flag the id/password as invalid and then need
  370. to let AS400 know that it just needs to display the logon dialog. */
  371. private boolean forcePrompt_ = false; //@prompt
  372. /**
  373. Constructs an AS400 object.
  374. <p>If running on IBM i, the target is the local system. This has the same effect as using <code>localhost</code> for the system name, *CURRENT for the user ID, and *CURRENT for the password.
  375. <p>If running on another operating system, a sign-on prompt may be displayed. The user is then able to specify the system name, user ID, and password.
  376. **/
  377. public AS400()
  378. {
  379. super();
  380. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object.");
  381. construct();
  382. systemNameLocal_ = resolveSystemNameLocal("");
  383. proxyServer_ = resolveProxyServer(proxyServer_);
  384. // Default to password authentication
  385. credVault_ = new PasswordVault();
  386. }
  387. /**
  388. Constructs an AS400 object. It uses the specified system name.
  389. <p>If running on IBM i to another system or to itself, the user ID and password of the current job are used.
  390. <p>If running on another operating system, the user may be prompted for the user ID and password if a default user has not been established for this system name.
  391. @param systemName The name of the IBM i system. Use <code>localhost</code> to access data locally.
  392. **/
  393. public AS400(String systemName)
  394. {
  395. super();
  396. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object, system name: '" + systemName + "'");
  397. if (systemName == null)
  398. {
  399. throw new NullPointerException("systemName");
  400. }
  401. construct();
  402. systemName_ = systemName;
  403. systemNameLocal_ = resolveSystemNameLocal(systemName);
  404. proxyServer_ = resolveProxyServer(proxyServer_);
  405. // Default to password authentication
  406. credVault_ = new PasswordVault();
  407. }
  408. /**
  409. Constructs an AS400 object. It uses the specified system name and user ID. If the sign-on prompt is displayed, the user is able to specify the password. Note that the user ID may be overridden.
  410. @param systemName The name of the IBM i system. Use <code>localhost</code> to access data locally.
  411. @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may be used to specify the current user ID.
  412. **/
  413. public AS400(String systemName, String userId)
  414. {
  415. super();
  416. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object, system name: '" + systemName + "' user ID: '" + userId + "'");
  417. if (systemName == null)
  418. {
  419. throw new NullPointerException("systemName");
  420. }
  421. if (userId == null)
  422. {
  423. throw new NullPointerException("userId");
  424. }
  425. if (userId.length() > 10)
  426. {
  427. throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
  428. }
  429. construct();
  430. systemName_ = systemName;
  431. systemNameLocal_ = resolveSystemNameLocal(systemName);
  432. userId_ = userId.toUpperCase();
  433. proxyServer_ = resolveProxyServer(proxyServer_);
  434. // Default to password authentication
  435. credVault_ = new PasswordVault();
  436. }
  437. /**
  438. Constructs an AS400 object. It uses the specified system name and profile token.
  439. @param systemName The name of the IBM i system. Use <code>localhost</code> to access data locally.
  440. @param profileToken The profile token to use to authenticate to the system.
  441. **/
  442. public AS400(String systemName, ProfileTokenCredential profileToken)
  443. {
  444. super();
  445. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object with profile token, system name: '" + systemName + "'");
  446. if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "profile token: " + profileToken);
  447. if (profileToken == null)
  448. {
  449. throw new NullPointerException("profileToken");
  450. }
  451. constructWithProfileToken(systemName, new ProfileTokenVault(profileToken));
  452. }
  453. /**
  454. * Constructs an AS400 object. The specified ProfileTokenProvider is used.
  455. * The token refresh threshold is determined by the ProfileTokenProvider.
  456. * @param tokenProvider The provider to use when a new profile token needs to be generated.
  457. * @see #AS400(String,ProfileTokenProvider,int)
  458. */
  459. public AS400(String systemName, ProfileTokenProvider tokenProvider)
  460. {
  461. this(systemName, tokenProvider, null);
  462. }
  463. /**
  464. * Constructs an AS400 object. The specified ProfileTokenProvider is used.
  465. * @param tokenProvider The provider to use when a new profile token needs to be generated.
  466. * @param refreshThreshold The refresh threshold, in seconds, for the profile token.
  467. * Used by the vault to manage the currency of the profile token
  468. * to help ensure it remains current for an indefinite period of time.
  469. * @see #AS400(String,ProfileTokenProvider)
  470. */
  471. public AS400(String systemName, ProfileTokenProvider tokenProvider, int refreshThreshold)
  472. {
  473. this(systemName, tokenProvider, new Integer(refreshThreshold));
  474. }
  475. private AS400(String systemName, ProfileTokenProvider tokenProvider, Integer refreshThreshold)
  476. {
  477. super();
  478. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object with a profile token provider, system name: '" + systemName + "'");
  479. if (tokenProvider == null)
  480. {
  481. throw new NullPointerException("tokenProvider");
  482. }
  483. if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "profile token provider:", tokenProvider.getClass().getName());
  484. // Was a refresh threshold specified?
  485. if (refreshThreshold != null) {
  486. constructWithProfileToken(systemName, new ManagedProfileTokenVault(tokenProvider, refreshThreshold.intValue()));
  487. }
  488. else {
  489. constructWithProfileToken(systemName, new ManagedProfileTokenVault(tokenProvider));
  490. }
  491. }
  492. /**
  493. * Common code for constructing an AS400 object that uses profile token authentication
  494. */
  495. private void constructWithProfileToken(String systemName, ProfileTokenVault credVault)
  496. {
  497. if (systemName == null)
  498. {
  499. throw new NullPointerException("systemName");
  500. }
  501. construct();
  502. systemName_ = systemName;
  503. systemNameLocal_ = resolveSystemNameLocal(systemName);
  504. // Assumption: The caller of this method has ensured that the credential
  505. // vault has been created and initialized correctly.
  506. credVault_ = credVault;
  507. proxyServer_ = resolveProxyServer(proxyServer_);
  508. }
  509. /**
  510. Constructs an AS400 object. It uses the specified system name, user ID, and password. No sign-on prompt is displayed unless the sign-on fails.
  511. @param systemName The name of the IBM i system. Use <code>localhost</code> to access data locally.
  512. @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may be used to specify the current user ID.
  513. @param password The user profile password to use to authenticate to the system. If running on IBM i, *CURRENT may be used to specify the current user ID.
  514. **/
  515. public AS400(String systemName, String userId, String password)
  516. {
  517. super();
  518. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object, system name: '" + systemName + "' user ID: '" + userId + "'");
  519. if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "password: '" + password + "'");
  520. if (systemName == null)
  521. {
  522. throw new NullPointerException("systemName");
  523. }
  524. if (userId == null)
  525. {
  526. throw new NullPointerException("userId");
  527. }
  528. if (userId.length() > 10)
  529. {
  530. throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
  531. }
  532. if (password == null)
  533. {
  534. throw new NullPointerException("password");
  535. }
  536. if (password.length() > 128)
  537. {
  538. throw new ExtendedIllegalArgumentException("password.length {" + password.length() + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
  539. }
  540. construct();
  541. systemName_ = systemName;
  542. systemNameLocal_ = resolveSystemNameLocal(systemName);
  543. userId_ = userId.toUpperCase();
  544. credVault_ = new PasswordVault(password);
  545. proxyServer_ = resolveProxyServer(proxyServer_);
  546. }
  547. // Private constructor for use when a new object is needed and the password is already twiddled.
  548. // Used by password cache and password verification code.
  549. private AS400(String systemName, String userId, CredentialVault pwVault)
  550. {
  551. super();
  552. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing internal AS400 object, system name: '" + systemName + "' user ID: '" + userId + "'");
  553. if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, pwVault.trace());
  554. // System name and user ID validation has been deferred to here.
  555. if (systemName == null)
  556. {
  557. throw new NullPointerException("systemName");
  558. }
  559. if (userId == null)
  560. {
  561. throw new NullPointerException("userId");
  562. }
  563. if (userId.length() > 10)
  564. {
  565. throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
  566. }
  567. construct();
  568. systemName_ = systemName;
  569. systemNameLocal_ = resolveSystemNameLocal(systemName);
  570. userId_ = userId.toUpperCase();
  571. // Create a copy of the supplied credential vault. This allows the AS400
  572. // object to have its own credential vault object while making the vault
  573. // contain the the same credential as the original vault we have been provided.
  574. // It is VERY important that the copy of the vault contain the same credential
  575. // as the original vault. This is because the Toolbox implementation has
  576. // always allowed two AS400 objects to share a credential (i.e. two AS400
  577. // objects can both share the same password credential). So we must maintain
  578. // that behavior, but we need to do so using two different credential vaults,
  579. // because each AS400 object must always have its very own credential vault.
  580. credVault_ = (CredentialVault)pwVault.clone();
  581. proxyServer_ = resolveProxyServer(proxyServer_);
  582. }
  583. /**
  584. Constructs an AS400 object. It uses the specified system name, user ID, and password. No sign-on prompt is displayed unless the sign-on fails.
  585. @param systemName The name of the IBM i system. Use <code>localhost</code> to access data locally.
  586. @param userId The user profile name to use to authenticate to the system. If running on IBM i, *CURRENT may be used to specify the current user ID.
  587. @param password The user profile password to use to authenticate to the system. If running on IBM i, *CURRENT may be used to specify the current user ID.
  588. @param proxyServer The name and port of the proxy server in the format <code>serverName[:port]</code>. If no port is specified, a default will be used.
  589. **/
  590. public AS400(String systemName, String userId, String password, String proxyServer)
  591. {
  592. super();
  593. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object, system name: '" + systemName + "' user ID: '" + userId + "' proxy server: '" + proxyServer + "'");
  594. if (PASSWORD_TRACE) Trace.log(Trace.DIAGNOSTIC, "password: '" + password + "'");
  595. if (systemName == null)
  596. {
  597. throw new NullPointerException("systemName");
  598. }
  599. if (userId == null)
  600. {
  601. throw new NullPointerException("userId");
  602. }
  603. if (userId.length() > 10)
  604. {
  605. throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
  606. }
  607. if (password == null)
  608. {
  609. throw new NullPointerException("password");
  610. }
  611. if (password.length() > 128)
  612. {
  613. throw new ExtendedIllegalArgumentException("password.length {" + password.length() + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
  614. }
  615. if (proxyServer == null)
  616. {
  617. throw new NullPointerException("proxyServer");
  618. }
  619. construct();
  620. systemName_ = systemName;
  621. systemNameLocal_ = resolveSystemNameLocal(systemName);
  622. userId_ = userId.toUpperCase();
  623. credVault_ = new PasswordVault(password);
  624. proxyServer_ = resolveProxyServer(proxyServer);
  625. }
  626. /**
  627. Constructs an AS400 object. It uses the same system name and user ID. This does not create a clone. The new object has the same behavior, but results in a new set of socket connections.
  628. @param system A previously instantiated AS400 object.
  629. **/
  630. public AS400(AS400 system)
  631. {
  632. super();
  633. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Constructing AS400 object, system: " + system);
  634. if (system == null)
  635. {
  636. throw new NullPointerException("system");
  637. }
  638. construct();
  639. systemName_ = system.systemName_;
  640. systemNameLocal_ = system.systemNameLocal_;
  641. userId_ = system.userId_;
  642. // Create a copy of the supplied credential vault. This allows the AS400
  643. // object to have its own credential vault object while making the vault
  644. // contain the the same credential as the original vault we have been provided.
  645. // It is VERY important that the copy of the vault contain the same credential
  646. // as the original vault. This is because the Toolbox implementation has
  647. // always allowed two AS400 objects to share a credential (i.e. two AS400
  648. // objects can both share the same password credential). So we must maintain
  649. // that behavior, but we need to do so using two different credential vaults,
  650. // because each AS400 object must always have its very own credential vault.
  651. credVault_ = (CredentialVault)system.credVault_.clone();
  652. gssCredential_ = system.gssCredential_;
  653. gssName_ = system.gssName_;
  654. gssOption_ = system.gssOption_;
  655. proxyServer_ = system.proxyServer_;
  656. // proxyClientConnection_ is not copied.
  657. guiAvailable_ = system.guiAvailable_;
  658. usePasswordCache_ = system.usePasswordCache_;
  659. useDefaultUser_ = system.useDefaultUser_;
  660. showCheckboxes_ = system.showCheckboxes_;
  661. // useSSLConnection_ is handled by SecureAS400 subclass.
  662. mustAddLanguageLibrary_ = system.mustAddLanguageLibrary_;
  663. mustUseSockets_ = system.mustUseSockets_;
  664. mustUseNetSockets_ = system.mustUseNetSockets_;
  665. mustUseSuppliedProfile_ = system.mustUseSuppliedProfile_;
  666. threadUsed_ = system.threadUsed_;
  667. locale_ = system.locale_;
  668. nlv_ = system.nlv_;
  669. socketProperties_ = system.socketProperties_;
  670. ccsid_ = system.ccsid_;
  671. // connectionListeners_ is not copied.
  672. // dispatcher_ is not copied.
  673. // propertyChangeListeners_ is not copied.
  674. // vetoableChangeListeners_ is not copied.
  675. // propertiesFrozen_ is not copied.
  676. // impl_ is not copied.
  677. // signonInfo_ is not copied.
  678. ddmRDB_ = system.ddmRDB_;
  679. }
  680. /**
  681. Adds a listener to be notified when a connection event occurs.
  682. @param listener The listener object.
  683. **/
  684. public void addConnectionListener(ConnectionListener listener)
  685. {
  686. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding connection listener.");
  687. if (listener == null)
  688. {
  689. throw new NullPointerException("listener");
  690. }
  691. synchronized (this)
  692. {
  693. // If first add.
  694. if (connectionListeners_ == null)
  695. {
  696. connectionListeners_ = new Vector();
  697. dispatcher_ = new ConnectionListener()
  698. {
  699. public void connected(ConnectionEvent event)
  700. {
  701. fireConnectEvent(event, true);
  702. }
  703. public void disconnected(ConnectionEvent event)
  704. {
  705. fireConnectEvent(event, false);
  706. }
  707. };
  708. }
  709. // If this is the first add and we are already connected.
  710. if (impl_ != null && connectionListeners_.isEmpty())
  711. {
  712. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Enabling connection listener dispatcher.");
  713. impl_.addConnectionListener(dispatcher_);
  714. }
  715. connectionListeners_.addElement(listener);
  716. }
  717. }
  718. /**
  719. Validates the user ID and password, and if successful, adds the information to the password cache.
  720. @param systemName The name of the IBM i system.
  721. @param userId The user profile name.
  722. @param password The user profile password.
  723. @exception AS400SecurityException If a security or authority error occurs.
  724. @exception IOException If an error occurs while communicating with the system.
  725. **/
  726. public static void addPasswordCacheEntry(String systemName, String userId, String password) throws AS400SecurityException, IOException
  727. {
  728. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding password cache entry, system name: '" + systemName + "' user ID: '" + userId + "'");
  729. addPasswordCacheEntry(new AS400(systemName, userId, password));
  730. }
  731. /**
  732. Validates the user ID and password, and if successful, adds the information to the password cache.
  733. @param systemName The name of the IBM i system.
  734. @param userId The user profile name.
  735. @param password The user profile password.
  736. @param proxyServer The name and port of the proxy server in the format <code>serverName[:port]</code>. If no port is specified, a default will be used.
  737. @exception AS400SecurityException If a security or authority error occurs.
  738. @exception IOException If an error occurs while communicating with the system.
  739. **/
  740. public static void addPasswordCacheEntry(String systemName, String userId, String password, String proxyServer) throws AS400SecurityException, IOException
  741. {
  742. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding password cache entry, system name: '" + systemName + "' user ID: '" + userId + "' proxy server: '" + proxyServer + "'");
  743. addPasswordCacheEntry(new AS400(systemName, userId, password, proxyServer));
  744. }
  745. // For use by AS400 and SecureAS400 objects.
  746. static void addPasswordCacheEntry(AS400 system) throws AS400SecurityException, IOException
  747. {
  748. system.validateSignon(); // Exception thrown if info not valid.
  749. setCacheEntry(system.systemName_, system.userId_, system.credVault_);
  750. }
  751. /**
  752. Adds a listener to be notified when the value of any property is changed.
  753. @param listener The listener object.
  754. **/
  755. public void addPropertyChangeListener(PropertyChangeListener listener)
  756. {
  757. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding property change listener.");
  758. if (listener == null)
  759. {
  760. throw new NullPointerException("listener");
  761. }
  762. synchronized (this)
  763. {
  764. // If first add.
  765. if (propertyChangeListeners_ == null)
  766. {
  767. propertyChangeListeners_ = new PropertyChangeSupport(this);
  768. }
  769. propertyChangeListeners_.addPropertyChangeListener(listener);
  770. }
  771. }
  772. /**
  773. Adds a listener to be notified when the value of any constrained property is changed. The vetoableChange method will be called.
  774. @param listener The listener object.
  775. **/
  776. public void addVetoableChangeListener(VetoableChangeListener listener)
  777. {
  778. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Adding vetoable change listener.");
  779. if (listener == null)
  780. {
  781. throw new NullPointerException("listener");
  782. }
  783. synchronized (this)
  784. {
  785. // If first add.
  786. if (vetoableChangeListeners_ == null)
  787. {
  788. vetoableChangeListeners_ = new VetoableChangeSupport(this);
  789. }
  790. vetoableChangeListeners_.addVetoableChangeListener(listener);
  791. }
  792. }
  793. /**
  794. Indicates if properties are frozen. If this is true, property changes should not be made. Properties are not the same thing as attributes. Properties are basic pieces of information which must be set to make the object usable, such as the system name, user ID or other properties that identify the resource.
  795. @return true if properties are frozen, false otherwise.
  796. **/
  797. public boolean arePropertiesFrozen()
  798. {
  799. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Checking if properties are frozen:", propertiesFrozen_);
  800. return propertiesFrozen_;
  801. }
  802. /**
  803. Authenticates the user profile name and user profile password.
  804. <p>This method is functionally equivalent to the <i>validateSignon()</i> method. It does not alter the user profile assigned to this object, impact the status of existing connections, or otherwise impact the user and authorities on which the application is running.
  805. <p>The system name needs to be set prior to calling this method.
  806. <p><b>Note:</b> Providing an incorrect password increments the number of failed sign-on attempts for the user profile, and can result in the profile being disabled.
  807. <p><b>Note:</b> This will return true if the information is successfully validated. An unsuccessful validation will cause an exception to be thrown, false is never returned.
  808. @param userId The user profile name.
  809. @param password The user profile password.
  810. @return true if successful.
  811. @exception AS400SecurityException If a security or authority error occurs.
  812. @exception IOException If an error occurs while communicating with the system.
  813. **/
  814. public boolean authenticate(String userId, String password) throws AS400SecurityException, IOException
  815. {
  816. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Authenticating signon information:", userId);
  817. return validateSignon(userId, password);
  818. }
  819. // Only load native version once.
  820. private static int nativeVersion = -1;
  821. private static int getNativeVersion()
  822. {
  823. try
  824. {
  825. if (AS400.nativeVersion == -1)
  826. {
  827. AS400.nativeVersion = Class.forName("com.ibm.as400.access.NativeVersion").newInstance().hashCode();
  828. }
  829. }
  830. catch (ClassNotFoundException e)
  831. {
  832. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Not using native optimizations; class 'NativeVersion' is not found.");
  833. AS400.nativeVersion = 0;
  834. }
  835. catch (Exception e)
  836. {
  837. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Not using native optimizations; unexpected exception while loading native version:", e);
  838. AS400.nativeVersion = 0;
  839. }
  840. return AS400.nativeVersion;
  841. }
  842. /**
  843. Indicates if this AS400 object is enabled to exploit Toolbox native optimizations. This requires that the native optimization classes are available on the classpath, and this AS400 object represents the local system and is configured to allow the native optimizations to be used.
  844. Note: If the authentication scheme is other than {@link #AUTHENTICATION_SCHEME_PASSWORD AUTHENTICATION_SCHEME_PASSWORD}, native optimizations will not be used.
  845. @return true if the native optimizations can be used; false otherwise.
  846. @see #isLocal
  847. @see #isMustUseSockets
  848. @see #getAuthenticationScheme
  849. **/
  850. public boolean canUseNativeOptimizations()
  851. {
  852. if (AS400.onAS400 && !mustUseSockets_ && systemNameLocal_ && proxyServer_.length() == 0 && credVault_.getType() == AUTHENTICATION_SCHEME_PASSWORD && getNativeVersion() == 2)
  853. {
  854. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Using native optimizations.");
  855. return true;
  856. }
  857. else
  858. {
  859. if (Trace.traceOn_)
  860. {
  861. Trace.log(Trace.DIAGNOSTIC, "Not using native optimizations. Reason follows:");
  862. if (!AS400.onAS400) {
  863. Trace.log(Trace.DIAGNOSTIC, " onAS400:", AS400.onAS400);
  864. }
  865. if (mustUseSockets_) {
  866. Trace.log(Trace.DIAGNOSTIC, " mustUseSockets:", mustUseSockets_);
  867. }
  868. if (!systemNameLocal_) {
  869. Trace.log(Trace.DIAGNOSTIC, " systemNameLocal:", systemNameLocal_);
  870. }
  871. if (proxyServer_.length() != 0) {
  872. Trace.log(Trace.DIAGNOSTIC, " proxyServer:", proxyServer_);
  873. }
  874. int credType = credVault_.getType();
  875. if (credType != AUTHENTICATION_SCHEME_PASSWORD) {
  876. // Design note: For various reasons (such as lack of requirement, and potential complications
  877. // when swapping during a token-based session), the Toolbox has never supported staying
  878. //on-thread when using profile tokens or other non-password based authentication schemes.
  879. Trace.log(Trace.DIAGNOSTIC, " authenticationScheme:", credType +
  880. " ("+credTypeToString(credType)+")");
  881. }
  882. if (getNativeVersion() != 2) {
  883. Trace.log(Trace.DIAGNOSTIC, " nativeVersion:", getNativeVersion());
  884. }
  885. }
  886. return false;
  887. }
  888. }
  889. private static final String credTypeToString(int credType)
  890. {
  891. String result;
  892. switch (credType)
  893. {
  894. case AUTHENTICATION_SCHEME_PASSWORD :
  895. result = "password";
  896. break;
  897. case AUTHENTICATION_SCHEME_GSS_TOKEN :
  898. result = "GSS token";
  899. break;
  900. case AUTHENTICATION_SCHEME_PROFILE_TOKEN :
  901. result = "profile token";
  902. break;
  903. case AUTHENTICATION_SCHEME_IDENTITY_TOKEN :
  904. result = "identity token";
  905. break;
  906. default :
  907. result = "unrecognized";
  908. }
  909. return result;
  910. }
  911. /**
  912. Changes the user profile password. The system name and user profile name need to be set prior to calling this method.
  913. @param oldPassword The old user profile password.
  914. @param newPassword The new user profile password.
  915. @exception AS400SecurityException If a security or authority error occurs.
  916. @exception IOException If an error occurs while communicating with the system.
  917. **/
  918. public void changePassword(String oldPassword, String newPassword) throws AS400SecurityException, IOException
  919. {
  920. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Changing password.");
  921. if (PASSWORD_TRACE)
  922. {
  923. Trace.log(Trace.DIAGNOSTIC, "oldPassword: '" + oldPassword + "'");
  924. Trace.log(Trace.DIAGNOSTIC, "newPassword: '" + newPassword + "'");
  925. }
  926. if (oldPassword == null)
  927. {
  928. throw new NullPointerException("oldPassword");
  929. }
  930. if (oldPassword.length() > 128)
  931. {
  932. throw new ExtendedIllegalArgumentException("oldPassword.length {" + oldPassword.length() + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
  933. }
  934. if (newPassword == null)
  935. {
  936. throw new NullPointerException("newPassword");
  937. }
  938. if (newPassword.length() > 128)
  939. {
  940. throw new ExtendedIllegalArgumentException("newPassword.length {" + newPassword.length() + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);
  941. }
  942. if (systemName_.length() == 0 && !systemNameLocal_)
  943. {
  944. Trace.log(Trace.ERROR, "Cannot change password before system name is set.");
  945. throw new ExtendedIllegalStateException("systemName", ExtendedIllegalStateException.PROPERTY_NOT_SET);
  946. }
  947. userId_ = resolveUserId(userId_);
  948. if (userId_.length() == 0)
  949. {
  950. Trace.log(Trace.ERROR, "Cannot change password before user ID is set.");
  951. throw new ExtendedIllegalStateException("userId", ExtendedIllegalStateException.PROPERTY_NOT_SET);
  952. }
  953. chooseImpl();
  954. // Synchronize to protect sign-on information.
  955. synchronized (this)
  956. {
  957. byte[] proxySeed = new byte[9];
  958. CredentialVault.rng.nextBytes(proxySeed);
  959. byte[] remoteSeed = impl_.exchangeSeed(proxySeed);
  960. if (PASSWORD_TRACE)
  961. {
  962. Trace.log(Trace.DIAGNOSTIC, "AS400 object proxySeed:", proxySeed);
  963. Trace.log(Trace.DIAGNOSTIC, "AS400 object remoteSeed:", remoteSeed);
  964. }
  965. // Note that in this particular case it is OK to just pass byte arrays
  966. // instead of credential vaults. That is because we have the clear text
  967. // passwords, so all we need to do is encode them and send them over
  968. // to the impl. After the password has been changed, we will update
  969. // our own credential vault with the new password, and create ourselves
  970. // the appropriate type of credential vault to store the password in.
  971. signonInfo_ = impl_.changePassword(systemName_, systemNameLocal_, userId_, CredentialVault.encode(proxySeed, remoteSeed, BinaryConverter.charArrayToByteArray(oldPassword.toCharArray())), CredentialVault.encode(proxySeed, remoteSeed, BinaryConverter.charArrayToByteArray(newPassword.toCharArray())));
  972. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Password changed successfully.");
  973. // Update credential vault with new password.
  974. credVault_.empty();
  975. credVault_ = new PasswordVault(newPassword);
  976. }
  977. }
  978. // Choose between remote and proxy implementation objects, set state information into remote implementation object. Synchronized to protect impl_ and propertiesFrozen_ instance variables. This method can safely be called multiple times because it checks its state before performing the code.
  979. private synchronized void chooseImpl()
  980. {
  981. if (impl_ == null)
  982. {
  983. impl_ = (AS400Impl)loadImpl2("com.ibm.as400.access.AS400ImplRemote", "com.ibm.as400.access.AS400ImplProxy");
  984. // If there is a connection listener. Connect the remote implementation connection events to this object.
  985. if (connectionListeners_ != null && !connectionListeners_.isEmpty())
  986. {
  987. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Enabling connection listener dispatcher.");
  988. impl_.addConnectionListener(dispatcher_);
  989. }
  990. }
  991. if (!propertiesFrozen_)
  992. {
  993. impl_.setState(useSSLConnection_, canUseNativeOptimizations(), threadUsed_, ccsid_, nlv_, socketProperties_, ddmRDB_, mustUseNetSockets_, mustUseSuppliedProfile_, mustAddLanguageLibrary_);
  994. propertiesFrozen_ = true;
  995. }
  996. impl_.setBidiStringType(this.getBidiStringType()); //@Bidi-HCG3
  997. }
  998. /**
  999. Clears the password cache for all systems within this Java virtual machine.
  1000. **/
  1001. public static void clearPasswordCache()
  1002. {
  1003. if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Clearing password cache.");
  1004. synchronized (AS400.systemList)
  1005. {
  1006. AS400.systemList.removeAllElements();
  1007. }
  1008. }
  1009. /**
  1010. Clears all the passwords