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