History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/security/auth/login/ConfigFile.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/security/auth/login/ConfigFile.java+675−0
@@ -0,0 +1,675 @@
1+/*
2+ * Copyright (c) 2000, 2011, 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 com.sun.security.auth.login;
27+
28+import javax.security.auth.AuthPermission;
29+import javax.security.auth.login.AppConfigurationEntry;
30+import java.io.*;
31+import java.util.*;
32+import java.net.URI;
33+import java.net.URL;
34+import java.net.MalformedURLException;
35+import java.text.MessageFormat;
36+import sun.security.util.Debug;
37+import sun.security.util.ResourcesMgr;
38+import sun.security.util.PropertyExpander;
39+
40+/**
41+ * This class represents a default implementation for
42+ * <code>javax.security.auth.login.Configuration</code>.
43+ *
44+ * <p> This object stores the runtime login configuration representation,
45+ * and is the amalgamation of multiple static login
46+ * configurations that resides in files.
47+ * The algorithm for locating the login configuration file(s) and reading their
48+ * information into this <code>Configuration</code> object is:
49+ *
50+ * <ol>
51+ * <li>
52+ * Loop through the <code>java.security.Security</code> properties,
53+ * <i>login.config.url.1</i>, <i>login.config.url.2</i>, ...,
54+ * <i>login.config.url.X</i>. These properties are set
55+ * in the Java security properties file, which is located in the file named
56+ * &lt;JAVA_HOME&gt;/lib/security/java.security.
57+ * &lt;JAVA_HOME&gt; refers to the value of the java.home system property,
58+ * and specifies the directory where the JRE is installed.
59+ * Each property value specifies a <code>URL</code> pointing to a
60+ * login configuration file to be loaded. Read in and load
61+ * each configuration.
62+ *
63+ * <li>
64+ * The <code>java.lang.System</code> property
65+ * <i>java.security.auth.login.config</i>
66+ * may also be set to a <code>URL</code> pointing to another
67+ * login configuration file
68+ * (which is the case when a user uses the -D switch at runtime).
69+ * If this property is defined, and its use is allowed by the
70+ * security property file (the Security property,
71+ * <i>policy.allowSystemProperty</i> is set to <i>true</i>),
72+ * also load that login configuration.
73+ *
74+ * <li>
75+ * If the <i>java.security.auth.login.config</i> property is defined using
76+ * "==" (rather than "="), then ignore all other specified
77+ * login configurations and only load this configuration.
78+ *
79+ * <li>
80+ * If no system or security properties were set, try to read from the file,
81+ * ${user.home}/.java.login.config, where ${user.home} is the value
82+ * represented by the "user.home" System property.
83+ * </ol>
84+ *
85+ * <p> The configuration syntax supported by this implementation
86+ * is exactly that syntax specified in the
87+ * <code>javax.security.auth.login.Configuration</code> class.
88+ *
89+ * @see javax.security.auth.login.LoginContext
90+ */
91+public class ConfigFile extends javax.security.auth.login.Configuration {
92+
93+ private StreamTokenizer st;
94+ private int lookahead;
95+ private int linenum;
96+ private HashMap<String, LinkedList<AppConfigurationEntry>> configuration;
97+ private boolean expandProp = true;
98+ private URL url;
99+
100+ private static Debug debugConfig = Debug.getInstance("configfile");
101+ private static Debug debugParser = Debug.getInstance("configparser");
102+
103+ /**
104+ * Create a new <code>Configuration</code> object.
105+ */
106+ public ConfigFile() {
107+ try {
108+ init(url);
109+ } catch (IOException ioe) {
110+ throw (SecurityException)
111+ new SecurityException(ioe.getMessage()).initCause(ioe);
112+ }
113+ }
114+
115+ /**
116+ * Create a new <code>Configuration</code> object from the specified URI.
117+ *
118+ * @param uri Create a new Configuration object from this URI.
119+ */
120+ public ConfigFile(URI uri) {
121+ // only load config from the specified URI
122+ try {
123+ url = uri.toURL();
124+ init(url);
125+ } catch (MalformedURLException mue) {
126+ throw (SecurityException)
127+ new SecurityException(mue.getMessage()).initCause(mue);
128+ } catch (IOException ioe) {
129+ throw (SecurityException)
130+ new SecurityException(ioe.getMessage()).initCause(ioe);
131+ }
132+ }
133+
134+ /**
135+ * Read and initialize the entire login Configuration.
136+ *
137+ * <p>
138+ *
139+ * @exception IOException if the Configuration can not be initialized. <p>
140+ * @exception SecurityException if the caller does not have permission
141+ * to initialize the Configuration.
142+ */
143+ private void init(URL url) throws IOException {
144+
145+ boolean initialized = false;
146+ FileReader fr = null;
147+ String sep = File.separator;
148+
149+ if ("false".equals(System.getProperty("policy.expandProperties"))) {
150+ expandProp = false;
151+ }
152+
153+ // new configuration
154+ HashMap<String, LinkedList<AppConfigurationEntry>> newConfig =
155+ new HashMap<>();
156+
157+ if (url != null) {
158+
159+ /**
160+ * If the caller specified a URI via Configuration.getInstance,
161+ * we only read from that URI
162+ */
163+ if (debugConfig != null) {
164+ debugConfig.println("reading " + url);
165+ }
166+ init(url, newConfig);
167+ configuration = newConfig;
168+ return;
169+ }
170+
171+ /**
172+ * Caller did not specify URI via Configuration.getInstance.
173+ * Read from URLs listed in the java.security properties file.
174+ */
175+
176+ String allowSys = java.security.Security.getProperty
177+ ("policy.allowSystemProperty");
178+
179+ if ("true".equalsIgnoreCase(allowSys)) {
180+ String extra_config = System.getProperty
181+ ("java.security.auth.login.config");
182+ if (extra_config != null) {
183+ boolean overrideAll = false;
184+ if (extra_config.startsWith("=")) {
185+ overrideAll = true;
186+ extra_config = extra_config.substring(1);
187+ }
188+ try {
189+ extra_config = PropertyExpander.expand(extra_config);
190+ } catch (PropertyExpander.ExpandException peee) {
191+ MessageFormat form = new MessageFormat
192+ (ResourcesMgr.getString
193+ ("Unable.to.properly.expand.config",
194+ "sun.security.util.AuthResources"));
195+ Object[] source = {extra_config};
196+ throw new IOException(form.format(source));
197+ }
198+
199+ URL configURL = null;
200+ try {
201+ configURL = new URL(extra_config);
202+ } catch (java.net.MalformedURLException mue) {
203+ File configFile = new File(extra_config);
204+ if (configFile.exists()) {
205+ configURL = configFile.toURI().toURL();
206+ } else {
207+ MessageFormat form = new MessageFormat
208+ (ResourcesMgr.getString
209+ ("extra.config.No.such.file.or.directory.",
210+ "sun.security.util.AuthResources"));
211+ Object[] source = {extra_config};
212+ throw new IOException(form.format(source));
213+ }
214+ }
215+
216+ if (debugConfig != null) {
217+ debugConfig.println("reading "+configURL);
218+ }
219+ init(configURL, newConfig);
220+ initialized = true;
221+ if (overrideAll) {
222+ if (debugConfig != null) {
223+ debugConfig.println("overriding other policies!");
224+ }
225+ configuration = newConfig;
226+ return;
227+ }
228+ }
229+ }
230+
231+ int n = 1;
232+ String config_url;
233+ while ((config_url = java.security.Security.getProperty
234+ ("login.config.url."+n)) != null) {
235+ try {
236+ config_url = PropertyExpander.expand
237+ (config_url).replace(File.separatorChar, '/');
238+ if (debugConfig != null) {
239+ debugConfig.println("\tReading config: " + config_url);
240+ }
241+ init(new URL(config_url), newConfig);
242+ initialized = true;
243+ } catch (PropertyExpander.ExpandException peee) {
244+ MessageFormat form = new MessageFormat
245+ (ResourcesMgr.getString
246+ ("Unable.to.properly.expand.config",
247+ "sun.security.util.AuthResources"));
248+ Object[] source = {config_url};
249+ throw new IOException(form.format(source));
250+ }
251+ n++;
252+ }
253+
254+ if (initialized == false && n == 1 && config_url == null) {
255+
256+ // get the config from the user's home directory
257+ if (debugConfig != null) {
258+ debugConfig.println("\tReading Policy " +
259+ "from ~/.java.login.config");
260+ }
261+ config_url = System.getProperty("user.home");
262+ String userConfigFile = config_url +
263+ File.separatorChar + ".java.login.config";
264+
265+ // No longer throws an exception when there's no config file
266+ // at all. Returns an empty Configuration instead.
267+ if (new File(userConfigFile).exists()) {
268+ init(new File(userConfigFile).toURI().toURL(),
269+ newConfig);
270+ }
271+ }
272+
273+ configuration = newConfig;
274+ }
275+
276+ private void init(URL config,
277+ HashMap<String, LinkedList<AppConfigurationEntry>> newConfig)
278+ throws IOException {
279+
280+ InputStreamReader isr = null;
281+ try {
282+ isr = new InputStreamReader(getInputStream(config), "UTF-8");
283+ readConfig(isr, newConfig);
284+ } catch (FileNotFoundException fnfe) {
285+ if (debugConfig != null) {
286+ debugConfig.println(fnfe.toString());
287+ }
288+ throw new IOException(ResourcesMgr.getString
289+ ("Configuration.Error.No.such.file.or.directory",
290+ "sun.security.util.AuthResources"));
291+ } finally {
292+ if (isr != null) {
293+ isr.close();
294+ }
295+ }
296+ }
297+
298+ /**
299+ * Retrieve an entry from the Configuration using an application name
300+ * as an index.
301+ *
302+ * <p>
303+ *
304+ * @param applicationName the name used to index the Configuration.
305+ * @return an array of AppConfigurationEntries which correspond to
306+ * the stacked configuration of LoginModules for this
307+ * application, or null if this application has no configured
308+ * LoginModules.
309+ */
310+ public AppConfigurationEntry[] getAppConfigurationEntry
311+ (String applicationName) {
312+
313+ LinkedList<AppConfigurationEntry> list = null;
314+ synchronized (configuration) {
315+ list = configuration.get(applicationName);
316+ }
317+
318+ if (list == null || list.size() == 0)
319+ return null;
320+
321+ AppConfigurationEntry[] entries =
322+ new AppConfigurationEntry[list.size()];
323+ Iterator<AppConfigurationEntry> iterator = list.iterator();
324+ for (int i = 0; iterator.hasNext(); i++) {
325+ AppConfigurationEntry e = iterator.next();
326+ entries[i] = new AppConfigurationEntry(e.getLoginModuleName(),
327+ e.getControlFlag(),
328+ e.getOptions());
329+ }
330+ return entries;
331+ }
332+
333+ /**
334+ * Refresh and reload the Configuration by re-reading all of the
335+ * login configurations.
336+ *
337+ * <p>
338+ *
339+ * @exception SecurityException if the caller does not have permission
340+ * to refresh the Configuration.
341+ */
342+ public synchronized void refresh() {
343+
344+ java.lang.SecurityManager sm = System.getSecurityManager();
345+ if (sm != null)
346+ sm.checkPermission(new AuthPermission("refreshLoginConfiguration"));
347+
348+ java.security.AccessController.doPrivileged
349+ (new java.security.PrivilegedAction<Void>() {
350+ public Void run() {
351+ try {
352+ init(url);
353+ } catch (java.io.IOException ioe) {
354+ throw (SecurityException) new SecurityException
355+ (ioe.getLocalizedMessage()).initCause(ioe);
356+ }
357+ return null;
358+ }
359+ });
360+ }
361+
362+ private void readConfig(Reader reader,
363+ HashMap<String, LinkedList<AppConfigurationEntry>> newConfig)
364+ throws IOException {
365+
366+ int linenum = 1;
367+
368+ if (!(reader instanceof BufferedReader))
369+ reader = new BufferedReader(reader);
370+
371+ st = new StreamTokenizer(reader);
372+ st.quoteChar('"');
373+ st.wordChars('$', '$');
374+ st.wordChars('_', '_');
375+ st.wordChars('-', '-');
376+ st.lowerCaseMode(false);
377+ st.slashSlashComments(true);
378+ st.slashStarComments(true);
379+ st.eolIsSignificant(true);
380+
381+ lookahead = nextToken();
382+ while (lookahead != StreamTokenizer.TT_EOF) {
383+ parseLoginEntry(newConfig);
384+ }
385+ }
386+
387+ private void parseLoginEntry(
388+ HashMap<String, LinkedList<AppConfigurationEntry>> newConfig)
389+ throws IOException {
390+
391+ String appName;
392+ String moduleClass;
393+ String sflag;
394+ AppConfigurationEntry.LoginModuleControlFlag controlFlag;
395+ LinkedList<AppConfigurationEntry> configEntries = new LinkedList<>();
396+
397+ // application name
398+ appName = st.sval;
399+ lookahead = nextToken();
400+
401+ if (debugParser != null) {
402+ debugParser.println("\tReading next config entry: " + appName);
403+ }
404+
405+ match("{");
406+
407+ // get the modules
408+ while (peek("}") == false) {
409+ // get the module class name
410+ moduleClass = match("module class name");
411+
412+ // controlFlag (required, optional, etc)
413+ sflag = match("controlFlag");
414+ if (sflag.equalsIgnoreCase("REQUIRED"))
415+ controlFlag =
416+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED;
417+ else if (sflag.equalsIgnoreCase("REQUISITE"))
418+ controlFlag =
419+ AppConfigurationEntry.LoginModuleControlFlag.REQUISITE;
420+ else if (sflag.equalsIgnoreCase("SUFFICIENT"))
421+ controlFlag =
422+ AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT;
423+ else if (sflag.equalsIgnoreCase("OPTIONAL"))
424+ controlFlag =
425+ AppConfigurationEntry.LoginModuleControlFlag.OPTIONAL;
426+ else {
427+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
428+ ("Configuration.Error.Invalid.control.flag.flag",
429+ "sun.security.util.AuthResources"));
430+ Object[] source = {sflag};
431+ throw new IOException(form.format(source));
432+ }
433+
434+ // get the args
435+ HashMap<String, String> options = new HashMap<>();
436+ String key;
437+ String value;
438+ while (peek(";") == false) {
439+ key = match("option key");
440+ match("=");
441+ try {
442+ value = expand(match("option value"));
443+ } catch (PropertyExpander.ExpandException peee) {
444+ throw new IOException(peee.getLocalizedMessage());
445+ }
446+ options.put(key, value);
447+ }
448+
449+ lookahead = nextToken();
450+
451+ // create the new element
452+ if (debugParser != null) {
453+ debugParser.println("\t\t" + moduleClass + ", " + sflag);
454+ java.util.Iterator<String> i = options.keySet().iterator();
455+ while (i.hasNext()) {
456+ key = i.next();
457+ debugParser.println("\t\t\t" +
458+ key +
459+ "=" +
460+ options.get(key));
461+ }
462+ }
463+ AppConfigurationEntry entry = new AppConfigurationEntry
464+ (moduleClass,
465+ controlFlag,
466+ options);
467+ configEntries.add(entry);
468+ }
469+
470+ match("}");
471+ match(";");
472+
473+ // add this configuration entry
474+ if (newConfig.containsKey(appName)) {
475+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
476+ ("Configuration.Error.Can.not.specify.multiple.entries.for.appName",
477+ "sun.security.util.AuthResources"));
478+ Object[] source = {appName};
479+ throw new IOException(form.format(source));
480+ }
481+ newConfig.put(appName, configEntries);
482+ }
483+
484+ private String match(String expect) throws IOException {
485+
486+ String value = null;
487+
488+ switch(lookahead) {
489+ case StreamTokenizer.TT_EOF:
490+
491+ MessageFormat form1 = new MessageFormat(ResourcesMgr.getString
492+ ("Configuration.Error.expected.expect.read.end.of.file.",
493+ "sun.security.util.AuthResources"));
494+ Object[] source1 = {expect};
495+ throw new IOException(form1.format(source1));
496+
497+ case '"':
498+ case StreamTokenizer.TT_WORD:
499+
500+ if (expect.equalsIgnoreCase("module class name") ||
501+ expect.equalsIgnoreCase("controlFlag") ||
502+ expect.equalsIgnoreCase("option key") ||
503+ expect.equalsIgnoreCase("option value")) {
504+ value = st.sval;
505+ lookahead = nextToken();
506+ } else {
507+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
508+ ("Configuration.Error.Line.line.expected.expect.found.value.",
509+ "sun.security.util.AuthResources"));
510+ Object[] source = {new Integer(linenum), expect, st.sval};
511+ throw new IOException(form.format(source));
512+ }
513+ break;
514+
515+ case '{':
516+
517+ if (expect.equalsIgnoreCase("{")) {
518+ lookahead = nextToken();
519+ } else {
520+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
521+ ("Configuration.Error.Line.line.expected.expect.",
522+ "sun.security.util.AuthResources"));
523+ Object[] source = {new Integer(linenum), expect, st.sval};
524+ throw new IOException(form.format(source));
525+ }
526+ break;
527+
528+ case ';':
529+
530+ if (expect.equalsIgnoreCase(";")) {
531+ lookahead = nextToken();
532+ } else {
533+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
534+ ("Configuration.Error.Line.line.expected.expect.",
535+ "sun.security.util.AuthResources"));
536+ Object[] source = {new Integer(linenum), expect, st.sval};
537+ throw new IOException(form.format(source));
538+ }
539+ break;
540+
541+ case '}':
542+
543+ if (expect.equalsIgnoreCase("}")) {
544+ lookahead = nextToken();
545+ } else {
546+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
547+ ("Configuration.Error.Line.line.expected.expect.",
548+ "sun.security.util.AuthResources"));
549+ Object[] source = {new Integer(linenum), expect, st.sval};
550+ throw new IOException(form.format(source));
551+ }
552+ break;
553+
554+ case '=':
555+
556+ if (expect.equalsIgnoreCase("=")) {
557+ lookahead = nextToken();
558+ } else {
559+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
560+ ("Configuration.Error.Line.line.expected.expect.",
561+ "sun.security.util.AuthResources"));
562+ Object[] source = {new Integer(linenum), expect, st.sval};
563+ throw new IOException(form.format(source));
564+ }
565+ break;
566+
567+ default:
568+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
569+ ("Configuration.Error.Line.line.expected.expect.found.value.",
570+ "sun.security.util.AuthResources"));
571+ Object[] source = {new Integer(linenum), expect, st.sval};
572+ throw new IOException(form.format(source));
573+ }
574+ return value;
575+ }
576+
577+ private boolean peek(String expect) {
578+ boolean found = false;
579+
580+ switch (lookahead) {
581+ case ',':
582+ if (expect.equalsIgnoreCase(","))
583+ found = true;
584+ break;
585+ case ';':
586+ if (expect.equalsIgnoreCase(";"))
587+ found = true;
588+ break;
589+ case '{':
590+ if (expect.equalsIgnoreCase("{"))
591+ found = true;
592+ break;
593+ case '}':
594+ if (expect.equalsIgnoreCase("}"))
595+ found = true;
596+ break;
597+ default:
598+ }
599+ return found;
600+ }
601+
602+ private int nextToken() throws IOException {
603+ int tok;
604+ while ((tok = st.nextToken()) == StreamTokenizer.TT_EOL) {
605+ linenum++;
606+ }
607+ return tok;
608+ }
609+
610+ /*
611+ * Fast path reading from file urls in order to avoid calling
612+ * FileURLConnection.connect() which can be quite slow the first time
613+ * it is called. We really should clean up FileURLConnection so that
614+ * this is not a problem but in the meantime this fix helps reduce
615+ * start up time noticeably for the new launcher. -- DAC
616+ */
617+ private InputStream getInputStream(URL url) throws IOException {
618+ if ("file".equalsIgnoreCase(url.getProtocol())) {
619+ // Compatibility notes:
620+ //
621+ // Code changed from
622+ // String path = url.getFile().replace('/', File.separatorChar);
623+ // return new FileInputStream(path);
624+ //
625+ // The original implementation would search for "/tmp/a%20b"
626+ // when url is "file:///tmp/a%20b". This is incorrect. The
627+ // current codes fix this bug and searches for "/tmp/a b".
628+ // For compatibility reasons, when the file "/tmp/a b" does
629+ // not exist, the file named "/tmp/a%20b" will be tried.
630+ //
631+ // This also means that if both file exists, the behavior of
632+ // this method is changed, and the current codes choose the
633+ // correct one.
634+ try {
635+ return url.openStream();
636+ } catch (Exception e) {
637+ String file = url.getPath();
638+ if (url.getHost().length() > 0) { // For Windows UNC
639+ file = "//" + url.getHost() + file;
640+ }
641+ if (debugConfig != null) {
642+ debugConfig.println("cannot read " + url +
643+ ", try " + file);
644+ }
645+ return new FileInputStream(file);
646+ }
647+ } else {
648+ return url.openStream();
649+ }
650+ }
651+
652+ private String expand(String value)
653+ throws PropertyExpander.ExpandException, IOException {
654+
655+ if ("".equals(value)) {
656+ return value;
657+ }
658+
659+ if (expandProp) {
660+
661+ String s = PropertyExpander.expand(value);
662+
663+ if (s == null || s.length() == 0) {
664+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
665+ ("Configuration.Error.Line.line.system.property.value.expanded.to.empty.value",
666+ "sun.security.util.AuthResources"));
667+ Object[] source = {new Integer(linenum), value};
668+ throw new IOException(form.format(source));
669+ }
670+ return s;
671+ } else {
672+ return value;
673+ }
674+ }
675+}