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