1 /*
   2  * Copyright (c) 1998, 2017, 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 javax.security.auth.login;
  27 
  28 import javax.security.auth.AuthPermission;
  29 
  30 import java.security.AccessController;
  31 import java.security.PrivilegedAction;
  32 import java.security.PrivilegedExceptionAction;
  33 import java.security.PrivilegedActionException;
  34 import java.security.NoSuchAlgorithmException;
  35 import java.security.NoSuchProviderException;
  36 import java.security.Provider;
  37 import java.security.Security;
  38 import java.util.Objects;
  39 
  40 import sun.security.jca.GetInstance;
  41 
  42 /**
  43  * A Configuration object is responsible for specifying which LoginModules
  44  * should be used for a particular application, and in what order the
  45  * LoginModules should be invoked.
  46  *
  47  * <p> A login configuration contains the following information.
  48  * Note that this example only represents the default syntax for the
  49  * {@code Configuration}.  Subclass implementations of this class
  50  * may implement alternative syntaxes and may retrieve the
  51  * {@code Configuration} from any source such as files, databases,
  52  * or servers.
  53  *
  54  * <pre>
  55  *      Name {
  56  *            ModuleClass  Flag    ModuleOptions;
  57  *            ModuleClass  Flag    ModuleOptions;
  58  *            ModuleClass  Flag    ModuleOptions;
  59  *      };
  60  *      Name {
  61  *            ModuleClass  Flag    ModuleOptions;
  62  *            ModuleClass  Flag    ModuleOptions;
  63  *      };
  64  *      other {
  65  *            ModuleClass  Flag    ModuleOptions;
  66  *            ModuleClass  Flag    ModuleOptions;
  67  *      };
  68  * </pre>
  69  *
  70  * <p> Each entry in the {@code Configuration} is indexed via an
  71  * application name, <i>Name</i>, and contains a list of
  72  * LoginModules configured for that application.  Each {@code LoginModule}
  73  * is specified via its fully qualified class name.
  74  * Authentication proceeds down the module list in the exact order specified.
  75  * If an application does not have a specific entry,
  76  * it defaults to the specific entry for "<i>other</i>".
  77  *
  78  * <p> The <i>Flag</i> value controls the overall behavior as authentication
  79  * proceeds down the stack.  The following represents a description of the
  80  * valid values for <i>Flag</i> and their respective semantics:
  81  *
  82  * <pre>
  83  *      1) Required     - The {@code LoginModule} is required to succeed.
  84  *                      If it succeeds or fails, authentication still continues
  85  *                      to proceed down the {@code LoginModule} list.
  86  *
  87  *      2) Requisite    - The {@code LoginModule} is required to succeed.
  88  *                      If it succeeds, authentication continues down the
  89  *                      {@code LoginModule} list.  If it fails,
  90  *                      control immediately returns to the application
  91  *                      (authentication does not proceed down the
  92  *                      {@code LoginModule} list).
  93  *
  94  *      3) Sufficient   - The {@code LoginModule} is not required to
  95  *                      succeed.  If it does succeed, control immediately
  96  *                      returns to the application (authentication does not
  97  *                      proceed down the {@code LoginModule} list).
  98  *                      If it fails, authentication continues down the
  99  *                      {@code LoginModule} list.
 100  *
 101  *      4) Optional     - The {@code LoginModule} is not required to
 102  *                      succeed.  If it succeeds or fails,
 103  *                      authentication still continues to proceed down the
 104  *                      {@code LoginModule} list.
 105  * </pre>
 106  *
 107  * <p> The overall authentication succeeds only if all <i>Required</i> and
 108  * <i>Requisite</i> LoginModules succeed.  If a <i>Sufficient</i>
 109  * {@code LoginModule} is configured and succeeds,
 110  * then only the <i>Required</i> and <i>Requisite</i> LoginModules prior to
 111  * that <i>Sufficient</i> {@code LoginModule} need to have succeeded for
 112  * the overall authentication to succeed. If no <i>Required</i> or
 113  * <i>Requisite</i> LoginModules are configured for an application,
 114  * then at least one <i>Sufficient</i> or <i>Optional</i>
 115  * {@code LoginModule} must succeed.
 116  *
 117  * <p> <i>ModuleOptions</i> is a space separated list of
 118  * {@code LoginModule}-specific values which are passed directly to
 119  * the underlying LoginModules.  Options are defined by the
 120  * {@code LoginModule} itself, and control the behavior within it.
 121  * For example, a {@code LoginModule} may define options to support
 122  * debugging/testing capabilities.  The correct way to specify options in the
 123  * {@code Configuration} is by using the following key-value pairing:
 124  * <i>debug="true"</i>.  The key and value should be separated by an
 125  * 'equals' symbol, and the value should be surrounded by double quotes.
 126  * If a String in the form, ${system.property}, occurs in the value,
 127  * it will be expanded to the value of the system property.
 128  * Note that there is no limit to the number of
 129  * options a {@code LoginModule} may define.
 130  *
 131  * <p> The following represents an example {@code Configuration} entry
 132  * based on the syntax above:
 133  *
 134  * <pre>
 135  * Login {
 136  *   com.sun.security.auth.module.UnixLoginModule required;
 137  *   com.sun.security.auth.module.Krb5LoginModule optional
 138  *                   useTicketCache="true"
 139  *                   ticketCache="${user.home}${/}tickets";
 140  * };
 141  * </pre>
 142  *
 143  * <p> This {@code Configuration} specifies that an application named,
 144  * "Login", requires users to first authenticate to the
 145  * <i>com.sun.security.auth.module.UnixLoginModule</i>, which is
 146  * required to succeed.  Even if the <i>UnixLoginModule</i>
 147  * authentication fails, the
 148  * <i>com.sun.security.auth.module.Krb5LoginModule</i>
 149  * still gets invoked.  This helps hide the source of failure.
 150  * Since the <i>Krb5LoginModule</i> is <i>Optional</i>, the overall
 151  * authentication succeeds only if the <i>UnixLoginModule</i>
 152  * (<i>Required</i>) succeeds.
 153  *
 154  * <p> Also note that the LoginModule-specific options,
 155  * <i>useTicketCache="true"</i> and
 156  * <i>ticketCache=${user.home}${/}tickets"</i>,
 157  * are passed to the <i>Krb5LoginModule</i>.
 158  * These options instruct the <i>Krb5LoginModule</i> to
 159  * use the ticket cache at the specified location.
 160  * The system properties, <i>user.home</i> and <i>/</i>
 161  * (file.separator), are expanded to their respective values.
 162  *
 163  * <p> There is only one Configuration object installed in the runtime at any
 164  * given time.  A Configuration object can be installed by calling the
 165  * {@code setConfiguration} method.  The installed Configuration object
 166  * can be obtained by calling the {@code getConfiguration} method.
 167  *
 168  * <p> If no Configuration object has been installed in the runtime, a call to
 169  * {@code getConfiguration} installs an instance of the default
 170  * Configuration implementation (a default subclass implementation of this
 171  * abstract class).
 172  * The default Configuration implementation can be changed by setting the value
 173  * of the {@code login.configuration.provider} security property to the fully
 174  * qualified name of the desired Configuration subclass implementation.
 175  *
 176  * <p> Application code can directly subclass Configuration to provide a custom
 177  * implementation.  In addition, an instance of a Configuration object can be
 178  * constructed by invoking one of the {@code getInstance} factory methods
 179  * with a standard type.  The default policy type is "JavaLoginConfig".
 180  * See the Configuration section in the <a href=
 181  * "{@docRoot}/../specs/security/standard-names.html#configuration-types">
 182  * Java Security Standard Algorithm Names Specification</a>
 183  * for a list of standard Configuration types.
 184  *
 185  * @since 1.4
 186  * @see javax.security.auth.login.LoginContext
 187  * @see java.security.Security security properties
 188  */
 189 public abstract class Configuration {
 190 
 191     private static Configuration configuration;
 192 
 193     private final java.security.AccessControlContext acc =
 194             java.security.AccessController.getContext();
 195 
 196     private static void checkPermission(String type) {
 197         SecurityManager sm = System.getSecurityManager();
 198         if (sm != null) {
 199             sm.checkPermission(new AuthPermission
 200                                 ("createLoginConfiguration." + type));
 201         }
 202     }
 203 
 204     /**
 205      * Sole constructor.  (For invocation by subclass constructors, typically
 206      * implicit.)
 207      */
 208     protected Configuration() { }
 209 
 210     /**
 211      * Get the installed login Configuration.
 212      *
 213      * @return the login Configuration.  If a Configuration object was set
 214      *          via the {@code Configuration.setConfiguration} method,
 215      *          then that object is returned.  Otherwise, a default
 216      *          Configuration object is returned.
 217      *
 218      * @exception SecurityException if the caller does not have permission
 219      *                          to retrieve the Configuration.
 220      *
 221      * @see #setConfiguration
 222      */
 223     public static Configuration getConfiguration() {
 224 
 225         SecurityManager sm = System.getSecurityManager();
 226         if (sm != null)
 227             sm.checkPermission(new AuthPermission("getLoginConfiguration"));
 228 
 229         synchronized (Configuration.class) {
 230             if (configuration == null) {
 231                 String config_class = null;
 232                 config_class = AccessController.doPrivileged
 233                     (new PrivilegedAction<>() {
 234                     public String run() {
 235                         return java.security.Security.getProperty
 236                                     ("login.configuration.provider");
 237                     }
 238                 });
 239                 if (config_class == null) {
 240                     config_class = "sun.security.provider.ConfigFile";
 241                 }
 242 
 243                 try {
 244                     final String finalClass = config_class;
 245                     Configuration untrustedImpl = AccessController.doPrivileged(
 246                             new PrivilegedExceptionAction<>() {
 247                                 public Configuration run() throws ClassNotFoundException,
 248                                         InstantiationException,
 249                                         IllegalAccessException {
 250                                     Class<? extends Configuration> implClass = Class.forName(
 251                                             finalClass, false,
 252                                             Thread.currentThread().getContextClassLoader()
 253                                     ).asSubclass(Configuration.class);
 254                                     @SuppressWarnings("deprecation")
 255                                     Configuration result = implClass.newInstance();
 256                                     return result;
 257                                 }
 258                             });
 259                     AccessController.doPrivileged(
 260                             new PrivilegedExceptionAction<>() {
 261                                 public Void run() {
 262                                     setConfiguration(untrustedImpl);
 263                                     return null;
 264                                 }
 265                             }, Objects.requireNonNull(untrustedImpl.acc)
 266                     );
 267                 } catch (PrivilegedActionException e) {
 268                     Exception ee = e.getException();
 269                     if (ee instanceof InstantiationException) {
 270                         throw (SecurityException) new
 271                             SecurityException
 272                                     ("Configuration error:" +
 273                                      ee.getCause().getMessage() +
 274                                      "\n").initCause(ee.getCause());
 275                     } else {
 276                         throw (SecurityException) new
 277                             SecurityException
 278                                     ("Configuration error: " +
 279                                      ee.toString() +
 280                                      "\n").initCause(ee);
 281                     }
 282                 }
 283             }
 284             return configuration;
 285         }
 286     }
 287 
 288     /**
 289      * Set the login {@code Configuration}.
 290      *
 291      * @param configuration the new {@code Configuration}
 292      *
 293      * @exception SecurityException if the current thread does not have
 294      *                  Permission to set the {@code Configuration}.
 295      *
 296      * @see #getConfiguration
 297      */
 298     public static void setConfiguration(Configuration configuration) {
 299         SecurityManager sm = System.getSecurityManager();
 300         if (sm != null)
 301             sm.checkPermission(new AuthPermission("setLoginConfiguration"));
 302         Configuration.configuration = configuration;
 303     }
 304 
 305     /**
 306      * Returns a Configuration object of the specified type.
 307      *
 308      * <p> This method traverses the list of registered security providers,
 309      * starting with the most preferred Provider.
 310      * A new Configuration object encapsulating the
 311      * ConfigurationSpi implementation from the first
 312      * Provider that supports the specified type is returned.
 313      *
 314      * <p> Note that the list of registered providers may be retrieved via
 315      * the {@link Security#getProviders() Security.getProviders()} method.
 316      *
 317      * @implNote
 318      * The JDK Reference Implementation additionally uses the
 319      * {@code jdk.security.provider.preferred}
 320      * {@link Security#getProperty(String) Security} property to determine
 321      * the preferred provider order for the specified algorithm. This
 322      * may be different than the order of providers returned by
 323      * {@link Security#getProviders() Security.getProviders()}.
 324      *
 325      * @param type the specified Configuration type.  See the Configuration
 326      *    section in the <a href=
 327      *    "{@docRoot}/../specs/security/standard-names.html#configuration-types">
 328      *    Java Security Standard Algorithm Names Specification</a>
 329      *    for a list of standard Configuration types.
 330      *
 331      * @param params parameters for the Configuration, which may be null.
 332      *
 333      * @return the new {@code Configuration} object
 334      *
 335      * @throws IllegalArgumentException if the specified parameters
 336      *         are not understood by the {@code ConfigurationSpi}
 337      *         implementation from the selected {@code Provider}
 338      *
 339      * @throws NoSuchAlgorithmException if no {@code Provider} supports a
 340      *         {@code ConfigurationSpi} implementation for the specified type
 341      *
 342      * @throws NullPointerException if {@code type} is {@code null}
 343      *
 344      * @throws SecurityException if the caller does not have permission
 345      *         to get a {@code Configuration} instance for the specified type
 346      *
 347      * @see Provider
 348      *
 349      * @since 1.6
 350      */
 351     public static Configuration getInstance(String type,
 352                                 Configuration.Parameters params)
 353                 throws NoSuchAlgorithmException {
 354 
 355         Objects.requireNonNull(type, "null type name");
 356         checkPermission(type);
 357         try {
 358             GetInstance.Instance instance = GetInstance.getInstance
 359                                                         ("Configuration",
 360                                                         ConfigurationSpi.class,
 361                                                         type,
 362                                                         params);
 363             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 364                                                         instance.provider,
 365                                                         type,
 366                                                         params);
 367         } catch (NoSuchAlgorithmException nsae) {
 368             return handleException (nsae);
 369         }
 370     }
 371 
 372     /**
 373      * Returns a Configuration object of the specified type.
 374      *
 375      * <p> A new Configuration object encapsulating the
 376      * ConfigurationSpi implementation from the specified provider
 377      * is returned.   The specified provider must be registered
 378      * in the provider list.
 379      *
 380      * <p> Note that the list of registered providers may be retrieved via
 381      * the {@link Security#getProviders() Security.getProviders()} method.
 382      *
 383      * @param type the specified Configuration type.  See the Configuration
 384      *    section in the <a href=
 385      *    "{@docRoot}/../specs/security/standard-names.html#configuration-types">
 386      *    Java Security Standard Algorithm Names Specification</a>
 387      *    for a list of standard Configuration types.
 388      *
 389      * @param params parameters for the Configuration, which may be null.
 390      *
 391      * @param provider the provider.
 392      *
 393      * @return the new {@code Configuration} object
 394      *
 395      * @throws IllegalArgumentException if the specified provider
 396      *         is {@code null} or empty, or if the specified parameters
 397      *         are not understood by the {@code ConfigurationSpi}
 398      *         implementation from the specified provider
 399      *
 400      * @throws NoSuchProviderException if the specified provider is not
 401      *         registered in the security provider list
 402      *
 403      * @throws NoSuchAlgorithmException if the specified provider does not
 404      *         support a {@code ConfigurationSpi} implementation for the
 405      *         specified type
 406      *
 407      * @throws NullPointerException if {@code type} is {@code null}
 408      *
 409      * @throws SecurityException if the caller does not have permission
 410      *         to get a {@code Configuration} instance for the specified type
 411      *
 412      * @see Provider
 413      * @since 1.6
 414      */
 415     public static Configuration getInstance(String type,
 416                                 Configuration.Parameters params,
 417                                 String provider)
 418                 throws NoSuchProviderException, NoSuchAlgorithmException {
 419 
 420         Objects.requireNonNull(type, "null type name");
 421         if (provider == null || provider.isEmpty()) {
 422             throw new IllegalArgumentException("missing provider");
 423         }
 424 
 425         checkPermission(type);
 426         try {
 427             GetInstance.Instance instance = GetInstance.getInstance
 428                                                         ("Configuration",
 429                                                         ConfigurationSpi.class,
 430                                                         type,
 431                                                         params,
 432                                                         provider);
 433             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 434                                                         instance.provider,
 435                                                         type,
 436                                                         params);
 437         } catch (NoSuchAlgorithmException nsae) {
 438             return handleException (nsae);
 439         }
 440     }
 441 
 442     /**
 443      * Returns a Configuration object of the specified type.
 444      *
 445      * <p> A new Configuration object encapsulating the
 446      * ConfigurationSpi implementation from the specified Provider
 447      * object is returned.  Note that the specified Provider object
 448      * does not have to be registered in the provider list.
 449      *
 450      * @param type the specified Configuration type.  See the Configuration
 451      *    section in the <a href=
 452      *    "{@docRoot}/../specs/security/standard-names.html#configuration-types">
 453      *    Java Security Standard Algorithm Names Specification</a>
 454      *    for a list of standard Configuration types.
 455      *
 456      * @param params parameters for the Configuration, which may be null.
 457      *
 458      * @param provider the Provider.
 459      *
 460      * @return the new {@code Configuration} object
 461      *
 462      * @throws IllegalArgumentException if the specified {@code Provider}
 463      *         is {@code null}, or if the specified parameters are not
 464      *         understood by the {@code ConfigurationSpi} implementation
 465      *         from the specified Provider
 466      *
 467      * @throws NoSuchAlgorithmException if the specified {@code Provider}
 468      *         does not support a {@code ConfigurationSpi} implementation
 469      *         for the specified type
 470      *
 471      * @throws NullPointerException if {@code type} is {@code null}
 472      *
 473      * @throws SecurityException if the caller does not have permission
 474      *         to get a {@code Configuration} instance for the specified type
 475      *
 476      * @see Provider
 477      * @since 1.6
 478      */
 479     public static Configuration getInstance(String type,
 480                                 Configuration.Parameters params,
 481                                 Provider provider)
 482                 throws NoSuchAlgorithmException {
 483 
 484         Objects.requireNonNull(type, "null type name");
 485         if (provider == null) {
 486             throw new IllegalArgumentException("missing provider");
 487         }
 488 
 489         checkPermission(type);
 490         try {
 491             GetInstance.Instance instance = GetInstance.getInstance
 492                                                         ("Configuration",
 493                                                         ConfigurationSpi.class,
 494                                                         type,
 495                                                         params,
 496                                                         provider);
 497             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 498                                                         instance.provider,
 499                                                         type,
 500                                                         params);
 501         } catch (NoSuchAlgorithmException nsae) {
 502             return handleException (nsae);
 503         }
 504     }
 505 
 506     private static Configuration handleException(NoSuchAlgorithmException nsae)
 507                 throws NoSuchAlgorithmException {
 508         Throwable cause = nsae.getCause();
 509         if (cause instanceof IllegalArgumentException) {
 510             throw (IllegalArgumentException)cause;
 511         }
 512         throw nsae;
 513     }
 514 
 515     /**
 516      * Return the Provider of this Configuration.
 517      *
 518      * <p> This Configuration instance will only have a Provider if it
 519      * was obtained via a call to {@code Configuration.getInstance}.
 520      * Otherwise this method returns null.
 521      *
 522      * @return the Provider of this Configuration, or null.
 523      *
 524      * @since 1.6
 525      */
 526     public Provider getProvider() {
 527         return null;
 528     }
 529 
 530     /**
 531      * Return the type of this Configuration.
 532      *
 533      * <p> This Configuration instance will only have a type if it
 534      * was obtained via a call to {@code Configuration.getInstance}.
 535      * Otherwise this method returns null.
 536      *
 537      * @return the type of this Configuration, or null.
 538      *
 539      * @since 1.6
 540      */
 541     public String getType() {
 542         return null;
 543     }
 544 
 545     /**
 546      * Return Configuration parameters.
 547      *
 548      * <p> This Configuration instance will only have parameters if it
 549      * was obtained via a call to {@code Configuration.getInstance}.
 550      * Otherwise this method returns null.
 551      *
 552      * @return Configuration parameters, or null.
 553      *
 554      * @since 1.6
 555      */
 556     public Configuration.Parameters getParameters() {
 557         return null;
 558     }
 559 
 560     /**
 561      * Retrieve the AppConfigurationEntries for the specified {@code name}
 562      * from this Configuration.
 563      *
 564      * @param name the name used to index the Configuration.
 565      *
 566      * @return an array of AppConfigurationEntries for the specified {@code name}
 567      *          from this Configuration, or null if there are no entries
 568      *          for the specified {@code name}
 569      */
 570     public abstract AppConfigurationEntry[] getAppConfigurationEntry
 571                                                         (String name);
 572 
 573     /**
 574      * Refresh and reload the Configuration.
 575      *
 576      * <p> This method causes this Configuration object to refresh/reload its
 577      * contents in an implementation-dependent manner.
 578      * For example, if this Configuration object stores its entries in a file,
 579      * calling {@code refresh} may cause the file to be re-read.
 580      *
 581      * <p> The default implementation of this method does nothing.
 582      * This method should be overridden if a refresh operation is supported
 583      * by the implementation.
 584      *
 585      * @exception SecurityException if the caller does not have permission
 586      *                          to refresh its Configuration.
 587      */
 588     public void refresh() { }
 589 
 590     /**
 591      * This subclass is returned by the getInstance calls.  All Configuration
 592      * calls are delegated to the underlying ConfigurationSpi.
 593      */
 594     private static class ConfigDelegate extends Configuration {
 595 
 596         private ConfigurationSpi spi;
 597         private Provider p;
 598         private String type;
 599         private Configuration.Parameters params;
 600 
 601         private ConfigDelegate(ConfigurationSpi spi, Provider p,
 602                         String type, Configuration.Parameters params) {
 603             this.spi = spi;
 604             this.p = p;
 605             this.type = type;
 606             this.params = params;
 607         }
 608 
 609         public String getType() { return type; }
 610 
 611         public Configuration.Parameters getParameters() { return params; }
 612 
 613         public Provider getProvider() { return p; }
 614 
 615         public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
 616             return spi.engineGetAppConfigurationEntry(name);
 617         }
 618 
 619         public void refresh() {
 620             spi.engineRefresh();
 621         }
 622     }
 623 
 624     /**
 625      * This represents a marker interface for Configuration parameters.
 626      *
 627      * @since 1.6
 628      */
 629     public static interface Parameters { }
 630 }