      1 /*
      2  * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25
     26 package java.security;
     27
     28 import java.io.IOException;
     29 import java.io.ObjectInputStream;
     30 import java.io.ObjectOutputStream;
     31 import java.io.ObjectStreamField;
     32 import java.util.*;
     33 import java.util.concurrent.ConcurrentHashMap;
     34 import java.util.concurrent.CopyOnWriteArrayList;
     35
     36 /**
     37  * A UnresolvedPermissionCollection stores a collection
     38  * of UnresolvedPermission permissions.
     39  *
     40  * @see java.security.Permission
     41  * @see java.security.Permissions
     42  * @see java.security.UnresolvedPermission
     43  *
     44  *
     45  * @author Roland Schemers
     46  * @since 1.2
     47  *
     48  * @serial include
     49  */
     50
     51 final class UnresolvedPermissionCollection
     52 extends PermissionCollection
     53 implements java.io.Serializable
     54 {
     55     /**
     56      * Key is permission type, value is a list of the UnresolvedPermissions
     57      * of the same type.
     58      * Not serialized; see serialization section at end of class.
     59      */
     60     private transient ConcurrentHashMap<String, List<UnresolvedPermission>> perms;
     61
     62     /**
     63      * Create an empty UnresolvedPermissionCollection object.
     64      *
     65      */
     66     public UnresolvedPermissionCollection() {
     67         perms = new ConcurrentHashMap<>(11);
     68     }
     69
     70     /**
     71      * Adds a permission to this UnresolvedPermissionCollection.
     72      * The key for the hash is the unresolved permission's type (class) name.
     73      *
     74      * @param permission the Permission object to add.
     75      */
     76     @Override
     77     public void add(Permission permission) {
     78         if (! (permission instanceof UnresolvedPermission))
     79             throw new IllegalArgumentException("invalid permission: "+
     80                                                permission);
     81         UnresolvedPermission up = (UnresolvedPermission) permission;
     82
     83         // Add permission to map. NOTE: cannot use lambda for
     84         // remappingFunction parameter until JDK-8076596 is fixed.
     85         perms.compute(up.getName(),
     86             new java.util.function.BiFunction<>() {
     87                 @Override
     88                 public List<UnresolvedPermission> apply(String key,
     89                                         List<UnresolvedPermission> oldValue) {
     90                     if (oldValue == null) {
     91                         List<UnresolvedPermission> v =
     92                             new CopyOnWriteArrayList<>();
     93                         v.add(up);
     94                         return v;
     95                     } else {
     96                         oldValue.add(up);
     97                         return oldValue;
     98                     }
     99                 }
    100             }
    101         );
    102     }
    103
    104     /**
    105      * get any unresolved permissions of the same type as p,
    106      * and return the List containing them.
    107      */
    108     List<UnresolvedPermission> getUnresolvedPermissions(Permission p) {
    109         return perms.get(p.getClass().getName());
    110     }
    111
    112     /**
    113      * always returns false for unresolved permissions
    114      *
    115      */
    116     @Override
    117     public boolean implies(Permission permission) {
    118         return false;
    119     }
    120
    121     /**
    122      * Returns an enumeration of all the UnresolvedPermission lists in the
    123      * container.
    124      *
    125      * @return an enumeration of all the UnresolvedPermission objects.
    126      */
    127     @Override
    128     public Enumeration<Permission> elements() {
    129         List<Permission> results =
    130             new ArrayList<>(); // where results are stored
    131
    132         // Get iterator of Map values (which are lists of permissions)
    133         for (List<UnresolvedPermission> l : perms.values()) {
    134             results.addAll(l);
    135         }
    136
    137         return Collections.enumeration(results);
    138     }
    139
    140     @java.io.Serial
    141     private static final long serialVersionUID = -7176153071733132400L;
    142
    143     // Need to maintain serialization interoperability with earlier releases,
    144     // which had the serializable field:
    145     // private Hashtable permissions; // keyed on type
    146
    147     /**
    148      * @serialField permissions java.util.Hashtable
    149      *     A table of the UnresolvedPermissions keyed on type, value is Vector
    150      *     of permissions
    151      */
    152     @java.io.Serial
    153     private static final ObjectStreamField[] serialPersistentFields = {
    154         new ObjectStreamField("permissions", Hashtable.class),
    155     };
    156
    157     /*
    158      * @serialData Default field.
    159      */
    160
    161     /**
    162      * Writes the contents of the perms field out as a Hashtable
    163      * in which the values are Vectors for
    164      * serialization compatibility with earlier releases.
    165      *
    166      * @param  out the {@code ObjectOutputStream} to which data is written
    167      * @throws IOException if an I/O error occurs
    168      */
    169     @java.io.Serial
    170     private void writeObject(ObjectOutputStream out) throws IOException {
    171         // Don't call out.defaultWriteObject()
    172
    173         // Copy perms into a Hashtable
    174         Hashtable<String, Vector<UnresolvedPermission>> permissions =
    175             new Hashtable<>(perms.size()*2);
    176
    177         // Convert each entry (List) into a Vector
    178         Set<Map.Entry<String, List<UnresolvedPermission>>> set = perms.entrySet();
    179         for (Map.Entry<String, List<UnresolvedPermission>> e : set) {
    180             // Convert list into Vector
    181             List<UnresolvedPermission> list = e.getValue();
    182             Vector<UnresolvedPermission> vec = new Vector<>(list);
    183
    184             // Add to Hashtable being serialized
    185             permissions.put(e.getKey(), vec);
    186         }
    187
    188         // Write out serializable fields
    189         ObjectOutputStream.PutField pfields = out.putFields();
    190         pfields.put("permissions", permissions);
    191         out.writeFields();
    192     }
    193
    194     /**
    195      * Reads in a Hashtable in which the values are Vectors of
    196      * UnresolvedPermissions and saves them in the perms field.
    197      *
    198      * @param  in the {@code ObjectInputStream} from which data is read
    199      * @throws IOException if an I/O error occurs
    200      * @throws ClassNotFoundException if a serialized class cannot be loaded
    201      */
    202     @java.io.Serial
    203     private void readObject(ObjectInputStream in) throws IOException,
    204     ClassNotFoundException {
    205         // Don't call defaultReadObject()
    206
    207         // Read in serialized fields
    208         ObjectInputStream.GetField gfields = in.readFields();
    209
    210         // Get permissions
    211         @SuppressWarnings("unchecked")
    212         // writeObject writes a Hashtable<String, Vector<UnresolvedPermission>>
    213         // for the permissions key, so this cast is safe, unless the data is corrupt.
    214         Hashtable<String, Vector<UnresolvedPermission>> permissions =
    215                 (Hashtable<String, Vector<UnresolvedPermission>>)
    216                 gfields.get("permissions", null);
    217         perms = new ConcurrentHashMap<>(permissions.size()*2);
    218
    219         // Convert each entry (Vector) into a List
    220         Set<Map.Entry<String, Vector<UnresolvedPermission>>> set = permissions.entrySet();
    221         for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
    222             // Convert Vector into ArrayList
    223             Vector<UnresolvedPermission> vec = e.getValue();
    224             List<UnresolvedPermission> list = new CopyOnWriteArrayList<>(vec);
    225
    226             // Add to Hashtable being serialized
    227             perms.put(e.getKey(), list);
    228         }
    229     }
    230 }