Path: blob/master/src/java.base/share/classes/javax/security/auth/SubjectDomainCombiner.java
41159 views
/*1* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.security.auth;2627import java.security.AccessController;28import java.security.Principal;29import java.security.PrivilegedAction;30import java.security.ProtectionDomain;31import java.util.Set;32import java.util.WeakHashMap;33import java.lang.ref.WeakReference;3435/**36* A {@code SubjectDomainCombiner} updates ProtectionDomains37* with Principals from the {@code Subject} associated with this38* {@code SubjectDomainCombiner}.39*40* @since 1.441* @deprecated This class is only useful in conjunction with42* {@linkplain SecurityManager the Security Manager}, which is deprecated43* and subject to removal in a future release. Consequently, this class44* is also deprecated and subject to removal. There is no replacement for45* the Security Manager or this class.46*/47@SuppressWarnings("removal")48@Deprecated(since="17", forRemoval=true)49public class SubjectDomainCombiner implements java.security.DomainCombiner {5051private Subject subject;52private WeakKeyValueMap<ProtectionDomain, ProtectionDomain> cachedPDs =53new WeakKeyValueMap<>();54private Set<Principal> principalSet;55private Principal[] principals;5657private static final sun.security.util.Debug debug =58sun.security.util.Debug.getInstance("combiner",59"\t[SubjectDomainCombiner]");6061/**62* Associate the provided {@code Subject} with this63* {@code SubjectDomainCombiner}.64*65* @param subject the {@code Subject} to be associated with66* this {@code SubjectDomainCombiner}.67*/68public SubjectDomainCombiner(Subject subject) {69this.subject = subject;7071if (subject.isReadOnly()) {72principalSet = subject.getPrincipals();73principals = principalSet.toArray74(new Principal[principalSet.size()]);75}76}7778/**79* Get the {@code Subject} associated with this80* {@code SubjectDomainCombiner}.81*82* @return the {@code Subject} associated with this83* {@code SubjectDomainCombiner}, or {@code null}84* if no {@code Subject} is associated with this85* {@code SubjectDomainCombiner}.86*87* @exception SecurityException if the caller does not have permission88* to get the {@code Subject} associated with this89* {@code SubjectDomainCombiner}.90*/91public Subject getSubject() {92java.lang.SecurityManager sm = System.getSecurityManager();93if (sm != null) {94sm.checkPermission(new AuthPermission95("getSubjectFromDomainCombiner"));96}97return subject;98}99100/**101* Update the relevant ProtectionDomains with the Principals102* from the {@code Subject} associated with this103* {@code SubjectDomainCombiner}.104*105* <p> A new {@code ProtectionDomain} instance is created106* for each non-static {@code ProtectionDomain} (107* (staticPermissionsOnly() == false)108* in the {@code currentDomains} array. Each new {@code ProtectionDomain}109* instance is created using the {@code CodeSource},110* {@code Permission}s and {@code ClassLoader}111* from the corresponding {@code ProtectionDomain} in112* {@code currentDomains}, as well as with the Principals from113* the {@code Subject} associated with this114* {@code SubjectDomainCombiner}. Static ProtectionDomains are115* combined as-is and no new instance is created.116*117* <p> All of the ProtectionDomains (static and newly instantiated) are118* combined into a new array. The ProtectionDomains from the119* {@code assignedDomains} array are appended to this new array,120* and the result is returned.121*122* <p> Note that optimizations such as the removal of duplicate123* ProtectionDomains may have occurred.124* In addition, caching of ProtectionDomains may be permitted.125*126* @param currentDomains the ProtectionDomains associated with the127* current execution Thread, up to the most recent128* privileged {@code ProtectionDomain}.129* The ProtectionDomains are listed in order of execution,130* with the most recently executing {@code ProtectionDomain}131* residing at the beginning of the array. This parameter may132* be {@code null} if the current execution Thread133* has no associated ProtectionDomains.134*135* @param assignedDomains the ProtectionDomains inherited from the136* parent Thread, or the ProtectionDomains from the137* privileged {@code context}, if a call to138* {@code AccessController.doPrivileged(..., context)}139* had occurred This parameter may be {@code null}140* if there were no ProtectionDomains inherited from the141* parent Thread, or from the privileged {@code context}.142*143* @return a new array consisting of the updated ProtectionDomains,144* or {@code null}.145*/146public ProtectionDomain[] combine(ProtectionDomain[] currentDomains,147ProtectionDomain[] assignedDomains) {148if (debug != null) {149if (subject == null) {150debug.println("null subject");151} else {152final Subject s = subject;153AccessController.doPrivileged154(new java.security.PrivilegedAction<Void>() {155public Void run() {156debug.println(s.toString());157return null;158}159});160}161printInputDomains(currentDomains, assignedDomains);162}163164if (currentDomains == null || currentDomains.length == 0) {165// No need to optimize assignedDomains because it should166// have been previously optimized (when it was set).167168// Note that we are returning a direct reference169// to the input array - since ACC does not clone170// the arrays when it calls combiner.combine,171// multiple ACC instances may share the same172// array instance in this case173174return assignedDomains;175}176177// optimize currentDomains178//179// No need to optimize assignedDomains because it should180// have been previously optimized (when it was set).181182currentDomains = optimize(currentDomains);183if (debug != null) {184debug.println("after optimize");185printInputDomains(currentDomains, assignedDomains);186}187188if (currentDomains == null && assignedDomains == null) {189return null;190}191192int cLen = (currentDomains == null ? 0 : currentDomains.length);193int aLen = (assignedDomains == null ? 0 : assignedDomains.length);194195// the ProtectionDomains for the new AccessControlContext196// that we will return197ProtectionDomain[] newDomains = new ProtectionDomain[cLen + aLen];198199boolean allNew = true;200synchronized(cachedPDs) {201if (!subject.isReadOnly() &&202!subject.getPrincipals().equals(principalSet)) {203204// if the Subject was mutated, clear the PD cache205Set<Principal> newSet = subject.getPrincipals();206synchronized(newSet) {207principalSet = new java.util.HashSet<Principal>(newSet);208}209principals = principalSet.toArray210(new Principal[principalSet.size()]);211cachedPDs.clear();212213if (debug != null) {214debug.println("Subject mutated - clearing cache");215}216}217218ProtectionDomain subjectPd;219for (int i = 0; i < cLen; i++) {220ProtectionDomain pd = currentDomains[i];221222subjectPd = cachedPDs.getValue(pd);223224if (subjectPd == null) {225if (pd.staticPermissionsOnly()) {226// keep static ProtectionDomain objects static227subjectPd = pd;228} else {229subjectPd = new ProtectionDomain(pd.getCodeSource(),230pd.getPermissions(),231pd.getClassLoader(),232principals);233}234cachedPDs.putValue(pd, subjectPd);235} else {236allNew = false;237}238newDomains[i] = subjectPd;239}240}241242if (debug != null) {243debug.println("updated current: ");244for (int i = 0; i < cLen; i++) {245debug.println("\tupdated[" + i + "] = " +246printDomain(newDomains[i]));247}248}249250// now add on the assigned domains251if (aLen > 0) {252System.arraycopy(assignedDomains, 0, newDomains, cLen, aLen);253254// optimize the result (cached PDs might exist in assignedDomains)255if (!allNew) {256newDomains = optimize(newDomains);257}258}259260// if aLen == 0 || allNew, no need to further optimize newDomains261262if (debug != null) {263if (newDomains == null || newDomains.length == 0) {264debug.println("returning null");265} else {266debug.println("combinedDomains: ");267for (int i = 0; i < newDomains.length; i++) {268debug.println("newDomain " + i + ": " +269printDomain(newDomains[i]));270}271}272}273274// return the new ProtectionDomains275if (newDomains == null || newDomains.length == 0) {276return null;277} else {278return newDomains;279}280}281282private static ProtectionDomain[] optimize(ProtectionDomain[] domains) {283if (domains == null || domains.length == 0)284return null;285286ProtectionDomain[] optimized = new ProtectionDomain[domains.length];287ProtectionDomain pd;288int num = 0;289for (int i = 0; i < domains.length; i++) {290291// skip domains with AllPermission292// XXX293//294// if (domains[i].implies(ALL_PERMISSION))295// continue;296297// skip System Domains298if ((pd = domains[i]) != null) {299300// remove duplicates301boolean found = false;302for (int j = 0; j < num && !found; j++) {303found = (optimized[j] == pd);304}305if (!found) {306optimized[num++] = pd;307}308}309}310311// resize the array if necessary312if (num > 0 && num < domains.length) {313ProtectionDomain[] downSize = new ProtectionDomain[num];314System.arraycopy(optimized, 0, downSize, 0, downSize.length);315optimized = downSize;316}317318return ((num == 0 || optimized.length == 0) ? null : optimized);319}320321private static void printInputDomains(ProtectionDomain[] currentDomains,322ProtectionDomain[] assignedDomains) {323if (currentDomains == null || currentDomains.length == 0) {324debug.println("currentDomains null or 0 length");325} else {326for (int i = 0; currentDomains != null &&327i < currentDomains.length; i++) {328if (currentDomains[i] == null) {329debug.println("currentDomain " + i + ": SystemDomain");330} else {331debug.println("currentDomain " + i + ": " +332printDomain(currentDomains[i]));333}334}335}336337if (assignedDomains == null || assignedDomains.length == 0) {338debug.println("assignedDomains null or 0 length");339} else {340debug.println("assignedDomains = ");341for (int i = 0; assignedDomains != null &&342i < assignedDomains.length; i++) {343if (assignedDomains[i] == null) {344debug.println("assignedDomain " + i + ": SystemDomain");345} else {346debug.println("assignedDomain " + i + ": " +347printDomain(assignedDomains[i]));348}349}350}351}352353private static String printDomain(final ProtectionDomain pd) {354if (pd == null) {355return "null";356}357return AccessController.doPrivileged(new PrivilegedAction<String>() {358public String run() {359return pd.toString();360}361});362}363364/**365* A HashMap that has weak keys and values.366*367* Key objects in this map are the "current" ProtectionDomain instances368* received via the combine method. Each "current" PD is mapped to a369* new PD instance that holds both the contents of the "current" PD,370* as well as the principals from the Subject associated with this combiner.371*372* The newly created "principal-based" PD values must be stored as373* WeakReferences since they contain strong references to the374* corresponding key object (the "current" non-principal-based PD),375* which will prevent the key from being GC'd. Specifically,376* a "principal-based" PD contains strong references to the CodeSource,377* signer certs, PermissionCollection and ClassLoader objects378* in the "current PD".379*/380private static class WeakKeyValueMap<K,V> extends381WeakHashMap<K,WeakReference<V>> {382383public V getValue(K key) {384WeakReference<V> wr = super.get(key);385if (wr != null) {386return wr.get();387}388return null;389}390391public V putValue(K key, V value) {392WeakReference<V> wr = super.put(key, new WeakReference<V>(value));393if (wr != null) {394return wr.get();395}396return null;397}398}399}400401402