alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Realm.java)

This example Java source code file (Realm.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

asn1exception, cloneable, config, deroutputstream, dervalue, illegalargumentexception, ioexception, krbexception, linkedlist, object, realm, realmexception, string, stringbuilder, util

The Realm.java Java example source code

/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 *
 *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
 *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
 */

package sun.security.krb5;

import sun.security.krb5.internal.Krb5;
import sun.security.util.*;
import java.io.IOException;
import java.util.*;

import sun.security.krb5.internal.util.KerberosString;

/**
 * Implements the ASN.1 Realm type.
 *
 * <xmp>
 * Realm ::= GeneralString
 * </xmp>
 * This class is immutable.
 */
public class Realm implements Cloneable {
    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.
     *
     * 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.
     *
     * The implementation ignores all values which equals to C or S, or
     * a "." in multiple values, or any duplicated realm names.
     *
     * 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.
     *
     * For example:
     *
     * [capaths]
     *    TIVOLI.COM = {
     *        IBM.COM = IBM_LDAPCENTRAL.COM MOONLITE.ORG
     *        IBM_LDAPCENTRAL.COM = LDAPCENTRAL.NET
     *        LDAPCENTRAL.NET = .
     *    }
     *
     * 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
     *
     *   TIVOLI.COM -> LDAPCENTRAL.NET -> IBM_LDAPCENTRAL.COM
     *              -> IBM_LDAPCENTRAL.COM -> MOONLITE.ORG
     *
     * 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();
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java Realm.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.