1 /*
   2  * Copyright (c) 1998, 2015, 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<String>() {
 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<Configuration>() {
 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<Void>() {
 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      * @param type the specified Configuration type.  See the Configuration
 315      *    section in the <a href=
 316      *    "{@docRoot}/../technotes/guides/security/StandardNames.html#Configuration">
 317      *    Java Cryptography Architecture Standard Algorithm Name
 318      *    Documentation</a> for a list of standard Configuration types.
 319      *
 320      * @param params parameters for the Configuration, which may be null.
 321      *
 322      * @return the new Configuration object.
 323      *
 324      * @exception SecurityException if the caller does not have permission
 325      *          to get a Configuration instance for the specified type.
 326      *
 327      * @exception NullPointerException if the specified type is null.
 328      *
 329      * @exception IllegalArgumentException if the specified parameters
 330      *          are not understood by the ConfigurationSpi implementation
 331      *          from the selected Provider.
 332      *
 333      * @exception NoSuchAlgorithmException if no Provider supports a
 334      *          ConfigurationSpi implementation for the specified type.
 335      *
 336      * @see Provider
 337      * @since 1.6
 338      */
 339     public static Configuration getInstance(String type,
 340                                 Configuration.Parameters params)
 341                 throws NoSuchAlgorithmException {
 342 
 343         checkPermission(type);
 344         try {
 345             GetInstance.Instance instance = GetInstance.getInstance
 346                                                         ("Configuration",
 347                                                         ConfigurationSpi.class,
 348                                                         type,
 349                                                         params);
 350             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 351                                                         instance.provider,
 352                                                         type,
 353                                                         params);
 354         } catch (NoSuchAlgorithmException nsae) {
 355             return handleException (nsae);
 356         }
 357     }
 358 
 359     /**
 360      * Returns a Configuration object of the specified type.
 361      *
 362      * <p> A new Configuration object encapsulating the
 363      * ConfigurationSpi implementation from the specified provider
 364      * is returned.   The specified provider must be registered
 365      * in the provider list.
 366      *
 367      * <p> Note that the list of registered providers may be retrieved via
 368      * the {@link Security#getProviders() Security.getProviders()} method.
 369      *
 370      * @param type the specified Configuration type.  See the Configuration
 371      *    section in the <a href=
 372      *    "{@docRoot}/../technotes/guides/security/StandardNames.html#Configuration">
 373      *    Java Cryptography Architecture Standard Algorithm Name
 374      *    Documentation</a> for a list of standard Configuration types.
 375      *
 376      * @param params parameters for the Configuration, which may be null.
 377      *
 378      * @param provider the provider.
 379      *
 380      * @return the new Configuration object.
 381      *
 382      * @exception SecurityException if the caller does not have permission
 383      *          to get a Configuration instance for the specified type.
 384      *
 385      * @exception NullPointerException if the specified type is null.
 386      *
 387      * @exception IllegalArgumentException if the specified provider
 388      *          is null or empty,
 389      *          or if the specified parameters are not understood by
 390      *          the ConfigurationSpi implementation from the specified provider.
 391      *
 392      * @exception NoSuchProviderException if the specified provider is not
 393      *          registered in the security provider list.
 394      *
 395      * @exception NoSuchAlgorithmException if the specified provider does not
 396      *          support a ConfigurationSpi implementation for the specified
 397      *          type.
 398      *
 399      * @see Provider
 400      * @since 1.6
 401      */
 402     public static Configuration getInstance(String type,
 403                                 Configuration.Parameters params,
 404                                 String provider)
 405                 throws NoSuchProviderException, NoSuchAlgorithmException {
 406 
 407         if (provider == null || provider.length() == 0) {
 408             throw new IllegalArgumentException("missing provider");
 409         }
 410 
 411         checkPermission(type);
 412         try {
 413             GetInstance.Instance instance = GetInstance.getInstance
 414                                                         ("Configuration",
 415                                                         ConfigurationSpi.class,
 416                                                         type,
 417                                                         params,
 418                                                         provider);
 419             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 420                                                         instance.provider,
 421                                                         type,
 422                                                         params);
 423         } catch (NoSuchAlgorithmException nsae) {
 424             return handleException (nsae);
 425         }
 426     }
 427 
 428     /**
 429      * Returns a Configuration object of the specified type.
 430      *
 431      * <p> A new Configuration object encapsulating the
 432      * ConfigurationSpi implementation from the specified Provider
 433      * object is returned.  Note that the specified Provider object
 434      * does not have to be registered in the provider list.
 435      *
 436      * @param type the specified Configuration type.  See the Configuration
 437      *    section in the <a href=
 438      *    "{@docRoot}/../technotes/guides/security/StandardNames.html#Configuration">
 439      *    Java Cryptography Architecture Standard Algorithm Name
 440      *    Documentation</a> for a list of standard Configuration types.
 441      *
 442      * @param params parameters for the Configuration, which may be null.
 443      *
 444      * @param provider the Provider.
 445      *
 446      * @return the new Configuration object.
 447      *
 448      * @exception SecurityException if the caller does not have permission
 449      *          to get a Configuration instance for the specified type.
 450      *
 451      * @exception NullPointerException if the specified type is null.
 452      *
 453      * @exception IllegalArgumentException if the specified Provider is null,
 454      *          or if the specified parameters are not understood by
 455      *          the ConfigurationSpi implementation from the specified Provider.
 456      *
 457      * @exception NoSuchAlgorithmException if the specified Provider does not
 458      *          support a ConfigurationSpi implementation for the specified
 459      *          type.
 460      *
 461      * @see Provider
 462      * @since 1.6
 463      */
 464     public static Configuration getInstance(String type,
 465                                 Configuration.Parameters params,
 466                                 Provider provider)
 467                 throws NoSuchAlgorithmException {
 468 
 469         if (provider == null) {
 470             throw new IllegalArgumentException("missing provider");
 471         }
 472 
 473         checkPermission(type);
 474         try {
 475             GetInstance.Instance instance = GetInstance.getInstance
 476                                                         ("Configuration",
 477                                                         ConfigurationSpi.class,
 478                                                         type,
 479                                                         params,
 480                                                         provider);
 481             return new ConfigDelegate((ConfigurationSpi)instance.impl,
 482                                                         instance.provider,
 483                                                         type,
 484                                                         params);
 485         } catch (NoSuchAlgorithmException nsae) {
 486             return handleException (nsae);
 487         }
 488     }
 489 
 490     private static Configuration handleException(NoSuchAlgorithmException nsae)
 491                 throws NoSuchAlgorithmException {
 492         Throwable cause = nsae.getCause();
 493         if (cause instanceof IllegalArgumentException) {
 494             throw (IllegalArgumentException)cause;
 495         }
 496         throw nsae;
 497     }
 498 
 499     /**
 500      * Return the Provider of this Configuration.
 501      *
 502      * <p> This Configuration instance will only have a Provider if it
 503      * was obtained via a call to {@code Configuration.getInstance}.
 504      * Otherwise this method returns null.
 505      *
 506      * @return the Provider of this Configuration, or null.
 507      *
 508      * @since 1.6
 509      */
 510     public Provider getProvider() {
 511         return null;
 512     }
 513 
 514     /**
 515      * Return the type of this Configuration.
 516      *
 517      * <p> This Configuration instance will only have a type if it
 518      * was obtained via a call to {@code Configuration.getInstance}.
 519      * Otherwise this method returns null.
 520      *
 521      * @return the type of this Configuration, or null.
 522      *
 523      * @since 1.6
 524      */
 525     public String getType() {
 526         return null;
 527     }
 528 
 529     /**
 530      * Return Configuration parameters.
 531      *
 532      * <p> This Configuration instance will only have parameters if it
 533      * was obtained via a call to {@code Configuration.getInstance}.
 534      * Otherwise this method returns null.
 535      *
 536      * @return Configuration parameters, or null.
 537      *
 538      * @since 1.6
 539      */
 540     public Configuration.Parameters getParameters() {
 541         return null;
 542     }
 543 
 544     /**
 545      * Retrieve the AppConfigurationEntries for the specified {@code name}
 546      * from this Configuration.
 547      *
 548      * @param name the name used to index the Configuration.
 549      *
 550      * @return an array of AppConfigurationEntries for the specified {@code name}
 551      *          from this Configuration, or null if there are no entries
 552      *          for the specified {@code name}
 553      */
 554     public abstract AppConfigurationEntry[] getAppConfigurationEntry
 555                                                         (String name);
 556 
 557     /**
 558      * Refresh and reload the Configuration.
 559      *
 560      * <p> This method causes this Configuration object to refresh/reload its
 561      * contents in an implementation-dependent manner.
 562      * For example, if this Configuration object stores its entries in a file,
 563      * calling {@code refresh} may cause the file to be re-read.
 564      *
 565      * <p> The default implementation of this method does nothing.
 566      * This method should be overridden if a refresh operation is supported
 567      * by the implementation.
 568      *
 569      * @exception SecurityException if the caller does not have permission
 570      *                          to refresh its Configuration.
 571      */
 572     public void refresh() { }
 573 
 574     /**
 575      * This subclass is returned by the getInstance calls.  All Configuration
 576      * calls are delegated to the underlying ConfigurationSpi.
 577      */
 578     private static class ConfigDelegate extends Configuration {
 579 
 580         private ConfigurationSpi spi;
 581         private Provider p;
 582         private String type;
 583         private Configuration.Parameters params;
 584 
 585         private ConfigDelegate(ConfigurationSpi spi, Provider p,
 586                         String type, Configuration.Parameters params) {
 587             this.spi = spi;
 588             this.p = p;
 589             this.type = type;
 590             this.params = params;
 591         }
 592 
 593         public String getType() { return type; }
 594 
 595         public Configuration.Parameters getParameters() { return params; }
 596 
 597         public Provider getProvider() { return p; }
 598 
 599         public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
 600             return spi.engineGetAppConfigurationEntry(name);
 601         }
 602 
 603         public void refresh() {
 604             spi.engineRefresh();
 605         }
 606     }
 607 
 608     /**
 609      * This represents a marker interface for Configuration parameters.
 610      *
 611      * @since 1.6
 612      */
 613     public static interface Parameters { }
 614 }