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 
checkPermission(String type)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      */
Configuration()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      */
getConfiguration()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      */
setConfiguration(Configuration configuration)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      */
getInstance(String type, Configuration.Parameters params)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      */
getInstance(String type, Configuration.Parameters params, String provider)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      */
getInstance(String type, Configuration.Parameters params, Provider provider)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 
handleException(NoSuchAlgorithmException nsae)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      */
getProvider()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      */
getType()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      */
getParameters()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      */
getAppConfigurationEntry(String name)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      */
refresh()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 
ConfigDelegate(ConfigurationSpi spi, Provider p, String type, Configuration.Parameters params)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 
getType()609         public String getType() { return type; }
610 
getParameters()611         public Configuration.Parameters getParameters() { return params; }
612 
getProvider()613         public Provider getProvider() { return p; }
614 
getAppConfigurationEntry(String name)615         public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
616             return spi.engineGetAppConfigurationEntry(name);
617         }
618 
refresh()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 }
631