From cb2a1c8a9223af1949128b9778e60709ecda806b Mon Sep 17 00:00:00 2001 From: John Eberhard Date: Tue, 3 Dec 2024 10:05:34 -0600 Subject: [PATCH] Profile Token Enhancements Signed-off-by: John Eberhard --- src/main/java/com/ibm/as400/access/AS400.java | 61 ++- .../java/com/ibm/as400/access/AS400Impl.java | 2 +- .../com/ibm/as400/access/AS400ImplProxy.java | 12 +- .../com/ibm/as400/access/AS400ImplRemote.java | 99 +++-- .../as400/access/ProfileTokenImplNative.java | 109 +++--- .../AS400BasicAuthenticationCredential.java | 5 +- .../auth/DefaultProfileTokenProvider.java | 1 - .../security/auth/ProfileTokenCredential.java | 352 ++++++++++-------- .../auth/ProfileTokenEnhancedInfo.java | 93 +++++ .../as400/security/auth/ProfileTokenImpl.java | 62 +-- .../security/auth/ProfileTokenImplRemote.java | 130 +++---- 11 files changed, 539 insertions(+), 387 deletions(-) create mode 100644 src/main/java/com/ibm/as400/security/auth/ProfileTokenEnhancedInfo.java diff --git a/src/main/java/com/ibm/as400/access/AS400.java b/src/main/java/com/ibm/as400/access/AS400.java index 8ce459cec..cb208bf88 100644 --- a/src/main/java/com/ibm/as400/access/AS400.java +++ b/src/main/java/com/ibm/as400/access/AS400.java @@ -37,6 +37,7 @@ import org.ietf.jgss.GSSManager; import com.ibm.as400.security.auth.ProfileTokenCredential; +import com.ibm.as400.security.auth.ProfileTokenEnhancedInfo; import com.ibm.as400.security.auth.ProfileTokenProvider; /** @@ -2706,7 +2707,6 @@ public ProfileTokenCredential getProfileToken(int tokenType, int timeoutInterval profileToken.setTimeoutInterval(timeoutInterval); profileToken.setVerificationID(verificationID); profileToken.setRemoteIPAddress(remoteIPAddress); - profileToken.setAdditionalAuthenticationFactor(additionalAuthenticationFactor_); } catch (PropertyVetoException e) { @@ -2726,7 +2726,7 @@ public ProfileTokenCredential getProfileToken(int tokenType, int timeoutInterval CredentialVault tempVault = (CredentialVault)credVault_.clone(); tempVault.storeEncodedUsingExternalSeeds(proxySeed, impl_.exchangeSeed(proxySeed)); - impl_.generateProfileToken(profileToken, userId_, tempVault, gssName_); + impl_.generateProfileToken(profileToken, userId_, tempVault, additionalAuthenticationFactor_, gssName_); } return profileToken; @@ -2866,7 +2866,7 @@ public ProfileTokenCredential getProfileToken(String userId, String password, in **/ public ProfileTokenCredential getProfileToken(String userId, char[] password, int tokenType, int timeoutInterval) throws AS400SecurityException, IOException, InterruptedException { - return getProfileToken(userId, password, null, tokenType, timeoutInterval, null, null); + return getProfileToken(userId, password, null, tokenType, timeoutInterval, null); } /** @@ -2913,6 +2913,49 @@ public ProfileTokenCredential getProfileToken(String userId, char[] password, in **/ public ProfileTokenCredential getProfileToken(String userId, char[] password, char[] additionalAuthFactor, int tokenType, int timeoutInterval, String verificationID, String remoteIPAddress) throws AS400SecurityException, IOException, InterruptedException + { + ProfileTokenEnhancedInfo enhancedInfo = new ProfileTokenEnhancedInfo(); + enhancedInfo.setVerificationID(verificationID); + enhancedInfo.setRemoteIPAddress(remoteIPAddress); + return getProfileToken(userId,password,additionalAuthFactor,tokenType, timeoutInterval, enhancedInfo); + } + + /** + * Authenticates the given user profile and password and returns a corresponding ProfileTokenCredential if + * successful. + *

+ * Invoking this method does not change the user ID and password assigned to the system or otherwise modify the user + * or authorities under which the application is running. + *

+ * This function is only supported if the system is at i5/OS V4R5M0 or greater. + *

+ * Note: Providing an incorrect password increments the number of failed sign-on attempts for the user + * profile, and can result in the profile being disabled. Refer to documentation on the + * ProfileTokenCredential class for additional restrictions. + * + * @param userId The user profile name. + * @param password The user profile password. + * @param additionalAuthFactor The additional authentication factor or null if not specifying one. + * @param tokenType The type of profile token to create. Possible types are defined as fields on the + * ProfileTokenCredential class: + *

+ * @param timeoutInterval The number of seconds to expiration when the token is created (1-3600). + * @param enhancedInfo Information used for creating an enhanced profile token. + * @return A ProfileTokenCredential representing the authenticated profile and password. + * @exception AS400SecurityException If a security or authority error occurs. + * @exception ExtendedIllegalArgumentException If userId length is not valid. + * @exception IOException If an error occurs while communicating with the system. + * @exception InterruptedException If this thread is interrupted. + **/ + public ProfileTokenCredential getProfileToken(String userId, char[] password, char[] additionalAuthFactor, int tokenType, int timeoutInterval, + ProfileTokenEnhancedInfo enhancedInfo ) throws AS400SecurityException, IOException, InterruptedException { connectService(AS400.SIGNON); @@ -2922,13 +2965,16 @@ public ProfileTokenCredential getProfileToken(String userId, char[] password, ch if (userId.length() > 10) throw new ExtendedIllegalArgumentException("userId", ExtendedIllegalArgumentException.LENGTH_NOT_VALID); + if (enhancedInfo == null) { + enhancedInfo = new ProfileTokenEnhancedInfo(); + } checkPasswordNullAndLength(password, "password"); if (isTurkish()) { userId = userId.toUpperCase(Locale.ENGLISH); if (Trace.traceOn_) Trace.log(Trace.DIAGNOSTIC, "This system locale is Turkish, userId.toUpperCase(Locale.ENGLISH)"); } - + userId = resolveUserId(userId.toUpperCase()); ProfileTokenCredential profileToken = new ProfileTokenCredential(); @@ -2937,9 +2983,8 @@ public ProfileTokenCredential getProfileToken(String userId, char[] password, ch profileToken.setSystem(this); profileToken.setTokenType(tokenType); profileToken.setTimeoutInterval(timeoutInterval); - profileToken.setVerificationID(verificationID); - profileToken.setRemoteIPAddress(remoteIPAddress); - profileToken.setAdditionalAuthenticationFactor(additionalAuthFactor); + profileToken.setEnhancedInfo(enhancedInfo); + } catch (PropertyVetoException e) { @@ -2953,7 +2998,7 @@ public ProfileTokenCredential getProfileToken(String userId, char[] password, ch { PasswordVault tempVault = new PasswordVault(password); tempVault.storeEncodedUsingExternalSeeds(proxySeed, impl_.exchangeSeed(proxySeed)); - impl_.generateProfileToken(profileToken, userId, tempVault, gssName_); + impl_.generateProfileToken(profileToken, userId, tempVault, additionalAuthFactor, gssName_); } return profileToken; diff --git a/src/main/java/com/ibm/as400/access/AS400Impl.java b/src/main/java/com/ibm/as400/access/AS400Impl.java index 865057af9..8528961eb 100644 --- a/src/main/java/com/ibm/as400/access/AS400Impl.java +++ b/src/main/java/com/ibm/as400/access/AS400Impl.java @@ -46,7 +46,7 @@ interface AS400Impl // Sets the raw bytes for the provided profile token. void generateProfileToken(ProfileTokenCredential profileToken, String userIdentity) throws AS400SecurityException, IOException; // Sets the raw bytes for the provided profile token. - void generateProfileToken(ProfileTokenCredential profileToken, String userId, CredentialVault vault, String gssName) throws AS400SecurityException, IOException, InterruptedException; + void generateProfileToken(ProfileTokenCredential profileToken, String userId, CredentialVault vault, char[] additionalAuthenticationFactor, String gssName) throws AS400SecurityException, IOException, InterruptedException; // Get the port for a service. int getServicePort(String systemName, int service); // Check service connection. diff --git a/src/main/java/com/ibm/as400/access/AS400ImplProxy.java b/src/main/java/com/ibm/as400/access/AS400ImplProxy.java index b2e44888e..f68ec4e1b 100644 --- a/src/main/java/com/ibm/as400/access/AS400ImplProxy.java +++ b/src/main/java/com/ibm/as400/access/AS400ImplProxy.java @@ -141,7 +141,7 @@ public void generateProfileToken(ProfileTokenCredential profileToken, String use new boolean[] { true, false }, // indicate that 1st arg gets modified true); ProfileTokenCredential returnArg = (ProfileTokenCredential)rv.getArgument(0); - profileToken.setToken(returnArg.getToken(),false); + profileToken.setToken(returnArg.getToken()); return; } catch (InvocationTargetException e) @@ -156,16 +156,16 @@ public void generateProfileToken(ProfileTokenCredential profileToken, String use // Sets the raw bytes for the provided profile token. @Override - public void generateProfileToken(ProfileTokenCredential profileToken, String userId, CredentialVault vault, String gssName) throws AS400SecurityException, IOException, InterruptedException + public void generateProfileToken(ProfileTokenCredential profileToken, String userId, CredentialVault vault, char[] additionalAuthFactor, String gssName) throws AS400SecurityException, IOException, InterruptedException { try { ProxyReturnValue rv = connection_.callMethod (pxId_, "generateProfileToken", - new Class[] { ProfileTokenCredential.class, String.class, CredentialVault.class, String.class }, - new Object[] { profileToken, userId, vault, gssName }, - new boolean[] { true, false, false, false }, // indicate that 1st arg gets modified + new Class[] { ProfileTokenCredential.class, String.class, CredentialVault.class,char[].class ,String.class }, + new Object[] { profileToken, userId, vault, additionalAuthFactor, gssName }, + new boolean[] { true, false, false, false, false }, // indicate that 1st arg gets modified true); ProfileTokenCredential returnArg = (ProfileTokenCredential)rv.getArgument(0); - profileToken.setToken(returnArg.getToken(),false); + profileToken.setToken(returnArg.getToken()); return; } catch (InvocationTargetException e) diff --git a/src/main/java/com/ibm/as400/access/AS400ImplRemote.java b/src/main/java/com/ibm/as400/access/AS400ImplRemote.java index a908f935d..004feb3cb 100644 --- a/src/main/java/com/ibm/as400/access/AS400ImplRemote.java +++ b/src/main/java/com/ibm/as400/access/AS400ImplRemote.java @@ -56,6 +56,7 @@ import org.ietf.jgss.GSSCredential; import com.ibm.as400.security.auth.ProfileTokenCredential; +import com.ibm.as400.security.auth.ProfileTokenEnhancedInfo; /** * This is the functional implementation of the AS400Impl interface. While @@ -943,13 +944,13 @@ public void generateProfileToken(ProfileTokenCredential profileToken, String use throw AS400ImplRemote.returnSecurityException(reply.getRC(), null, userId_); } - // [0]=factor, [1]=verification ID, [2]=remote ip address - Object[] additonalAuthInfo = getAdditionalAuthInfo(profileToken, null); + // [0]=notUsed, [1]=verification ID, [2]=remote ip address + Object[] additionalAuthInfo = getAdditionalAuthInfo(profileToken, null); SignonGenAuthTokenRequestDS req2 = new SignonGenAuthTokenRequestDS( BinaryConverter.charArrayToByteArray(userIdentity.toCharArray()), profileToken.getTokenType(), profileToken.getTimeoutInterval(), serverLevel_, - (byte[])additonalAuthInfo[1], (byte[])additonalAuthInfo[2]); + (byte[])additionalAuthInfo[1], (byte[])additionalAuthInfo[2]); SignonGenAuthTokenReplyDS rep = (SignonGenAuthTokenReplyDS) signonServer_.sendAndReceive(req2); int rc = rep.getRC(); @@ -963,13 +964,22 @@ public void generateProfileToken(ProfileTokenCredential profileToken, String use userId_); } try { - boolean enhancedProfileToken = false; int vrm = (version_ != null) ? version_.getVersionReleaseModification() : getVRM(); if (vrm > 0x00070500 ) { - enhancedProfileToken = true; /* server always generates enhanced profile token */ + /* server always generates enhanced profile token */ + ProfileTokenEnhancedInfo enhancedInfo = new ProfileTokenEnhancedInfo((String) additionalAuthInfo[3], + (String) additionalAuthInfo[4], + profileToken.getRemotePort(), + profileToken.getLocalIPAddress(), + profileToken.getLocalPort()); + enhancedInfo.setEnhancedTokenCreated(true); + profileToken.setToken(rep.getProfileTokenBytes(), + enhancedInfo); + } else { + profileToken.setToken(rep.getProfileTokenBytes()); } - profileToken.setToken(rep.getProfileTokenBytes(), enhancedProfileToken); + profileToken.setTokenCreator(ProfileTokenCredential.CREATOR_SIGNON_SERVER); } catch (PropertyVetoException e) { @@ -987,7 +997,7 @@ public void generateProfileToken(ProfileTokenCredential profileToken, String use } @Override - public void generateProfileToken(ProfileTokenCredential profileToken, String userId, CredentialVault vault, String gssName) + public void generateProfileToken(ProfileTokenCredential profileToken, String userId, CredentialVault vault, char[] additionalAuthFactor, String gssName) throws AS400SecurityException, IOException, InterruptedException { signonConnect(); @@ -1128,13 +1138,13 @@ else if (passwordLevel_ < 4) if (Trace.isTraceOn()) Trace.log(Trace.DIAGNOSTIC, "AS400ImplRemote generating profile token for user: " + userId); - // [0]=factor, [1]=verification ID, [2]=remote ip address - Object[] additonalAuthInfo = getAdditionalAuthInfo(profileToken, null); + // [0]=unused, [1]=verification ID, [2]=remote ip address + Object[] additionalAuthInfo = getAdditionalAuthInfo(profileToken, null); AS400GenAuthTknDS req = new AS400GenAuthTknDS(userIdEbcdic, authenticationBytes, authScheme, profileToken.getTokenType(), profileToken.getTimeoutInterval(), serverLevel_, - (byte[])additonalAuthInfo[0], (byte[])additonalAuthInfo[1], (byte[])additonalAuthInfo[2]); + additionalAuthFactor_, (byte[])additionalAuthInfo[1], (byte[])additionalAuthInfo[2]); CredentialVault.clearArray(authenticationBytes); AS400GenAuthTknReplyDS rep = (AS400GenAuthTknReplyDS) signonServer_.sendAndReceive(req); @@ -1151,13 +1161,19 @@ else if (passwordLevel_ < 4) } try { - boolean enhancedProfileToken = false; int vrm = (version_ != null) ? version_.getVersionReleaseModification() : getVRM(); if (vrm > 0x00070500 ) { - enhancedProfileToken = true; /* server always generates enhanced profile token */ + ProfileTokenEnhancedInfo enhancedInfo = new ProfileTokenEnhancedInfo((String) additionalAuthInfo[3], + (String) additionalAuthInfo[4], + profileToken.getRemotePort(), + profileToken.getLocalIPAddress(), + profileToken.getLocalPort()); + enhancedInfo.setEnhancedTokenCreated(true); + profileToken.setToken(rep.getProfileTokenBytes(), + enhancedInfo ); + } else { + profileToken.setToken(rep.getProfileTokenBytes()); } - - profileToken.setToken(rep.getProfileTokenBytes(), enhancedProfileToken); profileToken.setTokenCreator(ProfileTokenCredential.CREATOR_SIGNON_SERVER); } catch (PropertyVetoException e) { Trace.log(Trace.ERROR, e); @@ -5124,7 +5140,15 @@ public void setAdditionalAuthenticationFactor(char[] additionalAuthFactor) additionalAuthFactor_ = (null != additionalAuthFactor && 0 < additionalAuthFactor.length ) ? (new String(additionalAuthFactor)).getBytes(StandardCharsets.UTF_8) : null; } - + /* + * Get the additional authentication info to be sent to the server as well as + * the information that needs to be associated with an enhanced profile token. + * The output is the following + * object[1] = byte[] verification id in UTF-8 + * object[2] = byte[] remoteIPAddress in UTF-8 + * object[3] = String verificationId + * object[4] = String remoteIpAddress + */ private Object[] getAdditionalAuthInfo(ProfileTokenCredential profileToken, Boolean aafIndicator) { Object[] authdata = new Object[] { null, null, null }; @@ -5139,16 +5163,27 @@ private Object[] getAdditionalAuthInfo(ProfileTokenCredential profileToken, Bool if (profileToken == null && (credVault_ instanceof ProfileTokenVault)) profileToken = ((ProfileTokenVault)credVault_).getProfileTokenCredential(); - if (profileToken != null) - { - String verificationID_s = profileToken.getVerificationID(); - authdata[1] = (verificationID_s != null && !verificationID_s.isEmpty()) ? verificationID_s.getBytes(StandardCharsets.UTF_8) : null; - - String clientIPAddress_s = profileToken.getRemoteIPAddress(); - authdata[2] = (clientIPAddress_s != null && !clientIPAddress_s.isEmpty()) ? clientIPAddress_s.getBytes(StandardCharsets.UTF_8) : null; - - // Verification ID will always be set to something. However, depending on where token was created, the client IP address - // may or may not be set. If creating the token and it is not set, use the IP address of the sign-on server. Thus, all tokens + if (profileToken != null) { + String verificationID_s = profileToken.getVerificationID(); + if (verificationID_s == null || verificationID_s.isEmpty() ) { + /* Make sure a default value is set */ + verificationID_s = ProfileTokenCredential.DEFAULT_VERIFICATION_ID; + } + authdata[1] = verificationID_s.getBytes(StandardCharsets.UTF_8); + authdata[3] = verificationID_s; + + String clientIPAddress_s = profileToken.getRemoteIPAddress(); + if (clientIPAddress_s != null && !clientIPAddress_s.isEmpty()) { + authdata[2] = clientIPAddress_s.getBytes(StandardCharsets.UTF_8); + authdata[4] = clientIPAddress_s; + } else { + authdata[2] = null; + authdata[4] = null; + } + + // Verification ID will always be set to something. However, depending on where + // token was created, the client IP address + // may or may not be set. If creating the token and it is not set, use the IP address of the sign-on server. Thus, all tokens // that signon server creates should have client IP address. if (authdata[2] == null) { @@ -5157,15 +5192,25 @@ private Object[] getAdditionalAuthInfo(ProfileTokenCredential profileToken, Bool { // We are creating token, try to set client IP address using sign-on server. clientIPAddress_s = signonServer_.getLocalAddress(); - authdata[2] = (clientIPAddress_s != null && !clientIPAddress_s.isEmpty()) ? clientIPAddress_s.getBytes(StandardCharsets.UTF_8) : null; + if (clientIPAddress_s != null && !clientIPAddress_s.isEmpty()) { + authdata[2] = clientIPAddress_s.getBytes(StandardCharsets.UTF_8); + authdata[4] = clientIPAddress_s; + } else { + authdata[2] = null; + authdata[4] = null; + } + try { profileToken.setRemoteIPAddress(clientIPAddress_s); } catch (PropertyVetoException e) { throw new InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION, e); } } - else if (profileToken.getTokenCreator() != ProfileTokenCredential.CREATOR_SIGNON_SERVER) + else if (profileToken.getTokenCreator() != ProfileTokenCredential.CREATOR_SIGNON_SERVER) { + authdata[2] = "*NOUSE".getBytes(StandardCharsets.UTF_8); + authdata[4] = "*NOUSE"; + } } } } diff --git a/src/main/java/com/ibm/as400/access/ProfileTokenImplNative.java b/src/main/java/com/ibm/as400/access/ProfileTokenImplNative.java index 45174ce4f..bd935f694 100644 --- a/src/main/java/com/ibm/as400/access/ProfileTokenImplNative.java +++ b/src/main/java/com/ibm/as400/access/ProfileTokenImplNative.java @@ -91,7 +91,7 @@ public void destroy() throws DestroyFailedException * If errors occur while generating the token. * */ - public byte[] generateToken(String uid, char[] pwd, int type, int timeoutInterval) throws RetrieveFailedException + public byte[] generateRawToken(String uid, char[] pwd, int type, int timeoutInterval) throws RetrieveFailedException { if (pwd.length > 10) { @@ -102,9 +102,8 @@ public byte[] generateToken(String uid, char[] pwd, int type, int timeoutInterva return nativeCreateTokenChar(uid.toUpperCase(), pwd, type, timeoutInterval); } - @Override - public byte[] generateToken(String uid, int pwdSpecialValue, int type, int timeoutInterval, boolean[] enhancedProfileToken) throws RetrieveFailedException { - return generateToken(uid, pwdSpecialValue, null, AuthenticationIndicator.APPLICATION_AUTHENTICATION, null, null, 0, null, 0, type, timeoutInterval, enhancedProfileToken); + public byte[] generateRawToken(String uid, int pwdSpecialValue, int type, int timeoutInterval,ProfileTokenEnhancedInfo enhancedInfo) throws RetrieveFailedException { + return generateRawToken(uid, pwdSpecialValue, AuthenticationIndicator.APPLICATION_AUTHENTICATION, type, timeoutInterval, enhancedInfo); } /** @@ -120,14 +119,12 @@ public byte[] generateToken(String uid, int pwdSpecialValue, int type, int timeo * @param localPort * @param type * @param timeoutInterval - * @param enhancedProfileToken -- input/output one element boolean array. On input if the first element is false, then an enhancedProfileToken will not be created. - * on output, the first element indicates if an enhancedProfileToken was created. + * @param enhancedInfo * @return * @throws RetrieveFailedException */ - private byte[] generateToken(String uid, int pwdSpecialValue, char[] additionalAuthenticationFactor, int authenticationIndicator, - String verificationId, String remoteIpAddress, int remotePort, String localIpAddress, int localPort, - int type, int timeoutInterval, boolean[] enhancedProfileToken) throws RetrieveFailedException + private byte[] generateRawToken(String uid, int pwdSpecialValue, int authenticationIndicator, + int type, int timeoutInterval, ProfileTokenEnhancedInfo enhancedInfo) throws RetrieveFailedException { // Convert password special value from int to string @@ -149,37 +146,33 @@ private byte[] generateToken(String uid, int pwdSpecialValue, char[] additionalA // Call native method and return token bytes, we rely on the fact this class is only called if running on AS400. - if (!enhancedProfileToken[0] || !ProfileTokenCredential.useEnhancedProfileTokens() || AS400.nativeVRM.getVersionReleaseModification() <= 0x00070500) { - enhancedProfileToken[0]=false; /* Let the caller know this is NOT an enhanced profile token */ + if ((! enhancedInfo.getCreateEnhancedIfPossible() )|| + (!ProfileTokenCredential.useEnhancedProfileTokens()) || + (AS400.nativeVRM.getVersionReleaseModification() <= 0x00070500)) { + enhancedInfo.setCreateEnhancedIfPossible(false); return nativeCreateTokenChar(uid.toUpperCase(), pwdSpecialVal.toCharArray(), type, timeoutInterval); } else { - enhancedProfileToken[0]=true; /* Let the caller know this is an enhanced profile token */ - return EnhancedProfileTokenImplNative.nativeCreateTokenSpecialPassword(uid.toUpperCase(), pwdSpecialVal.toCharArray(), - additionalAuthenticationFactor, authenticationIndicator, verificationId, remoteIpAddress, remotePort, localIpAddress, localPort, + byte[] token = EnhancedProfileTokenImplNative.nativeCreateTokenSpecialPassword(uid.toUpperCase(), pwdSpecialVal.toCharArray(), + null, authenticationIndicator, enhancedInfo.getVerificationID(), enhancedInfo.getRemoteIPAddress(), enhancedInfo.getRemotePort(), + enhancedInfo.getLocalIPAddress(), enhancedInfo.getLocalPort(), type, timeoutInterval); + enhancedInfo.setEnhancedTokenCreated(true); + return token; } } - @Override - public ProfileTokenCredential generateToken(String uid, int pwdSpecialValue, ProfileTokenCredential profileTokenCred) + public ProfileTokenCredential generateProfileToken(String uid, int pwdSpecialValue, ProfileTokenCredential profileTokenCred) throws RetrieveFailedException, PropertyVetoException { - boolean [] enhancedProfileToken = new boolean[1]; - enhancedProfileToken[0] = true; - byte[] token = generateToken(uid, pwdSpecialValue, - profileTokenCred.getAdditionalAuthenticationFactor(), + ProfileTokenEnhancedInfo enhancedInfo = new ProfileTokenEnhancedInfo(); + byte[] token = generateRawToken(uid, pwdSpecialValue, profileTokenCred.getAuthenticationIndicator(), - profileTokenCred.getVerificationID(), - profileTokenCred.getRemoteIPAddress(), - profileTokenCred.getRemotePort(), - profileTokenCred.getLocalIPAddress(), - profileTokenCred.getLocalPort(), profileTokenCred.getTokenType(), profileTokenCred.getTimeoutInterval(), - enhancedProfileToken); + enhancedInfo); try { - profileTokenCred.setToken(token, enhancedProfileToken[0]); + profileTokenCred.setToken(token, enhancedInfo); profileTokenCred.setTokenCreator(ProfileTokenCredential.CREATOR_NATIVE_API); } catch (PropertyVetoException e) @@ -198,14 +191,16 @@ public ProfileTokenCredential generateToken(String uid, int pwdSpecialValue, Pro } + @Override - public byte[] generateTokenExtended(String uid, char [] pwd, int type, int timeoutInterval, boolean[] isEnhancedToken) throws RetrieveFailedException { - return generateTokenExtended(uid, pwd, null, null, null, 0, null, 0, type, timeoutInterval,isEnhancedToken); - } + - private byte[] generateTokenExtended(String uid, char[] pwd, char[] additionalAuthenticationFactor, - String verificationId, String remoteIpAddress, int remotePort, String localIpAddress, int localPort, - int type, int timeoutInterval, boolean[] isEnhancedToken) throws RetrieveFailedException + public byte[] generateRawTokenExtended(String uid, + char[] pwd, + char[] additionalAuthenticationFactor, + int type, + int timeoutInterval, + ProfileTokenEnhancedInfo enhancedInfo) throws RetrieveFailedException { if (Trace.isTraceOn()) { String pwdInfo ="null"; @@ -213,15 +208,15 @@ private byte[] generateTokenExtended(String uid, char[] pwd, char[] additionalAu String aafInfo = "null"; if (additionalAuthenticationFactor != null) aafInfo="char["+additionalAuthenticationFactor.length+"]"; Trace.log(Trace.INFORMATION, this, "generateTokenExtended("+uid+","+pwdInfo+","+ - aafInfo+","+verificationId+","+remoteIpAddress+","+ - remotePort+","+localIpAddress+","+localPort+","+type+","+timeoutInterval+")"); + aafInfo+","+enhancedInfo.getVerificationID()+","+enhancedInfo.getRemoteIPAddress()+","+ + enhancedInfo.getRemotePort()+","+enhancedInfo.getLocalIPAddress()+","+enhancedInfo.getLocalPort()+","+type+","+timeoutInterval+")"); } AS400 sys = getCredential().getSystem(); // Determine if we are using enhanced profile tokens boolean useEPT = false; try { - useEPT = isEnhancedToken[0] && (ProfileTokenCredential.useEnhancedProfileTokens() && sys.getVRM() > 0x00070500); + useEPT = enhancedInfo.getCreateEnhancedIfPossible() && (ProfileTokenCredential.useEnhancedProfileTokens() && sys.getVRM() > 0x00070500); } catch (AS400SecurityException|IOException e) { Trace.log(Trace.ERROR, "Unexpected Exception: ", e); @@ -231,13 +226,15 @@ private byte[] generateTokenExtended(String uid, char[] pwd, char[] additionalAu // The API QSYGENPT requires all parameters to be non-null. boolean isAAFNull = (additionalAuthenticationFactor == null || additionalAuthenticationFactor.length == 0); if (isAAFNull) additionalAuthenticationFactor = new char[] { ' ' }; - + String verificationId = enhancedInfo.getVerificationID(); boolean isVfyIDNull = (verificationId == null || verificationId.length() == 0); if (isVfyIDNull) verificationId = " "; + String remoteIpAddress = enhancedInfo.getRemoteIPAddress(); boolean isRemoteIPNull = (remoteIpAddress == null || remoteIpAddress.length() == 0); if (isRemoteIPNull) remoteIpAddress = " "; + String localIpAddress = enhancedInfo.getLocalIPAddress(); boolean isLocalIPNull = (localIpAddress == null || localIpAddress.length() == 0); if (isLocalIPNull) localIpAddress = " "; @@ -298,7 +295,7 @@ private byte[] generateTokenExtended(String uid, char[] pwd, char[] additionalAu parmlist[14] = new ProgramParameter(BinaryConverter.intToByteArray((isRemoteIPNull) ? 0 : parmlist[13].getInputData().length)); // Input: Remote port - parmlist[15] = new ProgramParameter(BinaryConverter.intToByteArray(remotePort)); + parmlist[15] = new ProgramParameter(BinaryConverter.intToByteArray(enhancedInfo.getRemotePort())); // Input: Local IP address parmlist[16] = new ProgramParameter(CharConverter.stringToByteArray(sys, localIpAddress)); @@ -307,11 +304,11 @@ private byte[] generateTokenExtended(String uid, char[] pwd, char[] additionalAu parmlist[17] = new ProgramParameter(BinaryConverter.intToByteArray((isLocalIPNull) ? 0 : parmlist[16].getInputData().length)); // Input: Local port - parmlist[18] = new ProgramParameter(BinaryConverter.intToByteArray(remotePort)); + parmlist[18] = new ProgramParameter(BinaryConverter.intToByteArray(enhancedInfo.getRemotePort())); - isEnhancedToken[0] = true; + enhancedInfo.setEnhancedTokenCreated(true); } else { - isEnhancedToken[0] = false; + enhancedInfo.setEnhancedTokenCreated(false); } ProgramCall programCall = new ProgramCall(sys); @@ -344,28 +341,28 @@ private byte[] generateTokenExtended(String uid, char[] pwd, char[] additionalAu return profileToken; } - @Override - public ProfileTokenCredential generateTokenExtended(String uid, char[] password, + + public ProfileTokenCredential generateProfileTokenExtended(String uid, char[] password, + ProfileTokenCredential profileTokenCred) throws RetrieveFailedException, PropertyVetoException { + return generateProfileTokenExtended(uid, password, null, profileTokenCred); + } + + public ProfileTokenCredential generateProfileTokenExtended(String uid, char[] password, char[] additionalAuthenticationFactor, ProfileTokenCredential profileTokenCred) throws RetrieveFailedException, PropertyVetoException { - boolean[] enhancedProfileToken = new boolean[1]; - enhancedProfileToken[0] = true; - byte[] token = generateTokenExtended(uid, password, - profileTokenCred.getAdditionalAuthenticationFactor(), - profileTokenCred.getVerificationID(), - profileTokenCred.getRemoteIPAddress(), - profileTokenCred.getRemotePort(), - profileTokenCred.getLocalIPAddress(), - profileTokenCred.getLocalPort(), + ProfileTokenEnhancedInfo enhancedInfo = new ProfileTokenEnhancedInfo(profileTokenCred.getEnhancedInfo()); + byte[] token = generateRawTokenExtended(uid, + password, + additionalAuthenticationFactor, profileTokenCred.getTokenType(), profileTokenCred.getTimeoutInterval(), - enhancedProfileToken); + enhancedInfo); try { - profileTokenCred.setToken(token,enhancedProfileToken[0]); - profileTokenCred.setTokenCreator(ProfileTokenCredential.CREATOR_NATIVE_API); - } + profileTokenCred.setToken(token, enhancedInfo); + profileTokenCred.setTokenCreator(ProfileTokenCredential.CREATOR_NATIVE_API); + } catch (PropertyVetoException e) { try { diff --git a/src/main/java/com/ibm/as400/security/auth/AS400BasicAuthenticationCredential.java b/src/main/java/com/ibm/as400/security/auth/AS400BasicAuthenticationCredential.java index 81cae199c..0f02a7a98 100644 --- a/src/main/java/com/ibm/as400/security/auth/AS400BasicAuthenticationCredential.java +++ b/src/main/java/com/ibm/as400/security/auth/AS400BasicAuthenticationCredential.java @@ -156,9 +156,8 @@ public void initialize(AS400BasicAuthenticationPrincipal principal, char[] passw * */ public void initialize(AS400BasicAuthenticationPrincipal principal, char[] password, char[] additionalAuthFactor, - int authenticationIndicator, String verificationID, String remoteIPAddress, int remotePort, - String localIPAddress, int localPort, boolean isPrivate, boolean isReusable, boolean isRenewable, - int timeoutInterval) throws Exception; + int authenticationIndicator, boolean isPrivate, boolean isReusable, boolean isRenewable, + int timeoutInterval, ProfileTokenEnhancedInfo enhancedInfo) throws Exception; /** * Indicates whether the credential is considered private. diff --git a/src/main/java/com/ibm/as400/security/auth/DefaultProfileTokenProvider.java b/src/main/java/com/ibm/as400/security/auth/DefaultProfileTokenProvider.java index 29c5909d9..b4a45c115 100644 --- a/src/main/java/com/ibm/as400/security/auth/DefaultProfileTokenProvider.java +++ b/src/main/java/com/ibm/as400/security/auth/DefaultProfileTokenProvider.java @@ -321,7 +321,6 @@ public ProfileTokenCredential create() throws AS400SecurityException newToken.setTimeoutInterval(getTimeoutInterval()); newToken.setTokenType(getTokenType()); - newToken.setAdditionalAuthenticationFactor(additionalFactor_); newToken.setVerificationID(verificationID_); newToken.setRemoteIPAddress(remoteIPAddress_); diff --git a/src/main/java/com/ibm/as400/security/auth/ProfileTokenCredential.java b/src/main/java/com/ibm/as400/security/auth/ProfileTokenCredential.java index 191390840..8a7bbbfe9 100644 --- a/src/main/java/com/ibm/as400/security/auth/ProfileTokenCredential.java +++ b/src/main/java/com/ibm/as400/security/auth/ProfileTokenCredential.java @@ -208,17 +208,8 @@ public final class ProfileTokenCredential extends AS400Credential implements AS4 private int type_ = TYPE_SINGLE_USE; private int timeoutInterval_ = 3600; - private boolean enhancedProfileToken_ = false; // We need to know if an enhanced profile - // was created. If so, a different native swap - // method is used. - private String verificationID_ = DEFAULT_VERIFICATION_ID; - private String localIPAddress_ = null; - private String remoteIPAddress_ = null; - private int localPort_ = 0; - private int remotePort_ = 0; - private char[] additionalAuthenticationFactor_ = null; private int authenticationIndicator_ = AuthenticationIndicator.APPLICATION_AUTHENTICATION; - + private ProfileTokenEnhancedInfo enhancedInfo_ = new ProfileTokenEnhancedInfo(); private boolean noRefresh_ = false; @@ -326,43 +317,12 @@ public ProfileTokenCredential() * @param timeoutInterval The number of seconds to expiration, used as the * default value when the token is refreshed (1-3600). * - * @deprecated Use the constructor with the enhancedProfileToken parameter * */ - @Deprecated public ProfileTokenCredential(AS400 system, byte[] token, int tokenType, int timeoutInterval) { - this(system, token, tokenType, timeoutInterval, null, null, null, 0, null, 0, false); + this(system, token, tokenType, timeoutInterval, null, null, 0, null, 0); } - /** - * Constructs and initializes a ProfileTokenCredential object. - * - *

- * This method allows a credential to be constructed based on an existing token - * (i.e. previously created using the QSYGENPT system API). It is the - * responsibility of the application to ensure the token attributes, such as the - * tokenType and timeoutInterval, are consistent with the - * specified token value. - * - * @param system The system associated with the credential. - * - * @param token The actual bytes for the token as it exists on the IBM - * i system. - * - * @param tokenType The type of token provided. Possible types are defined - * as fields on this class: - *

- * - * @param timeoutInterval The number of seconds to expiration, used as the - * default value when the token is refreshed (1-3600). - */ - public ProfileTokenCredential(AS400 system, byte[] token, int tokenType, int timeoutInterval, boolean enhancedProfileToken) { - this(system, token, tokenType, timeoutInterval, null, null, null, 0, null, 0, enhancedProfileToken); - } /** * Constructs and initializes a ProfileTokenCredential object. @@ -373,6 +333,10 @@ public ProfileTokenCredential(AS400 system, byte[] token, int tokenType, int tim * responsibility of the application to ensure the token attributes, such as * tokenType and timeoutInterval, are consistent with the * specified token value. + * + * If the token was created as an enhanced profile token, then the + * verificationId, remoteIpAddress, remotePort, localIpAddress, localPort + * parameter must be specified. * * @param system The system associated with the credential. * @@ -390,10 +354,8 @@ public ProfileTokenCredential(AS400 system, byte[] token, int tokenType, int tim * @param timeoutInterval The number of seconds to expiration, used as the * default value when the token is refreshed (1-3600). * - * @param additionalAuthFactor The additional authentication factor - * for the user - * - * @param verificationID The verification ID is the label that + * @param verificationID For an enhanced profile token, the + * verification ID is the label that * identifies the specific application, * service, or action associated with the * profile handle request. This value must @@ -410,54 +372,63 @@ public ProfileTokenCredential(AS400 system, byte[] token, int tokenType, int tim * be the DCM application ID or a similar * value that identifies the application * or service. + * If an enhance profile token is not used, + * then null should be passed. * - * @param remoteIPAddress If the API is used by a server to + * @param remoteIPAddress For an enhanced profile token, + * if the API is used by a server to * provide access to a the system, the * remote IP address should be obtained * from the socket connection (i.e. using * Socket.getInetAddress). Otherwise, null * should be passed. * - * @param remotePort If the API is used by a server to + * @param remotePort For an enhanced profile token, + * if the API is used by a server to * provide access to a the system, the * remote port should be obtained from the * socket connection (i.e. using * Socket.getPort ). Otherwise, use 0 if * there is not an associated connection. * - * @param localIPAddress If the API is used by a server to + * @param localIPAddress For an enhanced profile token, + * if the API is used by a server to * provide access to a the system, the * local IP address should be obtained * from the socket connection (i.e. using * Socket.getLocalAddress). Otherwise, * null should be passed. * - * @param localPort If the API is used by a server to + * @param localPort For an enhanced profile token, + * if the API is used by a server to * provide access to a the system, the * local port should be obtained from the * socket connection * (Socket.getLocalPort). Otherwise, use 0 * if there is not an associated * connection. - * @param enhancedProfileToken Indicates if the token is an enhanced profile token. */ public ProfileTokenCredential(AS400 system, byte[] token, int tokenType, int timeoutInterval, - char[] additionalAuthFactor, String verificationID, - String remoteIPAddress, int remotePort, String localIPAddress, int localPort, - boolean enhancedProfileToken) + String verificationID, + String remoteIPAddress, int remotePort, String localIPAddress, int localPort) { this(); try { setSystem(system); - setToken(token, enhancedProfileToken); + + if (verificationID != null && + remoteIPAddress != null && + localIPAddress != null ) { + enhancedInfo_.initialize(true, verificationID, remoteIPAddress, remotePort, localIPAddress, localPort); + setToken(token, enhancedInfo_); + + } else { + setToken(token); + } setTokenType(tokenType); setTimeoutInterval(timeoutInterval); - setAdditionalAuthenticationFactor(additionalAuthFactor); - setVerificationID(verificationID); - setRemoteIPAddress(remoteIPAddress); - setLocalIPAddress(localIPAddress); - setRemotePort(remotePort); - setLocalPort(localPort); + + } catch (PropertyVetoException pve) { AuthenticationSystem.handleUnexpectedException(pve); } @@ -635,15 +606,13 @@ public void initialize(AS400BasicAuthenticationPrincipal principal, String passw public void initialize(AS400BasicAuthenticationPrincipal principal, char[] password, boolean isPrivate, boolean isReusable, boolean isRenewable, int timeoutInterval) throws Exception { - initialize(principal, password, additionalAuthenticationFactor_, authenticationIndicator_, - verificationID_, remoteIPAddress_, remotePort_, localIPAddress_, localPort_, - isPrivate, isReusable, isRenewable, timeoutInterval); + initialize(principal, password, null, authenticationIndicator_, + isPrivate, isReusable, isRenewable, timeoutInterval, enhancedInfo_); } - @Override + public void initialize(AS400BasicAuthenticationPrincipal principal, char[] password, char[] additionalAuthFactor, int authenticationIndicator, - String verificationID, String remoteIPAddress, int remotePort, String localIPAddress, int localPort, - boolean isPrivate, boolean isReusable, boolean isRenewable, int timeoutInterval) throws Exception + boolean isPrivate, boolean isReusable, boolean isRenewable, int timeoutInterval, ProfileTokenEnhancedInfo enhancedInfo) throws Exception { if (Trace.isTraceOn()) { @@ -652,14 +621,16 @@ public void initialize(AS400BasicAuthenticationPrincipal principal, char[] passw .append(principal.toString()).append(", isPrivate == ").append(isPrivate) .append(", isReusable == ").append(isReusable).append(", isRenewable == ") .append(isRenewable).append(", timeoutInterval == ").append(timeoutInterval) - .append(", verificationID == ").append(verificationID) - .append(", localIPAddress == ").append(localIPAddress) - .append(", localPort == ").append(localPort) - .append(", remoteIPAddress == ").append(remoteIPAddress) - .append(", remotePort == ").append(remotePort) + .append(", verificationID == ").append(enhancedInfo.getVerificationID()) + .append(", localIPAddress == ").append(enhancedInfo.getLocalIPAddress()) + .append(", localPort == ").append(enhancedInfo.getLocalPort()) + .append(", remoteIPAddress == ").append(enhancedInfo.getRemoteIPAddress()) + .append(", remotePort == ").append(enhancedInfo.getRemotePort()) .toString()); } - + if (enhancedInfo_ != enhancedInfo) { + enhancedInfo_ = enhancedInfo; + } // Validate parameters if (isRenewable && !isReusable) { @@ -686,25 +657,23 @@ else if (isReusable) else setTokenType(TYPE_SINGLE_USE); - setAdditionalAuthenticationFactor(additionalAuthFactor); setAuthenticationIndicator(authenticationIndicator); - setVerificationID(verificationID); - setRemoteIPAddress(remoteIPAddress); - setLocalIPAddress(localIPAddress); - setRemotePort(remotePort); - setLocalPort(localPort); + setEnhancedInfo(enhancedInfo); // Generate the token setTokenExtended(pr, password); } - @Override + public void setEnhancedInfo(ProfileTokenEnhancedInfo enhancedInfo) { + enhancedInfo_ = new ProfileTokenEnhancedInfo(enhancedInfo); + } + + @Override void invalidateProperties() { super.invalidateProperties(); token_ = null; - verificationID_ = null; - localIPAddress_ = null; + enhancedInfo_.reset(); } @Override @@ -727,10 +696,12 @@ public boolean isReusable() { * value in memory. * * @param bytes The token bytes. - * @param enchancedProfileToken. set to true if enhancedProfile token */ - private void primitiveSetToken(byte[] bytes, boolean enhancedProfileToken) { - enhancedProfileToken_ = enhancedProfileToken; + void primitiveSetToken(byte[] bytes, boolean enhancedProfileToken ) { + if (!enhancedProfileToken) { + /* reset the enhanced values */ + enhancedInfo_.reset(); + } token_ = encode(addr_, mask_, bytes); } @@ -818,7 +789,7 @@ public synchronized void refresh(int type, int timeoutInterval) throws AS400Secu byte[] bytes = ((ProfileTokenImpl) getImpl()).refresh(type, timeoutInterval); // The token type is the same as before. The refresh doesn't need // to know an enhanced profile token is being used. - primitiveSetToken(bytes, enhancedProfileToken_); + primitiveSetToken(bytes, enhancedInfo_.wasEnhancedTokenCreated()); type_ = type; timeoutInterval_ = timeoutInterval; @@ -904,13 +875,31 @@ public void setTimeoutInterval(int seconds) throws PropertyVetoException * due to the current state. * */ -@Deprecated - public synchronized void setToken(byte[] bytes) throws PropertyVetoException { - setToken(bytes, false); + public synchronized void setToken(byte[] bytes) throws PropertyVetoException + { + + // Validate state + validatePropertyChange("token"); + + // Validate parms + if (bytes == null) { + Trace.log(Trace.ERROR, "Token byte array is null"); + throw new ExtendedIllegalArgumentException("bytes", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID); + } + + if (bytes.length != TOKEN_LENGTH) { + Trace.log(Trace.ERROR, "Token of length " + bytes.length + " not valid "); + throw new ExtendedIllegalArgumentException("bytes", ExtendedIllegalArgumentException.LENGTH_NOT_VALID); + } + + byte[] old = getToken(); + fireVetoableChange("token", old, bytes); + primitiveSetToken(bytes, false); + firePropertyChange("token", old, bytes); } /** - * Sets the actual bytes for the token as it exists on the IBM i system. + * Sets the actual bytes for the enhanced profile token as it exists on the IBM i system. * *

* This method allows a credential to be constructed based on an existing token @@ -918,6 +907,7 @@ public synchronized void setToken(byte[] bytes) throws PropertyVetoException { * responsibility of the application to ensure the token attributes, such as the * tokenType and timeoutInterval, are consistent with the * specified token value. + * This method should only be called if the token is an enhanced profile token. * *

* This property cannot be changed once a request initiates a connection for the @@ -925,8 +915,6 @@ public synchronized void setToken(byte[] bytes) throws PropertyVetoException { * * @param bytes The token bytes. * - * @param enhancedProfileToken Indicates if the token is an enhancedProfileToken - * * @exception PropertyVetoException If the change is vetoed. * * @exception ExtendedIllegalArgumentException If the provided value is not the @@ -936,8 +924,9 @@ public synchronized void setToken(byte[] bytes) throws PropertyVetoException { * due to the current state. * */ - public synchronized void setToken(byte[] bytes, boolean enhancedProfileToken) throws PropertyVetoException + public synchronized void setToken(byte[] bytes, ProfileTokenEnhancedInfo enhancedInfo) throws PropertyVetoException { + // Validate state validatePropertyChange("token"); @@ -954,10 +943,12 @@ public synchronized void setToken(byte[] bytes, boolean enhancedProfileToken) th byte[] old = getToken(); fireVetoableChange("token", old, bytes); - primitiveSetToken(bytes, enhancedProfileToken); + enhancedInfo_ = enhancedInfo; + primitiveSetToken(bytes, true); firePropertyChange("token", old, bytes); } + /** * Sets the token bytes based on the provided principal and password. * @@ -1091,10 +1082,9 @@ public void setToken(String name, String password) throws PropertyVetoException, // Generate and set the token value char[] passwordChars = password.toCharArray(); byte[] newToken; - boolean[] extendedProfileToken = new boolean[1]; - extendedProfileToken[0]=true; - newToken = impl.generateTokenExtended(name, passwordChars, getTokenType(), getTimeoutInterval(), extendedProfileToken); - setToken(newToken,extendedProfileToken[0]); + ProfileTokenEnhancedInfo enhancedInfo = new ProfileTokenEnhancedInfo(); + newToken = impl.generateRawTokenExtended(name, passwordChars, null, getTokenType(), getTimeoutInterval(), enhancedInfo); + primitiveSetToken(newToken,enhancedInfo.wasEnhancedTokenCreated()); Arrays.fill(passwordChars,'\0'); // If successful, all defining attributes are now set. @@ -1252,7 +1242,7 @@ public void setToken(String name, int passwordSpecialValue) throws PropertyVetoE // Generate and set the token value if (Trace.isTraceOn()) Trace.log(Trace.DIAGNOSTIC, "ProfileTokenCredential generating profile token w/special value for user: " + name); - impl.generateToken(name, passwordSpecialValue, this); + impl.generateProfileToken(name, passwordSpecialValue, this); // If successful, all defining attributes are now set. Set the impl for // subsequent references. @@ -1454,7 +1444,7 @@ public void setTokenExtended(String name, char[] password) throws PropertyVetoEx ProfileTokenImpl impl = (ProfileTokenImpl)getImplPrimitive(); // Generate and set the token value - impl.generateTokenExtended(name, password, this); + impl.generateProfileTokenExtended(name, password, null, this); // If successful, all defining attributes are now set. // Set the impl for subsequent references. @@ -1464,6 +1454,90 @@ public void setTokenExtended(String name, char[] password) throws PropertyVetoEx fireCreated(); } + + /** + * Sets the token bytes based on the provided user profile and password. + * + *

+ * The system property must be set prior to invoking this method. + * + *

+ * If successful, this method results in a new token being created on the IBM i + * system. The new token is generated using the previously established + * tokenType and timeoutInterval settings. + * + *

+ * This property cannot be changed once a request initiates a connection for the + * object to the IBM i system (for example, refresh). + * + * @param name The name of the user profile for which the token is to be + * generated. + * + * @param password The user profile password. + * + * @param additionalAuthenticationFactore The additional authentication factor used to authenticate. + * + * @exception AS400SecurityException If an IBM i system security or + * authentication error occurs. + * + * @exception PropertyVetoException If the change is vetoed. + * + * @exception ExtendedIllegalArgumentException If errors occur during parameter + * validation. + * + * @exception ExtendedIllegalStateException If the token cannot be + * initialized due to the current + * state. + * + */ + public void setTokenExtended(String name, char[] password, char[] additionalAuthenticationFactor) throws PropertyVetoException, AS400SecurityException + { + if (Trace.isTraceOn()) { + String passwordInfo = ""; + if (password != null) { + passwordInfo = "char["+password.length+"]"; + } else { + passwordInfo = "null"; + } + String nameInfo = ""; + if (name != null) nameInfo=name; + else nameInfo = "null"; + Trace.log(Trace.INFORMATION, "setTokenExtended("+nameInfo+","+passwordInfo+")"); + } + // Validate state + validatePropertySet("system", getSystem()); + + // Validate name and password parameters + if (name == null) { + Trace.log(Trace.ERROR, "User profile name is null"); + throw new ExtendedIllegalArgumentException("name", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID); + } + + if (name.length() > MAX_USERPROFILE_LENGTH) { + Trace.log(Trace.ERROR, "User profile name exceeds maximum allowed length"); + throw new ExtendedIllegalArgumentException("name", ExtendedIllegalArgumentException.LENGTH_NOT_VALID); + } + + if (password == null) { + Trace.log(Trace.ERROR, "User profile password is null"); + throw new ExtendedIllegalArgumentException("password", ExtendedIllegalArgumentException.PARAMETER_VALUE_NOT_VALID); + } + + // Instantiate a new impl but do not yet set as the default impl_ + ProfileTokenImpl impl = (ProfileTokenImpl)getImplPrimitive(); + + // Generate and set the token value + impl.generateProfileTokenExtended(name, password, additionalAuthenticationFactor, this); + + // If successful, all defining attributes are now set. + // Set the impl for subsequent references. + setImpl(impl); + + // Indicate that a new token was created. + fireCreated(); + } + + /** * Sets the type of token. * @@ -1575,36 +1649,6 @@ public static boolean useEnhancedProfileTokens() { return useEnhancedProfileTokens_; } - /** - * Set the additional authentication factor to be used when generating the profile token. - * Note that a copy of the value will be made and stored in the object. - * - * @param additionalAuthenticationFactor The additional authentication factor. - * @throws PropertyVetoException - */ - public void setAdditionalAuthenticationFactor(char[] additionalAuthenticationFactor) throws PropertyVetoException - { - validatePropertyChange("additionalAuthenticationFactor"); - - if (additionalAuthenticationFactor != null && additionalAuthenticationFactor.length > ProfileTokenCredential.MAX_ADDITIONALAUTHENTICATIONFACTOR_LENGTH) - throw new ExtendedIllegalArgumentException("additionalAuthenticationFactor", ExtendedIllegalArgumentException.LENGTH_NOT_VALID); - - char[] old = additionalAuthenticationFactor_; - fireVetoableChange("additionalAuthenticationFactor", old, additionalAuthenticationFactor); - additionalAuthenticationFactor_ = (additionalAuthenticationFactor != null) - ? Arrays.copyOf(additionalAuthenticationFactor, additionalAuthenticationFactor.length) : null; - firePropertyChange("additionalAuthenticationFactor", old, additionalAuthenticationFactor); - } - - /** - * Returns a copy of the additional authentication factor. - * - * @return The additional authentication factor. The value can be null if it has not been set. - */ - public char[] getAdditionalAuthenticationFactor() { - return (additionalAuthenticationFactor_ != null) - ? Arrays.copyOf(additionalAuthenticationFactor_, additionalAuthenticationFactor_.length) : null; - } /** * Set the verification ID to be associated with the profile token. The @@ -1621,24 +1665,25 @@ public void setVerificationID(String verificationID) throws PropertyVetoExceptio if (verificationID != null && verificationID.length() > ProfileTokenCredential.MAX_VERIFICATIONID_LENGTH) throw new ExtendedIllegalArgumentException("verificationID", ExtendedIllegalArgumentException.LENGTH_NOT_VALID); - String old = verificationID_; + String old = enhancedInfo_.getVerificationID(); fireVetoableChange("verificationID", old, verificationID); - verificationID_ = verificationID; + enhancedInfo_.setVerificationID(verificationID); firePropertyChange("verificationID", old, verificationID); } /** - * Returns the verification ID associated with the profile token. + * Returns the verification ID associated with an enhanced profile token. * - * @return The verification ID. If the value is not set to a value, the default verification ID of + * @return The verification ID. If this is not an enhanced profile token then "*NOUSE" is returned. + * If the value is not set to a value, the default verification ID of * "QIBM_OS400_JT400" will be returned. */ public String getVerificationID() { if (!useEnhancedProfileTokens_) return "*NOUSE"; - - return (verificationID_ != null) ? verificationID_ : DEFAULT_VERIFICATION_ID; + String verificationID = enhancedInfo_.getVerificationID(); + return (verificationID != null) ? verificationID : DEFAULT_VERIFICATION_ID; } /** @@ -1654,10 +1699,9 @@ public void setLocalIPAddress(String localIPAddress) throws PropertyVetoExceptio if (localIPAddress != null && localIPAddress.length() > ProfileTokenCredential.MAX_IPADDRESS_LENGTH) throw new ExtendedIllegalArgumentException("localIPAddress", ExtendedIllegalArgumentException.LENGTH_NOT_VALID); - - String old = localIPAddress_; - fireVetoableChange("localIPAddress", old, localIPAddress); - localIPAddress_ = localIPAddress; + String old = enhancedInfo_.getLocalIPAddress(); + fireVetoableChange("localIPAddress", old, localIPAddress ); + enhancedInfo_.setLocalIPAddress(localIPAddress); firePropertyChange("localIPAddress", old, localIPAddress); } @@ -1667,7 +1711,7 @@ public void setLocalIPAddress(String localIPAddress) throws PropertyVetoExceptio * @return The client IP address. The value can be null if it has not been set. */ public String getLocalIPAddress() { - return localIPAddress_; + return enhancedInfo_.getLocalIPAddress(); } /** @@ -1684,9 +1728,9 @@ public void setRemoteIPAddress(String remoteIPAddress) throws PropertyVetoExcept if (remoteIPAddress != null && remoteIPAddress.length() > ProfileTokenCredential.MAX_IPADDRESS_LENGTH) throw new ExtendedIllegalArgumentException("remoteIPAddress", ExtendedIllegalArgumentException.LENGTH_NOT_VALID); - String old = remoteIPAddress_; + String old = enhancedInfo_.getRemoteIPAddress(); fireVetoableChange("remoteIPAddress", old, remoteIPAddress); - remoteIPAddress_ = remoteIPAddress; + enhancedInfo_.setRemoteIPAddress( remoteIPAddress); firePropertyChange("remoteIPAddress", old, remoteIPAddress); } @@ -1696,7 +1740,7 @@ public void setRemoteIPAddress(String remoteIPAddress) throws PropertyVetoExcept * @return The remote IP address. The value can be null if it has not been set. */ public String getRemoteIPAddress() { - return useEnhancedProfileTokens_ ? remoteIPAddress_ : "*NOUSE"; + return useEnhancedProfileTokens_ ? enhancedInfo_.getRemoteIPAddress() : "*NOUSE"; } /** @@ -1713,9 +1757,9 @@ public void setRemotePort(int remotePort) throws PropertyVetoException if (remotePort < 0 || remotePort > 65535) throw new ExtendedIllegalArgumentException("remotePort", ExtendedIllegalArgumentException.PATH_NOT_VALID); - int old = remotePort; + int old = enhancedInfo_.getRemotePort(); fireVetoableChange("remotePort", old, remotePort); - remotePort_ = remotePort; + enhancedInfo_.setRemotePort(remotePort); firePropertyChange("remotePort", old, remotePort); } @@ -1725,7 +1769,7 @@ public void setRemotePort(int remotePort) throws PropertyVetoException * @return The remote port. A value of 0 indicates that the remote port is not specified. */ public int getRemotePort() { - return remotePort_; + return enhancedInfo_.getRemotePort(); } /** @@ -1742,9 +1786,9 @@ public void setLocalPort(int localPort) throws PropertyVetoException if (localPort < 0 || localPort > 65535) throw new ExtendedIllegalArgumentException("localPort", ExtendedIllegalArgumentException.PATH_NOT_VALID); - int old = localPort; + int old = enhancedInfo_.getLocalPort(); fireVetoableChange("localPort", old, localPort); - localPort_ = localPort; + enhancedInfo_.setLocalPort(localPort); firePropertyChange("localPort", old, localPort); } @@ -1754,7 +1798,7 @@ public void setLocalPort(int localPort) throws PropertyVetoException * @return The local port. A value of 0 indicates that the local port is not specified. */ public int getLocalPort() { - return localPort_; + return enhancedInfo_.getLocalPort(); } /** @@ -1865,8 +1909,12 @@ boolean isTokenSet() { * @return */ public boolean isEnhancedProfileToken() { - return enhancedProfileToken_; + return enhancedInfo_.wasEnhancedTokenCreated(); + } + + public ProfileTokenEnhancedInfo getEnhancedInfo() { + return enhancedInfo_; } - + } diff --git a/src/main/java/com/ibm/as400/security/auth/ProfileTokenEnhancedInfo.java b/src/main/java/com/ibm/as400/security/auth/ProfileTokenEnhancedInfo.java new file mode 100644 index 000000000..1460d3cda --- /dev/null +++ b/src/main/java/com/ibm/as400/security/auth/ProfileTokenEnhancedInfo.java @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// JTOpen (IBM Toolbox for Java - OSS version) +// +// Filename: ProfileTokenCredential.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-2003 International Business Machines Corporation and +// others. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +package com.ibm.as400.security.auth; + +import java.io.Serializable; + +/** + * The ProfileTokenEnhandeInfo class represents the additional information used + * by an enhanced profile token. + * + * * + */ +public final class ProfileTokenEnhancedInfo implements Serializable +{ + private static final long serialVersionUID = 1L; + private boolean enhancedTokenCreated_ = false; + private boolean createEnhancedIfPossible_ = true; + + private String verificationID_ = null; + private String remoteIPAddress_ = null; + private int remotePort_ = 0; + private String localIPAddress_ = null; + private int localPort_ = 0; + + public ProfileTokenEnhancedInfo() { + } + + public ProfileTokenEnhancedInfo(String verificationID, String remoteIPAddress, int remotePort, + String localIPAddress, int localPort) { + initialize(false, verificationID, remoteIPAddress, remotePort, localIPAddress, localPort); + } + + + public ProfileTokenEnhancedInfo(ProfileTokenEnhancedInfo enhancedInfo) { + initialize(false, + enhancedInfo.verificationID_, + enhancedInfo.remoteIPAddress_, + enhancedInfo.remotePort_, + enhancedInfo.localIPAddress_, + enhancedInfo.localPort_); + } + + public String getVerificationID() { return verificationID_; } + public String getRemoteIPAddress() { return remoteIPAddress_; } + public int getRemotePort() { return remotePort_; } + public String getLocalIPAddress() { return localIPAddress_; } + public int getLocalPort() { return localPort_; } + public boolean getCreateEnhancedIfPossible() { return createEnhancedIfPossible_;} + + public void setVerificationID(String verificationID ) { verificationID_ = verificationID; } + public void setRemoteIPAddress(String remoteIPAddress) { remoteIPAddress_ = remoteIPAddress; } + public void setRemotePort(int remotePort ) { remotePort_ = remotePort; } + public void setLocalIPAddress(String localIPAddress ) { localIPAddress_ = localIPAddress; } + public void setLocalPort(int localPort ) { localPort_ = localPort; } + public void setCreateEnhancedIfPossible(boolean ifPossible) { createEnhancedIfPossible_ = ifPossible;} + public boolean wasEnhancedTokenCreated() { return enhancedTokenCreated_; } + public void setEnhancedTokenCreated(boolean enhancedTokenCreated) { enhancedTokenCreated_ = enhancedTokenCreated; } + + public void reset() { + enhancedTokenCreated_ = false; + verificationID_ = null; + localIPAddress_ = null; + remoteIPAddress_ = null; + localPort_ = 0; + remotePort_ = 0; + } + + public void initialize(boolean enhancedTokenCreated, String verificationID, String remoteIPAddress, int remotePort, + String localIPAddress, int localPort) { + enhancedTokenCreated_ = enhancedTokenCreated; + verificationID_ = verificationID; + remoteIPAddress_ = remoteIPAddress; + remotePort_ = remotePort; + localIPAddress_ = localIPAddress; + localPort_ = localPort; + + } + + + + +} diff --git a/src/main/java/com/ibm/as400/security/auth/ProfileTokenImpl.java b/src/main/java/com/ibm/as400/security/auth/ProfileTokenImpl.java index bedb12b86..0aadbae44 100644 --- a/src/main/java/com/ibm/as400/security/auth/ProfileTokenImpl.java +++ b/src/main/java/com/ibm/as400/security/auth/ProfileTokenImpl.java @@ -32,44 +32,6 @@ public interface ProfileTokenImpl extends AS400CredentialImpl */ public final static String PW_STR_NOPWDCHK = "*NOPWDCHK "; - - /** - * Generates and returns a new profile token based on the provided information - * using a password special value. - * - * @param uid The name of the user profile for which the token is to - * be generated. - * - * @param pwdSpecialValue A password special value. Possible types are defined - * as fields on the ProfileTokenCredential class: - *

- *

- * - * @param type The type of token. Possible types are defined as - * fields on the ProfileTokenCredential class: - *

- *

- * - * @param timeoutInterval The number of seconds to expiration. - * - * @param enhancedProfileToken Input / output. On input, if true then an enhancedProfileToken will be generated if possible. - * On output, true if an enhancedProfileToken was generated. - * - * @return The token bytes. - * - * @exception RetrieveFailedException If errors occur while generating the - * token. - * - */ - byte[] generateToken(String uid, int pwdSpecialValue, int type, int timeoutInterval, boolean[] enhancedProfileToken) throws RetrieveFailedException; - /** * Generates and returns a new profile token based on the provided information * using a password special value. @@ -96,12 +58,13 @@ public interface ProfileTokenImpl extends AS400CredentialImpl * @exception PropertyVetoException If errors occur while setting the profile token credential. * */ - ProfileTokenCredential generateToken(String uid, int pwdSpecialValue, ProfileTokenCredential profileTokenCred) + ProfileTokenCredential generateProfileToken(String uid, int pwdSpecialValue, ProfileTokenCredential profileTokenCred) throws RetrieveFailedException, PropertyVetoException; + /** * Generates and returns a new profile token based on the provided information - * using a password string. + * using a password string and an additional authentication fatore * * @param uid The name of the user profile for which the token is to * be generated. @@ -109,6 +72,8 @@ ProfileTokenCredential generateToken(String uid, int pwdSpecialValue, ProfileTok * @param pwd The user profile password (encoded). Special values * are not supported by this method. * + * @param additionalAuthenticationFactor The additional authentication factor + * * @param type The type of token. Possible types are defined as * fields on the ProfileTokenCredential class: *