diff --git a/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
index c9499f1d1a0f528ed61cebc8ba95c1e2f60ce427..5da153d72ea1c4783746e30ae8ac972f771f63e8 100644
--- a/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
+++ b/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -395,7 +395,13 @@ public class Krb5LoginModule implements LoginModule {
private boolean succeeded = false;
private boolean commitSucceeded = false;
private String username;
+
+ // Encryption keys calculated from password. Assigned when storekey == true
+ // and useKeyTab == false (or true but not found)
private EncryptionKey[] encKeys = null;
+
+ KeyTab ktab = null;
+
private Credentials cred = null;
private PrincipalName principal = null;
@@ -663,28 +669,49 @@ public class Krb5LoginModule implements LoginModule {
(krb5PrincName.toString(),
PrincipalName.KRB_NT_PRINCIPAL);
}
+
+ /*
+ * Before dynamic KeyTab support (6894072), here we check if
+ * the keytab contains keys for the principal. If no, keytab
+ * will not be used and password is prompted for.
+ *
+ * After 6894072, we normally don't check it, and expect the
+ * keys can be populated until a real connection is made. The
+ * check is still done when isInitiator == true, where the keys
+ * will be used right now.
+ *
+ * Probably tricky relations:
+ *
+ * useKeyTab is config flag, but when it's true but the ktab
+ * does not contains keys for principal, we would use password
+ * and keep the flag unchanged (for reuse?). In this method,
+ * we use (ktab != null) to check whether keytab is used.
+ * After this method (and when storeKey == true), we use
+ * (encKeys == null) to check.
+ */
if (useKeyTab) {
- encKeys =
- EncryptionKey.acquireSecretKeys(principal, keyTabName);
-
- if (debug) {
- if (encKeys != null)
- System.out.println
- ("principal's key obtained from the keytab");
- else
- System.out.println
- ("Key for the principal " +
- principal +
- " not available in " +
- ((keyTabName == null) ?
- "default key tab" : keyTabName));
+ ktab = (keyTabName == null)
+ ? KeyTab.getInstance()
+ : KeyTab.getInstance(new File(keyTabName));
+ if (isInitiator) {
+ if (Krb5Util.keysFromJavaxKeyTab(ktab, principal).length
+ == 0) {
+ ktab = null;
+ if (debug) {
+ System.out.println
+ ("Key for the principal " +
+ principal +
+ " not available in " +
+ ((keyTabName == null) ?
+ "default key tab" : keyTabName));
+ }
+ }
}
-
}
KrbAsReqBuilder builder;
- // We can't get the key from the keytab so prompt
- if (encKeys == null) {
+
+ if (ktab == null) {
promptForPass(getPasswdFromSharedState);
builder = new KrbAsReqBuilder(principal, password);
if (isInitiator) {
@@ -693,9 +720,13 @@ public class Krb5LoginModule implements LoginModule {
// updated with PA info
cred = builder.action().getCreds();
}
- encKeys = builder.getKeys();
+ if (storeKey) {
+ encKeys = builder.getKeys();
+ // When encKeys is empty, the login actually fails.
+ // For compatibility, exception is thrown in commit().
+ }
} else {
- builder = new KrbAsReqBuilder(principal, encKeys);
+ builder = new KrbAsReqBuilder(principal, ktab);
if (isInitiator) {
cred = builder.action().getCreds();
}
@@ -705,10 +736,15 @@ public class Krb5LoginModule implements LoginModule {
if (debug) {
System.out.println("principal is " + principal);
HexDumpEncoder hd = new HexDumpEncoder();
- for (int i = 0; i < encKeys.length; i++) {
- System.out.println("EncryptionKey: keyType=" +
- encKeys[i].getEType() + " keyBytes (hex dump)=" +
- hd.encodeBuffer(encKeys[i].getBytes()));
+ if (ktab != null) {
+ System.out.println("Will use keytab");
+ } else if (storeKey) {
+ for (int i = 0; i < encKeys.length; i++) {
+ System.out.println("EncryptionKey: keyType=" +
+ encKeys[i].getEType() +
+ " keyBytes (hex dump)=" +
+ hd.encodeBuffer(encKeys[i].getBytes()));
+ }
}
}
@@ -989,8 +1025,8 @@ public class Krb5LoginModule implements LoginModule {
kerbTicket = Krb5Util.credsToTicket(cred);
}
- if (storeKey) {
- if (encKeys == null || encKeys.length <= 0) {
+ if (storeKey && encKeys != null) {
+ if (encKeys.length == 0) {
succeeded = false;
throw new LoginException("Null Server Key ");
}
@@ -1006,10 +1042,11 @@ public class Krb5LoginModule implements LoginModule {
}
}
- // Let us add the kerbClientPrinc,kerbTicket and kerbKey (if
+ // Let us add the kerbClientPrinc,kerbTicket and KeyTab/KerbKey (if
// storeKey is true)
- if (!princSet.contains(kerbClientPrinc))
+ if (!princSet.contains(kerbClientPrinc)) {
princSet.add(kerbClientPrinc);
+ }
// add the TGT
if (kerbTicket != null) {
@@ -1018,19 +1055,29 @@ public class Krb5LoginModule implements LoginModule {
}
if (storeKey) {
- for (int i = 0; i < kerbKeys.length; i++) {
- if (!privCredSet.contains(kerbKeys[i])) {
- privCredSet.add(kerbKeys[i]);
+ if (encKeys == null) {
+ if (!privCredSet.contains(ktab)) {
+ privCredSet.add(ktab);
+ // Compatibility; also add keys to privCredSet
+ for (KerberosKey key: ktab.getKeys(kerbClientPrinc)) {
+ privCredSet.add(new Krb5Util.KeysFromKeyTab(key));
+ }
}
- encKeys[i].destroy();
- encKeys[i] = null;
- if (debug) {
- System.out.println("Added server's key"
- + kerbKeys[i]);
- System.out.println("\t\t[Krb5LoginModule] " +
- "added Krb5Principal " +
- kerbClientPrinc.toString()
- + " to Subject");
+ } else {
+ for (int i = 0; i < kerbKeys.length; i ++) {
+ if (!privCredSet.contains(kerbKeys[i])) {
+ privCredSet.add(kerbKeys[i]);
+ }
+ encKeys[i].destroy();
+ encKeys[i] = null;
+ if (debug) {
+ System.out.println("Added server's key"
+ + kerbKeys[i]);
+ System.out.println("\t\t[Krb5LoginModule] " +
+ "added Krb5Principal " +
+ kerbClientPrinc.toString()
+ + " to Subject");
+ }
}
}
}
@@ -1106,7 +1153,8 @@ public class Krb5LoginModule implements LoginModule {
while (it.hasNext()) {
Object o = it.next();
if (o instanceof KerberosTicket ||
- o instanceof KerberosKey) {
+ o instanceof KerberosKey ||
+ o instanceof KeyTab) {
it.remove();
}
}
@@ -1161,6 +1209,7 @@ public class Krb5LoginModule implements LoginModule {
} else {
// remove temp results for the next try
encKeys = null;
+ ktab = null;
principal = null;
}
username = null;
diff --git a/src/share/classes/java/lang/ProcessBuilder.java b/src/share/classes/java/lang/ProcessBuilder.java
index c580f507d539afaf27262db5c1f51ad41113c453..6caaaeb906d32c24251cb017c313b272e3ba720f 100644
--- a/src/share/classes/java/lang/ProcessBuilder.java
+++ b/src/share/classes/java/lang/ProcessBuilder.java
@@ -938,6 +938,11 @@ public final class ProcessBuilder
* but at the very least the command must be a non-empty list of
* non-null strings.
*
+ *
A minimal set of system dependent environment variables may
+ * be required to start a process on some operating systems.
+ * As a result, the subprocess may inherit additional environment variable
+ * settings beyond those in the process builder's {@link #environment()}.
+ *
*
If there is a security manager, its
* {@link SecurityManager#checkExec checkExec}
* method is called with the first component of this object's
diff --git a/src/share/classes/java/lang/Runtime.java b/src/share/classes/java/lang/Runtime.java
index 5e4a1bceaba594ce03239a46c404e1da481309bf..3fc29d08376b69e3395758bf529fed7e5ded2d94 100644
--- a/src/share/classes/java/lang/Runtime.java
+++ b/src/share/classes/java/lang/Runtime.java
@@ -544,6 +544,11 @@ public class Runtime {
*
If envp is null, the subprocess inherits the
* environment settings of the current process.
*
+ *
A minimal set of system dependent environment variables may
+ * be required to start a process on some operating systems.
+ * As a result, the subprocess may inherit additional environment variable
+ * settings beyond those in the specified environment.
+ *
*
{@link ProcessBuilder#start()} is now the preferred way to
* start a process with a modified environment.
*
diff --git a/src/share/classes/java/util/AbstractSet.java b/src/share/classes/java/util/AbstractSet.java
index b99da00826dea463d491209d459e758218c284e4..1f1a49c250e4cdf058c12cdaaca3499c195baeb6 100644
--- a/src/share/classes/java/util/AbstractSet.java
+++ b/src/share/classes/java/util/AbstractSet.java
@@ -156,9 +156,11 @@ public abstract class AbstractSet extends AbstractCollection implements Se
* @throws UnsupportedOperationException if the removeAll operation
* is not supported by this set
* @throws ClassCastException if the class of an element of this set
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this set contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see #remove(Object)
* @see #contains(Object)
diff --git a/src/share/classes/java/util/ArrayList.java b/src/share/classes/java/util/ArrayList.java
index 128ec5b5fd864259cabdf53d4d1ce4a06d12f2a5..14b0fbf5599b76189fd30f5d89fa6daeba700814 100644
--- a/src/share/classes/java/util/ArrayList.java
+++ b/src/share/classes/java/util/ArrayList.java
@@ -628,9 +628,11 @@ public class ArrayList extends AbstractList
* @param c collection containing elements to be removed from this list
* @return {@code true} if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this list contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see Collection#contains(Object)
*/
@@ -646,9 +648,11 @@ public class ArrayList extends AbstractList
* @param c collection containing elements to be retained in this list
* @return {@code true} if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this list contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see Collection#contains(Object)
*/
diff --git a/src/share/classes/java/util/Collection.java b/src/share/classes/java/util/Collection.java
index 7d0bcdc5aa366753511117e6ccbe6a4e43ca8b59..b8f5869e861ab449d4b91628f9c2292069f553b8 100644
--- a/src/share/classes/java/util/Collection.java
+++ b/src/share/classes/java/util/Collection.java
@@ -60,7 +60,8 @@ package java.util;
* but is not required to, throw the exception if the collection to be added
* is empty.
*
- *
Some collection implementations have restrictions on the elements that
+ *
+ * Some collection implementations have restrictions on the elements that
* they may contain. For example, some implementations prohibit null elements,
* and some have restrictions on the types of their elements. Attempting to
* add an ineligible element throws an unchecked exception, typically
@@ -152,9 +153,11 @@ public interface Collection extends Iterable {
* @return true if this collection contains the specified
* element
* @throws ClassCastException if the type of the specified element
- * is incompatible with this collection (optional)
+ * is incompatible with this collection
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * collection does not permit null elements (optional)
+ * collection does not permit null elements
+ * (optional)
*/
boolean contains(Object o);
@@ -279,9 +282,11 @@ public interface Collection extends Iterable {
* @param o element to be removed from this collection, if present
* @return true if an element was removed as a result of this call
* @throws ClassCastException if the type of the specified element
- * is incompatible with this collection (optional)
+ * is incompatible with this collection
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * collection does not permit null elements (optional)
+ * collection does not permit null elements
+ * (optional)
* @throws UnsupportedOperationException if the remove operation
* is not supported by this collection
*/
@@ -299,10 +304,13 @@ public interface Collection extends Iterable {
* in the specified collection
* @throws ClassCastException if the types of one or more elements
* in the specified collection are incompatible with this
- * collection (optional)
+ * collection
+ * (optional)
* @throws NullPointerException if the specified collection contains one
* or more null elements and this collection does not permit null
- * elements (optional), or if the specified collection is null
+ * elements
+ * (optional),
+ * or if the specified collection is null.
* @see #contains(Object)
*/
boolean containsAll(Collection> c);
@@ -346,10 +354,13 @@ public interface Collection extends Iterable {
* is not supported by this collection
* @throws ClassCastException if the types of one or more elements
* in this collection are incompatible with the specified
- * collection (optional)
+ * collection
+ * (optional)
* @throws NullPointerException if this collection contains one or more
* null elements and the specified collection does not support
- * null elements (optional), or if the specified collection is null
+ * null elements
+ * (optional),
+ * or if the specified collection is null
* @see #remove(Object)
* @see #contains(Object)
*/
@@ -367,10 +378,13 @@ public interface Collection extends Iterable {
* is not supported by this collection
* @throws ClassCastException if the types of one or more elements
* in this collection are incompatible with the specified
- * collection (optional)
+ * collection
+ * (optional)
* @throws NullPointerException if this collection contains one or more
* null elements and the specified collection does not permit null
- * elements (optional), or if the specified collection is null
+ * elements
+ * (optional),
+ * or if the specified collection is null
* @see #remove(Object)
* @see #contains(Object)
*/
diff --git a/src/share/classes/java/util/Collections.java b/src/share/classes/java/util/Collections.java
index 80221c8795b160277be0a21123a4ca7c5ded2c65..d15a4292ddd818065a4570a0c5ba24ed19497724 100644
--- a/src/share/classes/java/util/Collections.java
+++ b/src/share/classes/java/util/Collections.java
@@ -3746,9 +3746,10 @@ public class Collections {
* @throws NullPointerException if either collection is {@code null}.
* @throws NullPointerException if one collection contains a {@code null}
* element and {@code null} is not an eligible element for the other collection.
- * (optional)
+ * (optional)
* @throws ClassCastException if one collection contains an element that is
- * of a type which is ineligible for the other collection. (optional)
+ * of a type which is ineligible for the other collection.
+ * (optional)
* @since 1.5
*/
public static boolean disjoint(Collection> c1, Collection> c2) {
diff --git a/src/share/classes/java/util/Deque.java b/src/share/classes/java/util/Deque.java
index b5516211be635b87c03d005c2d322643d7fdc9ba..051ae9cca46b7aa99106e6f2083d400f3745e3ae 100644
--- a/src/share/classes/java/util/Deque.java
+++ b/src/share/classes/java/util/Deque.java
@@ -351,9 +351,11 @@ public interface Deque extends Queue {
* @param o element to be removed from this deque, if present
* @return true if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
- * is incompatible with this deque (optional)
+ * is incompatible with this deque
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * deque does not permit null elements (optional)
+ * deque does not permit null elements
+ * (optional)
*/
boolean removeFirstOccurrence(Object o);
@@ -369,9 +371,11 @@ public interface Deque extends Queue {
* @param o element to be removed from this deque, if present
* @return true if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
- * is incompatible with this deque (optional)
+ * is incompatible with this deque
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * deque does not permit null elements (optional)
+ * deque does not permit null elements
+ * (optional)
*/
boolean removeLastOccurrence(Object o);
@@ -527,9 +531,11 @@ public interface Deque extends Queue {
* @param o element to be removed from this deque, if present
* @return true if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
- * is incompatible with this deque (optional)
+ * is incompatible with this deque
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * deque does not permit null elements (optional)
+ * deque does not permit null elements
+ * (optional)
*/
boolean remove(Object o);
@@ -542,9 +548,11 @@ public interface Deque extends Queue {
* @param o element whose presence in this deque is to be tested
* @return true if this deque contains the specified element
* @throws ClassCastException if the type of the specified element
- * is incompatible with this deque (optional)
+ * is incompatible with this deque
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * deque does not permit null elements (optional)
+ * deque does not permit null elements
+ * (optional)
*/
boolean contains(Object o);
diff --git a/src/share/classes/java/util/List.java b/src/share/classes/java/util/List.java
index 638fcc3a7d1276abb5585f8bee8362465077a9a6..d3d2a1b8947e617c8f51ee4d08663469722c110a 100644
--- a/src/share/classes/java/util/List.java
+++ b/src/share/classes/java/util/List.java
@@ -134,9 +134,11 @@ public interface List extends Collection {
* @param o element whose presence in this list is to be tested
* @return true if this list contains the specified element
* @throws ClassCastException if the type of the specified element
- * is incompatible with this list (optional)
+ * is incompatible with this list
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * list does not permit null elements (optional)
+ * list does not permit null elements
+ * (optional)
*/
boolean contains(Object o);
@@ -245,9 +247,11 @@ public interface List extends Collection {
* @param o element to be removed from this list, if present
* @return true if this list contained the specified element
* @throws ClassCastException if the type of the specified element
- * is incompatible with this list (optional)
+ * is incompatible with this list
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * list does not permit null elements (optional)
+ * list does not permit null elements
+ * (optional)
* @throws UnsupportedOperationException if the remove operation
* is not supported by this list
*/
@@ -265,10 +269,13 @@ public interface List extends Collection {
* specified collection
* @throws ClassCastException if the types of one or more elements
* in the specified collection are incompatible with this
- * list (optional)
+ * list
+ * (optional)
* @throws NullPointerException if the specified collection contains one
* or more null elements and this list does not permit null
- * elements (optional), or if the specified collection is null
+ * elements
+ * (optional),
+ * or if the specified collection is null
* @see #contains(Object)
*/
boolean containsAll(Collection> c);
@@ -334,9 +341,11 @@ public interface List extends Collection {
* @throws UnsupportedOperationException if the removeAll operation
* is not supported by this list
* @throws ClassCastException if the class of an element of this list
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this list contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see #remove(Object)
* @see #contains(Object)
@@ -354,9 +363,11 @@ public interface List extends Collection {
* @throws UnsupportedOperationException if the retainAll operation
* is not supported by this list
* @throws ClassCastException if the class of an element of this list
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this list contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see #remove(Object)
* @see #contains(Object)
@@ -493,9 +504,11 @@ public interface List extends Collection {
* @return the index of the first occurrence of the specified element in
* this list, or -1 if this list does not contain the element
* @throws ClassCastException if the type of the specified element
- * is incompatible with this list (optional)
+ * is incompatible with this list
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * list does not permit null elements (optional)
+ * list does not permit null elements
+ * (optional)
*/
int indexOf(Object o);
@@ -510,9 +523,11 @@ public interface List extends Collection {
* @return the index of the last occurrence of the specified element in
* this list, or -1 if this list does not contain the element
* @throws ClassCastException if the type of the specified element
- * is incompatible with this list (optional)
+ * is incompatible with this list
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * list does not permit null elements (optional)
+ * list does not permit null elements
+ * (optional)
*/
int lastIndexOf(Object o);
diff --git a/src/share/classes/java/util/Map.java b/src/share/classes/java/util/Map.java
index 2f8f1315c1fe22604a9d9358083ccf247aa0e009..ccdb28813a2f5933cb89c7d0018a3b72c7e79ac6 100644
--- a/src/share/classes/java/util/Map.java
+++ b/src/share/classes/java/util/Map.java
@@ -144,9 +144,11 @@ public interface Map {
* @return true if this map contains a mapping for the specified
* key
* @throws ClassCastException if the key is of an inappropriate type for
- * this map (optional)
+ * this map
+ * (optional)
* @throws NullPointerException if the specified key is null and this map
- * does not permit null keys (optional)
+ * does not permit null keys
+ * (optional)
*/
boolean containsKey(Object key);
@@ -162,9 +164,11 @@ public interface Map {
* @return true if this map maps one or more keys to the
* specified value
* @throws ClassCastException if the value is of an inappropriate type for
- * this map (optional)
+ * this map
+ * (optional)
* @throws NullPointerException if the specified value is null and this
- * map does not permit null values (optional)
+ * map does not permit null values
+ * (optional)
*/
boolean containsValue(Object value);
@@ -187,9 +191,11 @@ public interface Map {
* @return the value to which the specified key is mapped, or
* {@code null} if this map contains no mapping for the key
* @throws ClassCastException if the key is of an inappropriate type for
- * this map (optional)
+ * this map
+ * (optional)
* @throws NullPointerException if the specified key is null and this map
- * does not permit null keys (optional)
+ * does not permit null keys
+ * (optional)
*/
V get(Object key);
@@ -245,9 +251,11 @@ public interface Map {
* @throws UnsupportedOperationException if the remove operation
* is not supported by this map
* @throws ClassCastException if the key is of an inappropriate type for
- * this map (optional)
+ * this map
+ * (optional)
* @throws NullPointerException if the specified key is null and this
- * map does not permit null keys (optional)
+ * map does not permit null keys
+ * (optional)
*/
V remove(Object key);
@@ -466,4 +474,5 @@ public interface Map {
* @see #equals(Object)
*/
int hashCode();
+
}
diff --git a/src/share/classes/java/util/Set.java b/src/share/classes/java/util/Set.java
index 8d54f4f9d455865cd9e1831656c33411604bc36f..004e9708e562c4408f9395781183be546cd9f375 100644
--- a/src/share/classes/java/util/Set.java
+++ b/src/share/classes/java/util/Set.java
@@ -110,9 +110,11 @@ public interface Set extends Collection {
* @param o element whose presence in this set is to be tested
* @return true if this set contains the specified element
* @throws ClassCastException if the type of the specified element
- * is incompatible with this set (optional)
+ * is incompatible with this set
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * set does not permit null elements (optional)
+ * set does not permit null elements
+ * (optional)
*/
boolean contains(Object o);
@@ -236,9 +238,11 @@ public interface Set extends Collection {
* @param o object to be removed from this set, if present
* @return true if this set contained the specified element
* @throws ClassCastException if the type of the specified element
- * is incompatible with this set (optional)
+ * is incompatible with this set
+ * (optional)
* @throws NullPointerException if the specified element is null and this
- * set does not permit null elements (optional)
+ * set does not permit null elements
+ * (optional)
* @throws UnsupportedOperationException if the remove operation
* is not supported by this set
*/
@@ -257,10 +261,13 @@ public interface Set extends Collection {
* specified collection
* @throws ClassCastException if the types of one or more elements
* in the specified collection are incompatible with this
- * set (optional)
+ * set
+ * (optional)
* @throws NullPointerException if the specified collection contains one
* or more null elements and this set does not permit null
- * elements (optional), or if the specified collection is null
+ * elements
+ * (optional),
+ * or if the specified collection is null
* @see #contains(Object)
*/
boolean containsAll(Collection> c);
@@ -302,9 +309,11 @@ public interface Set extends Collection {
* @throws UnsupportedOperationException if the retainAll operation
* is not supported by this set
* @throws ClassCastException if the class of an element of this set
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this set contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see #remove(Object)
*/
@@ -322,9 +331,11 @@ public interface Set extends Collection {
* @throws UnsupportedOperationException if the removeAll operation
* is not supported by this set
* @throws ClassCastException if the class of an element of this set
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this set contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see #remove(Object)
* @see #contains(Object)
diff --git a/src/share/classes/java/util/Vector.java b/src/share/classes/java/util/Vector.java
index 0c89889b19bd13f884183a1386da94db0d2c258a..0d69591abce962f3230d8a4a02af21a505db2443 100644
--- a/src/share/classes/java/util/Vector.java
+++ b/src/share/classes/java/util/Vector.java
@@ -893,10 +893,13 @@ public class Vector
* @return true if this Vector changed as a result of the call
* @throws ClassCastException if the types of one or more elements
* in this vector are incompatible with the specified
- * collection (optional)
+ * collection
+ * (optional)
* @throws NullPointerException if this vector contains one or more null
* elements and the specified collection does not support null
- * elements (optional), or if the specified collection is null
+ * elements
+ * (optional),
+ * or if the specified collection is null
* @since 1.2
*/
public synchronized boolean removeAll(Collection> c) {
@@ -913,10 +916,13 @@ public class Vector
* @return true if this Vector changed as a result of the call
* @throws ClassCastException if the types of one or more elements
* in this vector are incompatible with the specified
- * collection (optional)
+ * collection
+ * (optional)
* @throws NullPointerException if this vector contains one or more null
* elements and the specified collection does not support null
- * elements (optional), or if the specified collection is null
+ * elements
+ * (optional),
+ * or if the specified collection is null
* @since 1.2
*/
public synchronized boolean retainAll(Collection> c) {
diff --git a/src/share/classes/java/util/concurrent/BlockingDeque.java b/src/share/classes/java/util/concurrent/BlockingDeque.java
index 3134eae8ec5d5c64abc84aebd6968149d49e193e..7f37f7e66ea3ebe4d47f9edd1cbcad350b3622f0 100644
--- a/src/share/classes/java/util/concurrent/BlockingDeque.java
+++ b/src/share/classes/java/util/concurrent/BlockingDeque.java
@@ -400,8 +400,10 @@ public interface BlockingDeque extends BlockingQueue, Deque {
* @param o element to be removed from this deque, if present
* @return true if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
- * is incompatible with this deque (optional)
- * @throws NullPointerException if the specified element is null (optional)
+ * is incompatible with this deque
+ * (optional)
+ * @throws NullPointerException if the specified element is null
+ * (optional)
*/
boolean removeFirstOccurrence(Object o);
@@ -416,8 +418,10 @@ public interface BlockingDeque extends BlockingQueue, Deque {
* @param o element to be removed from this deque, if present
* @return true if an element was removed as a result of this call
* @throws ClassCastException if the class of the specified element
- * is incompatible with this deque (optional)
- * @throws NullPointerException if the specified element is null (optional)
+ * is incompatible with this deque
+ * (optional)
+ * @throws NullPointerException if the specified element is null
+ * (optional)
*/
boolean removeLastOccurrence(Object o);
@@ -591,8 +595,10 @@ public interface BlockingDeque extends BlockingQueue, Deque {
* @param o element to be removed from this deque, if present
* @return true if this deque changed as a result of the call
* @throws ClassCastException if the class of the specified element
- * is incompatible with this deque (optional)
- * @throws NullPointerException if the specified element is null (optional)
+ * is incompatible with this deque
+ * (optional)
+ * @throws NullPointerException if the specified element is null
+ * (optional)
*/
boolean remove(Object o);
@@ -604,8 +610,10 @@ public interface BlockingDeque extends BlockingQueue, Deque {
* @param o object to be checked for containment in this deque
* @return true if this deque contains the specified element
* @throws ClassCastException if the class of the specified element
- * is incompatible with this deque (optional)
- * @throws NullPointerException if the specified element is null (optional)
+ * is incompatible with this deque
+ * (optional)
+ * @throws NullPointerException if the specified element is null
+ * (optional)
*/
public boolean contains(Object o);
diff --git a/src/share/classes/java/util/concurrent/BlockingQueue.java b/src/share/classes/java/util/concurrent/BlockingQueue.java
index 9886e6da3c103ed20b321c7ce159a415cf8890ab..4511d27efd76413731a872e9083d7e6eea5e40f4 100644
--- a/src/share/classes/java/util/concurrent/BlockingQueue.java
+++ b/src/share/classes/java/util/concurrent/BlockingQueue.java
@@ -303,8 +303,10 @@ public interface BlockingQueue extends Queue {
* @param o element to be removed from this queue, if present
* @return true if this queue changed as a result of the call
* @throws ClassCastException if the class of the specified element
- * is incompatible with this queue (optional)
- * @throws NullPointerException if the specified element is null (optional)
+ * is incompatible with this queue
+ * (optional)
+ * @throws NullPointerException if the specified element is null
+ * (optional)
*/
boolean remove(Object o);
@@ -316,8 +318,10 @@ public interface BlockingQueue extends Queue {
* @param o object to be checked for containment in this queue
* @return true if this queue contains the specified element
* @throws ClassCastException if the class of the specified element
- * is incompatible with this queue (optional)
- * @throws NullPointerException if the specified element is null (optional)
+ * is incompatible with this queue
+ * (optional)
+ * @throws NullPointerException if the specified element is null
+ * (optional)
*/
public boolean contains(Object o);
diff --git a/src/share/classes/java/util/concurrent/ConcurrentMap.java b/src/share/classes/java/util/concurrent/ConcurrentMap.java
index 25cf98ff0f1e5c6e8020ef8bd09969d27239a11f..4434c0563b4334e97411e79eef384e76606e0308 100644
--- a/src/share/classes/java/util/concurrent/ConcurrentMap.java
+++ b/src/share/classes/java/util/concurrent/ConcurrentMap.java
@@ -103,9 +103,11 @@ public interface ConcurrentMap extends Map {
* @throws UnsupportedOperationException if the remove operation
* is not supported by this map
* @throws ClassCastException if the key or value is of an inappropriate
- * type for this map (optional)
+ * type for this map
+ * (optional)
* @throws NullPointerException if the specified key or value is null,
- * and this map does not permit null keys or values (optional)
+ * and this map does not permit null keys or values
+ * (optional)
*/
boolean remove(Object key, Object value);
diff --git a/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java
index 2774e61136a7a3927e1c96ea6daaa21f8aa54b9c..785ec6fcede229d4c1f7e32c1a6a8ac6b13eee14 100644
--- a/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java
+++ b/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java
@@ -631,9 +631,11 @@ public class CopyOnWriteArrayList
* @param c collection containing elements to be removed from this list
* @return true if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this list contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see #remove(Object)
*/
@@ -671,9 +673,11 @@ public class CopyOnWriteArrayList
* @param c collection containing elements to be retained in this list
* @return true if this list changed as a result of the call
* @throws ClassCastException if the class of an element of this list
- * is incompatible with the specified collection (optional)
+ * is incompatible with the specified collection
+ * (optional)
* @throws NullPointerException if this list contains a null element and the
- * specified collection does not permit null elements (optional),
+ * specified collection does not permit null elements
+ * (optional),
* or if the specified collection is null
* @see #remove(Object)
*/
diff --git a/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java b/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..56ed40eed3e391fd8897d1d5c360076bce1d805a
--- /dev/null
+++ b/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+package javax.security.auth.kerberos;
+
+import sun.misc.JavaxSecurityAuthKerberosAccess;
+import sun.security.krb5.EncryptionKey;
+import sun.security.krb5.PrincipalName;
+
+class JavaxSecurityAuthKerberosAccessImpl
+ implements JavaxSecurityAuthKerberosAccess {
+ public EncryptionKey[] keyTabGetEncryptionKeys(
+ KeyTab ktab, PrincipalName principal) {
+ return ktab.getEncryptionKeys(principal);
+ }
+}
diff --git a/src/share/classes/javax/security/auth/kerberos/KerberosKey.java b/src/share/classes/javax/security/auth/kerberos/KerberosKey.java
index 7eb7118a5bcc7cb889e505f0b989a45a4bb33099..ba530f9583c849a69d08527206814f648de91561 100644
--- a/src/share/classes/javax/security/auth/kerberos/KerberosKey.java
+++ b/src/share/classes/javax/security/auth/kerberos/KerberosKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -35,14 +35,16 @@ import javax.security.auth.DestroyFailedException;
* principal.
*
* All Kerberos JAAS login modules that obtain a principal's password and
- * generate the secret key from it should use this class. Where available,
- * the login module might even read this secret key directly from a
- * Kerberos "keytab". Sometimes, such as when authenticating a server in
+ * generate the secret key from it should use this class.
+ * Sometimes, such as when authenticating a server in
* the absence of user-to-user authentication, the login module will store
* an instance of this class in the private credential set of a
* {@link javax.security.auth.Subject Subject} during the commit phase of the
* authentication process.
*
+ * A Kerberos service using a keytab to read secret keys should use
+ * the {@link KeyTab} class, where latest keys can be read when needed.
+ *
* It might be necessary for the application to be granted a
* {@link javax.security.auth.PrivateCredentialPermission
* PrivateCredentialPermission} if it needs to access the KerberosKey
diff --git a/src/share/classes/javax/security/auth/kerberos/KeyTab.java b/src/share/classes/javax/security/auth/kerberos/KeyTab.java
new file mode 100644
index 0000000000000000000000000000000000000000..c2f8dd79478baccae14b76c19a02033ddb0a9b7c
--- /dev/null
+++ b/src/share/classes/javax/security/auth/kerberos/KeyTab.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+package javax.security.auth.kerberos;
+
+import java.io.File;
+import java.util.Objects;
+import sun.misc.SharedSecrets;
+import sun.security.krb5.EncryptionKey;
+import sun.security.krb5.PrincipalName;
+import sun.security.krb5.RealmException;
+
+/**
+ * This class encapsulates a keytab file.
+ *
+ * A Kerberos JAAS login module that obtains long term secret keys from a
+ * keytab file should use this class. The login module will store
+ * an instance of this class in the private credential set of a
+ * {@link javax.security.auth.Subject Subject} during the commit phase of the
+ * authentication process.
+ *
+ * It might be necessary for the application to be granted a
+ * {@link javax.security.auth.PrivateCredentialPermission
+ * PrivateCredentialPermission} if it needs to access the KeyTab
+ * instance from a Subject. This permission is not needed when the
+ * application depends on the default JGSS Kerberos mechanism to access the
+ * KeyTab. In that case, however, the application will need an appropriate
+ * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}.
+ *
+ * The keytab file format is described at
+ *
+ * http://www.ioplex.com/utilities/keytab.txt.
+ *
+ * @since 1.7
+ */
+public final class KeyTab {
+
+ /*
+ * Impl notes:
+ *
+ * This class is only a name, a permanent link to the keytab source
+ * (can be missing). Itself has no content. In order to read content,
+ * take a snapshot and read from it.
+ *
+ * The snapshot is of type sun.security.krb5.internal.ktab.KeyTab, which
+ * contains the content of the keytab file when the snapshot is taken.
+ * Itself has no refresh function and mostly an immutable class (except
+ * for the create/add/save methods only used by the ktab command).
+ */
+
+ // Source, null if using the default one. Note that the default name
+ // is maintained in snapshot, this field is never "resolved".
+ private final File file;
+
+ // Set up JavaxSecurityAuthKerberosAccess in SharedSecrets
+ static {
+ SharedSecrets.setJavaxSecurityAuthKerberosAccess(
+ new JavaxSecurityAuthKerberosAccessImpl());
+ }
+
+ private KeyTab(File file) {
+ this.file = file;
+ }
+
+ /**
+ * Returns a {@code KeyTab} instance from a {@code File} object.
+ *
+ * The result of this method is never null. This method only associates
+ * the returned {@code KeyTab} object with the file and does not read it.
+ * @param file the keytab {@code File} object, must not be null
+ * @return the keytab instance
+ * @throws NullPointerException if the {@code file} argument is null
+ */
+ public static KeyTab getInstance(File file) {
+ if (file == null) {
+ throw new NullPointerException("file must be non null");
+ }
+ return new KeyTab(file);
+ }
+
+ /**
+ * Returns the default {@code KeyTab} instance.
+ *
+ * The result of this method is never null. This method only associates
+ * the returned {@code KeyTab} object with the default keytab file and
+ * does not read it.
+ * @return the default keytab instance.
+ */
+ public static KeyTab getInstance() {
+ return new KeyTab(null);
+ }
+
+ //Takes a snapshot of the keytab content
+ private sun.security.krb5.internal.ktab.KeyTab takeSnapshot() {
+ return sun.security.krb5.internal.ktab.KeyTab.getInstance(file);
+ }
+
+ /**
+ * Returns fresh keys for the given Kerberos principal.
+ *
+ * Implementation of this method should make sure the returned keys match
+ * the latest content of the keytab file. The result is a newly created
+ * copy that can be modified by the caller without modifying the keytab
+ * object. The caller should {@link KerberosKey#destroy() destroy} the
+ * result keys after they are used.
+ *
+ * Please note that the keytab file can be created after the
+ * {@code KeyTab} object is instantiated and its content may change over
+ * time. Therefore, an application should call this method only when it
+ * needs to use the keys. Any previous result from an earlier invocation
+ * could potentially be expired.
+ *
+ * If there is any error (say, I/O error or format error)
+ * during the reading process of the KeyTab file, a saved result should be
+ * returned. If there is no saved result (say, this is the first time this
+ * method is called, or, all previous read attempts failed), an empty array
+ * should be returned. This can make sure the result is not drastically
+ * changed during the (probably slow) update of the keytab file.
+ *
+ * Each time this method is called and the reading of the file succeeds
+ * with no exception (say, I/O error or file format error),
+ * the result should be saved for {@code principal}. The implementation can
+ * also save keys for other principals having keys in the same keytab object
+ * if convenient.
+ *
+ * Any unsupported key read from the keytab is ignored and not included
+ * in the result.
+ *
+ * @param principal the Kerberos principal, must not be null.
+ * @return the keys (never null, may be empty)
+ * @throws NullPointerException if the {@code principal}
+ * argument is null
+ * @throws SecurityException if a security manager exists and the read
+ * access to the keytab file is not permitted
+ */
+ public KerberosKey[] getKeys(KerberosPrincipal principal) {
+ try {
+ EncryptionKey[] keys = takeSnapshot().readServiceKeys(
+ new PrincipalName(principal.getName()));
+ KerberosKey[] kks = new KerberosKey[keys.length];
+ for (int i=0; i
+ * The caller can use the result to determine if it should fallback to
+ * another mechanism to read the keys.
+ * @return true if the keytab file exists; false otherwise.
+ * @throws SecurityException if a security manager exists and the read
+ * access to the keytab file is not permitted
+ */
+ public boolean exists() {
+ return !takeSnapshot().isMissing();
+ }
+
+ public String toString() {
+ return file == null ? "Default keytab" : file.toString();
+ }
+
+ /**
+ * Returns a hashcode for this KeyTab.
+ *
+ * @return a hashCode() for the KeyTab
+ */
+ public int hashCode() {
+ return Objects.hash(file);
+ }
+
+ /**
+ * Compares the specified Object with this KeyTab for equality.
+ * Returns true if the given object is also a
+ * KeyTab and the two
+ * KeyTab instances are equivalent.
+ *
+ * @param other the Object to compare to
+ * @return true if the specified object is equal to this KeyTab
+ */
+ public boolean equals(Object other) {
+ if (other == this)
+ return true;
+
+ if (! (other instanceof KeyTab)) {
+ return false;
+ }
+
+ KeyTab otherKtab = (KeyTab) other;
+ return Objects.equals(otherKtab.file, file);
+ }
+}
diff --git a/src/share/classes/sun/misc/JavaxSecurityAuthKerberosAccess.java b/src/share/classes/sun/misc/JavaxSecurityAuthKerberosAccess.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c8f9f2d3d20a8e66f27db2e8a61bac0606010ca
--- /dev/null
+++ b/src/share/classes/sun/misc/JavaxSecurityAuthKerberosAccess.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+package sun.misc;
+
+import javax.security.auth.kerberos.KeyTab;
+import sun.security.krb5.EncryptionKey;
+import sun.security.krb5.PrincipalName;
+
+/**
+ * An unsafe tunnel to get non-public access to classes in the
+ * javax.security.auth.kerberos package.
+ */
+public interface JavaxSecurityAuthKerberosAccess {
+ /**
+ * Returns keys for a principal in a keytab.
+ * @return the keys, never null, can be empty.
+ */
+ public EncryptionKey[] keyTabGetEncryptionKeys(
+ KeyTab ktab, PrincipalName principal);
+}
diff --git a/src/share/classes/sun/misc/SharedSecrets.java b/src/share/classes/sun/misc/SharedSecrets.java
index 0bd39b4a5d42f0b12478143bad17dce21db3ba11..969da9a744fe8dfadf558e8e220f1856fc5c52f5 100644
--- a/src/share/classes/sun/misc/SharedSecrets.java
+++ b/src/share/classes/sun/misc/SharedSecrets.java
@@ -29,6 +29,7 @@ import java.util.jar.JarFile;
import java.io.Console;
import java.io.FileDescriptor;
import java.security.ProtectionDomain;
+import javax.security.auth.kerberos.KeyTab;
import java.security.AccessController;
@@ -51,6 +52,7 @@ public class SharedSecrets {
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess;
private static JavaSecurityAccess javaSecurityAccess;
+ private static JavaxSecurityAuthKerberosAccess javaxSecurityAuthKerberosAccess;
public static JavaUtilJarAccess javaUtilJarAccess() {
if (javaUtilJarAccess == null) {
@@ -139,4 +141,16 @@ public class SharedSecrets {
}
return javaSecurityAccess;
}
+
+ public static void setJavaxSecurityAuthKerberosAccess
+ (JavaxSecurityAuthKerberosAccess jsaka) {
+ javaxSecurityAuthKerberosAccess = jsaka;
+ }
+
+ public static JavaxSecurityAuthKerberosAccess
+ getJavaxSecurityAuthKerberosAccess() {
+ if (javaxSecurityAuthKerberosAccess == null)
+ unsafe.ensureClassInitialized(KeyTab.class);
+ return javaxSecurityAuthKerberosAccess;
+ }
}
diff --git a/src/share/classes/sun/rmi/log/ReliableLog.java b/src/share/classes/sun/rmi/log/ReliableLog.java
index 30ea3f1d4647b4e5cc067a38f47cc7c1fca0d190..fe512c2d87c1273c6e851365e65c675cc19b52fa 100644
--- a/src/share/classes/sun/rmi/log/ReliableLog.java
+++ b/src/share/classes/sun/rmi/log/ReliableLog.java
@@ -380,9 +380,7 @@ public class ReliableLog {
} catch (IOException e) {
throw e;
} catch (Exception e) {
- throw new IOException("snapshot failed with exception of type: " +
- e.getClass().getName() +
- ", message was: " + e.getMessage());
+ throw new IOException("snapshot failed", e);
}
lastSnapshot = System.currentTimeMillis();
} finally {
diff --git a/src/share/classes/sun/rmi/server/Activation.java b/src/share/classes/sun/rmi/server/Activation.java
index 119910ed5ccb0760a8629e2547f32d5d1aab6e17..919edb7fb657ab45cfb99212f015eceb9e685a7f 100644
--- a/src/share/classes/sun/rmi/server/Activation.java
+++ b/src/share/classes/sun/rmi/server/Activation.java
@@ -30,6 +30,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
@@ -98,6 +99,7 @@ import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import sun.rmi.log.LogHandler;
import sun.rmi.log.ReliableLog;
import sun.rmi.registry.RegistryImpl;
@@ -147,10 +149,10 @@ public class Activation implements Serializable {
/** maps activation id to its respective group id */
private Map idTable =
- new HashMap();
+ new ConcurrentHashMap<>();
/** maps group id to its GroupEntry groups */
private Map groupTable =
- new HashMap();
+ new ConcurrentHashMap<>();
private byte majorVersion = MAJOR_VERSION;
private byte minorVersion = MINOR_VERSION;
@@ -236,9 +238,11 @@ public class Activation implements Serializable {
groupSemaphore = getInt("sun.rmi.activation.groupThrottle", 3);
groupCounter = 0;
Runtime.getRuntime().addShutdownHook(shutdownHook);
+
+ // Use array size of 0, since the value from calling size()
+ // may be out of date by the time toArray() is called.
ActivationGroupID[] gids =
- groupTable.keySet().toArray(
- new ActivationGroupID[groupTable.size()]);
+ groupTable.keySet().toArray(new ActivationGroupID[0]);
synchronized (startupLock = new Object()) {
// all the remote methods briefly synchronize on startupLock
@@ -274,6 +278,23 @@ public class Activation implements Serializable {
}
}
+ /**
+ * Previous versions used HashMap instead of ConcurrentHashMap.
+ * Replace any HashMaps found during deserialization with
+ * ConcurrentHashMaps.
+ */
+ private void readObject(ObjectInputStream ois)
+ throws IOException, ClassNotFoundException
+ {
+ ois.defaultReadObject();
+ if (! (groupTable instanceof ConcurrentHashMap)) {
+ groupTable = new ConcurrentHashMap<>(groupTable);
+ }
+ if (! (idTable instanceof ConcurrentHashMap)) {
+ idTable = new ConcurrentHashMap<>(idTable);
+ }
+ }
+
private static class SystemRegistryImpl extends RegistryImpl {
private static final String NAME = ActivationSystem.class.getName();
@@ -488,9 +509,7 @@ public class Activation implements Serializable {
ActivationGroupID id = new ActivationGroupID(systemStub);
GroupEntry entry = new GroupEntry(id, desc);
// table insertion must take place before log update
- synchronized (groupTable) {
- groupTable.put(id, entry);
- }
+ groupTable.put(id, entry);
addLogRecord(new LogRegisterGroup(id, desc));
return id;
}
@@ -515,11 +534,7 @@ public class Activation implements Serializable {
// remove entry before unregister so state is updated before
// logged
- synchronized (groupTable) {
- GroupEntry entry = getGroupEntry(id);
- groupTable.remove(id);
- entry.unregisterGroup(true);
- }
+ removeGroupEntry(id).unregisterGroup(true);
}
public ActivationDesc setActivationDesc(ActivationID id,
@@ -637,12 +652,7 @@ public class Activation implements Serializable {
unexport(system);
// destroy all child processes (groups)
- GroupEntry[] groupEntries;
- synchronized (groupTable) {
- groupEntries = groupTable.values().
- toArray(new GroupEntry[groupTable.size()]);
- }
- for (GroupEntry groupEntry : groupEntries) {
+ for (GroupEntry groupEntry : groupTable.values()) {
groupEntry.shutdown();
}
@@ -693,10 +703,8 @@ public class Activation implements Serializable {
}
// destroy all child processes (groups) quickly
- synchronized (groupTable) {
- for (GroupEntry groupEntry : groupTable.values()) {
- groupEntry.shutdownFast();
- }
+ for (GroupEntry groupEntry : groupTable.values()) {
+ groupEntry.shutdownFast();
}
}
}
@@ -708,33 +716,54 @@ public class Activation implements Serializable {
private ActivationGroupID getGroupID(ActivationID id)
throws UnknownObjectException
{
- synchronized (idTable) {
- ActivationGroupID groupID = idTable.get(id);
- if (groupID != null) {
- return groupID;
- }
+ ActivationGroupID groupID = idTable.get(id);
+ if (groupID != null) {
+ return groupID;
}
throw new UnknownObjectException("unknown object: " + id);
}
/**
- * Returns the group entry for the group id. Throws
- * UnknownGroupException if the group is not registered.
+ * Returns the group entry for the group id, optionally removing it.
+ * Throws UnknownGroupException if the group is not registered.
*/
- private GroupEntry getGroupEntry(ActivationGroupID id)
+ private GroupEntry getGroupEntry(ActivationGroupID id, boolean rm)
throws UnknownGroupException
{
if (id.getClass() == ActivationGroupID.class) {
- synchronized (groupTable) {
- GroupEntry entry = groupTable.get(id);
- if (entry != null && !entry.removed) {
- return entry;
- }
+ GroupEntry entry;
+ if (rm) {
+ entry = groupTable.remove(id);
+ } else {
+ entry = groupTable.get(id);
+ }
+ if (entry != null && !entry.removed) {
+ return entry;
}
}
throw new UnknownGroupException("group unknown");
}
+ /**
+ * Returns the group entry for the group id. Throws
+ * UnknownGroupException if the group is not registered.
+ */
+ private GroupEntry getGroupEntry(ActivationGroupID id)
+ throws UnknownGroupException
+ {
+ return getGroupEntry(id, false);
+ }
+
+ /**
+ * Removes and returns the group entry for the group id. Throws
+ * UnknownGroupException if the group is not registered.
+ */
+ private GroupEntry removeGroupEntry(ActivationGroupID id)
+ throws UnknownGroupException
+ {
+ return getGroupEntry(id, true);
+ }
+
/**
* Returns the group entry for the object's id. Throws
* UnknownObjectException if the object is not registered or the
@@ -744,11 +773,9 @@ public class Activation implements Serializable {
throws UnknownObjectException
{
ActivationGroupID gid = getGroupID(id);
- synchronized (groupTable) {
- GroupEntry entry = groupTable.get(gid);
- if (entry != null) {
- return entry;
- }
+ GroupEntry entry = groupTable.get(gid);
+ if (entry != null && !entry.removed) {
+ return entry;
}
throw new UnknownObjectException("object's group removed");
}
@@ -882,9 +909,7 @@ public class Activation implements Serializable {
}
// table insertion must take place before log update
- synchronized (idTable) {
- idTable.put(id, groupID);
- }
+ idTable.put(id, groupID);
if (addRecord) {
addLogRecord(new LogRegisterObject(id, desc));
@@ -901,10 +926,8 @@ public class Activation implements Serializable {
restartSet.remove(id);
}
- // table insertion must take place before log update
- synchronized (idTable) {
- idTable.remove(id);
- }
+ // table removal must take place before log update
+ idTable.remove(id);
if (addRecord) {
addLogRecord(new LogUnregisterObject(id));
}
@@ -919,9 +942,7 @@ public class Activation implements Serializable {
objects.entrySet())
{
ActivationID id = entry.getKey();
- synchronized (idTable) {
- idTable.remove(id);
- }
+ idTable.remove(id);
ObjectEntry objEntry = entry.getValue();
objEntry.removed = true;
}
diff --git a/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java b/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java
index 7a7156d9b1cad0b1b093e8c1ed3cb9f9c65d8e38..1df500bc5242a8bd217bb818a499c4659b1efde6 100644
--- a/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java
+++ b/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -29,7 +29,6 @@ import org.ietf.jgss.*;
import sun.security.jgss.GSSCaller;
import sun.security.jgss.spi.*;
import sun.security.krb5.*;
-import javax.security.auth.kerberos.*;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.AccessController;
@@ -43,40 +42,23 @@ import javax.security.auth.DestroyFailedException;
* @since 1.4
*/
public class Krb5AcceptCredential
- extends KerberosKey
implements Krb5CredElement {
private static final long serialVersionUID = 7714332137352567952L;
private Krb5NameElement name;
- /**
- * We cache an EncryptionKey representation of this key because many
- * Krb5 operation require a key in that form. At some point we might do
- * away with EncryptionKey altogether and use the base class
- * KerberosKey everywhere.
- */
- private EncryptionKey[] krb5EncryptionKeys;
+ private Krb5Util.ServiceCreds screds;
- private Krb5AcceptCredential(Krb5NameElement name, KerberosKey[] keys) {
+ private Krb5AcceptCredential(Krb5NameElement name, Krb5Util.ServiceCreds creds) {
/*
* Initialize this instance with the data from the acquired
* KerberosKey. This class needs to be a KerberosKey too
* hence we can't just store a reference.
*/
- super(keys[0].getPrincipal(),
- keys[0].getEncoded(),
- keys[0].getKeyType(),
- keys[0].getVersionNumber());
this.name = name;
- // Cache this for later use by the sun.security.krb5 package.
- krb5EncryptionKeys = new EncryptionKey[keys.length];
- for (int i = 0; i < keys.length; i++) {
- krb5EncryptionKeys[i] = new EncryptionKey(keys[i].getEncoded(),
- keys[i].getKeyType(),
- new Integer(keys[i].getVersionNumber()));
- }
+ this.screds = creds;
}
static Krb5AcceptCredential getInstance(final GSSCaller caller, Krb5NameElement name)
@@ -86,12 +68,12 @@ public class Krb5AcceptCredential
name.getKrb5PrincipalName().getName());
final AccessControlContext acc = AccessController.getContext();
- KerberosKey[] keys;
+ Krb5Util.ServiceCreds creds = null;
try {
- keys = AccessController.doPrivileged(
- new PrivilegedExceptionAction() {
- public KerberosKey[] run() throws Exception {
- return Krb5Util.getKeys(
+ creds = AccessController.doPrivileged(
+ new PrivilegedExceptionAction() {
+ public Krb5Util.ServiceCreds run() throws Exception {
+ return Krb5Util.getServiceCreds(
caller == GSSCaller.CALLER_UNKNOWN ? GSSCaller.CALLER_ACCEPT: caller,
serverPrinc, acc);
}});
@@ -103,17 +85,17 @@ public class Krb5AcceptCredential
throw ge;
}
- if (keys == null || keys.length == 0)
+ if (creds == null)
throw new GSSException(GSSException.NO_CRED, -1,
- "Failed to find any Kerberos Key");
+ "Failed to find any Kerberos credentails");
if (name == null) {
- String fullName = keys[0].getPrincipal().getName();
+ String fullName = creds.getName();
name = Krb5NameElement.getInstance(fullName,
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
}
- return new Krb5AcceptCredential(name, keys);
+ return new Krb5AcceptCredential(name, creds);
}
/**
@@ -171,7 +153,7 @@ public class Krb5AcceptCredential
}
EncryptionKey[] getKrb5EncryptionKeys() {
- return krb5EncryptionKeys;
+ return screds.getEKeys();
}
/**
@@ -193,13 +175,6 @@ public class Krb5AcceptCredential
* destroy in the base class.
*/
public void destroy() throws DestroyFailedException {
- if (krb5EncryptionKeys != null) {
- for (int i = 0; i < krb5EncryptionKeys.length; i++) {
- krb5EncryptionKeys[i].destroy();
- }
- krb5EncryptionKeys = null;
- }
-
- super.destroy();
+ screds.destroy();
}
}
diff --git a/src/share/classes/sun/security/jgss/krb5/Krb5Util.java b/src/share/classes/sun/security/jgss/krb5/Krb5Util.java
index d5b172f92497ecd41b6b2faffb50b64fc0da1356..22552a71c3fff910153721985e9b98ffe667da5a 100644
--- a/src/share/classes/sun/security/jgss/krb5/Krb5Util.java
+++ b/src/share/classes/sun/security/jgss/krb5/Krb5Util.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, 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
@@ -28,6 +28,7 @@ package sun.security.jgss.krb5;
import javax.security.auth.kerberos.KerberosTicket;
import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KeyTab;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import java.security.AccessControlContext;
@@ -38,7 +39,13 @@ import sun.security.krb5.Credentials;
import sun.security.krb5.EncryptionKey;
import sun.security.krb5.KrbException;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import sun.misc.SharedSecrets;
+import sun.security.krb5.PrincipalName;
/**
* Utilities for obtaining and converting Kerberos tickets.
*
@@ -75,7 +82,7 @@ public class Krb5Util {
// 1. Try to find service ticket in acc subject
Subject accSubj = Subject.getSubject(acc);
- KerberosTicket ticket = (KerberosTicket) SubjectComber.find(accSubj,
+ KerberosTicket ticket = SubjectComber.find(accSubj,
serverPrincipal, clientPrincipal, KerberosTicket.class);
if (ticket != null) {
@@ -87,7 +94,7 @@ public class Krb5Util {
// 2. Try to get ticket from login
try {
loginSubj = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
- ticket = (KerberosTicket) SubjectComber.find(loginSubj,
+ ticket = SubjectComber.find(loginSubj,
serverPrincipal, clientPrincipal, KerberosTicket.class);
if (ticket != null) {
return ticket; // found it
@@ -102,13 +109,13 @@ public class Krb5Util {
// Try to get TGT to acquire service ticket
// 3. Try to get TGT from acc subject
- KerberosTicket tgt = (KerberosTicket) SubjectComber.find(accSubj,
+ KerberosTicket tgt = SubjectComber.find(accSubj,
tgsPrincipal, clientPrincipal, KerberosTicket.class);
boolean fromAcc;
if (tgt == null && loginSubj != null) {
// 4. Try to get TGT from login subject
- tgt = (KerberosTicket) SubjectComber.find(loginSubj,
+ tgt = SubjectComber.find(loginSubj,
tgsPrincipal, clientPrincipal, KerberosTicket.class);
fromAcc = false;
} else {
@@ -145,14 +152,14 @@ public class Krb5Util {
// Try to get ticket from acc's Subject
Subject accSubj = Subject.getSubject(acc);
- KerberosTicket ticket = (KerberosTicket)
+ KerberosTicket ticket =
SubjectComber.find(accSubj, serverPrincipal, clientPrincipal,
KerberosTicket.class);
// Try to get ticket from Subject obtained from GSSUtil
if (ticket == null && !GSSUtil.useSubjectCredsOnly(caller)) {
Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
- ticket = (KerberosTicket) SubjectComber.find(subject,
+ ticket = SubjectComber.find(subject,
serverPrincipal, clientPrincipal, KerberosTicket.class);
}
return ticket;
@@ -182,37 +189,152 @@ public class Krb5Util {
return subject;
}
+ // A special KerberosKey, used as keys read from a KeyTab object.
+ // Each time new keys are read from KeyTab objects in the private
+ // credentials set, old ones are removed and new ones added.
+ public static class KeysFromKeyTab extends KerberosKey {
+ public KeysFromKeyTab(KerberosKey key) {
+ super(key.getPrincipal(), key.getEncoded(),
+ key.getKeyType(), key.getVersionNumber());
+ }
+ }
+
/**
- * Retrieves the keys for the specified server principal from
- * the Subject in the specified AccessControlContext.
- * If the ticket can not be found in the Subject, and if
- * useSubjectCredsOnly is false, then obtain keys from
- * a LoginContext.
+ * Credentials of a service, the private secret to authenticate its
+ * identity, which can be:
+ * 1. Some KerberosKeys (generated from password)
+ * 2. A KeyTab (for a typical service)
+ * 3. A TGT (for a user2user service. Not supported yet)
*
- * NOTE: This method is used by JSSE Kerberos Cipher Suites
+ * Note that some creds can coexist. For example, a user2user service
+ * can use its keytab (or keys) if the client can successfully obtain a
+ * normal service ticket, otherwise, it can uses the TGT (actually, the
+ * session key of the TGT) if the client can only acquire a service ticket
+ * of ENC-TKT-IN-SKEY style.
*/
- public static KerberosKey[] getKeys(GSSCaller caller,
+ public static class ServiceCreds {
+ private KerberosPrincipal kp;
+ private List ktabs;
+ private List kk;
+ private Subject subj;
+ //private KerberosTicket tgt; // user2user, not supported yet
+
+ private static ServiceCreds getInstance(
+ Subject subj, String serverPrincipal) {
+
+ ServiceCreds sc = new ServiceCreds();
+ sc.subj = subj;
+
+ for (KerberosPrincipal p: subj.getPrincipals(KerberosPrincipal.class)) {
+ if (serverPrincipal == null ||
+ p.getName().equals(serverPrincipal)) {
+ sc.kp = p;
+ serverPrincipal = p.getName();
+ break;
+ }
+ }
+ if (sc.kp == null) {
+ // Compatibility with old behavior: even when there is no
+ // KerberosPrincipal, we can find one from KerberosKeys
+ List keys = SubjectComber.findMany(
+ subj, null, null, KerberosKey.class);
+ if (!keys.isEmpty()) {
+ sc.kp = keys.get(0).getPrincipal();
+ serverPrincipal = sc.kp.getName();
+ if (DEBUG) {
+ System.out.println(">>> ServiceCreds: no kp?"
+ + " find one from kk: " + serverPrincipal);
+ }
+ } else {
+ return null;
+ }
+ }
+ sc.ktabs = SubjectComber.findMany(
+ subj, null, null, KeyTab.class);
+ sc.kk = SubjectComber.findMany(
+ subj, serverPrincipal, null, KerberosKey.class);
+ if (sc.ktabs.isEmpty() && sc.kk.isEmpty()) {
+ return null;
+ }
+ return sc;
+ }
+
+ public String getName() {
+ return kp.getName();
+ }
+
+ public KerberosKey[] getKKeys() {
+ if (ktabs.isEmpty()) {
+ return kk.toArray(new KerberosKey[kk.size()]);
+ } else {
+ List keys = new ArrayList<>();
+ for (KeyTab ktab: ktabs) {
+ for (KerberosKey k: ktab.getKeys(kp)) {
+ keys.add(k);
+ }
+ }
+ // Compatibility: also add keys to privCredSet. Remove old
+ // ones first, only remove those from keytab.
+ if (!subj.isReadOnly()) {
+ Set