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
26package com.sun.security.auth.login;
27
28import javax.security.auth.AuthPermission;
29import javax.security.auth.login.AppConfigurationEntry;
30import java.io.*;
31import java.util.*;
32import java.net.URI;
33import java.net.URL;
34import java.net.MalformedURLException;
35import java.text.MessageFormat;
36import sun.security.util.Debug;
37import sun.security.util.ResourcesMgr;
38import 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 */
91public 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}