--- a/jdk/src/share/classes/com/sun/jmx/remote/security/SubjectDelegator.java Mon Mar 03 14:14:10 2014 -0800
+++ b/jdk/src/share/classes/com/sun/jmx/remote/security/SubjectDelegator.java Fri Mar 07 10:15:36 2014 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, 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
@@ -34,22 +34,14 @@
import javax.management.remote.SubjectDelegationPermission;
-import com.sun.jmx.remote.util.CacheMap;
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.*;
public class SubjectDelegator {
- private static final int PRINCIPALS_CACHE_SIZE = 10;
- private static final int ACC_CACHE_SIZE = 10;
-
- private CacheMap<Subject, Principal[]> principalsCache;
- private CacheMap<Subject, AccessControlContext> accCache;
-
/* Return the AccessControlContext appropriate to execute an
operation on behalf of the delegatedSubject. If the
authenticatedAccessControlContext does not have permission to
delegate to that subject, throw SecurityException. */
- public synchronized AccessControlContext
+ public AccessControlContext
delegatedContext(AccessControlContext authenticatedACC,
Subject delegatedSubject,
boolean removeCallerContext)
@@ -58,56 +50,14 @@
if (System.getSecurityManager() != null && authenticatedACC == null) {
throw new SecurityException("Illegal AccessControlContext: null");
}
- if (principalsCache == null || accCache == null) {
- principalsCache =
- new CacheMap<>(PRINCIPALS_CACHE_SIZE);
- accCache =
- new CacheMap<>(ACC_CACHE_SIZE);
- }
-
- // Retrieve the principals for the given
- // delegated subject from the cache
- //
- Principal[] delegatedPrincipals = principalsCache.get(delegatedSubject);
-
- // Convert the set of principals stored in the
- // delegated subject into an array of principals
- // and store it in the cache
- //
- if (delegatedPrincipals == null) {
- delegatedPrincipals =
- delegatedSubject.getPrincipals().toArray(new Principal[0]);
- principalsCache.put(delegatedSubject, delegatedPrincipals);
- }
-
- // Retrieve the access control context for the
- // given delegated subject from the cache
- //
- AccessControlContext delegatedACC = accCache.get(delegatedSubject);
-
- // Build the access control context to be used
- // when executing code as the delegated subject
- // and store it in the cache
- //
- if (delegatedACC == null) {
- if (removeCallerContext) {
- delegatedACC =
- JMXSubjectDomainCombiner.getDomainCombinerContext(
- delegatedSubject);
- } else {
- delegatedACC =
- JMXSubjectDomainCombiner.getContext(delegatedSubject);
- }
- accCache.put(delegatedSubject, delegatedACC);
- }
// Check if the subject delegation permission allows the
// authenticated subject to assume the identity of each
// principal in the delegated subject
//
- final Principal[] dp = delegatedPrincipals;
- final Collection<Permission> permissions = new ArrayList<>(dp.length);
- for(Principal p : dp) {
+ Collection<Principal> ps = getSubjectPrincipals(delegatedSubject);
+ final Collection<Permission> permissions = new ArrayList<>(ps.size());
+ for(Principal p : ps) {
final String pname = p.getClass().getName() + "." + p.getName();
permissions.add(new SubjectDelegationPermission(pname));
}
@@ -122,7 +72,15 @@
};
AccessController.doPrivileged(action, authenticatedACC);
- return delegatedACC;
+ return getDelegatedAcc(delegatedSubject, removeCallerContext);
+ }
+
+ private AccessControlContext getDelegatedAcc(Subject delegatedSubject, boolean removeCallerContext) {
+ if (removeCallerContext) {
+ return JMXSubjectDomainCombiner.getDomainCombinerContext(delegatedSubject);
+ } else {
+ return JMXSubjectDomainCombiner.getContext(delegatedSubject);
+ }
}
/**
@@ -137,11 +95,9 @@
public static synchronized boolean
checkRemoveCallerContext(Subject subject) {
try {
- final Principal[] dp =
- subject.getPrincipals().toArray(new Principal[0]);
- for (int i = 0 ; i < dp.length ; i++) {
+ for (Principal p : getSubjectPrincipals(subject)) {
final String pname =
- dp[i].getClass().getName() + "." + dp[i].getName();
+ p.getClass().getName() + "." + p.getName();
final Permission sdp =
new SubjectDelegationPermission(pname);
AccessController.checkPermission(sdp);
@@ -151,4 +107,19 @@
}
return true;
}
+
+ /**
+ * Retrieves the {@linkplain Subject} principals
+ * @param subject The subject
+ * @return If the {@code Subject} is immutable it will return the principals directly.
+ * If the {@code Subject} is mutable it will create an unmodifiable copy.
+ */
+ private static Collection<Principal> getSubjectPrincipals(Subject subject) {
+ if (subject.isReadOnly()) {
+ return subject.getPrincipals();
+ }
+
+ List<Principal> principals = Arrays.asList(subject.getPrincipals().toArray(new Principal[0]));
+ return Collections.unmodifiableList(principals);
+ }
}
--- a/jdk/src/share/classes/com/sun/jmx/remote/util/CacheMap.java Mon Mar 03 14:14:10 2014 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2003, 2006, 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 com.sun.jmx.remote.util;
-
-import java.lang.ref.SoftReference;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.WeakHashMap;
-
-import com.sun.jmx.mbeanserver.Util;
-
-/**
- * <p>Like WeakHashMap, except that the keys of the <em>n</em> most
- * recently-accessed entries are kept as {@link SoftReference soft
- * references}. Accessing an element means creating it, or retrieving
- * it with {@link #get(Object) get}. Because these entries are kept
- * with soft references, they will tend to remain even if their keys
- * are not referenced elsewhere. But if memory is short, they will
- * be removed.</p>
- */
-public class CacheMap<K, V> extends WeakHashMap<K, V> {
- /**
- * <p>Create a <code>CacheMap</code> that can keep up to
- * <code>nSoftReferences</code> as soft references.</p>
- *
- * @param nSoftReferences Maximum number of keys to keep as soft
- * references. Access times for {@link #get(Object) get} and
- * {@link #put(Object, Object) put} have a component that scales
- * linearly with <code>nSoftReferences</code>, so this value
- * should not be too great.
- *
- * @throws IllegalArgumentException if
- * <code>nSoftReferences</code> is negative.
- */
- public CacheMap(int nSoftReferences) {
- if (nSoftReferences < 0) {
- throw new IllegalArgumentException("nSoftReferences = " +
- nSoftReferences);
- }
- this.nSoftReferences = nSoftReferences;
- }
-
- public V put(K key, V value) {
- cache(key);
- return super.put(key, value);
- }
-
- public V get(Object key) {
- cache(Util.<K>cast(key));
- return super.get(key);
- }
-
- /* We don't override remove(Object) or try to do something with
- the map's iterators to detect removal. So we may keep useless
- entries in the soft reference list for keys that have since
- been removed. The assumption is that entries are added to the
- cache but never removed. But the behavior is not wrong if
- they are in fact removed -- the caching is just less
- performant. */
-
- private void cache(K key) {
- Iterator<SoftReference<K>> it = cache.iterator();
- while (it.hasNext()) {
- SoftReference<K> sref = it.next();
- K key1 = sref.get();
- if (key1 == null)
- it.remove();
- else if (key.equals(key1)) {
- // Move this element to the head of the LRU list
- it.remove();
- cache.add(0, sref);
- return;
- }
- }
-
- int size = cache.size();
- if (size == nSoftReferences) {
- if (size == 0)
- return; // degenerate case, equivalent to WeakHashMap
- it.remove();
- }
-
- cache.add(0, new SoftReference<K>(key));
- }
-
- /* List of soft references for the most-recently referenced keys.
- The list is in most-recently-used order, i.e. the first element
- is the most-recently referenced key. There are never more than
- nSoftReferences elements of this list.
-
- If we didn't care about J2SE 1.3 compatibility, we could use
- LinkedHashSet in conjunction with a subclass of SoftReference
- whose equals and hashCode reflect the referent. */
- private final LinkedList<SoftReference<K>> cache =
- new LinkedList<SoftReference<K>>();
- private final int nSoftReferences;
-}
--- a/jdk/test/javax/management/remote/mandatory/util/CacheMapTest.java Mon Mar 03 14:14:10 2014 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2003, 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 7654321
- * @summary Tests the CacheMap class.
- * @author Eamonn McManus
- * @run clean CacheMapTest
- * @run build CacheMapTest
- * @run main CacheMapTest
- */
-
-import java.util.Iterator;
-import java.util.Map;
-
-import com.sun.jmx.remote.util.CacheMap;
-
-public class CacheMapTest {
- public static void main(String[] args) {
- try {
- boolean ok = test(5) && test(100);
- if (ok) {
- System.out.println("Test completed");
- return;
- } else {
- System.out.println("Test failed!");
- System.exit(1);
- }
- } catch (Exception e) {
- System.err.println("Unexpected exception: " + e);
- e.printStackTrace();
- System.exit(1);
- }
- }
-
- private static boolean test(int cacheSize) throws Exception {
- System.out.println("CacheMap test with cache size " + cacheSize);
- CacheMap map = new CacheMap(cacheSize);
- int size = 0;
- int maxIterations = cacheSize * 10;
- while (map.size() == size && size < maxIterations) {
- Integer key = new Integer(size);
- Object x = map.put(key, "x");
- if (x != null) {
- System.out.println("Map already had entry " + key + "!");
- return false;
- }
- x = map.get(key);
- if (!"x".equals(x)) {
- System.out.println("Got back surprising value: " + x);
- return false;
- }
- size++;
- }
- System.out.println("Map size is " + map.size() + " after inserting " +
- size + " elements");
- do {
- System.gc();
- Thread.sleep(1);
- System.out.println("Map size is " + map.size() + " after GC");
- } while (map.size() > cacheSize);
- if (map.size() < cacheSize) {
- System.out.println("Map shrank to less than cache size: " +
- map.size() + " (surprising but not wrong)");
- } else
- System.out.println("Map shrank to cache size as expected");
- int lowest = size - cacheSize;
- // lowest value that can still be in cache if LRU is respected
- for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
- Map.Entry entry = (Map.Entry) it.next();
- Integer x = (Integer) entry.getKey();
- int xx = x.intValue();
- if (xx < lowest || xx >= size) {
- System.out.println("Old value remained (" + x + "), " +
- "expected none earlier than " + lowest);
- return false;
- }
- Object xxx = entry.getValue();
- if (!"x".equals(xxx)) {
- System.out.println("Got back surprising value: " + xxx);
- return false;
- }
- }
- if (map.size() > 0)
- System.out.println("Remaining elements are the most recent ones");
- System.out.println("Test passed");
- return true;
- }
-}