1 /*
2  * Copyright (c) 1999, 2019, 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 sun.security.provider;
27 
28 import java.net.URL;
29 import java.util.*;
30 import java.security.CodeSource;
31 import java.security.Principal;
32 import java.security.cert.Certificate;
33 import java.lang.reflect.Constructor;
34 
35 import javax.security.auth.Subject;
36 import sun.security.provider.PolicyParser.PrincipalEntry;
37 import sun.security.util.ResourcesMgr;
38 
39 /**
40  * <p> This <code>SubjectCodeSource</code> class contains
41  * a <code>URL</code>, signer certificates, and either a <code>Subject</code>
42  * (that represents the <code>Subject</code> in the current
43  * <code>AccessControlContext</code>), or a linked list of Principals
44  * (that represent a "subject" in a <code>Policy</code>).
45  *
46  */
47 class SubjectCodeSource extends CodeSource implements java.io.Serializable {
48 
49     @java.io.Serial
50     private static final long serialVersionUID = 6039418085604715275L;
51 
52     private Subject subject;
53     private LinkedList<PrincipalEntry> principals;
54     private static final Class<?>[] PARAMS = { String.class };
55     private static final sun.security.util.Debug debug =
56         sun.security.util.Debug.getInstance("auth", "\t[Auth Access]");
57     @SuppressWarnings("serial") // Not statically typed as Serializable
58     private ClassLoader sysClassLoader;
59 
60     /**
61      * Creates a new <code>SubjectCodeSource</code>
62      * with the given <code>Subject</code>, principals, <code>URL</code>,
63      * and signers (Certificates).  The <code>Subject</code>
64      * represents the <code>Subject</code> associated with the current
65      * <code>AccessControlContext</code>.
66      * The Principals are given as a <code>LinkedList</code>
67      * of <code>PolicyParser.PrincipalEntry</code> objects.
68      * Typically either a <code>Subject</code> will be provided,
69      * or a list of <code>principals</code> will be provided
70      * (not both).
71      *
72      * <p>
73      *
74      * @param subject the <code>Subject</code> associated with this
75      *                  <code>SubjectCodeSource</code> <p>
76      *
77      * @param url the <code>URL</code> associated with this
78      *                  <code>SubjectCodeSource</code> <p>
79      *
80      * @param certs the signers associated with this
81      *                  <code>SubjectCodeSource</code> <p>
82      */
SubjectCodeSource(Subject subject, LinkedList<PrincipalEntry> principals, URL url, Certificate[] certs)83     SubjectCodeSource(Subject subject,
84         LinkedList<PrincipalEntry> principals,
85         URL url, Certificate[] certs) {
86 
87         super(url, certs);
88         this.subject = subject;
89         this.principals = (principals == null ?
90                 new LinkedList<PrincipalEntry>() :
91                 new LinkedList<PrincipalEntry>(principals));
92         sysClassLoader = java.security.AccessController.doPrivileged
93         (new java.security.PrivilegedAction<ClassLoader>() {
94             public ClassLoader run() {
95                     return ClassLoader.getSystemClassLoader();
96             }
97         });
98     }
99 
100     /**
101      * Get the Principals associated with this <code>SubjectCodeSource</code>.
102      * The Principals are retrieved as a <code>LinkedList</code>
103      * of <code>PolicyParser.PrincipalEntry</code> objects.
104      *
105      * <p>
106      *
107      * @return the Principals associated with this
108      *          <code>SubjectCodeSource</code> as a <code>LinkedList</code>
109      *          of <code>PolicyParser.PrincipalEntry</code> objects.
110      */
getPrincipals()111     LinkedList<PrincipalEntry> getPrincipals() {
112         return principals;
113     }
114 
115     /**
116      * Get the <code>Subject</code> associated with this
117      * <code>SubjectCodeSource</code>.  The <code>Subject</code>
118      * represents the <code>Subject</code> associated with the
119      * current <code>AccessControlContext</code>.
120      *
121      * <p>
122      *
123      * @return the <code>Subject</code> associated with this
124      *          <code>SubjectCodeSource</code>.
125      */
getSubject()126     Subject getSubject() {
127         return subject;
128     }
129 
130     /**
131      * Returns true if this <code>SubjectCodeSource</code> object "implies"
132      * the specified <code>CodeSource</code>.
133      * More specifically, this method makes the following checks.
134      * If any fail, it returns false.  If they all succeed, it returns true.
135      *
136      * <p>
137      * <ol>
138      * <li> The provided codesource must not be <code>null</code>.
139      * <li> codesource must be an instance of <code>SubjectCodeSource</code>.
140      * <li> super.implies(codesource) must return true.
141      * <li> for each principal in this codesource's principal list:
142      * <ol>
143      * <li>     if the principal is an instanceof
144      *          <code>Principal</code>, then the principal must
145      *          imply the provided codesource's <code>Subject</code>.
146      * <li>     if the principal is not an instanceof
147      *          <code>Principal</code>, then the provided
148      *          codesource's <code>Subject</code> must have an
149      *          associated <code>Principal</code>, <i>P</i>, where
150      *          P.getClass().getName equals principal.principalClass,
151      *          and P.getName() equals principal.principalName.
152      * </ol>
153      * </ol>
154      *
155      * <p>
156      *
157      * @param codesource the <code>CodeSource</code> to compare against.
158      *
159      * @return true if this <code>SubjectCodeSource</code> implies
160      *          the specified <code>CodeSource</code>.
161      */
implies(CodeSource codesource)162     public boolean implies(CodeSource codesource) {
163 
164         LinkedList<PrincipalEntry> subjectList = null;
165 
166         if (codesource == null ||
167             !(codesource instanceof SubjectCodeSource) ||
168             !(super.implies(codesource))) {
169 
170             if (debug != null)
171                 debug.println("\tSubjectCodeSource.implies: FAILURE 1");
172             return false;
173         }
174 
175         SubjectCodeSource that = (SubjectCodeSource)codesource;
176 
177         // if the principal list in the policy "implies"
178         // the Subject associated with the current AccessControlContext,
179         // then return true
180 
181         if (this.principals == null) {
182             if (debug != null)
183                 debug.println("\tSubjectCodeSource.implies: PASS 1");
184             return true;
185         }
186 
187         if (that.getSubject() == null ||
188             that.getSubject().getPrincipals().size() == 0) {
189             if (debug != null)
190                 debug.println("\tSubjectCodeSource.implies: FAILURE 2");
191             return false;
192         }
193 
194         ListIterator<PrincipalEntry> li = this.principals.listIterator(0);
195         while (li.hasNext()) {
196             PrincipalEntry pppe = li.next();
197             try {
198 
199                 // use new Principal.implies method
200 
201                 Class<?> pClass = Class.forName(pppe.principalClass,
202                                                 true, sysClassLoader);
203                 if (!Principal.class.isAssignableFrom(pClass)) {
204                     // not the right subtype
205                     throw new ClassCastException(pppe.principalClass +
206                                                  " is not a Principal");
207                 }
208                 Constructor<?> c = pClass.getConstructor(PARAMS);
209                 Principal p = (Principal)c.newInstance(new Object[] {
210                                                        pppe.principalName });
211 
212                 if (!p.implies(that.getSubject())) {
213                     if (debug != null)
214                         debug.println("\tSubjectCodeSource.implies: FAILURE 3");
215                     return false;
216                 } else {
217                     if (debug != null)
218                         debug.println("\tSubjectCodeSource.implies: PASS 2");
219                     return true;
220                 }
221             } catch (Exception e) {
222 
223                 // simply compare Principals
224 
225                 if (subjectList == null) {
226 
227                     if (that.getSubject() == null) {
228                         if (debug != null)
229                             debug.println("\tSubjectCodeSource.implies: " +
230                                         "FAILURE 4");
231                         return false;
232                     }
233                     Iterator<Principal> i =
234                                 that.getSubject().getPrincipals().iterator();
235 
236                     subjectList = new LinkedList<PrincipalEntry>();
237                     while (i.hasNext()) {
238                         Principal p = i.next();
239                         PrincipalEntry spppe = new PrincipalEntry
240                                 (p.getClass().getName(), p.getName());
241                         subjectList.add(spppe);
242                     }
243                 }
244 
245                 if (!subjectListImpliesPrincipalEntry(subjectList, pppe)) {
246                     if (debug != null)
247                         debug.println("\tSubjectCodeSource.implies: FAILURE 5");
248                     return false;
249                 }
250             }
251         }
252 
253         if (debug != null)
254             debug.println("\tSubjectCodeSource.implies: PASS 3");
255         return true;
256     }
257 
258     /**
259      * This method returns, true, if the provided <i>subjectList</i>
260      * "contains" the <code>Principal</code> specified
261      * in the provided <i>pppe</i> argument.
262      *
263      * Note that the provided <i>pppe</i> argument may have
264      * wildcards (*) for the <code>Principal</code> class and name,
265      * which need to be considered.
266      *
267      * <p>
268      *
269      * @param subjectList a list of PolicyParser.PrincipalEntry objects
270      *          that correspond to all the Principals in the Subject currently
271      *          on this thread's AccessControlContext. <p>
272      *
273      * @param pppe the Principals specified in a grant entry.
274      *
275      * @return true if the provided <i>subjectList</i> "contains"
276      *          the <code>Principal</code> specified in the provided
277      *          <i>pppe</i> argument.
278      */
subjectListImpliesPrincipalEntry( LinkedList<PrincipalEntry> subjectList, PrincipalEntry pppe)279     private boolean subjectListImpliesPrincipalEntry(
280                 LinkedList<PrincipalEntry> subjectList, PrincipalEntry pppe) {
281 
282         ListIterator<PrincipalEntry> li = subjectList.listIterator(0);
283         while (li.hasNext()) {
284             PrincipalEntry listPppe = li.next();
285 
286             if (pppe.getPrincipalClass().equals
287                         (PrincipalEntry.WILDCARD_CLASS) ||
288                 pppe.getPrincipalClass().equals(listPppe.getPrincipalClass()))
289             {
290                 if (pppe.getPrincipalName().equals
291                         (PrincipalEntry.WILDCARD_NAME) ||
292                     pppe.getPrincipalName().equals(listPppe.getPrincipalName()))
293                     return true;
294             }
295         }
296         return false;
297     }
298 
299     /**
300      * Tests for equality between the specified object and this
301      * object. Two <code>SubjectCodeSource</code> objects are considered equal
302      * if their locations are of identical value, if the two sets of
303      * Certificates are of identical values, and if the
304      * Subjects are equal, and if the PolicyParser.PrincipalEntry values
305      * are of identical values.  It is not required that
306      * the Certificates or PolicyParser.PrincipalEntry values
307      * be in the same order.
308      *
309      * <p>
310      *
311      * @param obj the object to test for equality with this object.
312      *
313      * @return true if the objects are considered equal, false otherwise.
314      */
equals(Object obj)315     public boolean equals(Object obj) {
316 
317         if (obj == this)
318             return true;
319 
320         if (super.equals(obj) == false)
321             return false;
322 
323         if (!(obj instanceof SubjectCodeSource))
324             return false;
325 
326         SubjectCodeSource that = (SubjectCodeSource)obj;
327 
328         // the principal lists must match
329         try {
330             if (this.getSubject() != that.getSubject())
331                 return false;
332         } catch (SecurityException se) {
333             return false;
334         }
335 
336         if ((this.principals == null && that.principals != null) ||
337             (this.principals != null && that.principals == null))
338             return false;
339 
340         if (this.principals != null && that.principals != null) {
341             if (!this.principals.containsAll(that.principals) ||
342                 !that.principals.containsAll(this.principals))
343 
344                 return false;
345         }
346 
347         return true;
348     }
349 
350     /**
351      * Return a hashcode for this <code>SubjectCodeSource</code>.
352      *
353      * <p>
354      *
355      * @return a hashcode for this <code>SubjectCodeSource</code>.
356      */
hashCode()357     public int hashCode() {
358         return super.hashCode();
359     }
360 
361     /**
362      * Return a String representation of this <code>SubjectCodeSource</code>.
363      *
364      * <p>
365      *
366      * @return a String representation of this <code>SubjectCodeSource</code>.
367      */
toString()368     public String toString() {
369         String returnMe = super.toString();
370         if (getSubject() != null) {
371             if (debug != null) {
372                 final Subject finalSubject = getSubject();
373                 returnMe = returnMe + "\n" +
374                         java.security.AccessController.doPrivileged
375                                 (new java.security.PrivilegedAction<String>() {
376                                 public String run() {
377                                     return finalSubject.toString();
378                                 }
379                         });
380             } else {
381                 returnMe = returnMe + "\n" + getSubject().toString();
382             }
383         }
384         if (principals != null) {
385             ListIterator<PrincipalEntry> li = principals.listIterator();
386             while (li.hasNext()) {
387                 PrincipalEntry pppe = li.next();
388                 returnMe = returnMe + ResourcesMgr.getAuthResourceString("NEWLINE") +
389                         pppe.getPrincipalClass() + " " +
390                         pppe.getPrincipalName();
391             }
392         }
393         return returnMe;
394     }
395 }
396