Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 74 additions & 5 deletions src/main/java/com/ibm/as400/access/AS400.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.net.UnknownHostException;
import java.net.URL;
import java.util.Arrays;
import java.util.Base64;
import java.util.GregorianCalendar;
import java.util.Hashtable;
import java.util.Locale;
Expand Down Expand Up @@ -388,6 +389,52 @@ public class AS400 implements Serializable, AutoCloseable
private boolean forcePrompt_ = false;
private int validateSignonTimeOut_ = 0;

private byte[] kerbTicket_;

// Prefix used to indicate that the password contains a base64-encoded Kerberos token.
public static final String KERBEROS_PREFIX = "_KERBEROSAUTH_";
public static final char[] KERBEROS_PREFIX_CHARS = KERBEROS_PREFIX.toCharArray();

private void setKerbTicket(byte[] ticket) {
this.kerbTicket_ = ticket.clone();
}

private byte[] getKerbTicket() {
return this.kerbTicket_;
}

public void clearKerbTicket() {
if (this.kerbTicket_ != null)
CredentialVault.clearArray(kerbTicket_);
}

// Determines if the password contains a Kerberos token
private boolean isKerbTicket(char[] auth){
char[] prefix = KERBEROS_PREFIX_CHARS;
if (auth == null || auth.length < prefix.length) {
return false;
}

for (int i = 0; i < prefix.length; i++) {
if (auth[i] != prefix[i]) {
return false;
}
}
return true;
}

// Extracts the Kerberos token from the password
private static char[] getKerbTicketFromPassword(char[] password) {
int prefixLen = KERBEROS_PREFIX_CHARS.length;
int tokenLen = password.length - prefixLen;

char[] tokenChars = new char[tokenLen];
System.arraycopy(password, prefixLen, tokenChars, 0, tokenLen);

return tokenChars;
}


/**
* Constructs an AS400 object.
* <p>
Expand Down Expand Up @@ -647,7 +694,6 @@ public AS400(String systemName, String userId, char[] password)
if (userId.length() > 10)
throw new ExtendedIllegalArgumentException("userId (" + userId + ")", ExtendedIllegalArgumentException.LENGTH_NOT_VALID);

checkPasswordNullAndLength(password, "password");
construct();
systemName_ = systemName;
systemNameLocal_ = resolveSystemNameLocal(systemName);
Expand All @@ -658,7 +704,17 @@ public AS400(String systemName, String userId, char[] password)
}

userId_ = userId.toUpperCase();
credVault_ = new PasswordVault(password);
// Create appropriate credential vault based on whether the password is a Kerberos token or a regular password.
boolean isKerberosTicket = isKerbTicket(password);
if (isKerberosTicket){
password = getKerbTicketFromPassword(password);
credVault_ = new GSSTokenVault();

this.setKerbTicket(Base64.getDecoder().decode((new String(password))));
}else{
checkPasswordNullAndLength(password, "password");
credVault_ = new PasswordVault(password);
}
proxyServer_ = resolveProxyServer(proxyServer_);
}

Expand Down Expand Up @@ -1794,6 +1850,10 @@ private synchronized void chooseImpl()
}
}

// If kerbTicket_ has been set, make sure the impl knows about it.
if (kerbTicket_ != null)
impl_.setKerbTicket(kerbTicket_);

if (!propertiesFrozen_)
{
impl_.setState(useSSLConnection_, canUseNativeOptimizations(), threadUsed_, ccsid_, nlv_,
Expand Down Expand Up @@ -4145,6 +4205,7 @@ public void removeVetoableChangeListener(VetoableChangeListener listener)
public synchronized void resetAllServices()
{
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Resetting all services.");
clearKerbTicket();
setStayAlive(0);

disconnectAllServices();
Expand Down Expand Up @@ -5443,9 +5504,17 @@ synchronized void signon(boolean keepConnection) throws AS400SecurityException,
&& (credVault_.getType() == AUTHENTICATION_SCHEME_GSS_TOKEN || gssOption_ != AS400.GSS_OPTION_NONE))
{
// Try for Kerberos.
byte[] newBytes = (gssCredential_ == null) ? TokenManager.getGSSToken(systemName_, gssName_) :
TokenManager2.getGSSToken(systemName_, gssCredential_);

byte[] newBytes = null;

if (kerbTicket_ != null && kerbTicket_.length > 0) {
if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "Using injected Kerberos ticket.");
newBytes = kerbTicket_.clone();
} else {
// Fall back to generating the token normally
newBytes = (gssCredential_ == null)
? TokenManager.getGSSToken(systemName_, gssName_)
: TokenManager2.getGSSToken(systemName_, gssCredential_);
}
// We do not have to empty the existing vault because the
// previous if-check assures us it is already empty.
credVault_ = new GSSTokenVault(newBytes);
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/ibm/as400/access/AS400Impl.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,7 @@ interface AS400Impl
String getSystemName();
/* Set the VRM for the object. Only set for the remote Impl */
void setVRM(int v, int r, int m);


void setKerbTicket(byte[] ticket);
}
11 changes: 11 additions & 0 deletions src/main/java/com/ibm/as400/access/AS400ImplProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ public SignonInfo skipSignon(String systemName, boolean systemNameLocal, String


private int bidiStringType = BidiStringType.DEFAULT;
private byte[] kerbTicket_;

/**
* Sets bidi string type of the connection.
Expand Down Expand Up @@ -404,4 +405,14 @@ public void setVRM(int v, int r, int m) {
public void setAdditionalAuthenticationFactor(char[] additionalAuthFactor) {
// Does nothing for the proxy class
}

@Override
public void setKerbTicket(byte[] ticket) {
this.kerbTicket_ = ticket;
}

private byte[] getKerbTicket() {
return this.kerbTicket_;
}

}
35 changes: 30 additions & 5 deletions src/main/java/com/ibm/as400/access/AS400ImplRemote.java
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ public class AS400ImplRemote implements AS400Impl

private static final String CLASSNAME = "com.ibm.as400.access.AS400ImplRemote";

// GSS Token, for Kerberos.
private byte[] kerbTicket_;

static {
if (Trace.traceOn_)
Trace.logLoadPath(CLASSNAME);
Expand Down Expand Up @@ -665,10 +668,14 @@ public int createUserHandle() throws AS400SecurityException, IOException
{
try
{
byte[] authenticationBytes = (gssCredential_ == null)
byte[] authenticationBytes;
if (this.kerbTicket_ != null){
authenticationBytes = this.kerbTicket_;
} else {
authenticationBytes = (gssCredential_ == null)
? TokenManager.getGSSToken(systemName_, gssName_)
: TokenManager2.getGSSToken(systemName_, gssCredential_);
}
IFSUserHandle2Req req = new IFSUserHandle2Req(authenticationBytes, aafIndicator_ ? additionalAuthFactor_ : null);
ds = (ClientAccessDataStream) connectedServer.sendAndReceive(req);
}
Expand Down Expand Up @@ -1016,9 +1023,13 @@ public void generateProfileToken(ProfileTokenCredential profileToken, String use
case AS400.AUTHENTICATION_SCHEME_GSS_TOKEN:
try
{
authenticationBytes = (gssCredential_ == null)
? TokenManager.getGSSToken(systemName_, gssName)
: TokenManager2.getGSSToken(systemName_, gssCredential_);
if (this.kerbTicket_ != null){
authenticationBytes = this.kerbTicket_;
} else {
authenticationBytes = (gssCredential_ == null)
? TokenManager.getGSSToken(systemName_, gssName)
: TokenManager2.getGSSToken(systemName_, gssCredential_);
}
}
catch (Exception e)
{
Expand Down Expand Up @@ -1838,6 +1849,8 @@ byte[] getPassword(byte[] clientSeed, byte[] serverSeed) throws AS400SecurityExc
if (credType == AS400.AUTHENTICATION_SCHEME_GSS_TOKEN)
{
try {
if (kerbTicket_ != null)
return kerbTicket_;
return (gssCredential_ == null)
? TokenManager.getGSSToken(systemName_, gssName_)
: TokenManager2.getGSSToken(systemName_, gssCredential_);
Expand Down Expand Up @@ -2216,6 +2229,8 @@ private byte[] getDdmEncryptedPassword(byte[] sharedPrivateKey, byte[] serverSee
if (credType == AS400.AUTHENTICATION_SCHEME_GSS_TOKEN)
{
try {
if (kerbTicket_ != null)
return kerbTicket_;
return (gssCredential_ == null)
? TokenManager.getGSSToken(systemName_, gssName_)
: TokenManager2.getGSSToken(systemName_, gssCredential_);
Expand Down Expand Up @@ -5402,4 +5417,14 @@ else if (profileToken.getTokenCreator() != ProfileTokenCredential.CREATOR_SIGNON
public String getLocalIPAddress() {
return localIPAddress_;
}

@Override
public void setKerbTicket(byte[] ticket) {
this.kerbTicket_ = ticket;
}

private byte[] getKerbTicket() {
return this.kerbTicket_;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,11 @@ public void close ()


as400_.disconnectServer (server_);
// Clear the sensitive auth token via the public AS400 object
if (as400PublicClassObj_ != null) {
as400PublicClassObj_.clearKerbTicket();
}

server_ = null;
}

Expand Down