Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/krb5/Realm.java
38830 views
/*1* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26*27* (C) Copyright IBM Corp. 1999 All Rights Reserved.28* Copyright 1997 The Open Group Research Institute. All rights reserved.29*/3031package sun.security.krb5;3233import sun.security.krb5.internal.Krb5;34import sun.security.util.*;35import java.io.IOException;36import java.util.*;3738import sun.security.krb5.internal.util.KerberosString;3940/**41* Implements the ASN.1 Realm type.42*43* {@code Realm ::= GeneralString}44*45* This class is immutable.46*/47public class Realm implements Cloneable {4849public static final boolean AUTODEDUCEREALM =50java.security.AccessController.doPrivileged(51new sun.security.action.GetBooleanAction(52"sun.security.krb5.autodeducerealm"));5354private final String realm; // not null nor empty5556public Realm(String name) throws RealmException {57realm = parseRealm(name);58}5960public static Realm getDefault() throws RealmException {61try {62return new Realm(Config.getInstance().getDefaultRealm());63} catch (RealmException re) {64throw re;65} catch (KrbException ke) {66throw new RealmException(ke);67}68}6970// Immutable class, no need to clone71public Object clone() {72return this;73}7475public boolean equals(Object obj) {76if (this == obj) {77return true;78}7980if (!(obj instanceof Realm)) {81return false;82}8384Realm that = (Realm)obj;85return this.realm.equals(that.realm);86}8788public int hashCode() {89return realm.hashCode();90}9192/**93* Constructs a Realm object.94* @param encoding a Der-encoded data.95* @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.96* @exception IOException if an I/O error occurs while reading encoded data.97* @exception RealmException if an error occurs while parsing a Realm object.98*/99public Realm(DerValue encoding)100throws Asn1Exception, RealmException, IOException {101if (encoding == null) {102throw new IllegalArgumentException("encoding can not be null");103}104realm = new KerberosString(encoding).toString();105if (realm == null || realm.length() == 0)106throw new RealmException(Krb5.REALM_NULL);107if (!isValidRealmString(realm))108throw new RealmException(Krb5.REALM_ILLCHAR);109}110111public String toString() {112return realm;113}114115// Extract realm from a string like dummy@REALM116public static String parseRealmAtSeparator(String name)117throws RealmException {118if (name == null) {119throw new IllegalArgumentException120("null input name is not allowed");121}122String temp = new String(name);123String result = null;124int i = 0;125while (i < temp.length()) {126if (temp.charAt(i) == PrincipalName.NAME_REALM_SEPARATOR) {127if (i == 0 || temp.charAt(i - 1) != '\\') {128if (i + 1 < temp.length()) {129result = temp.substring(i + 1, temp.length());130} else {131throw new IllegalArgumentException132("empty realm part not allowed");133}134break;135}136}137i++;138}139if (result != null) {140if (result.length() == 0)141throw new RealmException(Krb5.REALM_NULL);142if (!isValidRealmString(result))143throw new RealmException(Krb5.REALM_ILLCHAR);144}145return result;146}147148public static String parseRealmComponent(String name) {149if (name == null) {150throw new IllegalArgumentException151("null input name is not allowed");152}153String temp = new String(name);154String result = null;155int i = 0;156while (i < temp.length()) {157if (temp.charAt(i) == PrincipalName.REALM_COMPONENT_SEPARATOR) {158if (i == 0 || temp.charAt(i - 1) != '\\') {159if (i + 1 < temp.length())160result = temp.substring(i + 1, temp.length());161break;162}163}164i++;165}166return result;167}168169protected static String parseRealm(String name) throws RealmException {170String result = parseRealmAtSeparator(name);171if (result == null)172result = name;173if (result == null || result.length() == 0)174throw new RealmException(Krb5.REALM_NULL);175if (!isValidRealmString(result))176throw new RealmException(Krb5.REALM_ILLCHAR);177return result;178}179180// This is protected because the definition of a realm181// string is fixed182protected static boolean isValidRealmString(String name) {183if (name == null)184return false;185if (name.length() == 0)186return false;187for (int i = 0; i < name.length(); i++) {188if (name.charAt(i) == '/' ||189name.charAt(i) == '\0') {190return false;191}192}193return true;194}195196/**197* Encodes a Realm object.198* @return the byte array of encoded KrbCredInfo object.199* @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.200* @exception IOException if an I/O error occurs while reading encoded data.201*202*/203public byte[] asn1Encode() throws Asn1Exception, IOException {204DerOutputStream out = new DerOutputStream();205out.putDerValue(new KerberosString(this.realm).toDerValue());206return out.toByteArray();207}208209210/**211* Parse (unmarshal) a realm from a DER input stream. This form212* parsing might be used when expanding a value which is part of213* a constructed sequence and uses explicitly tagged type.214*215* @exception Asn1Exception on error.216* @param data the Der input stream value, which contains one or more marshaled value.217* @param explicitTag tag number.218* @param optional indicate if this data field is optional219* @return an instance of Realm.220*221*/222public static Realm parse(DerInputStream data, byte explicitTag, boolean optional)223throws Asn1Exception, IOException, RealmException {224if ((optional) && (((byte)data.peekByte() & (byte)0x1F) != explicitTag)) {225return null;226}227DerValue der = data.getDerValue();228if (explicitTag != (der.getTag() & (byte)0x1F)) {229throw new Asn1Exception(Krb5.ASN1_BAD_ID);230} else {231DerValue subDer = der.getData().getDerValue();232return new Realm(subDer);233}234}235236/**237* Returns an array of realms that may be traversed to obtain238* a TGT from the initiating realm cRealm to the target realm239* sRealm.240* <br>241* This method would read [capaths] to create a path, or generate a242* hierarchical path if [capaths] does not contain a sub-stanza for cRealm243* or the sub-stanza does not contain a tag for sRealm.244* <br>245* The returned list would never be null, and it always contains246* cRealm as the head entry. sRealm is not included as the tail.247*248* @param cRealm the initiating realm, not null249* @param sRealm the target realm, not null, not equals to cRealm250* @return array of realms including at least cRealm as the first251* element252*/253public static String[] getRealmsList(String cRealm, String sRealm) {254try {255// Try [capaths]256return parseCapaths(cRealm, sRealm);257} catch (KrbException ke) {258// Now assume the realms are organized hierarchically.259return parseHierarchy(cRealm, sRealm);260}261}262263/**264* Parses the [capaths] stanza of the configuration file for a265* list of realms to traverse to obtain credentials from the266* initiating realm cRealm to the target realm sRealm.267*268* For a given client realm C there is a tag C in [capaths] whose269* subtag S has a value which is a (possibly partial) path from C270* to S. When the path is partial, it contains only the tail of the271* full path. Values of other subtags will be used to build the full272* path. The value "." means a direct path from C to S. If realm S273* does not appear as a subtag, there is no path defined here.274*275* The implementation ignores all values which equals to C or S, or276* a "." in multiple values, or any duplicated realm names.277*278* When a path value has more than two realms, they can be specified279* with multiple key-value pairs each having a single value, but the280* order must not change.281*282* For example:283*284* [capaths]285* TIVOLI.COM = {286* IBM.COM = IBM_LDAPCENTRAL.COM MOONLITE.ORG287* IBM_LDAPCENTRAL.COM = LDAPCENTRAL.NET288* LDAPCENTRAL.NET = .289* }290*291* TIVOLI.COM has a direct path to LDAPCENTRAL.NET, which has a direct292* path to IBM_LDAPCENTRAL.COM. It also has a partial path to IBM.COM293* being "IBM_LDAPCENTRAL.COM MOONLITE.ORG". Merging these info together,294* a full path from TIVOLI.COM to IBM.COM will be295*296* TIVOLI.COM -> LDAPCENTRAL.NET -> IBM_LDAPCENTRAL.COM297* -> IBM_LDAPCENTRAL.COM -> MOONLITE.ORG298*299* Please note the sRealm IBM.COM does not appear in the path.300*301* @param cRealm the initiating realm302* @param sRealm the target realm, not the same as cRealm303* @returns array of realms including at least cRealm as the first304* element305* @throws KrbException if the config does not contain a sub-stanza306* for cRealm in [capaths] or the sub-stanza does not contain307* sRealm as a tag308*/309private static String[] parseCapaths(String cRealm, String sRealm)310throws KrbException {311312// This line could throw a KrbException313Config cfg = Config.getInstance();314315if (!cfg.exists("capaths", cRealm, sRealm)) {316throw new KrbException("No conf");317}318319LinkedList<String> path = new LinkedList<>();320321String head = sRealm;322while (true) {323String value = cfg.getAll("capaths", cRealm, head);324if (value == null) {325break;326}327String[] more = value.split("\\s+");328boolean changed = false;329for (int i=more.length-1; i>=0; i--) {330if (path.contains(more[i])331|| more[i].equals(".")332|| more[i].equals(cRealm)333|| more[i].equals(sRealm)334|| more[i].equals(head)) {335// Ignore invalid values336continue;337}338changed = true;339path.addFirst(more[i]);340}341if (!changed) break;342head = path.getFirst();343}344path.addFirst(cRealm);345return path.toArray(new String[path.size()]);346}347348/**349* Build a list of realm that can be traversed350* to obtain credentials from the initiating realm cRealm351* for a service in the target realm sRealm.352* @param cRealm the initiating realm353* @param sRealm the target realm, not the same as cRealm354* @return array of realms including cRealm as the first element355*/356private static String[] parseHierarchy(String cRealm, String sRealm) {357358String[] cComponents = cRealm.split("\\.");359String[] sComponents = sRealm.split("\\.");360361int cPos = cComponents.length;362int sPos = sComponents.length;363364boolean hasCommon = false;365for (sPos--, cPos--; sPos >=0 && cPos >= 0 &&366sComponents[sPos].equals(cComponents[cPos]);367sPos--, cPos--) {368hasCommon = true;369}370371// For those with common components:372// length pos373// SITES1.SALES.EXAMPLE.COM 4 1374// EVERYWHERE.EXAMPLE.COM 3 0375376// For those without common components:377// length pos378// DEVEL.EXAMPLE.COM 3 2379// PROD.EXAMPLE.ORG 3 2380381LinkedList<String> path = new LinkedList<>();382383// Un-common ones for client side384for (int i=0; i<=cPos; i++) {385path.addLast(subStringFrom(cComponents, i));386}387388// Common one389if (hasCommon) {390path.addLast(subStringFrom(cComponents, cPos+1));391}392393// Un-common ones for server side394for (int i=sPos; i>=0; i--) {395path.addLast(subStringFrom(sComponents, i));396}397398// Remove sRealm from path. Note that it might be added at last loop399// or as a common component, if sRealm is a parent of cRealm400path.removeLast();401402return path.toArray(new String[path.size()]);403}404405/**406* Creates a realm name using components from the given position.407* For example, subStringFrom({"A", "B", "C"}, 1) is "B.C".408*/409private static String subStringFrom(String[] components, int from) {410StringBuilder sb = new StringBuilder();411for (int i=from; i<components.length; i++) {412if (sb.length() != 0) sb.append('.');413sb.append(components[i]);414}415return sb.toString();416}417}418419420