/**
  * Initialize the maximum allowable clock skew by getting the OCSP clock skew system property. If
  * the property has not been set, or if its value is negative, set the skew to the default.
  */
 private static int initializeClockSkew() {
   Integer tmp =
       java.security.AccessController.doPrivileged(
           new GetIntegerAction("com.sun.security.ocsp.clockSkew"));
   if (tmp == null || tmp < 0) {
     return DEFAULT_MAX_CLOCK_SKEW;
   }
   // Convert to milliseconds, as the system property will be
   // specified in seconds
   return tmp * 1000;
 }
Exemple #2
0
/**
 * Implements the ASN.1 Realm type.
 *
 * <p><xmp> Realm ::= GeneralString </xmp> This class is immutable.
 */
public class Realm implements Cloneable {

  public static final boolean AUTODEDUCEREALM =
      java.security.AccessController.doPrivileged(
          new sun.security.action.GetBooleanAction("sun.security.krb5.autodeducerealm"));

  private final String realm; // not null nor empty

  public Realm(String name) throws RealmException {
    realm = parseRealm(name);
  }

  public static Realm getDefault() throws RealmException {
    try {
      return new Realm(Config.getInstance().getDefaultRealm());
    } catch (RealmException re) {
      throw re;
    } catch (KrbException ke) {
      throw new RealmException(ke);
    }
  }

  // Immutable class, no need to clone
  public Object clone() {
    return this;
  }

  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }

    if (!(obj instanceof Realm)) {
      return false;
    }

    Realm that = (Realm) obj;
    return this.realm.equals(that.realm);
  }

  public int hashCode() {
    return realm.hashCode();
  }

  /**
   * Constructs a Realm object.
   *
   * @param encoding a Der-encoded data.
   * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
   * @exception IOException if an I/O error occurs while reading encoded data.
   * @exception RealmException if an error occurs while parsing a Realm object.
   */
  public Realm(DerValue encoding) throws Asn1Exception, RealmException, IOException {
    if (encoding == null) {
      throw new IllegalArgumentException("encoding can not be null");
    }
    realm = new KerberosString(encoding).toString();
    if (realm == null || realm.length() == 0) throw new RealmException(Krb5.REALM_NULL);
    if (!isValidRealmString(realm)) throw new RealmException(Krb5.REALM_ILLCHAR);
  }

  public String toString() {
    return realm;
  }

  // Extract realm from a string like dummy@REALM
  public static String parseRealmAtSeparator(String name) throws RealmException {
    if (name == null) {
      throw new IllegalArgumentException("null input name is not allowed");
    }
    String temp = new String(name);
    String result = null;
    int i = 0;
    while (i < temp.length()) {
      if (temp.charAt(i) == PrincipalName.NAME_REALM_SEPARATOR) {
        if (i == 0 || temp.charAt(i - 1) != '\\') {
          if (i + 1 < temp.length()) {
            result = temp.substring(i + 1, temp.length());
          } else {
            throw new IllegalArgumentException("empty realm part not allowed");
          }
          break;
        }
      }
      i++;
    }
    if (result != null) {
      if (result.length() == 0) throw new RealmException(Krb5.REALM_NULL);
      if (!isValidRealmString(result)) throw new RealmException(Krb5.REALM_ILLCHAR);
    }
    return result;
  }

  public static String parseRealmComponent(String name) {
    if (name == null) {
      throw new IllegalArgumentException("null input name is not allowed");
    }
    String temp = new String(name);
    String result = null;
    int i = 0;
    while (i < temp.length()) {
      if (temp.charAt(i) == PrincipalName.REALM_COMPONENT_SEPARATOR) {
        if (i == 0 || temp.charAt(i - 1) != '\\') {
          if (i + 1 < temp.length()) result = temp.substring(i + 1, temp.length());
          break;
        }
      }
      i++;
    }
    return result;
  }

  protected static String parseRealm(String name) throws RealmException {
    String result = parseRealmAtSeparator(name);
    if (result == null) result = name;
    if (result == null || result.length() == 0) throw new RealmException(Krb5.REALM_NULL);
    if (!isValidRealmString(result)) throw new RealmException(Krb5.REALM_ILLCHAR);
    return result;
  }

  // This is protected because the definition of a realm
  // string is fixed
  protected static boolean isValidRealmString(String name) {
    if (name == null) return false;
    if (name.length() == 0) return false;
    for (int i = 0; i < name.length(); i++) {
      if (name.charAt(i) == '/' || name.charAt(i) == ':' || name.charAt(i) == '\0') {
        return false;
      }
    }
    return true;
  }

  /**
   * Encodes a Realm object.
   *
   * @return the byte array of encoded KrbCredInfo object.
   * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
   * @exception IOException if an I/O error occurs while reading encoded data.
   */
  public byte[] asn1Encode() throws Asn1Exception, IOException {
    DerOutputStream out = new DerOutputStream();
    out.putDerValue(new KerberosString(this.realm).toDerValue());
    return out.toByteArray();
  }

  /**
   * Parse (unmarshal) a realm from a DER input stream. This form parsing might be used when
   * expanding a value which is part of a constructed sequence and uses explicitly tagged type.
   *
   * @exception Asn1Exception on error.
   * @param data the Der input stream value, which contains one or more marshaled value.
   * @param explicitTag tag number.
   * @param optional indicate if this data field is optional
   * @return an instance of Realm.
   */
  public static Realm parse(DerInputStream data, byte explicitTag, boolean optional)
      throws Asn1Exception, IOException, RealmException {
    if ((optional) && (((byte) data.peekByte() & (byte) 0x1F) != explicitTag)) {
      return null;
    }
    DerValue der = data.getDerValue();
    if (explicitTag != (der.getTag() & (byte) 0x1F)) {
      throw new Asn1Exception(Krb5.ASN1_BAD_ID);
    } else {
      DerValue subDer = der.getData().getDerValue();
      return new Realm(subDer);
    }
  }

  /**
   * Returns an array of realms that may be traversed to obtain a TGT from the initiating realm
   * cRealm to the target realm sRealm. <br>
   * This method would read [capaths] to create a path, or generate a hierarchical path if [capaths]
   * does not contain a sub-stanza for cRealm or the sub-stanza does not contain a tag for sRealm.
   * <br>
   * The returned list would never be null, and it always contains cRealm as the head entry. sRealm
   * is not included as the tail.
   *
   * @param cRealm the initiating realm, not null
   * @param sRealm the target realm, not null, not equals to cRealm
   * @returns array of realms including at least cRealm as the first element
   */
  public static String[] getRealmsList(String cRealm, String sRealm) {
    try {
      // Try [capaths]
      return parseCapaths(cRealm, sRealm);
    } catch (KrbException ke) {
      // Now assume the realms are organized hierarchically.
      return parseHierarchy(cRealm, sRealm);
    }
  }

  /**
   * Parses the [capaths] stanza of the configuration file for a list of realms to traverse to
   * obtain credentials from the initiating realm cRealm to the target realm sRealm.
   *
   * <p>For a given client realm C there is a tag C in [capaths] whose subtag S has a value which is
   * a (possibly partial) path from C to S. When the path is partial, it contains only the tail of
   * the full path. Values of other subtags will be used to build the full path. The value "." means
   * a direct path from C to S. If realm S does not appear as a subtag, there is no path defined
   * here.
   *
   * <p>The implementation ignores all values which equals to C or S, or a "." in multiple values,
   * or any duplicated realm names.
   *
   * <p>When a path value has more than two realms, they can be specified with multiple key-value
   * pairs each having a single value, but the order must not change.
   *
   * <p>For example:
   *
   * <p>[capaths] TIVOLI.COM = { IBM.COM = IBM_LDAPCENTRAL.COM MOONLITE.ORG IBM_LDAPCENTRAL.COM =
   * LDAPCENTRAL.NET LDAPCENTRAL.NET = . }
   *
   * <p>TIVOLI.COM has a direct path to LDAPCENTRAL.NET, which has a direct path to
   * IBM_LDAPCENTRAL.COM. It also has a partial path to IBM.COM being "IBM_LDAPCENTRAL.COM
   * MOONLITE.ORG". Merging these info together, a full path from TIVOLI.COM to IBM.COM will be
   *
   * <p>TIVOLI.COM -> LDAPCENTRAL.NET -> IBM_LDAPCENTRAL.COM -> IBM_LDAPCENTRAL.COM -> MOONLITE.ORG
   *
   * <p>Please note the sRealm IBM.COM does not appear in the path.
   *
   * @param cRealm the initiating realm
   * @param sRealm the target realm, not the same as cRealm
   * @returns array of realms including at least cRealm as the first element
   * @throws KrbException if the config does not contain a sub-stanza for cRealm in [capaths] or the
   *     sub-stanza does not contain sRealm as a tag
   */
  private static String[] parseCapaths(String cRealm, String sRealm) throws KrbException {

    // This line could throw a KrbException
    Config cfg = Config.getInstance();

    if (!cfg.exists("capaths", cRealm, sRealm)) {
      throw new KrbException("No conf");
    }

    LinkedList<String> path = new LinkedList<>();

    String head = sRealm;
    while (true) {
      String value = cfg.getAll("capaths", cRealm, head);
      if (value == null) {
        break;
      }
      String[] more = value.split("\\s+");
      boolean changed = false;
      for (int i = more.length - 1; i >= 0; i--) {
        if (path.contains(more[i])
            || more[i].equals(".")
            || more[i].equals(cRealm)
            || more[i].equals(sRealm)
            || more[i].equals(head)) {
          // Ignore invalid values
          continue;
        }
        changed = true;
        path.addFirst(more[i]);
      }
      if (!changed) break;
      head = path.getFirst();
    }
    path.addFirst(cRealm);
    return path.toArray(new String[path.size()]);
  }

  /**
   * Build a list of realm that can be traversed to obtain credentials from the initiating realm
   * cRealm for a service in the target realm sRealm.
   *
   * @param cRealm the initiating realm
   * @param sRealm the target realm, not the same as cRealm
   * @returns array of realms including cRealm as the first element
   */
  private static String[] parseHierarchy(String cRealm, String sRealm) {

    String[] cComponents = cRealm.split("\\.");
    String[] sComponents = sRealm.split("\\.");

    int cPos = cComponents.length;
    int sPos = sComponents.length;

    boolean hasCommon = false;
    for (sPos--, cPos--;
        sPos >= 0 && cPos >= 0 && sComponents[sPos].equals(cComponents[cPos]);
        sPos--, cPos--) {
      hasCommon = true;
    }

    // For those with common components:
    //                            length  pos
    // SITES1.SALES.EXAMPLE.COM   4       1
    //   EVERYWHERE.EXAMPLE.COM   3       0

    // For those without common components:
    //                     length  pos
    // DEVEL.EXAMPLE.COM   3       2
    // PROD.EXAMPLE.ORG    3       2

    LinkedList<String> path = new LinkedList<>();

    // Un-common ones for client side
    for (int i = 0; i <= cPos; i++) {
      path.addLast(subStringFrom(cComponents, i));
    }

    // Common one
    if (hasCommon) {
      path.addLast(subStringFrom(cComponents, cPos + 1));
    }

    // Un-common ones for server side
    for (int i = sPos; i >= 0; i--) {
      path.addLast(subStringFrom(sComponents, i));
    }

    // Remove sRealm from path. Note that it might be added at last loop
    // or as a common component, if sRealm is a parent of cRealm
    path.removeLast();

    return path.toArray(new String[path.size()]);
  }

  /**
   * Creates a realm name using components from the given position. For example, subStringFrom({"A",
   * "B", "C"}, 1) is "B.C".
   */
  private static String subStringFrom(String[] components, int from) {
    StringBuilder sb = new StringBuilder();
    for (int i = from; i < components.length; i++) {
      if (sb.length() != 0) sb.append('.');
      sb.append(components[i]);
    }
    return sb.toString();
  }
}