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