2

I'm trying to connect to IBM midrange (AS400) machine from my java program and then reset a user's password. Using Jt400.jar, I manage to do so. But the problem is, I need to set the port to specificly use port 23. I want it to follow tn5250 on how it connect to AS400. From the IBM website here, I knew I can do so by using as400.connectToPort(23).

What confuses me, when I add that method, I got a java.lang.RuntimeException: java.lang.NegativeArraySizeException. I did try to search what's causing this exception which lead me to here and more explanation here. This is my code:

public void executeSetPassword(final String userName, final GuardedString password)  {

    if ((userName != null) && (password != null)) {
        final String host = configuration.getHost();
        final String remoteUser = configuration.getRemoteUser();
        GuardedString passwd = configuration.getPassword();
        boolean isSuccessful;

        final AS400 as400 = new AS400();

        try {
            as400.setSystemName(host);
            as400.setUserId(remoteUser);

            passwd.access(new Accessor(){
                @Override
                public void access(char[] clearChars) {
                    try {
                        as400.setPassword(new String(clearChars));
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                }});

            as400.setGuiAvailable(false);
            as400.connectToPort(23);

            final CommandCall cc = new CommandCall(as400);
            final StringBuilder command = new StringBuilder();
            password.access(new Accessor(){
                    @Override
                    public void access(char[] clearChars) {
                            command.append("CHGUSRPRF USRPRF(" + userName + ") PASSWORD(" + new String(clearChars) + ")");
                    }});
            try {
                isSuccessful = cc.run(command.toString());


                logger.info("command status is = " + isSuccessful);
                // getMessageList returns an array of AS400Message objects
                for(AS400Message msg : cc.getMessageList()){
                    logger.info(
                            "  msg: " + msg.getID() + ": " + msg.getText());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

This is the log file:

Thread Id: 1    Time: 2015-06-29 14:27:05.592   Class: com.mastersam.connectors.AS400.AS400ConnectorTests   Method: updateTest(AS400ConnectorTests.java:150)    Level: INFO Message: Running Update Test
Thread Id: 1    Time: 2015-06-29 14:27:05.705   Class: org.identityconnectors.framework.api.operations.UpdateApiOp  Method: update  Level: OK   Message: Enter: update(ObjectClass: __ACCOUNT__, Attribute: {Name=__UID__, Value=[fikrie1]}, [Attribute: {Name=__PASSWORD__, Value=[org.identityconnectors.common.security.GuardedString@408a7bb8]}], OperationOptions: {})
Thread Id: 1    Time: 2015-06-29 14:27:07.749   Class: org.identityconnectors.framework.api.operations.UpdateApiOp  Method: update  Level: OK   Message: Exception: 
java.lang.RuntimeException: java.lang.NegativeArraySizeException
at com.mastersam.connectors.AS400.AS400Connector.executeSetPassword(AS400Connector.java:261)
at com.mastersam.connectors.AS400.AS400Connector.update(AS400Connector.java:199)
at org.identityconnectors.framework.impl.api.local.operations.UpdateImpl.update(UpdateImpl.java:88)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.identityconnectors.framework.impl.api.local.operations.ConnectorAPIOperationRunnerProxy.invoke(ConnectorAPIOperationRunnerProxy.java:97)
at com.sun.proxy.$Proxy10.update(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.identityconnectors.framework.impl.api.local.operations.ThreadClassLoaderManagerProxy.invoke(ThreadClassLoaderManagerProxy.java:96)
at com.sun.proxy.$Proxy10.update(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.identityconnectors.framework.impl.api.DelegatingTimeoutProxy.invoke(DelegatingTimeoutProxy.java:98)
at com.sun.proxy.$Proxy10.update(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.identityconnectors.framework.impl.api.LoggingProxy.invoke(LoggingProxy.java:76)
at com.sun.proxy.$Proxy10.update(Unknown Source)
at org.identityconnectors.framework.impl.api.AbstractConnectorFacade.update(AbstractConnectorFacade.java:176)
at com.mastersam.connectors.AS400.AS400ConnectorTests.updateTest(AS400ConnectorTests.java:156)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
Caused by: java.lang.NegativeArraySizeException
at com.ibm.as400.access.AS400XChgRandSeedReplyDS.read(AS400XChgRandSeedReplyDS.java:58)
at com.ibm.as400.access.AS400ImplRemote.getConnection(AS400ImplRemote.java:823)
at com.ibm.as400.access.AS400ImplRemote.connectToPort(AS400ImplRemote.java:408)
at com.ibm.as400.access.AS400.connectToPort(AS400.java:1152)
at com.mastersam.connectors.AS400.AS400Connector.executeSetPassword(AS400Connector.java:239)
... 52 more
FAILED: updateTest
java.lang.RuntimeException: java.lang.NegativeArraySizeException
at com.mastersam.connectors.AS400.AS400Connector.executeSetPassword(AS400Connector.java:261)
at com.mastersam.connectors.AS400.AS400Connector.update(AS400Connector.java:199)
at org.identityconnectors.framework.impl.api.local.operations.UpdateImpl.update(UpdateImpl.java:88)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.identityconnectors.framework.impl.api.local.operations.ConnectorAPIOperationRunnerProxy.invoke(ConnectorAPIOperationRunnerProxy.java:97)
at com.sun.proxy.$Proxy10.update(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.identityconnectors.framework.impl.api.local.operations.ThreadClassLoaderManagerProxy.invoke(ThreadClassLoaderManagerProxy.java:96)
at com.sun.proxy.$Proxy10.update(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.identityconnectors.framework.impl.api.DelegatingTimeoutProxy.invoke(DelegatingTimeoutProxy.java:98)
at com.sun.proxy.$Proxy10.update(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.identityconnectors.framework.impl.api.LoggingProxy.invoke(LoggingProxy.java:76)
at com.sun.proxy.$Proxy10.update(Unknown Source)
at org.identityconnectors.framework.impl.api.AbstractConnectorFacade.update(AbstractConnectorFacade.java:176)
at com.mastersam.connectors.AS400.AS400ConnectorTests.updateTest(AS400ConnectorTests.java:156)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
Caused by: java.lang.NegativeArraySizeException
at com.ibm.as400.access.AS400XChgRandSeedReplyDS.read(AS400XChgRandSeedReplyDS.java:58)
at com.ibm.as400.access.AS400ImplRemote.getConnection(AS400ImplRemote.java:823)
at com.ibm.as400.access.AS400ImplRemote.connectToPort(AS400ImplRemote.java:408)
at com.ibm.as400.access.AS400.connectToPort(AS400.java:1152)
at com.mastersam.connectors.AS400.AS400Connector.executeSetPassword(AS400Connector.java:239)
... 52 more

So, why does adding one method from jt400 causes a NegativeArraySizeException?

While looking for alternative, I found more info on the JT400 method here, then tried to use as400.connectService(). From here, I assume the service that I should be using is COMMAND and SIGNON. This is part of my code after trying this method:

final AS400 as400 = new AS400();                
        try {

            as400.setSystemName(host);
            as400.setUserId(remoteUser);
            passwd.access(new Accessor(){
                @Override
                public void access(char[] clearChars) {
                    try {
                        as400.setPassword(new String(clearChars));
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                }});
            as400.setGuiAvailable(false);

            as400.connectService(7);      //I added this
            as400.setServicePort(7, 23);  //I added this
            as400.setServicePort(6, 23);  //I added this
            logger.info("port is = " + as400.getServicePort(7));
            final CommandCall cc = new CommandCall(as400);
            final StringBuilder command = new StringBuilder();
            password.access(new Accessor(){
                    @Override
                    public void access(char[] clearChars) {
                            command.append("CHGUSRPRF USRPRF(" + userName + ") PASSWORD(" + new String(clearChars) + ")");
                    }});
            try {

                isSuccessful = cc.run(command.toString());
                as400.setServicePort(2, 23); //I added this
                logger.info("port is = " + as400.getServicePort(2));
}

According to the log, the port is 23. But when I double check using Wireshark apps, the port that it use to connect to AS400 is not 23. Please guide me if I'm doing a mistake anywhere.

Other thing that I have tried,

  1. Swap line between as400.connectService() and as400.setServicePort()

    • Causes the same error as the previous one : java.lang.NegativeArraySizeException
  2. Check either port 23 is available to use or not. Use tn5250 to connect to AS400. The connection is ok.

  3. Set as400.connectToPort() to use other port.

    • Causes the same error like using port 23.
Buck Calabro
  • 7,558
  • 22
  • 25
Mohd Fikrie
  • 197
  • 4
  • 21
  • 5
    JTOpen is designed to communicate with the IBM i host servers, which have a common protocol for authenticating a connection. Trying to use JTOpen to communicate with the TELNET port will not work since JTOpen doesn't know that the port is a TELNET port. JTOpen sends the message intended for an IBM i host server and the TELNET server returns information that it doesn't understand. You cannot get JTOpen to use port 23 since it doesn't speak the TELNET protocol. – jweberhard Jun 30 '15 at 11:55
  • @jweberhard I see. Just to verify what I understand. The port number was specificly set for telnet use only. And JTOpen doesnt handle telnet protocol. So I should set other port for it to handle. Right? – Mohd Fikrie Jul 01 '15 at 02:12
  • 1
    @MohdFikrie You only need to set the port on the JT400 side is the sysadmin has changed the ports on the server side. It looks like you are trying to emulate a telnet client, but JT400 is not the tool for doing that. – Buck Calabro Jul 01 '15 at 20:20
  • Nobody asked what version your using. Too bad IBM doesn't have the brains to put this into a Maven repo cause I would assume your on the most current version. – danny117 Jun 19 '18 at 17:28

1 Answers1

5

connectToPort() returns a Socket object, not an AS400 object. Therefore, you can't use any AS400 classes to interact with that returned Socket object.

You might consider changePassword() instead of trying to stuff commands down the telnet port.

changePassword

public void changePassword(java.lang.String oldPassword,
                  java.lang.String newPassword)
                    throws AS400SecurityException,
                           java.io.IOException

Changes the user profile password. The system name and user profile name need to be set prior to calling this method.

Parameters:
    oldPassword - The old user profile password.
    newPassword - The new user profile password.
Throws:
    AS400SecurityException - If a security or authority error occurs.
    java.io.IOException - If an error occurs while communicating with the system.
Buck Calabro
  • 7,558
  • 22
  • 25
  • Does changePassword() works for changing other users as well? eg. If I were to login with user A, then change user B's password. Will this method works? Or is it just to change the user's A password? – Mohd Fikrie Jul 01 '15 at 02:16
  • If you want to change user B's password you can connect as user B and issue changePassword() with that connection. If you really want to run a CHGUSRPRF command for any user, from one particular user, look at AS400.CommandCall() – Buck Calabro Jul 01 '15 at 20:15
  • Obviously the user used to change the password must have authority to the profile that the password is being changed for. – David G Jul 14 '15 at 17:29