Mercurial > hg > openjdk > jdk7 > jdk
changeset 4109:401ef8c488e0
Merge
author | vinnie |
---|---|
date | Thu, 21 Apr 2011 14:25:46 +0100 |
parents | 7cd0403492b6 (current diff) 7fd31e477313 (diff) |
children | e9ec52c63a9f b626f78c57e1 cec45f3353be |
files | |
diffstat | 46 files changed, 1644 insertions(+), 522 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java Thu Apr 21 14:25:46 2011 +0100 @@ -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 @@ 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 @@ (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 @@ // 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 @@ 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 @@ 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 @@ } } - // 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 @@ } 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 @@ 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 @@ } else { // remove temp results for the next try encKeys = null; + ktab = null; principal = null; } username = null;
--- a/src/share/classes/java/lang/ProcessBuilder.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/lang/ProcessBuilder.java Thu Apr 21 14:25:46 2011 +0100 @@ -938,6 +938,11 @@ * but at the very least the command must be a non-empty list of * non-null strings. * + * <p>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()}. + * * <p>If there is a security manager, its * {@link SecurityManager#checkExec checkExec} * method is called with the first component of this object's
--- a/src/share/classes/java/lang/Runtime.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/lang/Runtime.java Thu Apr 21 14:25:46 2011 +0100 @@ -544,6 +544,11 @@ * <p>If <tt>envp</tt> is <tt>null</tt>, the subprocess inherits the * environment settings of the current process. * + * <p>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. + * * <p>{@link ProcessBuilder#start()} is now the preferred way to * start a process with a modified environment. *
--- a/src/share/classes/java/util/AbstractSet.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/AbstractSet.java Thu Apr 21 14:25:46 2011 +0100 @@ -156,9 +156,11 @@ * @throws UnsupportedOperationException if the <tt>removeAll</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see #remove(Object) * @see #contains(Object)
--- a/src/share/classes/java/util/ArrayList.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/ArrayList.java Thu Apr 21 14:25:46 2011 +0100 @@ -628,9 +628,11 @@ * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see Collection#contains(Object) */ @@ -646,9 +648,11 @@ * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see Collection#contains(Object) */
--- a/src/share/classes/java/util/Collection.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/Collection.java Thu Apr 21 14:25:46 2011 +0100 @@ -60,7 +60,8 @@ * but is not required to, throw the exception if the collection to be added * is empty. * - * <p>Some collection implementations have restrictions on the elements that + * <p><a name="optional-restrictions"/> + * 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 @@ * @return <tt>true</tt> 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 + * (<a href="#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * collection does not permit null elements (optional) + * collection does not permit null elements + * (<a href="#optional-restrictions">optional</a>) */ boolean contains(Object o); @@ -279,9 +282,11 @@ * @param o element to be removed from this collection, if present * @return <tt>true</tt> 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 + * (<a href="#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * collection does not permit null elements (optional) + * collection does not permit null elements + * (<a href="#optional-restrictions">optional</a>) * @throws UnsupportedOperationException if the <tt>remove</tt> operation * is not supported by this collection */ @@ -299,10 +304,13 @@ * 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 + * (<a href="#optional-restrictions">optional</a>) * @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 + * (<a href="#optional-restrictions">optional</a>), + * or if the specified collection is null. * @see #contains(Object) */ boolean containsAll(Collection<?> c); @@ -346,10 +354,13 @@ * 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 + * (<a href="#optional-restrictions">optional</a>) * @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 + * (<a href="#optional-restrictions">optional</a>), + * or if the specified collection is null * @see #remove(Object) * @see #contains(Object) */ @@ -367,10 +378,13 @@ * 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 + * (<a href="#optional-restrictions">optional</a>) * @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 + * (<a href="#optional-restrictions">optional</a>), + * or if the specified collection is null * @see #remove(Object) * @see #contains(Object) */
--- a/src/share/classes/java/util/Collections.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/Collections.java Thu Apr 21 14:25:46 2011 +0100 @@ -3746,9 +3746,10 @@ * @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) + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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. + * (<a href="Collection.html#optional-restrictions">optional</a>) * @since 1.5 */ public static boolean disjoint(Collection<?> c1, Collection<?> c2) {
--- a/src/share/classes/java/util/Deque.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/Deque.java Thu Apr 21 14:25:46 2011 +0100 @@ -351,9 +351,11 @@ * @param o element to be removed from this deque, if present * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * deque does not permit null elements (optional) + * deque does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) */ boolean removeFirstOccurrence(Object o); @@ -369,9 +371,11 @@ * @param o element to be removed from this deque, if present * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * deque does not permit null elements (optional) + * deque does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) */ boolean removeLastOccurrence(Object o); @@ -527,9 +531,11 @@ * @param o element to be removed from this deque, if present * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * deque does not permit null elements (optional) + * deque does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) */ boolean remove(Object o); @@ -542,9 +548,11 @@ * @param o element whose presence in this deque is to be tested * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * deque does not permit null elements (optional) + * deque does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) */ boolean contains(Object o);
--- a/src/share/classes/java/util/List.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/List.java Thu Apr 21 14:25:46 2011 +0100 @@ -134,9 +134,11 @@ * @param o element whose presence in this list is to be tested * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * list does not permit null elements (optional) + * list does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) */ boolean contains(Object o); @@ -245,9 +247,11 @@ * @param o element to be removed from this list, if present * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * list does not permit null elements (optional) + * list does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws UnsupportedOperationException if the <tt>remove</tt> operation * is not supported by this list */ @@ -265,10 +269,13 @@ * specified collection * @throws ClassCastException if the types of one or more elements * in the specified collection are incompatible with this - * list (optional) + * list + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), + * or if the specified collection is null * @see #contains(Object) */ boolean containsAll(Collection<?> c); @@ -334,9 +341,11 @@ * @throws UnsupportedOperationException if the <tt>removeAll</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see #remove(Object) * @see #contains(Object) @@ -354,9 +363,11 @@ * @throws UnsupportedOperationException if the <tt>retainAll</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see #remove(Object) * @see #contains(Object) @@ -493,9 +504,11 @@ * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * list does not permit null elements (optional) + * list does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) */ int indexOf(Object o); @@ -510,9 +523,11 @@ * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * list does not permit null elements (optional) + * list does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) */ int lastIndexOf(Object o);
--- a/src/share/classes/java/util/Map.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/Map.java Thu Apr 21 14:25:46 2011 +0100 @@ -144,9 +144,11 @@ * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified key is null and this map - * does not permit null keys (optional) + * does not permit null keys + * (<a href="Collection.html#optional-restrictions">optional</a>) */ boolean containsKey(Object key); @@ -162,9 +164,11 @@ * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified value is null and this - * map does not permit null values (optional) + * map does not permit null values + * (<a href="Collection.html#optional-restrictions">optional</a>) */ boolean containsValue(Object value); @@ -187,9 +191,11 @@ * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified key is null and this map - * does not permit null keys (optional) + * does not permit null keys + * (<a href="Collection.html#optional-restrictions">optional</a>) */ V get(Object key); @@ -245,9 +251,11 @@ * @throws UnsupportedOperationException if the <tt>remove</tt> operation * is not supported by this map * @throws ClassCastException if the key is of an inappropriate type for - * this map (optional) + * this map + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified key is null and this - * map does not permit null keys (optional) + * map does not permit null keys + * (<a href="Collection.html#optional-restrictions">optional</a>) */ V remove(Object key); @@ -466,4 +474,5 @@ * @see #equals(Object) */ int hashCode(); + }
--- a/src/share/classes/java/util/Set.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/Set.java Thu Apr 21 14:25:46 2011 +0100 @@ -110,9 +110,11 @@ * @param o element whose presence in this set is to be tested * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * set does not permit null elements (optional) + * set does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) */ boolean contains(Object o); @@ -236,9 +238,11 @@ * @param o object to be removed from this set, if present * @return <tt>true</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws NullPointerException if the specified element is null and this - * set does not permit null elements (optional) + * set does not permit null elements + * (<a href="Collection.html#optional-restrictions">optional</a>) * @throws UnsupportedOperationException if the <tt>remove</tt> operation * is not supported by this set */ @@ -257,10 +261,13 @@ * specified collection * @throws ClassCastException if the types of one or more elements * in the specified collection are incompatible with this - * set (optional) + * set + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), + * or if the specified collection is null * @see #contains(Object) */ boolean containsAll(Collection<?> c); @@ -302,9 +309,11 @@ * @throws UnsupportedOperationException if the <tt>retainAll</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see #remove(Object) */ @@ -322,9 +331,11 @@ * @throws UnsupportedOperationException if the <tt>removeAll</tt> 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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see #remove(Object) * @see #contains(Object)
--- a/src/share/classes/java/util/Vector.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/Vector.java Thu Apr 21 14:25:46 2011 +0100 @@ -893,10 +893,13 @@ * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), + * or if the specified collection is null * @since 1.2 */ public synchronized boolean removeAll(Collection<?> c) { @@ -913,10 +916,13 @@ * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="Collection.html#optional-restrictions">optional</a>), + * or if the specified collection is null * @since 1.2 */ public synchronized boolean retainAll(Collection<?> c) {
--- a/src/share/classes/java/util/concurrent/BlockingDeque.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/concurrent/BlockingDeque.java Thu Apr 21 14:25:46 2011 +0100 @@ -400,8 +400,10 @@ * @param o element to be removed from this deque, if present * @return <tt>true</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified element is null + * (<a href="../Collection.html#optional-restrictions">optional</a>) */ boolean removeFirstOccurrence(Object o); @@ -416,8 +418,10 @@ * @param o element to be removed from this deque, if present * @return <tt>true</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified element is null + * (<a href="../Collection.html#optional-restrictions">optional</a>) */ boolean removeLastOccurrence(Object o); @@ -591,8 +595,10 @@ * @param o element to be removed from this deque, if present * @return <tt>true</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified element is null + * (<a href="../Collection.html#optional-restrictions">optional</a>) */ boolean remove(Object o); @@ -604,8 +610,10 @@ * @param o object to be checked for containment in this deque * @return <tt>true</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified element is null + * (<a href="../Collection.html#optional-restrictions">optional</a>) */ public boolean contains(Object o);
--- a/src/share/classes/java/util/concurrent/BlockingQueue.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/concurrent/BlockingQueue.java Thu Apr 21 14:25:46 2011 +0100 @@ -303,8 +303,10 @@ * @param o element to be removed from this queue, if present * @return <tt>true</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified element is null + * (<a href="../Collection.html#optional-restrictions">optional</a>) */ boolean remove(Object o); @@ -316,8 +318,10 @@ * @param o object to be checked for containment in this queue * @return <tt>true</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) + * @throws NullPointerException if the specified element is null + * (<a href="../Collection.html#optional-restrictions">optional</a>) */ public boolean contains(Object o);
--- a/src/share/classes/java/util/concurrent/ConcurrentMap.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/concurrent/ConcurrentMap.java Thu Apr 21 14:25:46 2011 +0100 @@ -103,9 +103,11 @@ * @throws UnsupportedOperationException if the <tt>remove</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) */ boolean remove(Object key, Object value);
--- a/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Thu Apr 21 14:25:46 2011 +0100 @@ -631,9 +631,11 @@ * @param c collection containing elements to be removed from this list * @return <tt>true</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="../Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see #remove(Object) */ @@ -671,9 +673,11 @@ * @param c collection containing elements to be retained in this list * @return <tt>true</tt> 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 + * (<a href="../Collection.html#optional-restrictions">optional</a>) * @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 + * (<a href="../Collection.html#optional-restrictions">optional</a>), * or if the specified collection is null * @see #remove(Object) */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java Thu Apr 21 14:25:46 2011 +0100 @@ -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); + } +}
--- a/src/share/classes/javax/security/auth/kerberos/KerberosKey.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/javax/security/auth/kerberos/KerberosKey.java Thu Apr 21 14:25:46 2011 +0100 @@ -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 @@ * principal.<p> * * 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.<p> * + * A Kerberos service using a keytab to read secret keys should use + * the {@link KeyTab} class, where latest keys can be read when needed.<p> + * * It might be necessary for the application to be granted a * {@link javax.security.auth.PrivateCredentialPermission * PrivateCredentialPermission} if it needs to access the KerberosKey
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/javax/security/auth/kerberos/KeyTab.java Thu Apr 21 14:25:46 2011 +0100 @@ -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. + * <p> + * 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. + * <p> + * 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}. + * <p> + * The keytab file format is described at + * <a href="http://www.ioplex.com/utilities/keytab.txt"> + * http://www.ioplex.com/utilities/keytab.txt</a>. + * + * @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. + * <p> + * 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. + * <p> + * 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. + * <p> + * 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. + * <p> + * 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. + * <p> + * 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. + * <p> + * 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. + * <p> + * 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<kks.length; i++) { + Integer tmp = keys[i].getKeyVersionNumber(); + kks[i] = new KerberosKey( + principal, + keys[i].getBytes(), + keys[i].getEType(), + tmp == null ? 0 : tmp.intValue()); + keys[i].destroy(); + } + return kks; + } catch (RealmException re) { + return new KerberosKey[0]; + } + } + + EncryptionKey[] getEncryptionKeys(PrincipalName principal) { + return takeSnapshot().readServiceKeys(principal); + } + + /** + * Checks if the keytab file exists. Implementation of this method + * should make sure that the result matches the latest status of the + * keytab file. + * <p> + * 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 <code>KeyTab</code> + */ + 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 + * <code>KeyTab</code> and the two + * <code>KeyTab</code> 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); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/sun/misc/JavaxSecurityAuthKerberosAccess.java Thu Apr 21 14:25:46 2011 +0100 @@ -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); +}
--- a/src/share/classes/sun/misc/SharedSecrets.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/misc/SharedSecrets.java Thu Apr 21 14:25:46 2011 +0100 @@ -29,6 +29,7 @@ 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 @@ 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 @@ } return javaSecurityAccess; } + + public static void setJavaxSecurityAuthKerberosAccess + (JavaxSecurityAuthKerberosAccess jsaka) { + javaxSecurityAuthKerberosAccess = jsaka; + } + + public static JavaxSecurityAuthKerberosAccess + getJavaxSecurityAuthKerberosAccess() { + if (javaxSecurityAuthKerberosAccess == null) + unsafe.ensureClassInitialized(KeyTab.class); + return javaxSecurityAuthKerberosAccess; + } }
--- a/src/share/classes/sun/rmi/log/ReliableLog.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/rmi/log/ReliableLog.java Thu Apr 21 14:25:46 2011 +0100 @@ -380,9 +380,7 @@ } 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 {
--- a/src/share/classes/sun/rmi/server/Activation.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/rmi/server/Activation.java Thu Apr 21 14:25:46 2011 +0100 @@ -30,6 +30,7 @@ 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.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 @@ /** maps activation id to its respective group id */ private Map<ActivationID,ActivationGroupID> idTable = - new HashMap<ActivationID,ActivationGroupID>(); + new ConcurrentHashMap<>(); /** maps group id to its GroupEntry groups */ private Map<ActivationGroupID,GroupEntry> groupTable = - new HashMap<ActivationGroupID,GroupEntry>(); + new ConcurrentHashMap<>(); private byte majorVersion = MAJOR_VERSION; private byte minorVersion = MINOR_VERSION; @@ -236,9 +238,11 @@ 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 @@ } } + /** + * 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 @@ 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 @@ // 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 @@ 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 @@ } // destroy all child processes (groups) quickly - synchronized (groupTable) { - for (GroupEntry groupEntry : groupTable.values()) { - groupEntry.shutdownFast(); - } + for (GroupEntry groupEntry : groupTable.values()) { + groupEntry.shutdownFast(); } } } @@ -708,13 +716,32 @@ 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, optionally removing it. + * Throws UnknownGroupException if the group is not registered. + */ + private GroupEntry getGroupEntry(ActivationGroupID id, boolean rm) + throws UnknownGroupException + { + if (id.getClass() == ActivationGroupID.class) { + GroupEntry entry; + if (rm) { + entry = groupTable.remove(id); + } else { + entry = groupTable.get(id); + } + if (entry != null && !entry.removed) { + return entry; } } - throw new UnknownObjectException("unknown object: " + id); + throw new UnknownGroupException("group unknown"); } /** @@ -724,15 +751,17 @@ private GroupEntry getGroupEntry(ActivationGroupID id) throws UnknownGroupException { - if (id.getClass() == ActivationGroupID.class) { - synchronized (groupTable) { - GroupEntry entry = groupTable.get(id); - if (entry != null && !entry.removed) { - return entry; - } - } - } - throw new UnknownGroupException("group unknown"); + 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); } /** @@ -744,11 +773,9 @@ 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 @@ } // 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 @@ 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 @@ objects.entrySet()) { ActivationID id = entry.getKey(); - synchronized (idTable) { - idTable.remove(id); - } + idTable.remove(id); ObjectEntry objEntry = entry.getValue(); objEntry.removed = true; }
--- a/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/jgss/krb5/Krb5AcceptCredential.java Thu Apr 21 14:25:46 2011 +0100 @@ -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 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 @@ * @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 @@ name.getKrb5PrincipalName().getName()); final AccessControlContext acc = AccessController.getContext(); - KerberosKey[] keys; + Krb5Util.ServiceCreds creds = null; try { - keys = AccessController.doPrivileged( - new PrivilegedExceptionAction<KerberosKey[]>() { - public KerberosKey[] run() throws Exception { - return Krb5Util.getKeys( + creds = AccessController.doPrivileged( + new PrivilegedExceptionAction<Krb5Util.ServiceCreds>() { + public Krb5Util.ServiceCreds run() throws Exception { + return Krb5Util.getServiceCreds( caller == GSSCaller.CALLER_UNKNOWN ? GSSCaller.CALLER_ACCEPT: caller, serverPrinc, acc); }}); @@ -103,17 +85,17 @@ 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 @@ } EncryptionKey[] getKrb5EncryptionKeys() { - return krb5EncryptionKeys; + return screds.getEKeys(); } /** @@ -193,13 +175,6 @@ * 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(); } }
--- a/src/share/classes/sun/security/jgss/krb5/Krb5Util.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/jgss/krb5/Krb5Util.java Thu Apr 21 14:25:46 2011 +0100 @@ -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 @@ 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.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 @@ // 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 @@ // 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 @@ // 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 @@ // 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 @@ 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<KeyTab> ktabs; + private List<KerberosKey> 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<KerberosKey> 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<KerberosKey> 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<Object> pcs = subj.getPrivateCredentials(); + synchronized (pcs) { + Iterator<Object> iterator = pcs.iterator(); + while (iterator.hasNext()) { + Object obj = iterator.next(); + if (obj instanceof KeysFromKeyTab) { + KerberosKey key = (KerberosKey)obj; + if (Objects.equals(key.getPrincipal(), kp)) { + iterator.remove(); + } + } + } + } + for (KerberosKey key: keys) { + subj.getPrivateCredentials().add(new KeysFromKeyTab(key)); + } + } + return keys.toArray(new KerberosKey[keys.size()]); + } + } + + public EncryptionKey[] getEKeys() { + KerberosKey[] kkeys = getKKeys(); + EncryptionKey[] ekeys = new EncryptionKey[kkeys.length]; + for (int i=0; i<ekeys.length; i++) { + ekeys[i] = new EncryptionKey( + kkeys[i].getEncoded(), kkeys[i].getKeyType(), + new Integer(kkeys[i].getVersionNumber())); + } + return ekeys; + } + + public void destroy() { + kp = null; + ktabs = null; + kk = null; + } + } + /** + * Retrieves the ServiceCreds for the specified server principal from + * the Subject in the specified AccessControlContext. If not found, and if + * useSubjectCredsOnly is false, then obtain from a LoginContext. + * + * NOTE: This method is also used by JSSE Kerberos Cipher Suites + */ + public static ServiceCreds getServiceCreds(GSSCaller caller, String serverPrincipal, AccessControlContext acc) throws LoginException { Subject accSubj = Subject.getSubject(acc); - List<KerberosKey> kkeys = (List<KerberosKey>)SubjectComber.findMany( - accSubj, serverPrincipal, null, KerberosKey.class); - - if (kkeys == null && !GSSUtil.useSubjectCredsOnly(caller)) { - Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID); - kkeys = (List<KerberosKey>) SubjectComber.findMany(subject, - serverPrincipal, null, KerberosKey.class); + ServiceCreds sc = null; + if (accSubj != null) { + sc = ServiceCreds.getInstance(accSubj, serverPrincipal); } - - int len; - if (kkeys != null && (len = kkeys.size()) > 0) { - KerberosKey[] keys = new KerberosKey[len]; - kkeys.toArray(keys); - return keys; - } else { - return null; + if (sc == null && !GSSUtil.useSubjectCredsOnly(caller)) { + Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID); + sc = ServiceCreds.getInstance(subject, serverPrincipal); } + return sc; } public static KerberosTicket credsToTicket(Credentials serviceCreds) { @@ -247,4 +369,17 @@ kerbTicket.getRenewTill(), kerbTicket.getClientAddresses()); } + + /** + * A helper method to get EncryptionKeys from a javax..KeyTab + * @param ktab the javax..KeyTab class + * @param cname the PrincipalName + * @return the EKeys, never null, might be empty + */ + public static EncryptionKey[] keysFromJavaxKeyTab( + KeyTab ktab, PrincipalName cname) { + return SharedSecrets.getJavaxSecurityAuthKerberosAccess(). + keyTabGetEncryptionKeys(ktab, cname); + } + }
--- a/src/share/classes/sun/security/jgss/krb5/SubjectComber.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/jgss/krb5/SubjectComber.java Thu Apr 21 14:25:46 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -33,10 +33,11 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; +import javax.security.auth.kerberos.KeyTab; /** - * This utility looks through the current Subject and retrieves a ticket or key - * for the desired client/server principals. + * This utility looks through the current Subject and retrieves private + * credentials for the desired client/server principals. * * @author Ram Marti * @since 1.4.2 @@ -52,58 +53,70 @@ private SubjectComber() { // Cannot create one of these } - static Object find(Subject subject, String serverPrincipal, - String clientPrincipal, Class credClass) { + static <T> T find(Subject subject, String serverPrincipal, + String clientPrincipal, Class<T> credClass) { - return findAux(subject, serverPrincipal, clientPrincipal, credClass, + return (T)findAux(subject, serverPrincipal, clientPrincipal, credClass, true); } - static Object findMany(Subject subject, String serverPrincipal, - String clientPrincipal, Class credClass) { + static <T> List<T> findMany(Subject subject, String serverPrincipal, + String clientPrincipal, Class<T> credClass) { - return findAux(subject, serverPrincipal, clientPrincipal, credClass, + return (List<T>)findAux(subject, serverPrincipal, clientPrincipal, credClass, false); } /** - * Find the ticket or key for the specified client/server principals + * Find private credentials for the specified client/server principals * in the subject. Returns null if the subject is null. * - * @return the ticket or key + * @return the private credentials */ - private static Object findAux(Subject subject, String serverPrincipal, - String clientPrincipal, Class credClass, boolean oneOnly) { + private static <T> Object findAux(Subject subject, String serverPrincipal, + String clientPrincipal, Class<T> credClass, boolean oneOnly) { if (subject == null) { return null; } else { - List<Object> answer = (oneOnly ? null : new ArrayList<Object>()); + List<T> answer = (oneOnly ? null : new ArrayList<T>()); - if (credClass == KerberosKey.class) { - // We are looking for a KerberosKey credentials for the - // serverPrincipal - Iterator<KerberosKey> iterator = - subject.getPrivateCredentials(KerberosKey.class).iterator(); + if (credClass == KeyTab.class) { // Principal un-related + // We are looking for credentials unrelated to serverPrincipal + Iterator<T> iterator = + subject.getPrivateCredentials(credClass).iterator(); while (iterator.hasNext()) { - KerberosKey key = iterator.next(); - if (serverPrincipal == null || - serverPrincipal.equals(key.getPrincipal().getName())) { + T t = iterator.next(); + if (DEBUG) { + System.out.println("Found " + credClass.getSimpleName()); + } + if (oneOnly) { + return t; + } else { + answer.add(t); + } + } + } else if (credClass == KerberosKey.class) { + // We are looking for credentials for the serverPrincipal + Iterator<T> iterator = + subject.getPrivateCredentials(credClass).iterator(); + while (iterator.hasNext()) { + T t = iterator.next(); + String name = ((KerberosKey)t).getPrincipal().getName(); + if (serverPrincipal == null || serverPrincipal.equals(name)) { if (DEBUG) { - System.out.println("Found key for " - + key.getPrincipal() + "(" + - key.getKeyType() + ")"); + System.out.println("Found " + + credClass.getSimpleName() + " for " + name); } if (oneOnly) { - return key; + return t; } else { if (serverPrincipal == null) { // Record name so that keys returned will all // belong to the same principal - serverPrincipal = - key.getPrincipal().getName(); + serverPrincipal = name; } - answer.add(key); + answer.add(t); } } } @@ -167,7 +180,7 @@ serverPrincipal = ticket.getServer().getName(); } - answer.add(ticket); + answer.add((T)ticket); } } }
--- a/src/share/classes/sun/security/krb5/Config.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/krb5/Config.java Thu Apr 21 14:25:46 2011 +0100 @@ -110,7 +110,6 @@ public static synchronized void refresh() throws KrbException { singleton = new Config(); - KeyTab.refresh(); KdcComm.initStatic(); }
--- a/src/share/classes/sun/security/krb5/EncryptionKey.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/krb5/EncryptionKey.java Thu Apr 21 14:25:46 2011 +0100 @@ -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 @@ -138,8 +138,7 @@ * @returns an array of secret keys or null if none were found. */ public static EncryptionKey[] acquireSecretKeys(PrincipalName princ, - String keytab) - throws KrbException, IOException { + String keytab) { if (princ == null) throw new IllegalArgumentException( @@ -148,11 +147,6 @@ // KeyTab getInstance(keytab) will call KeyTab.getInstance() // if keytab is null KeyTab ktab = KeyTab.getInstance(keytab); - - if (ktab == null) { - return null; - } - return ktab.readServiceKeys(princ); }
--- a/src/share/classes/sun/security/krb5/KrbAsRep.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/krb5/KrbAsRep.java Thu Apr 21 14:25:46 2011 +0100 @@ -37,6 +37,8 @@ import sun.security.util.*; import java.io.IOException; import java.util.Objects; +import javax.security.auth.kerberos.KeyTab; +import sun.security.jgss.krb5.Krb5Util; /** * This class encapsulates a AS-REP message that the KDC sends to the @@ -90,29 +92,32 @@ } /** - * Called by KrbAsReqBuilder to resolve a AS-REP message using keys. - * @param keys user provided keys, not null + * Called by KrbAsReqBuilder to resolve a AS-REP message using a keytab. + * @param ktab the keytab, not null * @param asReq the original AS-REQ sent, used to validate AS-REP + * @param cname the user principal name, used to locate keys in ktab */ - void decryptUsingKeys(EncryptionKey[] keys, KrbAsReq asReq) + void decryptUsingKeyTab(KeyTab ktab, KrbAsReq asReq, PrincipalName cname) throws KrbException, Asn1Exception, IOException { EncryptionKey dkey = null; int encPartKeyType = rep.encPart.getEType(); Integer encPartKvno = rep.encPart.kvno; - try { - dkey = EncryptionKey.findKey(encPartKeyType, encPartKvno, keys); - } catch (KrbException ke) { - if (ke.returnCode() == Krb5.KRB_AP_ERR_BADKEYVER) { - // Fallback to no kvno. In some cases, keytab is generated - // not by sysadmin but Java's ktab command - dkey = EncryptionKey.findKey(encPartKeyType, keys); + try { + dkey = EncryptionKey.findKey(encPartKeyType, encPartKvno, + Krb5Util.keysFromJavaxKeyTab(ktab, cname)); + } catch (KrbException ke) { + if (ke.returnCode() == Krb5.KRB_AP_ERR_BADKEYVER) { + // Fallback to no kvno. In some cases, keytab is generated + // not by sysadmin but Java's ktab command + dkey = EncryptionKey.findKey(encPartKeyType, + Krb5Util.keysFromJavaxKeyTab(ktab, cname)); + } } - } - if (dkey == null) { - throw new KrbException(Krb5.API_INVALID_ARG, - "Cannot find key for type/kvno to decrypt AS REP - " + - EType.toString(encPartKeyType) + "/" + encPartKvno); - } + if (dkey == null) { + throw new KrbException(Krb5.API_INVALID_ARG, + "Cannot find key for type/kvno to decrypt AS REP - " + + EType.toString(encPartKeyType) + "/" + encPartKvno); + } decrypt(dkey, asReq); }
--- a/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java Thu Apr 21 14:25:46 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -27,6 +27,8 @@ import java.io.IOException; import java.util.Arrays; +import javax.security.auth.kerberos.KeyTab; +import sun.security.jgss.krb5.Krb5Util; import sun.security.krb5.internal.HostAddresses; import sun.security.krb5.internal.KDCOptions; import sun.security.krb5.internal.KRBError; @@ -42,13 +44,16 @@ * 1. Gather information to create AS-REQ * 2. Create and send AS-REQ * 3. Receive AS-REP and KRB-ERROR (-KRB_ERR_RESPONSE_TOO_BIG) and parse them - * 4. Emit credentials and secret keys (for JAAS storeKey=true) + * 4. Emit credentials and secret keys (for JAAS storeKey=true with password) * * This class does not: * 1. Deal with real communications (KdcComm does it, and TGS-REQ) * a. Name of KDCs for a realm * b. Server availability, timeout, UDP or TCP * d. KRB_ERR_RESPONSE_TOO_BIG + * 2. Stores its own copy of password, this means: + * a. Do not change/wipe it before Builder finish + * b. Builder will not wipe it for you * * With this class: * 1. KrbAsReq has only one constructor @@ -70,19 +75,17 @@ private HostAddresses addresses; // Secret source: can't be changed once assigned, only one (of the two - // sources) can be set and should be non-null - private EncryptionKey[] keys; - private char[] password; + // sources) can be set to non-null + private final char[] password; + private final KeyTab ktab; // Used to create a ENC-TIMESTAMP in the 2nd AS-REQ - private EncryptionKey pakey; private PAData[] paList; // PA-DATA from both KRB-ERROR and AS-REP. // Used by getKeys() only. // Only AS-REP should be enough per RFC, // combined in case etypes are different. // The generated and received: - int[] eTypes; private KrbAsReq req; private KrbAsRep rep; @@ -94,7 +97,7 @@ private State state; // Called by other constructors - private KrbAsReqBuilder(PrincipalName cname) + private void init(PrincipalName cname) throws KrbException { if (cname.getRealm() == null) { cname.setRealm(Config.getInstance().getDefaultRealm()); @@ -114,14 +117,11 @@ * This argument will neither be modified nor stored by the method. * @throws KrbException */ - public KrbAsReqBuilder(PrincipalName cname, EncryptionKey[] keys) + public KrbAsReqBuilder(PrincipalName cname, KeyTab ktab) throws KrbException { - this(cname); - this.keys = new EncryptionKey[keys.length]; - for (int i=0; i<keys.length; i++) { - this.keys[i] = (EncryptionKey)keys[i].clone(); - } - eTypes = EType.getDefaults("default_tkt_enctypes", keys); + init(cname); + this.ktab = ktab; + this.password = null; } /** @@ -137,30 +137,24 @@ */ public KrbAsReqBuilder(PrincipalName cname, char[] pass) throws KrbException { - this(cname); + init(cname); this.password = pass.clone(); - eTypes = EType.getDefaults("default_tkt_enctypes"); + this.ktab = null; } /** - * Retrieves an array of secret keys for the client. This is useful if + * Retrieves an array of secret keys for the client. This is used when * the client supplies password but need keys to act as an acceptor * (in JAAS words, isInitiator=true and storeKey=true) - * @return original keys if initiated with keys, or generated keys if - * password. In latter case, PA-DATA from server might be used to - * generate keys. All "default_tkt_enctypes" keys will be generated, - * Never null. + * @return generated keys from password. PA-DATA from server might be used. + * All "default_tkt_enctypes" keys will be generated, Never null. + * @throws IllegalStateException if not constructed from a password * @throws KrbException */ public EncryptionKey[] getKeys() throws KrbException { checkState(State.REQ_OK, "Cannot get keys"); - if (keys != null) { - EncryptionKey[] result = new EncryptionKey[keys.length]; - for (int i=0; i<keys.length; i++) { - result[i] = (EncryptionKey)keys[i].clone(); - } - return result; - } else { + if (password != null) { + int[] eTypes = EType.getDefaults("default_tkt_enctypes"); EncryptionKey[] result = new EncryptionKey[eTypes.length]; /* @@ -205,6 +199,8 @@ } } return result; + } else { + throw new IllegalStateException("Required password not provided"); } } @@ -241,12 +237,22 @@ /** * Build a KrbAsReq object from all info fed above. Normally this method * will be called twice: initial AS-REQ and second with pakey + * @param key null (initial AS-REQ) or pakey (with preauth) * @return the KrbAsReq object * @throws KrbException * @throws IOException */ - private KrbAsReq build() throws KrbException, IOException { - return new KrbAsReq(pakey, + private KrbAsReq build(EncryptionKey key) throws KrbException, IOException { + int[] eTypes; + if (password != null) { + eTypes = EType.getDefaults("default_tkt_enctypes"); + } else { + EncryptionKey[] ks = Krb5Util.keysFromJavaxKeyTab(ktab, cname); + eTypes = EType.getDefaults("default_tkt_enctypes", + ks); + for (EncryptionKey k: ks) k.destroy(); + } + return new KrbAsReq(key, options, cname, sname, @@ -263,9 +269,10 @@ * @throws Asn1Exception * @throws IOException */ - private KrbAsReqBuilder resolve() throws KrbException, Asn1Exception, IOException { - if (keys != null) { - rep.decryptUsingKeys(keys, req); + private KrbAsReqBuilder resolve() + throws KrbException, Asn1Exception, IOException { + if (ktab != null) { + rep.decryptUsingKeyTab(ktab, req, cname); } else { rep.decryptUsingPassword(password, req, cname); } @@ -292,9 +299,10 @@ private KrbAsReqBuilder send() throws KrbException, IOException { boolean preAuthFailedOnce = false; KdcComm comm = new KdcComm(cname.getRealmAsString()); + EncryptionKey pakey = null; while (true) { try { - req = build(); + req = build(pakey); rep = new KrbAsRep(comm.send(req.encoding())); return this; } catch (KrbException ke) { @@ -308,7 +316,10 @@ preAuthFailedOnce = true; KRBError kerr = ke.getError(); if (password == null) { - pakey = EncryptionKey.findKey(kerr.getEType(), keys); + EncryptionKey[] ks = Krb5Util.keysFromJavaxKeyTab(ktab, cname); + pakey = EncryptionKey.findKey(kerr.getEType(), ks); + if (pakey != null) pakey = (EncryptionKey)pakey.clone(); + for (EncryptionKey k: ks) k.destroy(); } else { PAData.SaltAndParams snp = PAData.getSaltAndParams( kerr.getEType(), kerr.getPA()); @@ -317,7 +328,7 @@ // does not recommend this pakey = EncryptionKey.acquireSecretKey(password, snp.salt == null ? cname.getSalt() : snp.salt, - eTypes[0], + EType.getDefaults("default_tkt_enctypes")[0], null); } else { pakey = EncryptionKey.acquireSecretKey(password, @@ -369,15 +380,8 @@ */ public void destroy() { state = State.DESTROYED; - if (keys != null) { - for (EncryptionKey k: keys) { - k.destroy(); - } - keys = null; - } if (password != null) { Arrays.fill(password, (char)0); - password = null; } }
--- a/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java Thu Apr 21 14:25:46 2011 +0100 @@ -40,6 +40,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.util.Comparator; import java.util.HashMap; import java.util.Map; @@ -50,92 +51,138 @@ * This class represents key table. The key table functions deal with storing * and retrieving service keys for use in authentication exchanges. * + * A KeyTab object is always constructed, if the file specified does not + * exist, it's still valid but empty. If there is an I/O error or file format + * error, it's invalid. + * + * The class is immutable on the read side (the write side is only used by + * the ktab tool). + * * @author Yanni Zhang */ public class KeyTab implements KeyTabConstants { - int kt_vno; - private static KeyTab singleton = null; + private static final boolean DEBUG = Krb5.DEBUG; - private static String name; + private static String defaultTabName = null; + + // Attention: Currently there is no way to remove a keytab from this map, + // this might lead to a memory leak. + private static Map<String,KeyTab> map = new HashMap<>(); + + // KeyTab file does not exist. Note: a missing keytab is still valid + private boolean isMissing = false; + + // KeyTab file is invalid, possibly an I/O error or a file format error. + private boolean isValid = true; + + private final String tabName; + private long lastModified; + private int kt_vno; + private Vector<KeyTabEntry> entries = new Vector<>(); - private KeyTab(String filename) throws IOException, RealmException { - init(filename); - } - - public static KeyTab getInstance(String s) { - name = parse(s); - if (name == null) { - return getInstance(); + /** + * Constructs a KeyTab object. + * + * If there is any I/O error or format errot during the loading, the + * isValid flag is set to false, and all half-read entries are dismissed. + * @param filename path name for the keytab file, must not be null + */ + private KeyTab(String filename) { + tabName = filename; + try { + lastModified = new File(tabName).lastModified(); + KeyTabInputStream kis = + new KeyTabInputStream(new FileInputStream(filename)); + load(kis); + kis.close(); + } catch (FileNotFoundException e) { + entries.clear(); + isMissing = true; + } catch (Exception ioe) { + entries.clear(); + isValid = false; } - return getInstance(new File(name)); } /** - * Gets the single instance of KeyTab class. - * @param file the key tab file. - * @return single instance of KeyTab; - * return null if error occurs while reading data out of the file. + * Read a keytab file. Returns a new object and save it into cache when + * new content (modified since last read) is available. If keytab file is + * invalid, the old object will be returned. This is a safeguard for + * partial-written keytab files or non-stable network. Please note that + * a missing keytab is valid, which is equivalent to an empty keytab. + * + * @param s file name of keytab, must not be null + * @return the keytab object, can be invalid, but never null. */ - public static KeyTab getInstance(File file) { - try { - if (!(file.exists())) { - singleton = null; - } else { - String fname = file.getAbsolutePath(); - // Since this class deals with file I/O operations, - // we want only one class instance existing. - if (singleton != null) { - File kfile = new File(singleton.name); - String kname = kfile.getAbsolutePath(); - if (kname.equalsIgnoreCase(fname)) { - if (DEBUG) { - System.out.println("KeyTab instance already exists"); - } - } - } else { - singleton = new KeyTab(fname); - } - } - } catch (Exception e) { - singleton = null; - if (DEBUG) { - System.out.println("Could not obtain an instance of KeyTab" + - e.getMessage()); - } + private synchronized static KeyTab getInstance0(String s) { + long lm = new File(s).lastModified(); + KeyTab old = map.get(s); + if (old != null && old.isValid() && old.lastModified == lm) { + return old; } - return singleton; + KeyTab ktab = new KeyTab(s); + if (ktab.isValid()) { // A valid new keytab + map.put(s, ktab); + return ktab; + } else if (old != null) { // An existing old one + return old; + } else { + return ktab; // first read is invalid + } } /** - * Gets the single instance of KeyTab class. - * @return single instance of KeyTab; return null if default keytab file - * does not exist, or error occurs while reading data from the file. + * Gets a KeyTab object. + * @param s the key tab file name. + * @return the KeyTab object, never null. + */ + public static KeyTab getInstance(String s) { + if (s == null) { + return getInstance(); + } else { + return getInstance0(s); + } + } + + /** + * Gets a KeyTab object. + * @param file the key tab file. + * @return the KeyTab object, never null. + */ + public static KeyTab getInstance(File file) { + if (file == null) { + return getInstance(); + } else { + return getInstance0(file.getPath()); + } + } + + /** + * Gets the default KeyTab object. + * @return the KeyTab object, never null. */ public static KeyTab getInstance() { - try { - name = getDefaultKeyTab(); - if (name != null) { - singleton = getInstance(new File(name)); - } - } catch (Exception e) { - singleton = null; - if (DEBUG) { - System.out.println("Could not obtain an instance of KeyTab" + - e.getMessage()); - } - } - return singleton; + return getInstance(getDefaultTabName()); + } + + public boolean isMissing() { + return isMissing; + } + + public boolean isValid() { + return isValid; } /** * The location of keytab file will be read from the configuration file * If it is not specified, consider user.home as the keytab file's * default location. + * @return never null */ - private static String getDefaultKeyTab() { - if (name != null) { - return name; + private static String getDefaultTabName() { + if (defaultTabName != null) { + return defaultTabName; } else { String kname = null; try { @@ -145,7 +192,7 @@ StringTokenizer st = new StringTokenizer(keytab_names, " "); while (st.hasMoreTokens()) { kname = parse(st.nextToken()); - if (kname != null) { + if (new File(kname).exists()) { break; } } @@ -165,19 +212,20 @@ new sun.security.action.GetPropertyAction("user.dir")); } - if (user_home != null) { - kname = user_home + File.separator + "krb5.keytab"; - } + kname = user_home + File.separator + "krb5.keytab"; } + defaultTabName = kname; return kname; } } + /** + * Parses some common keytab name formats + * @param name never null + * @return never null + */ private static String parse(String name) { - String kname = null; - if (name == null) { - return null; - } + String kname; if ((name.length() >= 5) && (name.substring(0, 5).equalsIgnoreCase("FILE:"))) { kname = name.substring(5); @@ -194,18 +242,6 @@ return kname; } - private synchronized void init(String filename) - throws IOException, RealmException { - - if (filename != null) { - KeyTabInputStream kis = - new KeyTabInputStream(new FileInputStream(filename)); - load(kis); - kis.close(); - name = filename; - } - } - private void load(KeyTabInputStream kis) throws IOException, RealmException { @@ -234,14 +270,13 @@ * etypes that have been configured for use. If there are multiple * keys with same etype, the one with the highest kvno is returned. * @param service the PrincipalName of the requested service - * @return an array containing all the service keys + * @return an array containing all the service keys, never null */ public EncryptionKey[] readServiceKeys(PrincipalName service) { KeyTabEntry entry; EncryptionKey key; int size = entries.size(); ArrayList<EncryptionKey> keys = new ArrayList<>(size); - for (int i = size-1; i >= 0; i--) { entry = entries.elementAt(i); if (entry.service.match(service)) { @@ -260,10 +295,7 @@ } } } - size = keys.size(); - if (size == 0) - return null; EncryptionKey[] retVal = keys.toArray(new EncryptionKey[size]); // Sort keys according to default_tkt_enctypes @@ -328,10 +360,13 @@ return false; } - public static String tabName() { - return name; + public String tabName() { + return tabName; } + /////////////////// THE WRITE SIDE /////////////////////// + /////////////// only used by ktab tool ////////////////// + /** * Adds a new entry in the key table. * @param service the service which will have a new entry in the key table. @@ -394,7 +429,7 @@ */ public synchronized static KeyTab create() throws IOException, RealmException { - String dname = getDefaultKeyTab(); + String dname = getDefaultTabName(); return create(dname); } @@ -408,8 +443,7 @@ new KeyTabOutputStream(new FileOutputStream(name)); kos.writeVersion(KRB5_KT_VNO); kos.close(); - singleton = new KeyTab(name); - return singleton; + return new KeyTab(name); } /** @@ -417,7 +451,7 @@ */ public synchronized void save() throws IOException { KeyTabOutputStream kos = - new KeyTabOutputStream(new FileOutputStream(name)); + new KeyTabOutputStream(new FileOutputStream(tabName)); kos.writeVersion(kt_vno); for (int i = 0; i < entries.size(); i++) { kos.writeEntry(entries.elementAt(i)); @@ -490,13 +524,4 @@ kos.write16(KRB5_KT_VNO); kos.close(); } - - public static void refresh() { - if (singleton != null) { - if (DEBUG) { - System.out.println("Refreshing Keytab"); - } - singleton = null; - } - } }
--- a/src/share/classes/sun/security/ssl/ServerHandshaker.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java Thu Apr 21 14:25:46 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -1285,11 +1285,12 @@ // check permission to access and use the secret key of the // Kerberized "host" service - if (kerberosKeys != null) { - + if (kerberosKeys != null && kerberosKeys.length > 0) { if (debug != null && Debug.isOn("handshake")) { - System.out.println("Using Kerberos key: " + - kerberosKeys[0]); + for (SecretKey k: kerberosKeys) { + System.out.println("Using Kerberos key: " + + k); + } } String serverPrincipal =
--- a/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java Thu Apr 21 14:25:46 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -40,7 +40,7 @@ import sun.security.ssl.Krb5Proxy; /** - * An implementatin of Krb5Proxy that simply delegates to the appropriate + * An implementation of Krb5Proxy that simply delegates to the appropriate * Kerberos APIs. */ public class Krb5ProxyImpl implements Krb5Proxy { @@ -62,7 +62,7 @@ @Override public SecretKey[] getServerKeys(AccessControlContext acc) throws LoginException { - return Krb5Util.getKeys(GSSCaller.CALLER_SSL_SERVER, null, acc); + return Krb5Util.getServiceCreds(GSSCaller.CALLER_SSL_SERVER, null, acc).getKKeys(); } @Override
--- a/src/windows/classes/java/lang/ProcessEnvironment.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/windows/classes/java/lang/ProcessEnvironment.java Thu Apr 21 14:25:46 2011 +0100 @@ -143,7 +143,7 @@ public void remove() { i.remove();} }; } - private static Map.Entry<String,String> checkedEntry (Object o) { + private static Map.Entry<String,String> checkedEntry(Object o) { Map.Entry<String,String> e = (Map.Entry<String,String>) o; nonNullString(e.getKey()); nonNullString(e.getValue()); @@ -285,7 +285,7 @@ return (Map<String,String>) theEnvironment.clone(); } - // Only for use by Runtime.exec(...String[]envp...) + // Only for use by ProcessBuilder.environment(String[] envp) static Map<String,String> emptyEnvironment(int capacity) { return new ProcessEnvironment(capacity); } @@ -299,19 +299,46 @@ Collections.sort(list, entryComparator); StringBuilder sb = new StringBuilder(size()*30); - for (Map.Entry<String,String> e : list) - sb.append(e.getKey()) - .append('=') - .append(e.getValue()) - .append('\u0000'); - // Ensure double NUL termination, - // even if environment is empty. - if (sb.length() == 0) + int cmp = -1; + + // Some versions of MSVCRT.DLL require SystemRoot to be set. + // So, we make sure that it is always set, even if not provided + // by the caller. + final String SYSTEMROOT = "SystemRoot"; + + for (Map.Entry<String,String> e : list) { + String key = e.getKey(); + String value = e.getValue(); + if (cmp < 0 && (cmp = nameComparator.compare(key, SYSTEMROOT)) > 0) { + // Not set, so add it here + addToEnvIfSet(sb, SYSTEMROOT); + } + addToEnv(sb, key, value); + } + if (cmp < 0) { + // Got to end of list and still not found + addToEnvIfSet(sb, SYSTEMROOT); + } + if (sb.length() == 0) { + // Environment was empty and SystemRoot not set in parent sb.append('\u0000'); + } + // Block is double NUL terminated sb.append('\u0000'); return sb.toString(); } + // add the environment variable to the child, if it exists in parent + private static void addToEnvIfSet(StringBuilder sb, String name) { + String s = getenv(name); + if (s != null) + addToEnv(sb, name, s); + } + + private static void addToEnv(StringBuilder sb, String name, String val) { + sb.append(name).append('=').append(val).append('\u0000'); + } + static String toEnvironmentBlock(Map<String,String> map) { return map == null ? null : ((ProcessEnvironment)map).toEnvironmentBlock();
--- a/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java Thu Apr 21 14:25:46 2011 +0100 @@ -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 @@ -30,12 +30,15 @@ package sun.security.krb5.internal.tools; +import java.io.File; import sun.security.krb5.*; import sun.security.krb5.internal.*; import sun.security.krb5.internal.ccache.*; import java.io.IOException; import java.util.Arrays; +import javax.security.auth.kerberos.KerberosPrincipal; import sun.security.util.Password; +import javax.security.auth.kerberos.KeyTab; /** * Kinit tool for obtaining Kerberos v5 tickets. @@ -153,7 +156,6 @@ System.out.println("Principal is " + principal); } char[] psswd = options.password; - EncryptionKey[] skeys = null; boolean useKeytab = options.useKeytabFile(); if (!useKeytab) { if (princName == null) { @@ -186,17 +188,9 @@ } } - // assert princName and principal are nonnull - skeys = EncryptionKey.acquireSecretKeys(principal, ktabName); - - if (skeys == null || skeys.length == 0) { - String msg = "No supported key found in keytab"; - if (princName != null) { - msg += " for principal " + princName; - } - throw new KrbException(msg); - } - builder = new KrbAsReqBuilder(principal, skeys); + builder = new KrbAsReqBuilder(principal, ktabName == null + ? KeyTab.getInstance() + : KeyTab.getInstance(new File(ktabName))); } KDCOptions opt = new KDCOptions();
--- a/src/windows/classes/sun/security/krb5/internal/tools/Klist.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/windows/classes/sun/security/krb5/internal/tools/Klist.java Thu Apr 21 14:25:46 2011 +0100 @@ -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 @@ -95,16 +95,15 @@ } break; case 'k': - if (klist.name == null) { - klist.target = KeyTab.getInstance(); - klist.name = KeyTab.tabName(); - } else klist.target = KeyTab.getInstance(klist.name); - if (klist.target != null) { - klist.displayTab(); - } else { + try { + KeyTab ktab = KeyTab.getInstance(klist.name); + klist.target = ktab; + klist.name = ktab.tabName(); + } catch (Exception e) { klist.displayMessage("KeyTab"); System.exit(-1); } + klist.displayTab(); break; default: if (klist.name != null) { @@ -295,9 +294,10 @@ void displayMessage(String target) { if (name == null) { - name = ""; + System.out.println("Default " + target + " not found."); + } else { + System.out.println(target + " " + name + " not found."); } - System.out.println(target + " " + name + " not found."); } /** * Reformats the date from the form -
--- a/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java Thu Apr 21 14:23:57 2011 +0100 +++ b/src/windows/classes/sun/security/krb5/internal/tools/Ktab.java Thu Apr 21 14:25:46 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, 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 @@ -321,7 +321,7 @@ * Lists key table name and entries in it. */ void listKt() { - System.out.println("Keytab name: " + KeyTab.tabName()); + System.out.println("Keytab name: " + table.tabName()); KeyTabEntry[] entries = table.getEntries(); if ((entries != null) && (entries.length > 0)) { String[][] output = new String[entries.length+1][showTime?3:2];
--- a/test/java/lang/ProcessBuilder/Basic.java Thu Apr 21 14:23:57 2011 +0100 +++ b/test/java/lang/ProcessBuilder/Basic.java Thu Apr 21 14:25:46 2011 +0100 @@ -26,7 +26,7 @@ * @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689 * 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313 * 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958 - * 4947220 7018606 + * 4947220 7018606 7034570 * @summary Basic tests for Process and Environment Variable code * @run main/othervm/timeout=300 Basic * @author Martin Buchholz @@ -1440,11 +1440,12 @@ // Check for sort order of environment variables on Windows. //---------------------------------------------------------------- try { + String systemRoot = "SystemRoot=" + System.getenv("SystemRoot"); // '+' < 'A' < 'Z' < '_' < 'a' < 'z' < '~' String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=", - "+=+", "_=_", "~=~"}; + "+=+", "_=_", "~=~", systemRoot}; String output = nativeEnv(envp); - String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n_=_\n~=~\n"; + String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n"+systemRoot+"\n_=_\n~=~\n"; // On Windows, Java must keep the environment sorted. // Order is random on Unix, so this test does the sort. if (! Windows.is()) @@ -1453,6 +1454,21 @@ } catch (Throwable t) { unexpected(t); } //---------------------------------------------------------------- + // Test Runtime.exec(...envp...) + // and check SystemRoot gets set automatically on Windows + //---------------------------------------------------------------- + try { + if (Windows.is()) { + String systemRoot = "SystemRoot=" + System.getenv("SystemRoot"); + String[]envp = {"FOO=BAR","BAZ=GORP","QUUX=", + "+=+", "_=_", "~=~"}; + String output = nativeEnv(envp); + String expected = "+=+\nBAZ=GORP\nFOO=BAR\nQUUX=\n"+systemRoot+"\n_=_\n~=~\n"; + equal(output, expected); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- // System.getenv() must be consistent with System.getenv(String) //---------------------------------------------------------------- try {
--- a/test/sun/security/krb5/auto/Context.java Thu Apr 21 14:23:57 2011 +0100 +++ b/test/sun/security/krb5/auto/Context.java Thu Apr 21 14:25:46 2011 +0100 @@ -44,6 +44,7 @@ import com.sun.security.jgss.AuthorizationDataEntry; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import javax.security.auth.kerberos.KeyTab; /** * Context of a JGSS subject, encapsulating Subject and GSSContext. @@ -107,15 +108,19 @@ return out; } + public static Context fromUserPass( + String user, char[] pass, boolean storeKey) throws Exception { + return fromUserPass(null, user, pass, storeKey); + } /** * Logins with a username and a password, using Krb5LoginModule directly * @param storeKey true if key should be saved, used on acceptor side */ - public static Context fromUserPass(String user, char[] pass, boolean storeKey) - throws Exception { + public static Context fromUserPass(Subject s, + String user, char[] pass, boolean storeKey) throws Exception { Context out = new Context(); out.name = user; - out.s = new Subject(); + out.s = s == null ? new Subject() : s; Krb5LoginModule krb5 = new Krb5LoginModule(); Map<String, String> map = new HashMap<>(); Map<String, Object> shared = new HashMap<>(); @@ -198,12 +203,25 @@ * @throws java.lang.Exception */ public void startAsServer(final Oid mech) throws Exception { + startAsServer(null, mech); + } + + /** + * Starts as a server with the specified service name + * @param name the service name + * @param mech GSS mech + * @throws java.lang.Exception + */ + public void startAsServer(final String name, final Oid mech) throws Exception { doAs(new Action() { @Override public byte[] run(Context me, byte[] dummy) throws Exception { GSSManager m = GSSManager.getInstance(); me.x = (ExtendedGSSContext)m.createContext(m.createCredential( - null, + name == null ? null : + (name.indexOf('@') < 0 ? + m.createName(name, null) : + m.createName(name, GSSName.NT_HOSTBASED_SERVICE)), GSSCredential.INDEFINITE_LIFETIME, mech, GSSCredential.ACCEPT_ONLY)); @@ -230,6 +248,14 @@ } /** + * Accesses the internal subject. + * @return the subject + */ + public Subject s() { + return s; + } + + /** * Disposes the GSSContext within * @throws org.ietf.jgss.GSSException */ @@ -297,7 +323,7 @@ } catch (Exception e) { ;// Don't care } - System.out.println("====================================="); + System.out.println("====== Private Credentials Set ======"); for (Object o : s.getPrivateCredentials()) { System.out.println(" " + o.getClass()); if (o instanceof KerberosTicket) { @@ -315,6 +341,8 @@ for (Object k : map.keySet()) { System.out.println(" " + k + ": " + map.get(k)); } + } else { + System.out.println(" " + o); } } if (x != null && x instanceof ExtendedGSSContext) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/krb5/auto/DynamicKeytab.java Thu Apr 21 14:25:46 2011 +0100 @@ -0,0 +1,140 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6894072 + * @run main/othervm DynamicKeytab + * @summary always refresh keytab + */ + +import java.io.File; +import java.io.FileOutputStream; +import org.ietf.jgss.GSSException; +import sun.security.jgss.GSSUtil; +import sun.security.krb5.KrbException; +import sun.security.krb5.internal.Krb5; + +public class DynamicKeytab { + + Context c, s; + public static void main(String[] args) + throws Exception { + new DynamicKeytab().go(); + } + + void go() throws Exception { + OneKDC k = new OneKDC(null); + k.writeJAASConf(); + + new File(OneKDC.KTAB).delete(); + + + // Starts with no keytab + c = Context.fromJAAS("client"); + s = Context.fromJAAS("com.sun.security.jgss.krb5.accept"); + + // Test 1: read new key 1 from keytab + k.addPrincipal(OneKDC.SERVER, "pass1".toCharArray()); + k.writeKtab(OneKDC.KTAB); + connect(); + + // Test 2: service key cached, find 1 in keytab (now contains 1 and 2) + k.addPrincipal(OneKDC.SERVER, "pass2".toCharArray()); + k.appendKtab(OneKDC.KTAB); + connect(); + + // Test 3: re-login. Now find 2 in keytab + c = Context.fromJAAS("client"); + connect(); + + // Test 4: re-login, KDC use 3 this time. + c = Context.fromJAAS("client"); + // Put 3 and 4 into keytab but keep the real key back to 3. + k.addPrincipal(OneKDC.SERVER, "pass3".toCharArray()); + k.appendKtab(OneKDC.KTAB); + k.addPrincipal(OneKDC.SERVER, "pass4".toCharArray()); + k.appendKtab(OneKDC.KTAB); + k.addPrincipal(OneKDC.SERVER, "pass3".toCharArray()); + connect(); + + // Test 5: invalid keytab file, should ignore + new FileOutputStream(OneKDC.KTAB).write("BADBADBAD".getBytes()); + connect(); + + // Test 6: delete keytab file, identical to revoke all + new File(OneKDC.KTAB).delete(); + try { + connect(); + throw new Exception("Should not success"); + } catch (GSSException gsse) { + System.out.println(gsse); + KrbException ke = (KrbException)gsse.getCause(); + // KrbApReq.authenticate(*) if (dkey == null)... + // This should have been Krb5.KRB_AP_ERR_NOKEY + if (ke.returnCode() != Krb5.API_INVALID_ARG) { + throw new Exception("Not expected failure code: " + + ke.returnCode()); + } + } + + // Test 7: 3 revoked, should fail (now contains only 5) + k.addPrincipal(OneKDC.SERVER, "pass5".toCharArray()); + k.writeKtab(OneKDC.KTAB); // overwrite keytab, which means + // old key is revoked + try { + connect(); + throw new Exception("Should not success"); + } catch (GSSException gsse) { + System.out.println(gsse); + KrbException ke = (KrbException)gsse.getCause(); + if (ke.returnCode() != Krb5.KRB_AP_ERR_BADKEYVER) { + throw new Exception("Not expected failure code: " + + ke.returnCode()); + } + } + + // Test 8: an empty KDC means revoke all + KDC.create("EMPTY.REALM").writeKtab(OneKDC.KTAB); + try { + connect(); + throw new Exception("Should not success"); + } catch (GSSException gsse) { + System.out.println(gsse); + KrbException ke = (KrbException)gsse.getCause(); + // KrbApReq.authenticate(*) if (dkey == null)... + // This should have been Krb5.KRB_AP_ERR_NOKEY + if (ke.returnCode() != Krb5.API_INVALID_ARG) { + throw new Exception("Not expected failure code: " + + ke.returnCode()); + } + } + } + + void connect() throws Exception { + Thread.sleep(2000); // make sure ktab timestamp is different + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + } +}
--- a/test/sun/security/krb5/auto/KDC.java Thu Apr 21 14:23:57 2011 +0100 +++ b/test/sun/security/krb5/auto/KDC.java Thu Apr 21 14:25:46 2011 +0100 @@ -228,7 +228,33 @@ } /** - * Write all principals' keys from multiple KDCsinto one keytab file. + * Writes or appends KDC keys into a keytab. See doc for writeMultiKtab. + * @param append true if append, otherwise, overwrite. + */ + private static void writeKtab0(String tab, boolean append, KDC... kdcs) + throws IOException, KrbException { + KeyTab ktab = append ? KeyTab.getInstance(tab) : KeyTab.create(tab); + for (KDC kdc: kdcs) { + for (String name : kdc.passwords.keySet()) { + char[] pass = kdc.passwords.get(name); + int kvno = 0; + if (Character.isDigit(pass[pass.length-1])) { + kvno = pass[pass.length-1] - '0'; + } + ktab.addEntry(new PrincipalName(name, + name.indexOf('/') < 0 ? + PrincipalName.KRB_NT_UNKNOWN : + PrincipalName.KRB_NT_SRV_HST), + pass, + kvno, + true); + } + } + ktab.save(); + } + + /** + * Writes all principals' keys from multiple KDCs into one keytab file. * Note that the keys for the krbtgt principals will not be written. * <p> * Attention: This method references krb5.conf settings. If you need to @@ -252,17 +278,16 @@ */ public static void writeMultiKtab(String tab, KDC... kdcs) throws IOException, KrbException { - KeyTab ktab = KeyTab.create(tab); - for (KDC kdc: kdcs) { - for (String name : kdc.passwords.keySet()) { - ktab.addEntry(new PrincipalName(name, - name.indexOf('/') < 0 ? - PrincipalName.KRB_NT_UNKNOWN : - PrincipalName.KRB_NT_SRV_HST), - kdc.passwords.get(name), -1, true); - } - } - ktab.save(); + writeKtab0(tab, false, kdcs); + } + + /** + * Appends all principals' keys from multiple KDCs to one keytab file. + * See writeMultiKtab for details. + */ + public static void appendMultiKtab(String tab, KDC... kdcs) + throws IOException, KrbException { + writeKtab0(tab, true, kdcs); } /** @@ -273,6 +298,13 @@ } /** + * Appends keys in this KDC to a ktab. + */ + public void appendKtab(String tab) throws IOException, KrbException { + KDC.appendMultiKtab(tab, this); + } + + /** * Adds a new principal to this realm with a given password. * @param user the principal's name. For a service principal, use the * form of host/f.q.d.n
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/krb5/auto/KeyTabCompat.java Thu Apr 21 14:25:46 2011 +0100 @@ -0,0 +1,90 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6894072 + * @compile -XDignore.symbol.file KeyTabCompat.java + * @run main/othervm KeyTabCompat + * @summary always refresh keytab + */ + +import javax.security.auth.kerberos.KerberosKey; +import sun.security.jgss.GSSUtil; + +/* + * There are 2 compat issues to check: + * + * 1. If there is only KerberosKeys in private credential set and no + * KerberosPrincipal. JAAS login should go on. + * 2. Even if KeyTab is used, user can still get KerberosKeys from + * private credentials set. + */ +public class KeyTabCompat { + + public static void main(String[] args) + throws Exception { + OneKDC kdc = new OneKDC("aes128-cts"); + kdc.writeJAASConf(); + kdc.addPrincipal(OneKDC.SERVER, "pass1".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + Context c, s; + + // Part 1 + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + s = Context.fromUserPass(OneKDC.USER2, OneKDC.PASS2, true); + + s.s().getPrincipals().clear(); + + c.startAsClient(OneKDC.USER2, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + + Context.handshake(c, s); + + // Part 2 + c = Context.fromJAAS("client"); + s = Context.fromJAAS("server"); + + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + s.status(); + + if (s.s().getPrivateCredentials(KerberosKey.class).size() != 1) { + throw new Exception("There should be one KerberosKey"); + } + + Thread.sleep(2000); // make sure ktab timestamp is different + + kdc.addPrincipal(OneKDC.SERVER, "pass2".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + Context.handshake(c, s); + s.status(); + + if (s.s().getPrivateCredentials(KerberosKey.class).size() != 1) { + throw new Exception("There should be only one KerberosKey"); + } + + } +}
--- a/test/sun/security/krb5/auto/LoginModuleOptions.java Thu Apr 21 14:23:57 2011 +0100 +++ b/test/sun/security/krb5/auto/LoginModuleOptions.java Thu Apr 21 14:25:46 2011 +0100 @@ -28,7 +28,6 @@ * @summary Krb5LoginModule a little too restrictive, and the doc is not clear. */ import com.sun.security.auth.module.Krb5LoginModule; -import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.security.auth.Subject; @@ -36,7 +35,6 @@ import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; public class LoginModuleOptions { @@ -61,10 +59,12 @@ // 1. ccache -> keytab login(null, "useTicketCache", "true", "ticketCache", "krbcc_non_exists", "useKeyTab", "true", "principal", "dummy"); + // 2. keytab -> shared login(null, "useKeyTab", "true", "principal", "dummy", "keyTab", "ktab_non_exist", "tryFirstPass", "true", NAME, OneKDC.USER, PWD, OneKDC.PASS); + // 3. shared -> callback // 3.1. useFirstPass, no callback boolean failed = false;
--- a/test/sun/security/krb5/auto/SSL.java Thu Apr 21 14:23:57 2011 +0100 +++ b/test/sun/security/krb5/auto/SSL.java Thu Apr 21 14:25:46 2011 +0100 @@ -48,7 +48,7 @@ public class SSL { private static String krb5Cipher; - private static final int LOOP_LIMIT = 1; + private static final int LOOP_LIMIT = 3; private static int loopCount = 0; private static volatile String server; private static volatile int port; @@ -98,13 +98,13 @@ fos.close(); f.deleteOnExit(); - final Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + Context c; final Context s = Context.fromJAAS("ssl"); - c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); + // There's no keytab file when server starts. s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); - new Thread(new Runnable() { + Thread server = new Thread(new Runnable() { public void run() { try { s.doAs(new JsseServerAction(), null); @@ -112,12 +112,57 @@ e.printStackTrace(); } } - }).start(); + }); + server.setDaemon(true); + server.start(); // Warm the server Thread.sleep(2000); + // Now create the keytab + + /* + // Add 3 versions of keys into keytab + KeyTab ktab = KeyTab.create(OneKDC.KTAB); + PrincipalName service = new PrincipalName( + "host/" + server, PrincipalName.KRB_NT_SRV_HST); + ktab.addEntry(service, "pass1".toCharArray(), 1); + ktab.addEntry(service, "pass2".toCharArray(), 2); + ktab.addEntry(service, "pass3".toCharArray(), 3); + ktab.save(); + + // and use the middle one as the real key + kdc.addPrincipal("host/" + server, "pass2".toCharArray()); + */ + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); c.doAs(new JsseClientAction(), null); + + // Add another version of key, make sure it can be loaded + Thread.sleep(2000); + ktab = KeyTab.getInstance(OneKDC.KTAB); + ktab.addEntry(service, "pass4".toCharArray(), 4, true); + ktab.save(); + kdc.addPrincipal("host/" + server, "pass4".toCharArray()); + + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); + c.doAs(new JsseClientAction(), null); + + // Revoke the old key + /*Thread.sleep(2000); + ktab = KeyTab.create(OneKDC.KTAB); + ktab.addEntry(service, "pass5".toCharArray(), 5, false); + ktab.save(); + + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); + try { + c.doAs(new JsseClientAction(), null); + throw new Exception("Should fail this time."); + } catch (SSLException e) { + // Correct behavior. + }*/ } // Following codes copied from @@ -126,6 +171,7 @@ public byte[] run(Context s, byte[] input) throws Exception { SSLSocketFactory sslsf = (SSLSocketFactory) SSLSocketFactory.getDefault(); + System.out.println("Connecting " + server + ":" + port); SSLSocket sslSocket = (SSLSocket) sslsf.createSocket(server, port); // Enable only a KRB5 cipher suite. @@ -154,6 +200,9 @@ System.out.println("Server is: " + peer.toString()); sslSocket.close(); + // This line should not be needed. It's the server's duty to + // forget the old key + //sslSocket.getSession().invalidate(); return null; } } @@ -165,6 +214,7 @@ SSLServerSocket sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(0); // any port port = sslServerSocket.getLocalPort(); + System.out.println("Listening on " + port); // Enable only a KRB5 cipher suite. String enabledSuites[] = {krb5Cipher};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/krb5/auto/TwoPrinces.java Thu Apr 21 14:25:46 2011 +0100 @@ -0,0 +1,102 @@ +/* + * 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. + * + * 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. + */ + +/* + * @test + * @bug 6894072 + * @compile -XDignore.symbol.file TwoPrinces.java + * @run main/othervm TwoPrinces + * @summary always refresh keytab + */ + +import java.io.File; +import java.io.FileOutputStream; +import sun.security.jgss.GSSUtil; +import sun.security.krb5.Config; + +public class TwoPrinces { + + public static void main(String[] args) + throws Exception { + + KDC k1 = KDC.create("R1"); + k1.addPrincipal("u1", "hello".toCharArray()); + k1.addPrincipalRandKey("krbtgt/R1"); + k1.addPrincipalRandKey("host/same.host"); + + KDC k2 = KDC.create("R2"); + k2.addPrincipal("u2", "hello".toCharArray()); + k2.addPrincipalRandKey("krbtgt/R2"); + k2.addPrincipalRandKey("host/same.host"); + + System.setProperty("java.security.krb5.conf", "krb5.conf"); + + // R1 is the default realm now + KDC.saveConfig("krb5.conf", k1, k2); + Config.refresh(); + + k1.writeKtab("ktab1"); + k2.writeKtab("ktab2"); + + // A JAAS config file with 2 Krb5LoginModules, after commit, the + // subject with have principals and keytabs from both sides + System.setProperty("java.security.auth.login.config", "jaas.conf"); + File f = new File("jaas.conf"); + FileOutputStream fos = new FileOutputStream(f); + fos.write(( + "me {\n" + + " com.sun.security.auth.module.Krb5LoginModule required" + + " isInitiator=true principal=\"host/same.host@R1\"" + + " useKeyTab=true keyTab=ktab1 storeKey=true;\n" + + " com.sun.security.auth.module.Krb5LoginModule required" + + " isInitiator=true principal=\"host/same.host@R2\"" + + " useKeyTab=true keyTab=ktab2 storeKey=true;\n" + + "};\n" + ).getBytes()); + fos.close(); + + /* + * This server side context will be able to act as services in both + * realms. Please note that we still don't support a single instance + * of server to accept connections from two realms at the same time. + * Therefore, we must call startAsServer in a given realm to start + * working there. The same Subject never changes anyway. + */ + Context s = Context.fromJAAS("me"); + + // Default realm still R1 + s.startAsServer("host@same.host", GSSUtil.GSS_KRB5_MECH_OID); + Context c1 = Context.fromUserPass("u1", "hello".toCharArray(), false); + c1.startAsClient("host@same.host", GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c1, s); + + KDC.saveConfig("krb5.conf", k2, k1); + Config.refresh(); + + // Default realm now R2 + s.startAsServer("host@same.host", GSSUtil.GSS_KRB5_MECH_OID); + Context c2 = Context.fromUserPass("u2", "hello".toCharArray(), false); + c2.startAsClient("host@same.host", GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c2, s); + } +}
--- a/test/sun/security/krb5/ktab/KeyTabIndex.java Thu Apr 21 14:23:57 2011 +0100 +++ b/test/sun/security/krb5/ktab/KeyTabIndex.java Thu Apr 21 14:25:46 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -44,7 +44,6 @@ KeyTab.getInstance("ktab").getClass(); } }; - KeyTab.refresh(); for (int i=0; i<10; i++) { new Thread(t).start(); }