All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.ibm.as400.access.CredentialVault Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename:  CredentialVault.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) 2009-2009 International Business Machines Corporation and
// others.  All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

import java.io.Serializable;

/**
 * A vault which holds an authentication credential to one or more IBM i host servers.
 * The type of credential stored varies, depending on the sub-class implementation.
 */
abstract class CredentialVault implements Cloneable, Serializable
{
  static final boolean PASSWORD_TRACE = false;

  // Random number generator for seeds.
  static java.util.Random rng = new java.util.Random();

  /** The credential, which is always encoded before being stored */
  /* Note:  This may be null if this is a ProfileToken that can be refreshed */
  /* Any subclass that does not set this must implement the following methods */
  /*  clone 
   *  isEmpty
   *  getClearCredential
   *  storeEncodedUsingExternalSeeds
   *  storeEncodedUsingInternalSeeds
   *  disposeOfCredential
   *  decode
   *  trace
   */
  
  protected byte[] encodedCredential_;

  /**
   * A credential is encoded with an algorithm that requires a set of seeds.
   * These seeds can be generated internally or they can be provided
   * by an external source.  If they are provided by an external source,
   * then seeds to decode the credential must be provided for us to decode it.
   */
  private boolean externalSeedsWereUsed_;

  /**
   * Constructs a CredentialVault object that does not contain a credential.
   */
  protected CredentialVault() {
    this(null);
  }

  /**
   * Constructs a CredentialVault object that contains the provided credential.
   *
   * @param credential The credential to store within the vault
   */
  protected CredentialVault(byte[] credential)
  {
    if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "CredentialVault(byte[] credential) called");

    if (credential == null) {
      encodedCredential_ = null;
    }
    else {
      // Never store the credential "as is"
      encodedCredential_ = store(credential);
    }
    // We have encoded the credential using internally generated seeds.
    externalSeedsWereUsed_ = false;
  }

  /**
   * Creates and returns a copy of the credential vault.  Implementation of this
   * method is specific to the type of credential vault being copied.
   * Some vaults will copy the credential itself into the new vault,
   * others will not.
   *
   * @return A newly created credential vault that is a copy of this one
   */
  public Object clone()
  {
    if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "CredentialVault clone called");

    CredentialVault vaultClone;
    try {
      vaultClone = (CredentialVault)super.clone();
    }
    catch (CloneNotSupportedException e) {
      Trace.log(Trace.ERROR, e);
      throw new InternalErrorException(InternalErrorException.UNEXPECTED_EXCEPTION, e);
    }
    synchronized(this)
    {
      if (encodedCredential_ != null)
      {
        byte[] credentialCopy = new byte[encodedCredential_.length];
        System.arraycopy(encodedCredential_, 0, credentialCopy, 0, credentialCopy.length);
        vaultClone.encodedCredential_ = credentialCopy;
      }
      vaultClone.externalSeedsWereUsed_ = externalSeedsWereUsed_;
    }
    return vaultClone;
  }

  /**
   * Retrieves the type of credential stored in the vault.
   *
   * @return The type of credential stored in the vault.
   * Possible values are:
   * 
    *
  • AS400.AUTHENTICATION_SCHEME_PASSWORD *
  • AS400.AUTHENTICATION_SCHEME_GSS_TOKEN *
  • AS400.AUTHENTICATION_SCHEME_PROFILE_TOKEN *
  • AS400.AUTHENTICATION_SCHEME_IDENTITY_TOKEN *
      */ protected abstract int getType(); /** * Purges the credential inside the vault. All resources consumed by the * credential vault are freed. If this method is invoked and the vault is * already empty, the method simply returns and no exception is thrown. */ protected synchronized void empty() { disposeOfCredential(); } // Cleans up the credential information. protected void finalize() throws Throwable { try { empty(); } finally { super.finalize(); } } /** * Queries the vault to see if it contains a credential. * * @return true if the vault does not contain a credential, false if it does */ protected boolean isEmpty() { return (encodedCredential_ == null); } /** * Retrieves the unencoded credential from the vault. Note that the * credential will only be "clear" in the sense that any encoding done * internally by the CredentialVault is removed. Any encoding done * externally to the credential will remain intact. * * @return The unencoded credential from the vault. */ protected synchronized byte[] getClearCredential() { if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "CredentialVault.getClearCredential called"); // Make sure we have a credential to give them. if (isEmpty()) { Trace.log(Trace.ERROR, "Credential vault is empty"); throw new ExtendedIllegalStateException("credential", ExtendedIllegalStateException.PROPERTY_NOT_SET); } return resolve(encodedCredential_); } /** * Store the credential, after encoding using the provided external seeds. * Any internal encoding previously done by the CredentialVault will be undone * prior to encoding the credential with the provided external seeds. * * @param firstSeed The first seed to use for encoding * @param secondSeed The second seed to use for encoding */ protected synchronized void storeEncodedUsingExternalSeeds(byte[] firstSeed, byte[] secondSeed) { if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "CredentialVault.storedEncodedUsingExternalSeeds called"); // If the credential was already encoded using externally-supplied seeds, then we must not encode it again. if (externalSeedsWereUsed_) { Trace.log(Trace.ERROR, "Called storeEncodedUsingExternalSeeds() when credential was already encoded using external seeds."); throw new InternalErrorException(InternalErrorException.UNKNOWN); } else { externalSeedsWereUsed_ = true; } if (!isEmpty()) { encodedCredential_ = CredentialVault.encode(firstSeed, secondSeed, getClearCredential()); } } /** * Store the credential, after encoding using internally generated seeds. * The credential is first decoded using the provided external seeds. * The decoded credential will then be encoded using internally generated seeds * and remain in the vault. * * @param firstSeed The first seed to use for decoding * @param secondSeed The second seed to use for decoding */ protected synchronized void storeEncodedUsingInternalSeeds(byte[] firstSeed, byte[] secondSeed) { if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "CredentialVault.storedEncodedUsingInternalSeeds called"); // If the credential was not encoded using externally-supplied seeds, then we cannot decode it. if (!externalSeedsWereUsed_) { Trace.log(Trace.ERROR, "Called storeEncodedUsingInternalSeeds() when credential was not previously encoded using external seeds."); throw new InternalErrorException(InternalErrorException.UNKNOWN); } else { externalSeedsWereUsed_ = false; } if (!isEmpty()) { encodedCredential_ = store(CredentialVault.decode(firstSeed, secondSeed, encodedCredential_)); } } /** * Disposes of the credential, thus emptying the vault. */ protected void disposeOfCredential() { if (Trace.traceOn_) Trace.log(Trace.INFORMATION, "CredentialVault.disposeOfCredential called"); encodedCredential_ = null; } /** * Encodes the credential, represented as a array of bytes, using * internally generated random seeds. The provided credential * byte array is never modified by this method. * * @param credential The credential to encode * @return The encoded credential */ protected byte[] store(byte[] credential) { byte[] newAdder = new byte[9]; rng.nextBytes(newAdder); byte[] newMask = new byte[7]; rng.nextBytes(newMask); byte[] infoBytes = encode(newAdder, newMask, credential); byte[] returnBytes = new byte[infoBytes.length + 16]; // // The format for the stored bytes is // // adder : mask : encodedBytes // // First store the adder System.arraycopy(newAdder, 0, returnBytes, 0, 9); // Next store the mask System.arraycopy(newMask, 0, returnBytes, 9, 7); // Finally, store the encoded bytes System.arraycopy(infoBytes, 0, returnBytes, 16, infoBytes.length); if (PASSWORD_TRACE) { Trace.log(Trace.DIAGNOSTIC, "AS400 object store, bytes:", returnBytes); } return returnBytes; } /** * Decodes and returns the internally encoded credential. * The encoded credential byte array is never modified by this method. * * @return The credential stored in the vault, with all internal encoding removed */ protected synchronized byte[] resolve(byte[] encodedBytes) { if (PASSWORD_TRACE) { Trace.log(Trace.DIAGNOSTIC, "AS400 object resolve:", encodedBytes); } if (encodedBytes == null) { return null; } // The first 9 bytes in the array are the adder byte[] adder = new byte[9]; System.arraycopy(encodedBytes, 0, adder, 0, 9); // The next 7 bytes are the mask byte[] mask = new byte[7]; System.arraycopy(encodedBytes, 9, mask, 0, 7); // And everything that is left is the encoded bytes byte[] infoBytes = new byte[encodedBytes.length - 16]; System.arraycopy(encodedBytes, 16, infoBytes, 0, encodedBytes.length - 16); return decode(adder, mask, infoBytes); } /** * Encodes the given credential bytes using the provided adder and mask. * The encoded credential is stored and returned in a newly allocated byte array. * The provided credential byte array is never modified by this method. * * @param adder Used for encoding * @param mask Used for encoding * @param credential The credential to encode, represented as an array of bytes * * @return A newly allocated array of bytes representing the encoded credential */ protected static byte[] encode(byte[] adder, byte[] mask, final byte[] credential) { if (PASSWORD_TRACE) { Trace.log(Trace.DIAGNOSTIC, "AS400 object encode:"); Trace.log(Trace.DIAGNOSTIC, " adder:", adder); Trace.log(Trace.DIAGNOSTIC, " mask:", mask); Trace.log(Trace.DIAGNOSTIC, " bytes:", credential); } if (credential == null) return null; int length = credential.length; byte[] buf = new byte[length]; for (int i = 0; i < length; ++i) { buf[i] = (byte)(credential[i] + adder[i % 9]); } for (int i = 0; i < length; ++i) { buf[i] = (byte)(buf[i] ^ mask[i % 7]); } if (PASSWORD_TRACE) { Trace.log(Trace.DIAGNOSTIC, " return:", buf); } return buf; } /** * Decodes the given credential bytes using the provided adder and mask. * The decoded credential is returned in a newly allocated byte array. * The provided credential byte array is never modified by this method. * * @param adder Used for encoding * @param mask Used for encoding * @param credential The credential to encode, represented as an array of bytes * * @return A newly allocated array of bytes representing the decoded credential */ protected static byte[] decode(byte[] adder, byte[] mask, byte[] credential) { if (PASSWORD_TRACE) { Trace.log(Trace.DIAGNOSTIC, "AS400 object decode:"); Trace.log(Trace.DIAGNOSTIC, " adder:", adder); Trace.log(Trace.DIAGNOSTIC, " mask:", mask); Trace.log(Trace.DIAGNOSTIC, " bytes:", credential); } int length = credential.length; byte[] buf = new byte[length]; for (int i = 0; i < length; ++i) { buf[i] = (byte)(mask[i % 7] ^ credential[i]); } for (int i = 0; i < length; ++i) { buf[i] = (byte)(buf[i] - adder[i % 9]); } if (PASSWORD_TRACE) { Trace.log(Trace.DIAGNOSTIC, " return:", buf); } return buf; } /** * Decodes the credential bytes using the provided adder and mask. * The decoded credential is returned in a newly allocated byte array. * * @param adder Used for encoding * @param mask Used for encoding * * @return A newly allocated array of bytes representing the decoded credential */ protected byte[] decode(byte[] adder, byte[] mask) { return CredentialVault.decode(adder, mask, encodedCredential_); } /** * Provides a minimal amount of tracing information about the credential * vault in a nicely formatted string. * * @return The tracing information represented as a string */ protected String trace() { StringBuffer sb = new StringBuffer(); sb.append("type="); sb.append(getType()); sb.append(" : bytes="); Trace.printByteArray(sb, encodedCredential_); // accepts null arg return sb.toString(); } public static void clearArray(char[] passwordChars) { for (int i = 0; i < passwordChars.length; i++) { passwordChars[i]=(char) i; } } public static boolean isStarCurrent(char[] password) { if ((password.length == 8) && password[0]=='*' && ((password[1] == 'C') || (password[1] == 'c')) && ((password[2] == 'U') || (password[2] == 'u')) && ((password[3] == 'R') || (password[3] == 'r')) && ((password[4] == 'R') || (password[4] == 'r')) && ((password[5] == 'E') || (password[5] == 'e')) && ((password[6] == 'N') || (password[6] == 'n')) && ((password[7] == 'T') || (password[7] == 't'))) { return true; } return false; } public static int getHashCode(char[] password) { int len = password.length; int hashcode = 0; for (int i = 0; i < len; i++) { hashcode =+ password[i] * 31 ^ (len - 1) ; } return hashcode; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy