Path: blob/master/src/java.xml/share/classes/jdk/xml/internal/SecuritySupport.java
40948 views
/*1* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package jdk.xml.internal;2526import java.io.File;27import java.io.FileInputStream;28import java.io.FileNotFoundException;29import java.io.IOException;30import java.io.InputStream;31import java.net.URL;32import java.security.AccessController;33import java.security.CodeSource;34import java.security.PrivilegedAction;35import java.security.PrivilegedActionException;36import java.security.PrivilegedExceptionAction;37import java.text.MessageFormat;38import java.util.Locale;39import java.util.MissingResourceException;40import java.util.Properties;41import java.util.ResourceBundle;4243/**44* This class contains utility methods for reading resources in the JAXP packages45*/46public class SecuritySupport {47public final static String NEWLINE = System.lineSeparator();4849/**50* Cache for properties in java.home/conf/jaxp.properties51*/52static final Properties cacheProps = new Properties();5354/**55* Flag indicating whether java.home/conf/jaxp.properties has been read56*/57static volatile boolean firstTime = true;5859private SecuritySupport() {}6061public static String getErrorMessage(Locale locale, String bundle, String key,62Object[] arguments) {63ResourceBundle rb;64if (locale != null) {65rb = ResourceBundle.getBundle(bundle,locale);66} else {67rb = ResourceBundle.getBundle(bundle);68}6970String msg = rb.getString(key);71if (arguments != null) {72msg = MessageFormat.format(msg, arguments);73}74return msg;75}7677/**78* Reads a system property with privilege79*80* @param propName the name of the property81* @return the value of the property82*/83@SuppressWarnings("removal")84public static String getSystemProperty(final String propName) {85return86AccessController.doPrivileged(87(PrivilegedAction<String>) () -> System.getProperty(propName));88}8990/**91* Reads a system property with privilege92*93* @param propName the name of the property94* @return the value of the property95*/96public static String getSystemProperty(final String propName, String defValue) {97String value = getSystemProperty(propName);98if (value == null) {99return defValue;100}101return value;102}103104/**105* Reads a system property with specified type.106*107* @param <T> the type of the property value108* @param type the type of the property value109* @param propName the name of the property110* @param defValue the default value111* @return the value of the property, or the default value if no system112* property is found113*/114public static <T> T getSystemProperty(Class<T> type, String propName, String defValue) {115String value = getSystemProperty(propName);116if (value == null) {117value = defValue;118}119if (Integer.class.isAssignableFrom(type)) {120return type.cast(Integer.parseInt(value));121} else if (Boolean.class.isAssignableFrom(type)) {122return type.cast(Boolean.parseBoolean(value));123}124return type.cast(value);125}126127/**128* Reads JAXP system property in this order: system property,129* $java.home/conf/jaxp.properties if the system property is not specified130*131* @param <T> the type of the property value132* @param type the type of the property value133* @param propName the name of the property134* @param defValue the default value135* @return the value of the property, or the default value if no system136* property is found137*/138public static <T> T getJAXPSystemProperty(Class<T> type, String propName, String defValue) {139String value = getJAXPSystemProperty(propName);140if (value == null) {141value = defValue;142}143if (Integer.class.isAssignableFrom(type)) {144return type.cast(Integer.parseInt(value));145} else if (Boolean.class.isAssignableFrom(type)) {146return type.cast(Boolean.parseBoolean(value));147}148return type.cast(value);149}150151/**152* Reads JAXP system property in this order: system property,153* $java.home/conf/jaxp.properties if the system property is not specified154*155* @param propName the name of the property156* @return the value of the property157*/158public static String getJAXPSystemProperty(String propName) {159String value = getSystemProperty(propName);160if (value == null) {161value = readJAXPProperty(propName);162}163return value;164}165166/**167* Reads the specified property from $java.home/conf/jaxp.properties168*169* @param propName the name of the property170* @return the value of the property171*/172public static String readJAXPProperty(String propName) {173String value = null;174InputStream is = null;175try {176if (firstTime) {177synchronized (cacheProps) {178if (firstTime) {179String configFile = getSystemProperty("java.home") + File.separator180+ "conf" + File.separator + "jaxp.properties";181File f = new File(configFile);182if (isFileExists(f)) {183is = getFileInputStream(f);184cacheProps.load(is);185}186firstTime = false;187}188}189}190value = cacheProps.getProperty(propName);191192} catch (IOException ex) {193} finally {194if (is != null) {195try {196is.close();197} catch (IOException ex) {}198}199}200201return value;202}203204/**205* Tests whether the file denoted by this abstract pathname is a directory.206* @param f the file to be tested207* @return true if it is a directory, false otherwise208*/209@SuppressWarnings("removal")210public static boolean isDirectory(final File f) {211return (AccessController.doPrivileged((PrivilegedAction<Boolean>) ()212-> f.isDirectory()));213}214215/**216* Tests whether the file exists.217*218* @param f the file to be tested219* @return true if the file exists, false otherwise220*/221@SuppressWarnings("removal")222public static boolean isFileExists(final File f) {223return (AccessController.doPrivileged((PrivilegedAction<Boolean>) ()224-> f.exists()));225}226227/**228* Creates and returns a new FileInputStream from a file.229* @param file the specified file230* @return the FileInputStream231* @throws FileNotFoundException if the file is not found232*/233@SuppressWarnings("removal")234public static FileInputStream getFileInputStream(final File file)235throws FileNotFoundException {236try {237return AccessController.doPrivileged((PrivilegedExceptionAction<FileInputStream>) ()238-> new FileInputStream(file));239} catch (PrivilegedActionException e) {240throw (FileNotFoundException) e.getException();241}242}243244/**245* Returns the resource as a stream.246* @param name the resource name247* @return the resource stream248*/249@SuppressWarnings("removal")250public static InputStream getResourceAsStream(final String name) {251return AccessController.doPrivileged((PrivilegedAction<InputStream>) () ->252SecuritySupport.class.getResourceAsStream("/"+name));253}254255/**256* Gets a resource bundle using the specified base name, the default locale, and the caller's class loader.257* @param bundle the base name of the resource bundle, a fully qualified class name258* @return a resource bundle for the given base name and the default locale259*/260public static ResourceBundle getResourceBundle(String bundle) {261return getResourceBundle(bundle, Locale.getDefault());262}263264/**265* Gets a resource bundle using the specified base name and locale, and the caller's class loader.266* @param bundle the base name of the resource bundle, a fully qualified class name267* @param locale the locale for which a resource bundle is desired268* @return a resource bundle for the given base name and locale269*/270@SuppressWarnings("removal")271public static ResourceBundle getResourceBundle(final String bundle, final Locale locale) {272return AccessController.doPrivileged((PrivilegedAction<ResourceBundle>) () -> {273try {274return ResourceBundle.getBundle(bundle, locale);275} catch (MissingResourceException e) {276try {277return ResourceBundle.getBundle(bundle, new Locale("en", "US"));278} catch (MissingResourceException e2) {279throw new MissingResourceException(280"Could not load any resource bundle by " + bundle, bundle, "");281}282}283});284}285286/**287* Checks whether the file exists.288* @param f the specified file289* @return true if the file exists, false otherwise290*/291@SuppressWarnings("removal")292public static boolean doesFileExist(final File f) {293return (AccessController.doPrivileged((PrivilegedAction<Boolean>) () -> f.exists()));294}295296/**297* Checks the LastModified attribute of a file.298* @param f the specified file299* @return the LastModified attribute300*/301@SuppressWarnings("removal")302static long getLastModified(final File f) {303return (AccessController.doPrivileged((PrivilegedAction<Long>) () -> f.lastModified()));304}305306/**307* Strip off path from an URI308*309* @param uri an URI with full path310* @return the file name only311*/312public static String sanitizePath(String uri) {313if (uri == null) {314return "";315}316int i = uri.lastIndexOf("/");317if (i > 0) {318return uri.substring(i+1, uri.length());319}320return "";321}322323/**324* Check the protocol used in the systemId against allowed protocols325*326* @param systemId the Id of the URI327* @param allowedProtocols a list of allowed protocols separated by comma328* @param accessAny keyword to indicate allowing any protocol329* @return the name of the protocol if rejected, null otherwise330*/331public static String checkAccess(String systemId, String allowedProtocols,332String accessAny) throws IOException {333if (systemId == null || (allowedProtocols != null &&334allowedProtocols.equalsIgnoreCase(accessAny))) {335return null;336}337338String protocol;339if (!systemId.contains(":")) {340protocol = "file";341} else {342URL url = new URL(systemId);343protocol = url.getProtocol();344if (protocol.equalsIgnoreCase("jar")) {345String path = url.getPath();346protocol = path.substring(0, path.indexOf(":"));347} else if (protocol.equalsIgnoreCase("jrt")) {348// if the systemId is "jrt" then allow access if "file" allowed349protocol = "file";350}351}352353if (isProtocolAllowed(protocol, allowedProtocols)) {354//access allowed355return null;356} else {357return protocol;358}359}360361/**362* Check if the protocol is in the allowed list of protocols. The check363* is case-insensitive while ignoring whitespaces.364*365* @param protocol a protocol366* @param allowedProtocols a list of allowed protocols367* @return true if the protocol is in the list368*/369private static boolean isProtocolAllowed(String protocol, String allowedProtocols) {370if (allowedProtocols == null) {371return false;372}373String temp[] = allowedProtocols.split(",");374for (String t : temp) {375t = t.trim();376if (t.equalsIgnoreCase(protocol)) {377return true;378}379}380return false;381}382383@SuppressWarnings("removal")384public static ClassLoader getContextClassLoader() {385return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> {386ClassLoader cl = Thread.currentThread().getContextClassLoader();387if (cl == null)388cl = ClassLoader.getSystemClassLoader();389return cl;390});391}392393394@SuppressWarnings("removal")395public static ClassLoader getSystemClassLoader() {396return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> {397ClassLoader cl = null;398try {399cl = ClassLoader.getSystemClassLoader();400} catch (SecurityException ex) {401}402return cl;403});404}405406@SuppressWarnings("removal")407public static ClassLoader getParentClassLoader(final ClassLoader cl) {408return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> {409ClassLoader parent = null;410try {411parent = cl.getParent();412} catch (SecurityException ex) {413}414415// eliminate loops in case of the boot416// ClassLoader returning itself as a parent417return (parent == cl) ? null : parent;418});419}420421422// Used for debugging purposes423@SuppressWarnings("removal")424public static String getClassSource(Class<?> cls) {425return AccessController.doPrivileged((PrivilegedAction<String>) () -> {426CodeSource cs = cls.getProtectionDomain().getCodeSource();427if (cs != null) {428URL loc = cs.getLocation();429return loc != null ? loc.toString() : "(no location)";430} else {431return "(no code source)";432}433});434}435436// ---------------- For SAX ----------------------437/**438* Returns the current thread's context class loader, or the system class loader439* if the context class loader is null.440* @return the current thread's context class loader, or the system class loader441* @throws SecurityException442*/443@SuppressWarnings("removal")444public static ClassLoader getClassLoader() throws SecurityException{445return AccessController.doPrivileged((PrivilegedAction<ClassLoader>)() -> {446ClassLoader cl = Thread.currentThread().getContextClassLoader();447if (cl == null) {448cl = ClassLoader.getSystemClassLoader();449}450451return cl;452});453}454455@SuppressWarnings("removal")456public static InputStream getResourceAsStream(final ClassLoader cl, final String name)457{458return AccessController.doPrivileged((PrivilegedAction<InputStream>) () -> {459InputStream ris;460if (cl == null) {461ris = SecuritySupport.class.getResourceAsStream(name);462} else {463ris = cl.getResourceAsStream(name);464}465return ris;466});467}468}469470471