jtopenlite.com.ibm.jtopenlite.SignonConnection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jt400 Show documentation
Show all versions of jt400 Show documentation
The Open Source version of the IBM Toolbox for Java
///////////////////////////////////////////////////////////////////////////////
//
// JTOpenLite
//
// Filename: SignonConnection.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 2011-2012 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.jtopenlite;
import java.io.*;
import java.net.*;
import javax.net.ssl.SSLSocketFactory;
/**
* Represents a TCP/IP socket connection to the System i Signon host server (QSYSWRK/QZSOSIGN prestart jobs).
**/
public class SignonConnection extends HostServerConnection //implements Connection
{
/**
* The default TCP/IP port the Signon host server listens on.
* If your system has been configured to use a different port, use
* the {@link PortMapper PortMapper} class to determine the port.
**/
public static final int DEFAULT_SIGNON_SERVER_PORT = 8476;
public static final int DEFAULT_SSL_SIGNON_SERVER_PORT = 9476;
private SignonConnection(SystemInfo info, Socket socket, HostInputStream in, HostOutputStream out, String user)
{
super(info, user, info.getSignonJobName(), socket, in, out);
}
protected void sendEndJobRequest() throws IOException
{
}
/**
* Issues a request to the Signon host server to authenticate the specified user and password.
**/
public void authenticate(String user, String password) throws IOException
{
if (isClosed()) throw new IOException("Connection closed");
Object[] ret = getInfo(true, getInfo().getSystem(), out_, in_);
byte[] clientSeed = (byte[])ret[1];
byte[] serverSeed = (byte[])ret[2];
byte[] userBytes = getUserBytes(user, getInfo().getPasswordLevel());
byte[] passwordBytes = getPasswordBytes(password, getInfo().getPasswordLevel());
password = null;
byte[] encryptedPassword = getEncryptedPassword(userBytes, passwordBytes, clientSeed, serverSeed, getInfo().getPasswordLevel());
// Authenticate.
byte[] userEBCDICBytes = (getInfo().getPasswordLevel() < 2) ? userBytes : getUserBytes(user, 0);
sendSignonInfoRequest(out_, getInfo(), userEBCDICBytes, encryptedPassword);
out_.flush();
int length = in_.readInt();
if (length < 20)
{
throw DataStreamException.badLength("signonInfo", length);
}
in_.skipBytes(16);
int rc = in_.readInt();
int numRead = 24;
try
{
if (rc != 0)
{
String message = "Bad return code from signon info: 0x"+Integer.toHexString(rc);
switch (rc)
{
case 0x20001:
message = "User ID is not known.";
break;
case 0x3000B:
message = "Password is incorrect.";
break;
}
throw new IOException(message);
}
else
{
int serverCCSID = 0;
boolean foundServerCCSID = false;
while (numRead < length && !foundServerCCSID)
{
int ll = in_.readInt();
int cp = in_.readShort();
int currentRead = 0;
switch (cp)
{
case 0x1114:
serverCCSID = in_.readInt();
currentRead = 4;
foundServerCCSID = true;
break;
}
in_.skipBytes(ll-6-currentRead);
numRead += ll;
}
if (foundServerCCSID)
{
getInfo().setServerCCSID(serverCCSID);
}
}
}
finally
{
in_.skipBytes(length-numRead);
in_.end();
}
}
private static Object[] getInfo(boolean doSeeds, String system, HostOutputStream out, HostInputStream in) throws IOException
{
Object[] ret = new Object[3];
final long clientSeedLong = sendSignonExchangeAttributeRequest(out);
if (doSeeds)
{
byte[] clientSeed = Conv.longToByteArray(clientSeedLong);
ret[1] = clientSeed;
}
out.flush();
int length = in.readInt();
if (length < 20)
{
throw DataStreamException.badLength("signonExchangeAttributes", length);
}
in.skipBytes(16);
int rc = in.readInt();
if (rc != 0)
{
in.skipBytes(length-24);
throw DataStreamException.badReturnCode("signonExchangeAttributes", rc);
}
int curLength = 24;
int serverVersion = -1;
boolean foundServerVersion = false;
int serverLevel = -1;
boolean foundServerLevel = false;
boolean foundServerSeed = false;
int passwordLevel = -1;
boolean foundPasswordLevel = false;
String jobName = null;
// while (curLength < length && !foundServerSeed && !foundPasswordLevel && !foundJobName)
while (curLength < length && (!foundServerVersion || !foundServerLevel || !foundPasswordLevel || (!doSeeds || (doSeeds && !foundServerSeed))))
{
int oldLength = curLength;
int ll = in.readInt();
int cp = in.readShort();
curLength += 6;
switch (cp)
{
case 0x1101:
serverVersion = in.readInt();
curLength += 4;
foundServerVersion = true;
break;
case 0x1102:
serverLevel = in.readShort();
curLength += 2;
foundServerLevel = true;
break;
case 0x1103:
if (doSeeds)
{
byte[] serverSeed = new byte[ll-6];
in.readFully(serverSeed);
ret[2] = serverSeed;
curLength += ll-6;
foundServerSeed = true;
}
else
{
in.skipBytes(ll-6);
curLength += ll-6;
}
break;
case 0x1119:
passwordLevel = in.read();
curLength += 1;
foundPasswordLevel = true;
break;
case 0x111F:
in.skipBytes(4); // CCSID is always 0.
curLength += 4;
byte[] jobBytes = new byte[ll-10];
in.readFully(jobBytes);
jobName = Conv.ebcdicByteArrayToString(jobBytes, 0, jobBytes.length);
curLength += ll-10;
break;
default:
in.skipBytes(ll-6);
curLength += ll-6;
break;
}
int diff = ll - (curLength - oldLength);
if (diff > 0)
{
in.skipBytes(diff);
}
}
in.skipBytes(length-curLength);
in.end();
ret[0] = new SystemInfo(system, serverVersion, serverLevel, passwordLevel, jobName);
return ret;
}
/**
* Connects to the Signon host server on the default port and authenticates the specified user.
**/
public static SignonConnection getConnection(String system, String user, String password) throws IOException
{
return getConnection(false, system, user, password);
}
/**
* Connects to the Signon host server on the default port and authenticates the specified user.
**/
public static SignonConnection getConnection(final boolean isSSL, String system, String user, String password) throws IOException
{
return getConnection(isSSL, system, user, password, isSSL? DEFAULT_SSL_SIGNON_SERVER_PORT: DEFAULT_SIGNON_SERVER_PORT);
}
/**
* Connects to the Signon host server on the specified port and authenticates the specified user.
**/
public static SignonConnection getConnection(String system, String user, String password, int signonPort) throws IOException {
return getConnection(false, system, user, password, signonPort);
}
/**
* Connects to the Signon host server on the specified port and authenticates the specified user.
**/
public static SignonConnection getConnection(final boolean isSSL, String system, String user, String password, int signonPort) throws IOException
{
if (signonPort > 0 && signonPort < 65536)
{
Socket signonServer = isSSL? SSLSocketFactory.getDefault().createSocket(system, signonPort) : new Socket(system, signonPort);
InputStream in = signonServer.getInputStream();
OutputStream out = signonServer.getOutputStream();
HostOutputStream dout = new HostOutputStream(new BufferedOutputStream(out));
HostInputStream din = new HostInputStream(new BufferedInputStream(in));
SystemInfo info = (SystemInfo)getInfo(false, system, dout, din)[0];
SignonConnection conn = new SignonConnection(info, signonServer, din, dout, user);
conn.authenticate(user, password);
return conn;
}
else
{
throw new IOException("Bad port number: "+signonPort);
}
}
private static long sendSignonExchangeAttributeRequest(HostOutputStream out) throws IOException
{
out.writeInt(52); // Length;
out.writeShort(0); // Header ID (almost always zero for all datastreams).
out.writeShort(0xE009); // Server ID.
out.writeInt(0); // CS instance.
out.writeInt(0); // Correlation ID.
out.writeShort(0); // Template length.
out.writeShort(0x7003); // ReqRep ID.
out.writeInt(10); // Client version LL.
out.writeShort(0x1101); // Client version CP.
out.writeInt(1); // Client version.
out.writeInt(8); // Client datastream level LL.
out.writeShort(0x1102); // Client datastream level CP.
out.writeShort(2); // Client datastream level.
out.writeInt(14); // Client seed LL.
out.writeShort(0x1103); // Client seed CP.
long clientSeed = System.currentTimeMillis();
out.writeLong(clientSeed); // Client seed.
return clientSeed;
}
private static void sendSignonInfoRequest(HostOutputStream out, SystemInfo info, byte[] userBytes, byte[] encryptedPassword) throws IOException
{
int total = 37 + encryptedPassword.length + 16;
final boolean newerServer = info.getServerLevel() >= 5;
if (newerServer) total += 7;
out.writeInt(total); // Length.
out.writeShort(0); // Header ID (almost always zero for all datastreams).
out.writeShort(0xE009); // Server ID.
out.writeInt(0); // CS instance.
out.writeInt(0); // Correlation ID.
out.writeShort(0x0001); // Template length.
out.writeShort(0x7004); // ReqRep ID.
out.writeByte(encryptedPassword.length == 8 ? 1 : 3); // Password encryption type.
out.writeInt(10); // Client CCSID LL.
out.writeShort(0x1113); // Client CCSID CP.
out.writeInt(1200); // Client CCSID (big endian UTF-16).
out.writeInt(6+encryptedPassword.length); // Password LL.
out.writeShort(0x1105); // Password CP. 0x1115 is other.
out.write(encryptedPassword); // Password.
out.writeInt(16); // User ID LL.
out.writeShort(0x1104); // User ID CP.
out.write(userBytes); // User ID.
if (newerServer)
{
out.writeInt(7); // Return error messages LL.
out.writeShort(0x1128); // Return error messages CP.
out.writeByte(1); // Return error messages.
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy