1 /*
   2  * Copyright (c) 1998, 2016, 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}/../technotes/guides/security/StandardNames.html#Configuration">
 182  * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
 183  * for a list of standard Configuration types.
 184  *
 185  * @see javax.security.auth.login.LoginContext
 186  * @see java.security.Security security properties
 187  */
 188 public abstract class Configuration {
 189 
 190     private static Configuration configuration;
 191 
 192     private final java.security.AccessControlContext acc =
 193             java.security.AccessController.getContext();
 194 
 195     private static void checkPermission(String type) {
 196         SecurityManager sm = System.getSecurityManager();
 197         if (sm != null) {
 198             sm.checkPermission(new AuthPermission
 199                                 ("createLoginConfiguration." + type));
 200         }
 201     }
 202 
 203     /**
 204      * Sole constructor.  (For invocation by subclass constructors, typically
 205      * implicit.)
 206      */
 207     protected Configuration() { }
 208 
 209     /**
 210      * Get the installed login Configuration.
 211      *
 212      * @return the login Configuration.  If a Configuration object was set
 213      *          via the {@code Configuration.setConfiguration} method,
 214      *          then that object is returned.  Otherwise, a default
 215      *          Configuration object is returned.
 216      *
 217      * @exception SecurityException if the caller does not have permission
 218      *                          to retrieve the Configuration.
 219      *
 220      * @see #setConfiguration
 221      */
 222     public static Configuration getConfiguration() {
 223 
 224         SecurityManager sm = System.getSecurityManager();
 225         if (sm != null)
 226             sm.checkPermission(new AuthPermission("getLoginConfiguration"));
 227 
 228         synchronized (Configuration.class) {
 229             if (configuration == null) {
 230                 String config_class = null;
 231                 config_class = AccessController.doPrivileged
 232                     (new PrivilegedAction<>() {
 233                     public String run() {
 234                         return java.security.Security.getProperty
 235                                     ("login.configuration.provider");
 236                     }
 237                 });
 238                 if (config_class == null) {
 239                     config_class = "sun.security.provider.ConfigFile";
 240                 }
 241 
 242                 try {
 243                     final String finalClass = config_class;
 244                     Configuration untrustedImpl = AccessController.doPrivileged(
 245                             new PrivilegedExceptionAction<>() {
 246                                 public Configuration run() throws ClassNotFoundException,
 247                                         InstantiationException,
 248                                         IllegalAccessException {
 249                                     Class<? extends Configuration> implClass = Class.forName(
 250                                             finalClass, false,
 251                                             Thread.currentThread().getContextClassLoader()
 252                                     ).asSubclass(Configuration.class);
 253                                     return implClass.newInstance();
 254                                 }
 255                             });
 256                     AccessController.doPrivileged(
 257                             new PrivilegedExceptionAction<>() {
 258                                 public Void run() {
 259                                     setConfiguration(untrustedImpl);
 260                                     return null;
 261                                 }
 262                             }, Objects.requireNonNull(untrustedImpl.acc)
 263                     );
 264                 } catch (PrivilegedActionException e) {
 265                     Exception ee = e.getException();
 266                     if (ee instanceof InstantiationException) {
 267                         throw (SecurityException) new
 268                             SecurityException
 269                                     ("Configuration error:" +
 270                                      ee.getCause().getMessage() +
 271                                      "\n").initCause(ee.getCause());
 272                     } else {
 273                         throw (SecurityException) new
 274                             SecurityException
 275                                     ("Configuration error: " +
 276                                      ee.toString() +
 277                                      "\n").initCause(ee);
 278                     }
 279                 }
 280             }
 281             return configuration;
 282         }
 283     }
 284 
 285     /**
 286      * Set the login {@code Configuration}.
 287      *
 288      * @param configuration the new {@code Configuration}
 289      *
 290      * @exception SecurityException if the current thread does not have
 291      *                  Permission to set the {@code Configuration}.
 292      *
 293      * @see #getConfiguration
 294      */
 295     public static void setConfiguration(Configuration configuration) {
 296         SecurityManager sm = System.getSecurityManager();
 297         if (sm != null)
 298             sm.checkPermission(new AuthPermission("setLoginConfiguration"));
 299         Configuration.configuration = configuration;
 300     }
 301 
 302     /**
 303      * Returns a Configuration object of the specified type.
 304      *
 305      * <p> This method traverses the list of registered security providers,
 306      * starting with the most preferred Provider.
 307      * A new Configuration object encapsulating the
 308      * ConfigurationSpi implementation from the first
 309      * Provider that supports the specified type is returned.
 310      *
 311      * <p> Note that the list of registered providers may be retrieved via
 312      * the {@link Security#getProviders() Security.getProviders()} method.
 313      *
 314      * @implNote
 315      * The JDK Reference Implementation additionally uses the
 316      * {@code jdk.security.provider.preferred}
 317      * {@link Security#getProperty(String) Security} property to determine
 318      * the preferred provider order for the specified algorithm. This
 319      * may be different than the order of providers returned by
 320      * {@link Security#getProviders() Security.getProviders()}.
 321      *
 322      * @param type the specified Configuration type.  See the Configuration
 323      *    section in the <a href=
 324      *    "{@docRoot}/../technotes/guides/security/StandardNames.html#Configuration">
 325      *    Java Cryptography Architecture Standard Algorithm Name
 326      *    Documentation</a> for a list of standard Configuration types.
 327      *
 328      * @param params parameters for the Configuration, which may be null.
 329      *
 330      * @return the new Configuration object.
 331      *
 332      * @exception SecurityException if the caller does not have permission
 333      *          to get a Configuration instance for the specified type.
 334      *
 335      * @exception NullPointerException if the specified type is null.
 336      *
 337      * @exception IllegalArgumentException if the specified parameters
 338      *          are not understood by the ConfigurationSpi implementation
 339      *          from the selected Provider.
 340      *
 341      * @exception NoSuchAlgorithmException if no Provider supports a
 342      *          ConfigurationSpi implementation for the specified type.
 343      *
 344      * @see Provider
 345      * @since 1.6
 346      */
 347     public static Configuration getInstance(String type,
 348                                 Configuration.Parameters params)
 349                 throws NoSuchAlgorithmException {
 350 
 351         checkPermission(type);
 352         try {
 353             GetInstance.Instance instance = GetInstance.getInstance
 354                                                         ("Configuration",
 355                                                         ConfigurationSpi.class,
 356                                                         type,
 357                                                         params);
 358             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 359                                                         instance.provider,
 360                                                         type,
 361                                                         params);
 362         } catch (NoSuchAlgorithmException nsae) {
 363             return handleException (nsae);
 364         }
 365     }
 366 
 367     /**
 368      * Returns a Configuration object of the specified type.
 369      *
 370      * <p> A new Configuration object encapsulating the
 371      * ConfigurationSpi implementation from the specified provider
 372      * is returned.   The specified provider must be registered
 373      * in the provider list.
 374      *
 375      * <p> Note that the list of registered providers may be retrieved via
 376      * the {@link Security#getProviders() Security.getProviders()} method.
 377      *
 378      * @param type the specified Configuration type.  See the Configuration
 379      *    section in the <a href=
 380      *    "{@docRoot}/../technotes/guides/security/StandardNames.html#Configuration">
 381      *    Java Cryptography Architecture Standard Algorithm Name
 382      *    Documentation</a> for a list of standard Configuration types.
 383      *
 384      * @param params parameters for the Configuration, which may be null.
 385      *
 386      * @param provider the provider.
 387      *
 388      * @return the new Configuration object.
 389      *
 390      * @exception SecurityException if the caller does not have permission
 391      *          to get a Configuration instance for the specified type.
 392      *
 393      * @exception NullPointerException if the specified type is null.
 394      *
 395      * @exception IllegalArgumentException if the specified provider
 396      *          is null or empty,
 397      *          or if the specified parameters are not understood by
 398      *          the ConfigurationSpi implementation from the specified provider.
 399      *
 400      * @exception NoSuchProviderException if the specified provider is not
 401      *          registered in the security provider list.
 402      *
 403      * @exception NoSuchAlgorithmException if the specified provider does not
 404      *          support a ConfigurationSpi implementation for the specified
 405      *          type.
 406      *
 407      * @see Provider
 408      * @since 1.6
 409      */
 410     public static Configuration getInstance(String type,
 411                                 Configuration.Parameters params,
 412                                 String provider)
 413                 throws NoSuchProviderException, NoSuchAlgorithmException {
 414 
 415         if (provider == null || provider.length() == 0) {
 416             throw new IllegalArgumentException("missing provider");
 417         }
 418 
 419         checkPermission(type);
 420         try {
 421             GetInstance.Instance instance = GetInstance.getInstance
 422                                                         ("Configuration",
 423                                                         ConfigurationSpi.class,
 424                                                         type,
 425                                                         params,
 426                                                         provider);
 427             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 428                                                         instance.provider,
 429                                                         type,
 430                                                         params);
 431         } catch (NoSuchAlgorithmException nsae) {
 432             return handleException (nsae);
 433         }
 434     }
 435 
 436     /**
 437      * Returns a Configuration object of the specified type.
 438      *
 439      * <p> A new Configuration object encapsulating the
 440      * ConfigurationSpi implementation from the specified Provider
 441      * object is returned.  Note that the specified Provider object
 442      * does not have to be registered in the provider list.
 443      *
 444      * @param type the specified Configuration type.  See the Configuration
 445      *    section in the <a href=
 446      *    "{@docRoot}/../technotes/guides/security/StandardNames.html#Configuration">
 447      *    Java Cryptography Architecture Standard Algorithm Name
 448      *    Documentation</a> for a list of standard Configuration types.
 449      *
 450      * @param params parameters for the Configuration, which may be null.
 451      *
 452      * @param provider the Provider.
 453      *
 454      * @return the new Configuration object.
 455      *
 456      * @exception SecurityException if the caller does not have permission
 457      *          to get a Configuration instance for the specified type.
 458      *
 459      * @exception NullPointerException if the specified type is null.
 460      *
 461      * @exception IllegalArgumentException if the specified Provider is null,
 462      *          or if the specified parameters are not understood by
 463      *          the ConfigurationSpi implementation from the specified Provider.
 464      *
 465      * @exception NoSuchAlgorithmException if the specified Provider does not
 466      *          support a ConfigurationSpi implementation for the specified
 467      *          type.
 468      *
 469      * @see Provider
 470      * @since 1.6
 471      */
 472     public static Configuration getInstance(String type,
 473                                 Configuration.Parameters params,
 474                                 Provider provider)
 475                 throws NoSuchAlgorithmException {
 476 
 477         if (provider == null) {
 478             throw new IllegalArgumentException("missing provider");
 479         }
 480 
 481         checkPermission(type);
 482         try {
 483             GetInstance.Instance instance = GetInstance.getInstance
 484                                                         ("Configuration",
 485                                                         ConfigurationSpi.class,
 486                                                         type,
 487                                                         params,
 488                                                         provider);
 489             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 490                                                         instance.provider,
 491                                                         type,
 492                                                         params);
 493         } catch (NoSuchAlgorithmException nsae) {
 494             return handleException (nsae);
 495         }
 496     }
 497 
 498     private static Configuration handleException(NoSuchAlgorithmException nsae)
 499                 throws NoSuchAlgorithmException {
 500         Throwable cause = nsae.getCause();
 501         if (cause instanceof IllegalArgumentException) {
 502             throw (IllegalArgumentException)cause;
 503         }
 504         throw nsae;
 505     }
 506 
 507     /**
 508      * Return the Provider of this Configuration.
 509      *
 510      * <p> This Configuration instance will only have a Provider if it
 511      * was obtained via a call to {@code Configuration.getInstance}.
 512      * Otherwise this method returns null.
 513      *
 514      * @return the Provider of this Configuration, or null.
 515      *
 516      * @since 1.6
 517      */
 518     public Provider getProvider() {
 519         return null;
 520     }
 521 
 522     /**
 523      * Return the type of this Configuration.
 524      *
 525      * <p> This Configuration instance will only have a type if it
 526      * was obtained via a call to {@code Configuration.getInstance}.
 527      * Otherwise this method returns null.
 528      *
 529      * @return the type of this Configuration, or null.
 530      *
 531      * @since 1.6
 532      */
 533     public String getType() {
 534         return null;
 535     }
 536 
 537     /**
 538      * Return Configuration parameters.
 539      *
 540      * <p> This Configuration instance will only have parameters if it
 541      * was obtained via a call to {@code Configuration.getInstance}.
 542      * Otherwise this method returns null.
 543      *
 544      * @return Configuration parameters, or null.
 545      *
 546      * @since 1.6
 547      */
 548     public Configuration.Parameters getParameters() {
 549         return null;
 550     }
 551 
 552     /**
 553      * Retrieve the AppConfigurationEntries for the specified {@code name}
 554      * from this Configuration.
 555      *
 556      * @param name the name used to index the Configuration.
 557      *
 558      * @return an array of AppConfigurationEntries for the specified {@code name}
 559      *          from this Configuration, or null if there are no entries
 560      *          for the specified {@code name}
 561      */
 562     public abstract AppConfigurationEntry[] getAppConfigurationEntry
 563                                                         (String name);
 564 
 565     /**
 566      * Refresh and reload the Configuration.
 567      *
 568      * <p> This method causes this Configuration object to refresh/reload its
 569      * contents in an implementation-dependent manner.
 570      * For example, if this Configuration object stores its entries in a file,
 571      * calling {@code refresh} may cause the file to be re-read.
 572      *
 573      * <p> The default implementation of this method does nothing.
 574      * This method should be overridden if a refresh operation is supported
 575      * by the implementation.
 576      *
 577      * @exception SecurityException if the caller does not have permission
 578      *                          to refresh its Configuration.
 579      */
 580     public void refresh() { }
 581 
 582     /**
 583      * This subclass is returned by the getInstance calls.  All Configuration
 584      * calls are delegated to the underlying ConfigurationSpi.
 585      */
 586     private static class ConfigDelegate extends Configuration {
 587 
 588         private ConfigurationSpi spi;
 589         private Provider p;
 590         private String type;
 591         private Configuration.Parameters params;
 592 
 593         private ConfigDelegate(ConfigurationSpi spi, Provider p,
 594                         String type, Configuration.Parameters params) {
 595             this.spi = spi;
 596             this.p = p;
 597             this.type = type;
 598             this.params = params;
 599         }
 600 
 601         public String getType() { return type; }
 602 
 603         public Configuration.Parameters getParameters() { return params; }
 604 
 605         public Provider getProvider() { return p; }
 606 
 607         public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
 608             return spi.engineGetAppConfigurationEntry(name);
 609         }
 610 
 611         public void refresh() {
 612             spi.engineRefresh();
 613         }
 614     }
 615 
 616     /**
 617      * This represents a marker interface for Configuration parameters.
 618      *
 619      * @since 1.6
 620      */
 621     public static interface Parameters { }
 622 }