com.ibm.as400.access.ClassDecoupler 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
The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename: ClassDecoupler.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) 1997-2017 International Business Machines Corporation and
// others. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
package com.ibm.as400.access;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.util.*;
/**
* This class exists to remove the dependencies AS400ImplRemote had on some of
* the DDM and DB datastream classes. In this way, a JarMaker-ed jt400.jar file
* can effectively operate its AS400 object without needing the DDM or JDBC classes.
**/
public class ClassDecoupler
{
// For future use.
// static
// {
// // Identify all DDM server reply data streams.
// AS400Server.addReplyStream(new DDMEXCSATReplyDataStream(), AS400.RECORDACCESS);
// AS400Server.addReplyStream(new DDMACCSECReplyDataStream(), AS400.RECORDACCESS);
// AS400Server.addReplyStream(new DDMSECCHKReplyDataStream(), AS400.RECORDACCESS);
// AS400Server.addReplyStream(new DDMASPReplyDataStream(), AS400.RECORDACCESS);
// }
/** force the use of ENCUSRPWD using JVM properties */
public static boolean forceENCUSRPWD = false;
/** force the use of AES using JVM properties */
public static boolean forceAES = false;
static
{
String property = System.getProperty("com.ibm.as400.access.DDMPWDRQD");
if (property != null && property.toUpperCase().equals("ENCUSRPWD"))
forceENCUSRPWD = true;
property = System.getProperty("com.ibm.as400.access.DDMENCALC");
if (property != null && property.toUpperCase().equals("AES"))
forceAES = true;
}
static void freeDBReplyStream(DataStream ds)
{
if (ds instanceof DBReplyRequestedDS)
((DBReplyRequestedDS)ds).returnToPool();
}
// TODO so much duplication in this method!!
static Object[] connectDDMPhase1(OutputStream outStream, InputStream inStream, boolean aesEncryption, int authScheme, int connectionID) throws ServerStartupException, IOException
{
KeyPair keyPair = null;
String encryptUserId = null;
// Exchange server start up/security information with DDM server.
// Exchange attributes.
DDMEXCSATRequestDataStream EXCSATRequest = new DDMEXCSATRequestDataStream();
if (Trace.traceOn_) EXCSATRequest.setConnectionID(connectionID);
EXCSATRequest.write(outStream);
DDMEXCSATReplyDataStream EXCSATReply = new DDMEXCSATReplyDataStream();
if (Trace.traceOn_) EXCSATReply.setConnectionID(connectionID);
EXCSATReply.read(inStream);
if (!EXCSATReply.checkReply())
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED);
byte[] jobString = EXCSATReply.getEXTNAM();
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "DDM EXCSAT successful.");
int authSchemeToUse;
if (forceENCUSRPWD) /*@U4A*/
{
authSchemeToUse = AS400.AUTHENTICATION_SCHEME_DDM_EUSERIDPWD;
encryptUserId = "TRUE";
try
{
if (!forceAES)
{
try {
keyPair = DDMTerm.getDESKeyPair();
}
catch (InvalidAlgorithmParameterException iape)
{
// JDK 1.8 does not support 256 bit keys Upgrade to AES
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "ClassDecoupler: Upgrading to AES due to InvalidAlgorithmParameterException ", iape);
forceAES=true;
keyPair = DDMTerm.getAESKeyPair();
}
}
else
keyPair = DDMTerm.getAESKeyPair();
}
catch (GeneralSecurityException e) {
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED, e);
}
}
else
authSchemeToUse = authScheme;
// We currently don't need to pass the IASP to the ACCSEC, but may in the future
DDMACCSECRequestDataStream ACCSECReq = new DDMACCSECRequestDataStream(aesEncryption, authSchemeToUse, null, keyPair, forceAES);
if (Trace.traceOn_) ACCSECReq.setConnectionID(connectionID);
ACCSECReq.write(outStream);
DDMACCSECReplyDataStream ACCSECRep = new DDMACCSECReplyDataStream();
if (Trace.traceOn_) ACCSECRep.setConnectionID(connectionID);
ACCSECRep.read(inStream);
if ( !ACCSECRep.checkReply(authSchemeToUse) )
{
// Check to see if *ENCUSRPWD supported, if so then renegotiate the setting @U4A
authSchemeToUse = AS400.AUTHENTICATION_SCHEME_DDM_EUSERIDPWD;
if (ACCSECRep.checkReplyForEUSRIDPWD(authScheme))
{
try
{
if (!forceAES)
{
try {
keyPair = DDMTerm.getDESKeyPair();
}
catch (InvalidAlgorithmParameterException iape)
{
// JDK 1.8 does not support 256 bit keys Upgrade to AES
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "ClassDecoupler: Upgrading to AES due to InvalidAlgorithmParameterException ", iape);
forceAES = true;
keyPair = DDMTerm.getAESKeyPair();
}
}
else
keyPair = DDMTerm.getAESKeyPair();
}
catch (GeneralSecurityException e) {
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED, e);
}
// We currently don't need to pass the IASP to the ACCSEC, but may in the future.
ACCSECReq = new DDMACCSECRequestDataStream(aesEncryption, authSchemeToUse, null, keyPair, forceAES);
if (Trace.traceOn_) ACCSECReq.setConnectionID(connectionID);
ACCSECReq.write(outStream);
ACCSECRep = new DDMACCSECReplyDataStream();
if (Trace.traceOn_) ACCSECRep.setConnectionID(connectionID);
ACCSECRep.read(inStream);
// Check to see if we need to upgrade to AES
if (ACCSECRep.aesUpgrade())
{
try
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "ClassDecoupler: Upgrading to AES due to server negotiation");
keyPair = DDMTerm.getAESKeyPair();
forceAES = true;
}
catch (GeneralSecurityException e) {
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED, e);
}
// We currently don't need to pass the IASP to the ACCSEC, but may in the future.
ACCSECReq = new DDMACCSECRequestDataStream(aesEncryption, authSchemeToUse, null, keyPair, forceAES);
if (Trace.traceOn_) ACCSECReq.setConnectionID(connectionID);
ACCSECReq.write(outStream);
ACCSECRep = new DDMACCSECReplyDataStream();
if (Trace.traceOn_) ACCSECRep.setConnectionID(connectionID);
ACCSECRep.read(inStream);
}
if (!ACCSECRep.checkReplyForEUSRIDPWD(authScheme))
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED);
encryptUserId = "TRUE";
}
else
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED);
}
else if (ACCSECRep.aesUpgrade())
{
// we need to upgrade to AES
try
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "ClassDecoupler: Upgrading to AES due to server negotiation");
keyPair = DDMTerm.getAESKeyPair();
forceAES = true;
}
catch (GeneralSecurityException e) {
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED, e);
}
// We currently don't need to pass the IASP to the ACCSEC, but may in the future.
ACCSECReq = new DDMACCSECRequestDataStream(aesEncryption, authSchemeToUse, null, keyPair, forceAES);
if (Trace.traceOn_) ACCSECReq.setConnectionID(connectionID);
ACCSECReq.write(outStream);
ACCSECRep = new DDMACCSECReplyDataStream();
if (Trace.traceOn_) ACCSECRep.setConnectionID(connectionID);
ACCSECRep.read(inStream);
if (!ACCSECRep.checkReplyForEUSRIDPWD(authScheme))
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED);
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "DDM ACCSEC successful.");
// Seeds for substitute password generation.
byte[] clientSeed = null;
byte[] serverSeed = null;
if (encryptUserId != null)
serverSeed = ACCSECRep.getServerSeed();
else if ((authScheme == AS400.AUTHENTICATION_SCHEME_PASSWORD) || (authSchemeToUse == AS400.AUTHENTICATION_SCHEME_DDM_EUSERIDPWD))
{
clientSeed = ACCSECReq.getClientSeed();
serverSeed = ACCSECRep.getServerSeed();
}
return new Object[] { clientSeed, serverSeed, jobString, encryptUserId, keyPair };
}
static void connectDDMPhase2(OutputStream outStream, InputStream inStream, byte[] userIDbytes,
byte[] ddmSubstitutePassword, byte[] iaspBytes, int authScheme, String ddmRDB,
String systemName, int connectionID,
byte[] addAuthFactor, byte[] verificationID, byte[] clientIPAddr) throws ServerStartupException, IOException, AS400SecurityException
{
// If the ddmSubstitutePassword length is 8, then we are using DES encryption.
// If its length is 20, then we are using SHA encryption.
// Build the SECCHK request; we build the request here so that we are not
// passing the password around anymore than we have to.
DDMSECCHKRequestDataStream SECCHKReq = new DDMSECCHKRequestDataStream(userIDbytes, ddmSubstitutePassword, iaspBytes, authScheme, addAuthFactor, verificationID, clientIPAddr);
if (Trace.traceOn_) SECCHKReq.setConnectionID(connectionID);
// Send the SECCHK request.
SECCHKReq.write(outStream);
DDMSECCHKReplyDataStream SECCHKRep = new DDMSECCHKReplyDataStream();
if (Trace.traceOn_) SECCHKRep.setConnectionID(connectionID);
SECCHKRep.read(inStream);
// Validate the reply.
if (!SECCHKRep.checkReply())
{
int rc = SECCHKRep.getErrorCode();
switch (rc)
{
case DDMTerm.PASSWORD_EXPIRED:
throw new AS400SecurityException(AS400SecurityException.PASSWORD_EXPIRED);
case DDMTerm.PASSWORD_INVALID:
throw new AS400SecurityException(AS400SecurityException.PASSWORD_INCORRECT);
case DDMTerm.PASSWORD_MISSING:
throw new AS400SecurityException(AS400SecurityException.PASSWORD_NOT_SET);
case DDMTerm.USERID_INVALID:
throw new AS400SecurityException(AS400SecurityException.USERID_UNKNOWN);
case DDMTerm.USERID_MISSING:
throw new AS400SecurityException(AS400SecurityException.USERID_NOT_SET);
case DDMTerm.USERID_REVOKED:
throw new AS400SecurityException(AS400SecurityException.USERID_DISABLE);
case DDMTerm.NEWPASSWORD_INVALID:
throw new AS400SecurityException(AS400SecurityException.PASSWORD_NEW_DISALLOWED);
case DDMTerm.LOCALSECURITY_SERVICE_RETRYABLE_ERROR:
throw new AS400SecurityException(AS400SecurityException.SECURITY_GENERAL);
case DDMTerm.LOCALSECURITY_SERVICE_NON_RETRYABLE_ERROR:
throw new AS400SecurityException(AS400SecurityException.SECURITY_GENERAL);
default:
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED);
}
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "DDM SECCHK successful.");
if (iaspBytes != null)
{
// We need to send an RDB datastream to make sure the RDB name we sent on the SECCHK is a valid RDB.
DDMASPRequestDataStream aspReq = new DDMASPRequestDataStream(iaspBytes);
if (Trace.traceOn_) aspReq.setConnectionID(connectionID);
aspReq.write(outStream);
DDMASPReplyDataStream aspRep = new DDMASPReplyDataStream();
if (Trace.traceOn_) aspRep.setConnectionID(connectionID);
aspRep.read(inStream);
if (!aspRep.checkReply())
{
if (Trace.traceOn_) Trace.log(Trace.ERROR, "RDB name '"+ddmRDB+"' is not a valid IASP name on system '"+systemName+"'.");
throw new ServerStartupException(ServerStartupException.CONNECTION_NOT_ESTABLISHED);
}
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "DDM RDB name '"+ddmRDB+"' verified.");
}
}
static DataStream constructDDMDataStream(InputStream inStream, Hashtable replyStreams, AS400ImplRemote system, int connectionID) throws IOException
{
return DDMDataStream.construct(inStream, replyStreams, system, connectionID);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy