aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/sun/security/krb5/internal/ReferralsCache.java
diff options
context:
space:
mode:
authorDana Dahlstrom <dahlstrom@google.com>2020-02-12 11:00:00 -0800
committerDana Dahlstrom <dahlstrom@google.com>2020-02-12 11:00:00 -0800
commit86a106a12234cee1498a2159104fcba7f3c0efed (patch)
treed87095c67859d1df4f0b8b34b4744aa68bcccce2 /src/share/classes/sun/security/krb5/internal/ReferralsCache.java
parent48adcc45b3935045b1ff2013ecfd05e6f3bdb1cc (diff)
parenta7492bb2a38c1c41216929de6ba6a0a553bd4338 (diff)
downloadjdk8u_jdk-86a106a12234cee1498a2159104fcba7f3c0efed.tar.gz
Merge tag jb8u242-b1644.3
Change-Id: Ia7492bb2a38c1c41216929de6ba6a0a553bd4338
Diffstat (limited to 'src/share/classes/sun/security/krb5/internal/ReferralsCache.java')
-rw-r--r--src/share/classes/sun/security/krb5/internal/ReferralsCache.java159
1 files changed, 159 insertions, 0 deletions
diff --git a/src/share/classes/sun/security/krb5/internal/ReferralsCache.java b/src/share/classes/sun/security/krb5/internal/ReferralsCache.java
new file mode 100644
index 0000000000..970d432aba
--- /dev/null
+++ b/src/share/classes/sun/security/krb5/internal/ReferralsCache.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc.
+ * 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.
+ */
+
+package sun.security.krb5.internal;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import sun.security.krb5.Credentials;
+import sun.security.krb5.PrincipalName;
+
+/*
+ * ReferralsCache class implements a cache scheme for referral TGTs as
+ * described in RFC 6806 - 10. Caching Information. The goal is to optimize
+ * resources (such as network traffic) when a client requests credentials for a
+ * service principal to a given KDC. If a referral TGT was previously received,
+ * cached information is used instead of issuing a new query. Once a referral
+ * TGT expires, the corresponding referral entry in the cache is removed.
+ */
+final class ReferralsCache {
+
+ private static Map<ReferralCacheKey, Map<String, ReferralCacheEntry>>
+ referralsMap = new HashMap<>();
+
+ static private final class ReferralCacheKey {
+ private PrincipalName cname;
+ private PrincipalName sname;
+ ReferralCacheKey (PrincipalName cname, PrincipalName sname) {
+ this.cname = cname;
+ this.sname = sname;
+ }
+ public boolean equals(Object other) {
+ if (!(other instanceof ReferralCacheKey))
+ return false;
+ ReferralCacheKey that = (ReferralCacheKey)other;
+ return cname.equals(that.cname) &&
+ sname.equals(that.sname);
+ }
+ public int hashCode() {
+ return cname.hashCode() + sname.hashCode();
+ }
+ }
+
+ static final class ReferralCacheEntry {
+ private final Credentials creds;
+ private final String toRealm;
+ ReferralCacheEntry(Credentials creds, String toRealm) {
+ this.creds = creds;
+ this.toRealm = toRealm;
+ }
+ Credentials getCreds() {
+ return creds;
+ }
+ String getToRealm() {
+ return toRealm;
+ }
+ }
+
+ /*
+ * Add a new referral entry to the cache, including: client principal,
+ * service principal, source KDC realm, destination KDC realm and
+ * referral TGT.
+ *
+ * If a loop is generated when adding the new referral, the first hop is
+ * automatically removed. For example, let's assume that adding a
+ * REALM-3.COM -> REALM-1.COM referral generates the following loop:
+ * REALM-1.COM -> REALM-2.COM -> REALM-3.COM -> REALM-1.COM. Then,
+ * REALM-1.COM -> REALM-2.COM referral entry is removed from the cache.
+ */
+ static synchronized void put(PrincipalName cname, PrincipalName service,
+ String fromRealm, String toRealm, Credentials creds) {
+ ReferralCacheKey k = new ReferralCacheKey(cname, service);
+ pruneExpired(k);
+ if (creds.getEndTime().before(new Date())) {
+ return;
+ }
+ Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
+ if (entries == null) {
+ entries = new HashMap<String, ReferralCacheEntry>();
+ referralsMap.put(k, entries);
+ }
+ entries.remove(fromRealm);
+ ReferralCacheEntry newEntry = new ReferralCacheEntry(creds, toRealm);
+ entries.put(fromRealm, newEntry);
+
+ // Remove loops within the cache
+ ReferralCacheEntry current = newEntry;
+ List<ReferralCacheEntry> seen = new LinkedList<>();
+ while (current != null) {
+ if (seen.contains(current)) {
+ // Loop found. Remove the first referral to cut the loop.
+ entries.remove(newEntry.getToRealm());
+ break;
+ }
+ seen.add(current);
+ current = entries.get(current.getToRealm());
+ }
+ }
+
+ /*
+ * Obtain a referral entry from the cache given a client principal,
+ * service principal and a source KDC realm.
+ */
+ static synchronized ReferralCacheEntry get(PrincipalName cname,
+ PrincipalName service, String fromRealm) {
+ ReferralCacheKey k = new ReferralCacheKey(cname, service);
+ pruneExpired(k);
+ Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
+ if (entries != null) {
+ ReferralCacheEntry toRef = entries.get(fromRealm);
+ if (toRef != null) {
+ return toRef;
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Remove referral entries from the cache when referral TGTs expire.
+ */
+ private static void pruneExpired(ReferralCacheKey k) {
+ Date now = new Date();
+ Map<String, ReferralCacheEntry> entries = referralsMap.get(k);
+ if (entries != null) {
+ for (Entry<String, ReferralCacheEntry> mapEntry :
+ entries.entrySet()) {
+ if (mapEntry.getValue().getCreds().getEndTime().before(now)) {
+ entries.remove(mapEntry.getKey());
+ }
+ }
+ }
+ }
+}