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