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