Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/provider/PolicyParser.java
38830 views
/*1* Copyright (c) 1997, 2014, 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*/2425package sun.security.provider;2627import java.io.*;28import java.lang.RuntimePermission;29import java.net.SocketPermission;30import java.net.URL;31import java.security.GeneralSecurityException;32import java.security.Principal;33import java.text.MessageFormat;34import java.util.*;35import javax.security.auth.x500.X500Principal;3637import sun.security.util.Debug;38import sun.security.util.PropertyExpander;39import sun.security.util.ResourcesMgr;4041/**42* The policy for a Java runtime (specifying43* which permissions are available for code from various principals)44* is represented as a separate45* persistent configuration. The configuration may be stored as a46* flat ASCII file, as a serialized binary file of47* the Policy class, or as a database. <p>48*49* <p>The Java runtime creates one global Policy object, which is used to50* represent the static policy configuration file. It is consulted by51* a ProtectionDomain when the protection domain initializes its set of52* permissions. <p>53*54* <p>The Policy <code>init</code> method parses the policy55* configuration file, and then56* populates the Policy object. The Policy object is agnostic in that57* it is not involved in making policy decisions. It is merely the58* Java runtime representation of the persistent policy configuration59* file. <p>60*61* <p>When a protection domain needs to initialize its set of62* permissions, it executes code such as the following63* to ask the global Policy object to populate a64* Permissions object with the appropriate permissions:65* <pre>66* policy = Policy.getPolicy();67* Permissions perms = policy.getPermissions(protectiondomain)68* </pre>69*70* <p>The protection domain contains a CodeSource71* object, which encapsulates its codebase (URL) and public key attributes.72* It also contains the principals associated with the domain.73* The Policy object evaluates the global policy in light of who the74* principal is and what the code source is and returns an appropriate75* Permissions object.76*77* @author Roland Schemers78* @author Ram Marti79*80* @since 1.281*/8283public class PolicyParser {8485private static final String EXTDIRS_PROPERTY = "java.ext.dirs";86private static final String OLD_EXTDIRS_EXPANSION =87"${" + EXTDIRS_PROPERTY + "}";8889// package-private: used by PolicyFile for static policy90static final String EXTDIRS_EXPANSION = "${{" + EXTDIRS_PROPERTY + "}}";919293private Vector<GrantEntry> grantEntries;94private Map<String, DomainEntry> domainEntries;9596// Convenience variables for parsing97private static final Debug debug = Debug.getInstance("parser",98"\t[Policy Parser]");99private StreamTokenizer st;100private int lookahead;101private boolean expandProp = false;102private String keyStoreUrlString = null; // unexpanded103private String keyStoreType = null;104private String keyStoreProvider = null;105private String storePassURL = null;106107private String expand(String value)108throws PropertyExpander.ExpandException109{110return expand(value, false);111}112113private String expand(String value, boolean encodeURL)114throws PropertyExpander.ExpandException115{116if (!expandProp) {117return value;118} else {119return PropertyExpander.expand(value, encodeURL);120}121}122123/**124* Creates a PolicyParser object.125*/126127public PolicyParser() {128grantEntries = new Vector<GrantEntry>();129}130131132public PolicyParser(boolean expandProp) {133this();134this.expandProp = expandProp;135}136137/**138* Reads a policy configuration into the Policy object using a139* Reader object. <p>140*141* @param policy the policy Reader object.142*143* @exception ParsingException if the policy configuration contains144* a syntax error.145*146* @exception IOException if an error occurs while reading the policy147* configuration.148*/149150public void read(Reader policy)151throws ParsingException, IOException152{153if (!(policy instanceof BufferedReader)) {154policy = new BufferedReader(policy);155}156157/**158* Configure the stream tokenizer:159* Recognize strings between "..."160* Don't convert words to lowercase161* Recognize both C-style and C++-style comments162* Treat end-of-line as white space, not as a token163*/164st = new StreamTokenizer(policy);165166st.resetSyntax();167st.wordChars('a', 'z');168st.wordChars('A', 'Z');169st.wordChars('.', '.');170st.wordChars('0', '9');171st.wordChars('_', '_');172st.wordChars('$', '$');173st.wordChars(128 + 32, 255);174st.whitespaceChars(0, ' ');175st.commentChar('/');176st.quoteChar('\'');177st.quoteChar('"');178st.lowerCaseMode(false);179st.ordinaryChar('/');180st.slashSlashComments(true);181st.slashStarComments(true);182183/**184* The main parsing loop. The loop is executed once185* for each entry in the config file. The entries186* are delimited by semicolons. Once we've read in187* the information for an entry, go ahead and try to188* add it to the policy vector.189*190*/191192lookahead = st.nextToken();193GrantEntry ge = null;194while (lookahead != StreamTokenizer.TT_EOF) {195if (peek("grant")) {196ge = parseGrantEntry();197// could be null if we couldn't expand a property198if (ge != null)199add(ge);200} else if (peek("keystore") && keyStoreUrlString==null) {201// only one keystore entry per policy file, others will be202// ignored203parseKeyStoreEntry();204} else if (peek("keystorePasswordURL") && storePassURL==null) {205// only one keystore passwordURL per policy file, others will be206// ignored207parseStorePassURL();208} else if (ge == null && keyStoreUrlString == null &&209storePassURL == null && peek("domain")) {210if (domainEntries == null) {211domainEntries = new TreeMap<>();212}213DomainEntry de = parseDomainEntry();214if (de != null) {215String domainName = de.getName();216if (!domainEntries.containsKey(domainName)) {217domainEntries.put(domainName, de);218} else {219MessageFormat form =220new MessageFormat(ResourcesMgr.getString(221"duplicate.keystore.domain.name"));222Object[] source = {domainName};223throw new ParsingException(form.format(source));224}225}226} else {227// error?228}229match(";");230}231232if (keyStoreUrlString == null && storePassURL != null) {233throw new ParsingException(ResourcesMgr.getString234("keystorePasswordURL.can.not.be.specified.without.also.specifying.keystore"));235}236}237238public void add(GrantEntry ge)239{240grantEntries.addElement(ge);241}242243public void replace(GrantEntry origGe, GrantEntry newGe)244{245grantEntries.setElementAt(newGe, grantEntries.indexOf(origGe));246}247248public boolean remove(GrantEntry ge)249{250return grantEntries.removeElement(ge);251}252253/**254* Returns the (possibly expanded) keystore location, or null if the255* expansion fails.256*/257public String getKeyStoreUrl() {258try {259if (keyStoreUrlString!=null && keyStoreUrlString.length()!=0) {260return expand(keyStoreUrlString, true).replace261(File.separatorChar, '/');262}263} catch (PropertyExpander.ExpandException peee) {264if (debug != null) {265debug.println(peee.toString());266}267return null;268}269return null;270}271272public void setKeyStoreUrl(String url) {273keyStoreUrlString = url;274}275276public String getKeyStoreType() {277return keyStoreType;278}279280public void setKeyStoreType(String type) {281keyStoreType = type;282}283284public String getKeyStoreProvider() {285return keyStoreProvider;286}287288public void setKeyStoreProvider(String provider) {289keyStoreProvider = provider;290}291292public String getStorePassURL() {293try {294if (storePassURL!=null && storePassURL.length()!=0) {295return expand(storePassURL, true).replace296(File.separatorChar, '/');297}298} catch (PropertyExpander.ExpandException peee) {299if (debug != null) {300debug.println(peee.toString());301}302return null;303}304return null;305}306307public void setStorePassURL(String storePassURL) {308this.storePassURL = storePassURL;309}310311/**312* Enumerate all the entries in the global policy object.313* This method is used by policy admin tools. The tools314* should use the Enumeration methods on the returned object315* to fetch the elements sequentially.316*/317public Enumeration<GrantEntry> grantElements(){318return grantEntries.elements();319}320321public Collection<DomainEntry> getDomainEntries() {322return domainEntries.values();323}324325/**326* write out the policy327*/328329public void write(Writer policy)330{331PrintWriter out = new PrintWriter(new BufferedWriter(policy));332333Enumeration<GrantEntry> enum_ = grantElements();334335out.println("/* AUTOMATICALLY GENERATED ON "+336(new java.util.Date()) + "*/");337out.println("/* DO NOT EDIT */");338out.println();339340// write the (unexpanded) keystore entry as the first entry of the341// policy file342if (keyStoreUrlString != null) {343writeKeyStoreEntry(out);344}345if (storePassURL != null) {346writeStorePassURL(out);347}348349// write "grant" entries350while (enum_.hasMoreElements()) {351GrantEntry ge = enum_.nextElement();352ge.write(out);353out.println();354}355out.flush();356}357358/**359* parses a keystore entry360*/361private void parseKeyStoreEntry() throws ParsingException, IOException {362match("keystore");363keyStoreUrlString = match("quoted string");364365// parse keystore type366if (!peek(",")) {367return; // default type368}369match(",");370371if (peek("\"")) {372keyStoreType = match("quoted string");373} else {374throw new ParsingException(st.lineno(),375ResourcesMgr.getString("expected.keystore.type"));376}377378// parse keystore provider379if (!peek(",")) {380return; // provider optional381}382match(",");383384if (peek("\"")) {385keyStoreProvider = match("quoted string");386} else {387throw new ParsingException(st.lineno(),388ResourcesMgr.getString("expected.keystore.provider"));389}390}391392private void parseStorePassURL() throws ParsingException, IOException {393match("keyStorePasswordURL");394storePassURL = match("quoted string");395}396397/**398* writes the (unexpanded) keystore entry399*/400private void writeKeyStoreEntry(PrintWriter out) {401out.print("keystore \"");402out.print(keyStoreUrlString);403out.print('"');404if (keyStoreType != null && keyStoreType.length() > 0)405out.print(", \"" + keyStoreType + "\"");406if (keyStoreProvider != null && keyStoreProvider.length() > 0)407out.print(", \"" + keyStoreProvider + "\"");408out.println(";");409out.println();410}411412private void writeStorePassURL(PrintWriter out) {413out.print("keystorePasswordURL \"");414out.print(storePassURL);415out.print('"');416out.println(";");417out.println();418}419420/**421* parse a Grant entry422*/423private GrantEntry parseGrantEntry()424throws ParsingException, IOException425{426GrantEntry e = new GrantEntry();427LinkedList<PrincipalEntry> principals = null;428boolean ignoreEntry = false;429430match("grant");431432while(!peek("{")) {433434if (peekAndMatch("Codebase")) {435if (e.codeBase != null)436throw new ParsingException(437st.lineno(),438ResourcesMgr.getString439("multiple.Codebase.expressions"));440e.codeBase = match("quoted string");441peekAndMatch(",");442} else if (peekAndMatch("SignedBy")) {443if (e.signedBy != null)444throw new ParsingException(445st.lineno(),446ResourcesMgr.getString(447"multiple.SignedBy.expressions"));448e.signedBy = match("quoted string");449450// verify syntax of the aliases451StringTokenizer aliases = new StringTokenizer(e.signedBy,452",", true);453int actr = 0;454int cctr = 0;455while (aliases.hasMoreTokens()) {456String alias = aliases.nextToken().trim();457if (alias.equals(","))458cctr++;459else if (alias.length() > 0)460actr++;461}462if (actr <= cctr)463throw new ParsingException(464st.lineno(),465ResourcesMgr.getString(466"SignedBy.has.empty.alias"));467468peekAndMatch(",");469} else if (peekAndMatch("Principal")) {470if (principals == null) {471principals = new LinkedList<>();472}473474String principalClass;475String principalName;476477if (peek("\"")) {478// both the principalClass and principalName479// will be replaced later480principalClass = PrincipalEntry.REPLACE_NAME;481principalName = match("principal type");482} else {483// check for principalClass wildcard484if (peek("*")) {485match("*");486principalClass = PrincipalEntry.WILDCARD_CLASS;487} else {488principalClass = match("principal type");489}490491// check for principalName wildcard492if (peek("*")) {493match("*");494principalName = PrincipalEntry.WILDCARD_NAME;495} else {496principalName = match("quoted string");497}498499// disallow WILDCARD_CLASS && actual name500if (principalClass.equals(PrincipalEntry.WILDCARD_CLASS) &&501!principalName.equals(PrincipalEntry.WILDCARD_NAME)) {502if (debug != null) {503debug.println("disallowing principal that " +504"has WILDCARD class but no WILDCARD name");505}506throw new ParsingException507(st.lineno(),508ResourcesMgr.getString509("can.not.specify.Principal.with.a.wildcard.class.without.a.wildcard.name"));510}511}512513try {514principalName = expand(principalName);515516if (principalClass.equals517("javax.security.auth.x500.X500Principal") &&518!principalName.equals(PrincipalEntry.WILDCARD_NAME)) {519520// 4702543: X500 names with an EmailAddress521// were encoded incorrectly. construct a new522// X500Principal with correct encoding.523524X500Principal p = new X500Principal525((new X500Principal(principalName)).toString());526principalName = p.getName();527}528529principals.add530(new PrincipalEntry(principalClass, principalName));531} catch (PropertyExpander.ExpandException peee) {532// ignore the entire policy entry533// but continue parsing all the info534// so we can get to the next entry535if (debug != null) {536debug.println("principal name expansion failed: " +537principalName);538}539ignoreEntry = true;540}541peekAndMatch(",");542543} else {544throw new ParsingException(st.lineno(),545ResourcesMgr.getString(546"expected.codeBase.or.SignedBy.or.Principal"));547}548}549550if (principals != null) e.principals = principals;551match("{");552553while(!peek("}")) {554if (peek("Permission")) {555try {556PermissionEntry pe = parsePermissionEntry();557e.add(pe);558} catch (PropertyExpander.ExpandException peee) {559// ignore. The add never happened560if (debug != null) {561debug.println(peee.toString());562}563skipEntry(); // BugId 4219343564}565match(";");566} else {567throw new568ParsingException(st.lineno(),569ResourcesMgr.getString(570"expected.permission.entry"));571}572}573match("}");574575try {576if (e.signedBy != null) e.signedBy = expand(e.signedBy);577if (e.codeBase != null) {578579// For backward compatibility with 1.4580if (e.codeBase.equals(OLD_EXTDIRS_EXPANSION)) {581e.codeBase = EXTDIRS_EXPANSION;582}583int es;584if ((es=e.codeBase.indexOf(EXTDIRS_EXPANSION)) < 0) {585e.codeBase = expand(e.codeBase, true).replace586(File.separatorChar, '/');587} else {588// expand the system property "java.ext.dirs",589// parse it into its path components,590// and then create a grant entry for each component591String[] extDirs = parseExtDirs(e.codeBase, es);592if (extDirs != null && extDirs.length > 0) {593for (int i = 0; i < extDirs.length; i++) {594GrantEntry newGe = (GrantEntry)e.clone();595newGe.codeBase = extDirs[i];596add(newGe);597598if (debug != null) {599debug.println("creating policy entry for " +600"expanded java.ext.dirs path:\n\t\t" +601extDirs[i]);602}603}604}605ignoreEntry = true;606}607}608} catch (PropertyExpander.ExpandException peee) {609if (debug != null) {610debug.println(peee.toString());611}612return null;613}614615return (ignoreEntry == true) ? null : e;616}617618/**619* parse a Permission entry620*/621private PermissionEntry parsePermissionEntry()622throws ParsingException, IOException, PropertyExpander.ExpandException623{624PermissionEntry e = new PermissionEntry();625626// Permission627match("Permission");628e.permission = match("permission type");629630if (peek("\"")) {631// Permission name632e.name = expand(match("quoted string"));633}634635if (!peek(",")) {636return e;637}638match(",");639640if (peek("\"")) {641e.action = expand(match("quoted string"));642if (!peek(",")) {643return e;644}645match(",");646}647648if (peekAndMatch("SignedBy")) {649e.signedBy = expand(match("quoted string"));650}651return e;652}653654/**655* parse a domain entry656*/657private DomainEntry parseDomainEntry()658throws ParsingException, IOException659{660boolean ignoreEntry = false;661DomainEntry domainEntry;662String name = null;663Map<String, String> properties = new HashMap<>();664665match("domain");666name = match("domain name");667668while(!peek("{")) {669// get the domain properties670properties = parseProperties("{");671}672match("{");673domainEntry = new DomainEntry(name, properties);674675while(!peek("}")) {676677match("keystore");678name = match("keystore name");679// get the keystore properties680if (!peek("}")) {681properties = parseProperties(";");682}683match(";");684domainEntry.add(new KeyStoreEntry(name, properties));685}686match("}");687688return (ignoreEntry == true) ? null : domainEntry;689}690691/*692* Return a collection of domain properties or keystore properties.693*/694private Map<String, String> parseProperties(String terminator)695throws ParsingException, IOException {696697Map<String, String> properties = new HashMap<>();698String key;699String value;700while (!peek(terminator)) {701key = match("property name");702match("=");703704try {705value = expand(match("quoted string"));706} catch (PropertyExpander.ExpandException peee) {707throw new IOException(peee.getLocalizedMessage());708}709properties.put(key.toLowerCase(Locale.ENGLISH), value);710}711712return properties;713}714715// package-private: used by PolicyFile for static policy716static String[] parseExtDirs(String codebase, int start) {717718String s = System.getProperty(EXTDIRS_PROPERTY);719String globalPrefix = (start > 0 ? codebase.substring(0, start) : "file:");720int end = start + EXTDIRS_EXPANSION.length();721String globalSuffix = (end < codebase.length() ? codebase.substring(end) :722(String) null);723724String[] dirs = null;725String localSuffix;726if (s != null) {727StringTokenizer st =728new StringTokenizer(s, File.pathSeparator);729int count = st.countTokens();730dirs = new String[count];731for (int i = 0; i < count; i++) {732File file = new File(st.nextToken());733dirs[i] = sun.net.www.ParseUtil.encodePath734(file.getAbsolutePath());735736if (!dirs[i].startsWith("/")) {737dirs[i] = "/" + dirs[i];738}739740localSuffix = (globalSuffix == null ?741(dirs[i].endsWith("/") ? "*" : "/*") :742globalSuffix);743744dirs[i] = globalPrefix + dirs[i] + localSuffix;745}746}747return dirs;748}749750private boolean peekAndMatch(String expect)751throws ParsingException, IOException752{753if (peek(expect)) {754match(expect);755return true;756} else {757return false;758}759}760761private boolean peek(String expect) {762boolean found = false;763764switch (lookahead) {765766case StreamTokenizer.TT_WORD:767if (expect.equalsIgnoreCase(st.sval))768found = true;769break;770case ',':771if (expect.equalsIgnoreCase(","))772found = true;773break;774case '{':775if (expect.equalsIgnoreCase("{"))776found = true;777break;778case '}':779if (expect.equalsIgnoreCase("}"))780found = true;781break;782case '"':783if (expect.equalsIgnoreCase("\""))784found = true;785break;786case '*':787if (expect.equalsIgnoreCase("*"))788found = true;789break;790case ';':791if (expect.equalsIgnoreCase(";"))792found = true;793break;794default:795796}797return found;798}799800private String match(String expect)801throws ParsingException, IOException802{803String value = null;804805switch (lookahead) {806case StreamTokenizer.TT_NUMBER:807throw new ParsingException(st.lineno(), expect,808ResourcesMgr.getString("number.") +809String.valueOf(st.nval));810case StreamTokenizer.TT_EOF:811MessageFormat form = new MessageFormat(812ResourcesMgr.getString813("expected.expect.read.end.of.file."));814Object[] source = {expect};815throw new ParsingException(form.format(source));816case StreamTokenizer.TT_WORD:817if (expect.equalsIgnoreCase(st.sval)) {818lookahead = st.nextToken();819} else if (expect.equalsIgnoreCase("permission type")) {820value = st.sval;821lookahead = st.nextToken();822} else if (expect.equalsIgnoreCase("principal type")) {823value = st.sval;824lookahead = st.nextToken();825} else if (expect.equalsIgnoreCase("domain name") ||826expect.equalsIgnoreCase("keystore name") ||827expect.equalsIgnoreCase("property name")) {828value = st.sval;829lookahead = st.nextToken();830} else {831throw new ParsingException(st.lineno(), expect,832st.sval);833}834break;835case '"':836if (expect.equalsIgnoreCase("quoted string")) {837value = st.sval;838lookahead = st.nextToken();839} else if (expect.equalsIgnoreCase("permission type")) {840value = st.sval;841lookahead = st.nextToken();842} else if (expect.equalsIgnoreCase("principal type")) {843value = st.sval;844lookahead = st.nextToken();845} else {846throw new ParsingException(st.lineno(), expect, st.sval);847}848break;849case ',':850if (expect.equalsIgnoreCase(","))851lookahead = st.nextToken();852else853throw new ParsingException(st.lineno(), expect, ",");854break;855case '{':856if (expect.equalsIgnoreCase("{"))857lookahead = st.nextToken();858else859throw new ParsingException(st.lineno(), expect, "{");860break;861case '}':862if (expect.equalsIgnoreCase("}"))863lookahead = st.nextToken();864else865throw new ParsingException(st.lineno(), expect, "}");866break;867case ';':868if (expect.equalsIgnoreCase(";"))869lookahead = st.nextToken();870else871throw new ParsingException(st.lineno(), expect, ";");872break;873case '*':874if (expect.equalsIgnoreCase("*"))875lookahead = st.nextToken();876else877throw new ParsingException(st.lineno(), expect, "*");878break;879case '=':880if (expect.equalsIgnoreCase("="))881lookahead = st.nextToken();882else883throw new ParsingException(st.lineno(), expect, "=");884break;885default:886throw new ParsingException(st.lineno(), expect,887new String(new char[] {(char)lookahead}));888}889return value;890}891892/**893* skip all tokens for this entry leaving the delimiter ";"894* in the stream.895*/896private void skipEntry() throws ParsingException, IOException {897while(lookahead != ';') {898switch (lookahead) {899case StreamTokenizer.TT_NUMBER:900throw new ParsingException(st.lineno(), ";",901ResourcesMgr.getString("number.") +902String.valueOf(st.nval));903case StreamTokenizer.TT_EOF:904throw new ParsingException(ResourcesMgr.getString905("expected.read.end.of.file."));906default:907lookahead = st.nextToken();908}909}910}911912/**913* Each grant entry in the policy configuration file is914* represented by a915* GrantEntry object. <p>916*917* <p>918* For example, the entry919* <pre>920* grant signedBy "Duke" {921* permission java.io.FilePermission "/tmp", "read,write";922* };923*924* </pre>925* is represented internally926* <pre>927*928* pe = new PermissionEntry("java.io.FilePermission",929* "/tmp", "read,write");930*931* ge = new GrantEntry("Duke", null);932*933* ge.add(pe);934*935* </pre>936*937* @author Roland Schemers938*939* version 1.19, 05/21/98940*/941942public static class GrantEntry {943944public String signedBy;945public String codeBase;946public LinkedList<PrincipalEntry> principals;947public Vector<PermissionEntry> permissionEntries;948949public GrantEntry() {950principals = new LinkedList<PrincipalEntry>();951permissionEntries = new Vector<PermissionEntry>();952}953954public GrantEntry(String signedBy, String codeBase) {955this.codeBase = codeBase;956this.signedBy = signedBy;957principals = new LinkedList<PrincipalEntry>();958permissionEntries = new Vector<PermissionEntry>();959}960961public void add(PermissionEntry pe)962{963permissionEntries.addElement(pe);964}965966public boolean remove(PrincipalEntry pe)967{968return principals.remove(pe);969}970971public boolean remove(PermissionEntry pe)972{973return permissionEntries.removeElement(pe);974}975976public boolean contains(PrincipalEntry pe)977{978return principals.contains(pe);979}980981public boolean contains(PermissionEntry pe)982{983return permissionEntries.contains(pe);984}985986/**987* Enumerate all the permission entries in this GrantEntry.988*/989public Enumeration<PermissionEntry> permissionElements(){990return permissionEntries.elements();991}992993994public void write(PrintWriter out) {995out.print("grant");996if (signedBy != null) {997out.print(" signedBy \"");998out.print(signedBy);999out.print('"');1000if (codeBase != null)1001out.print(", ");1002}1003if (codeBase != null) {1004out.print(" codeBase \"");1005out.print(codeBase);1006out.print('"');1007if (principals != null && principals.size() > 0)1008out.print(",\n");1009}1010if (principals != null && principals.size() > 0) {1011Iterator<PrincipalEntry> pli = principals.iterator();1012while (pli.hasNext()) {1013out.print(" ");1014PrincipalEntry pe = pli.next();1015pe.write(out);1016if (pli.hasNext())1017out.print(",\n");1018}1019}1020out.println(" {");1021Enumeration<PermissionEntry> enum_ = permissionEntries.elements();1022while (enum_.hasMoreElements()) {1023PermissionEntry pe = enum_.nextElement();1024out.write(" ");1025pe.write(out);1026}1027out.println("};");1028}10291030public Object clone() {1031GrantEntry ge = new GrantEntry();1032ge.codeBase = this.codeBase;1033ge.signedBy = this.signedBy;1034ge.principals = new LinkedList<PrincipalEntry>(this.principals);1035ge.permissionEntries =1036new Vector<PermissionEntry>(this.permissionEntries);1037return ge;1038}1039}10401041/**1042* Principal info (class and name) in a grant entry1043*/1044public static class PrincipalEntry implements Principal {10451046public static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS";1047public static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME";1048public static final String REPLACE_NAME = "PolicyParser.REPLACE_NAME";10491050String principalClass;1051String principalName;10521053/**1054* A PrincipalEntry consists of the Principal class and Principal name.1055*1056* @param principalClass the Principal class1057* @param principalName the Principal name1058* @throws NullPointerException if principalClass or principalName1059* are null1060*/1061public PrincipalEntry(String principalClass, String principalName) {1062if (principalClass == null || principalName == null)1063throw new NullPointerException(ResourcesMgr.getString(1064"null.principalClass.or.principalName"));1065this.principalClass = principalClass;1066this.principalName = principalName;1067}10681069boolean isWildcardName() {1070return principalName.equals(WILDCARD_NAME);1071}10721073boolean isWildcardClass() {1074return principalClass.equals(WILDCARD_CLASS);1075}10761077boolean isReplaceName() {1078return principalClass.equals(REPLACE_NAME);1079}10801081public String getPrincipalClass() {1082return principalClass;1083}10841085public String getPrincipalName() {1086return principalName;1087}10881089public String getDisplayClass() {1090if (isWildcardClass()) {1091return "*";1092} else if (isReplaceName()) {1093return "";1094}1095else return principalClass;1096}10971098public String getDisplayName() {1099return getDisplayName(false);1100}11011102public String getDisplayName(boolean addQuote) {1103if (isWildcardName()) {1104return "*";1105}1106else {1107if (addQuote) return "\"" + principalName + "\"";1108else return principalName;1109}1110}11111112@Override1113public String getName() {1114return principalName;1115}11161117@Override1118public String toString() {1119if (!isReplaceName()) {1120return getDisplayClass() + "/" + getDisplayName();1121} else {1122return getDisplayName();1123}1124}11251126/**1127* Test for equality between the specified object and this object.1128* Two PrincipalEntries are equal if their class and name values1129* are equal.1130*1131* @param obj the object to test for equality with this object1132* @return true if the objects are equal, false otherwise1133*/1134@Override1135public boolean equals(Object obj) {1136if (this == obj)1137return true;11381139if (!(obj instanceof PrincipalEntry))1140return false;11411142PrincipalEntry that = (PrincipalEntry)obj;1143return (principalClass.equals(that.principalClass) &&1144principalName.equals(that.principalName));1145}11461147/**1148* Return a hashcode for this PrincipalEntry.1149*1150* @return a hashcode for this PrincipalEntry1151*/1152@Override1153public int hashCode() {1154return principalClass.hashCode();1155}11561157public void write(PrintWriter out) {1158out.print("principal " + getDisplayClass() + " " +1159getDisplayName(true));1160}1161}11621163/**1164* Each permission entry in the policy configuration file is1165* represented by a1166* PermissionEntry object. <p>1167*1168* <p>1169* For example, the entry1170* <pre>1171* permission java.io.FilePermission "/tmp", "read,write";1172* </pre>1173* is represented internally1174* <pre>1175*1176* pe = new PermissionEntry("java.io.FilePermission",1177* "/tmp", "read,write");1178* </pre>1179*1180* @author Roland Schemers1181*1182* version 1.19, 05/21/981183*/11841185public static class PermissionEntry {11861187public String permission;1188public String name;1189public String action;1190public String signedBy;11911192public PermissionEntry() {1193}11941195public PermissionEntry(String permission,1196String name,1197String action) {1198this.permission = permission;1199this.name = name;1200this.action = action;1201}12021203/**1204* Calculates a hash code value for the object. Objects1205* which are equal will also have the same hashcode.1206*/1207@Override1208public int hashCode() {1209int retval = permission.hashCode();1210if (name != null) retval ^= name.hashCode();1211if (action != null) retval ^= action.hashCode();1212return retval;1213}12141215@Override1216public boolean equals(Object obj) {1217if (obj == this)1218return true;12191220if (! (obj instanceof PermissionEntry))1221return false;12221223PermissionEntry that = (PermissionEntry) obj;12241225if (this.permission == null) {1226if (that.permission != null) return false;1227} else {1228if (!this.permission.equals(that.permission)) return false;1229}12301231if (this.name == null) {1232if (that.name != null) return false;1233} else {1234if (!this.name.equals(that.name)) return false;1235}12361237if (this.action == null) {1238if (that.action != null) return false;1239} else {1240if (!this.action.equals(that.action)) return false;1241}12421243if (this.signedBy == null) {1244if (that.signedBy != null) return false;1245} else {1246if (!this.signedBy.equals(that.signedBy)) return false;1247}12481249// everything matched -- the 2 objects are equal1250return true;1251}12521253public void write(PrintWriter out) {1254out.print("permission ");1255out.print(permission);1256if (name != null) {1257out.print(" \"");12581259// ATTENTION: regex with double escaping,1260// the normal forms look like:1261// $name =~ s/\\/\\\\/g; and1262// $name =~ s/\"/\\\"/g;1263// and then in a java string, it's escaped again12641265out.print(name.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\\"", "\\\\\\\""));1266out.print('"');1267}1268if (action != null) {1269out.print(", \"");1270out.print(action);1271out.print('"');1272}1273if (signedBy != null) {1274out.print(", signedBy \"");1275out.print(signedBy);1276out.print('"');1277}1278out.println(";");1279}1280}12811282/**1283* Each domain entry in the keystore domain configuration file is1284* represented by a DomainEntry object.1285*/1286static class DomainEntry {1287private final String name;1288private final Map<String, String> properties;1289private final Map<String, KeyStoreEntry> entries;12901291DomainEntry(String name, Map<String, String> properties) {1292this.name = name;1293this.properties = properties;1294entries = new HashMap<>();1295}12961297String getName() {1298return name;1299}13001301Map<String, String> getProperties() {1302return properties;1303}13041305Collection<KeyStoreEntry> getEntries() {1306return entries.values();1307}13081309void add(KeyStoreEntry entry) throws ParsingException {1310String keystoreName = entry.getName();1311if (!entries.containsKey(keystoreName)) {1312entries.put(keystoreName, entry);1313} else {1314MessageFormat form = new MessageFormat(ResourcesMgr.getString(1315"duplicate.keystore.name"));1316Object[] source = {keystoreName};1317throw new ParsingException(form.format(source));1318}1319}13201321@Override1322public String toString() {1323StringBuilder s =1324new StringBuilder("\ndomain ").append(name);13251326if (properties != null) {1327for (Map.Entry<String, String> property :1328properties.entrySet()) {1329s.append("\n ").append(property.getKey()).append('=')1330.append(property.getValue());1331}1332}1333s.append(" {\n");13341335if (entries != null) {1336for (KeyStoreEntry entry : entries.values()) {1337s.append(entry).append("\n");1338}1339}1340s.append("}");13411342return s.toString();1343}1344}13451346/**1347* Each keystore entry in the keystore domain configuration file is1348* represented by a KeyStoreEntry object.1349*/13501351static class KeyStoreEntry {1352private final String name;1353private final Map<String, String> properties;13541355KeyStoreEntry(String name, Map<String, String> properties) {1356this.name = name;1357this.properties = properties;1358}13591360String getName() {1361return name;1362}13631364Map<String, String> getProperties() {1365return properties;1366}13671368@Override1369public String toString() {1370StringBuilder s = new StringBuilder("\n keystore ").append(name);1371if (properties != null) {1372for (Map.Entry<String, String> property :1373properties.entrySet()) {1374s.append("\n ").append(property.getKey()).append('=')1375.append(property.getValue());1376}1377}1378s.append(";");13791380return s.toString();1381}1382}13831384public static class ParsingException extends GeneralSecurityException {13851386private static final long serialVersionUID = -4330692689482574072L;13871388private String i18nMessage;13891390/**1391* Constructs a ParsingException with the specified1392* detail message. A detail message is a String that describes1393* this particular exception, which may, for example, specify which1394* algorithm is not available.1395*1396* @param msg the detail message.1397*/1398public ParsingException(String msg) {1399super(msg);1400i18nMessage = msg;1401}14021403public ParsingException(int line, String msg) {1404super("line " + line + ": " + msg);1405MessageFormat form = new MessageFormat1406(ResourcesMgr.getString("line.number.msg"));1407Object[] source = {new Integer(line), msg};1408i18nMessage = form.format(source);1409}14101411public ParsingException(int line, String expect, String actual) {1412super("line " + line + ": expected [" + expect +1413"], found [" + actual + "]");1414MessageFormat form = new MessageFormat(ResourcesMgr.getString1415("line.number.expected.expect.found.actual."));1416Object[] source = {new Integer(line), expect, actual};1417i18nMessage = form.format(source);1418}14191420@Override1421public String getLocalizedMessage() {1422return i18nMessage;1423}1424}14251426public static void main(String arg[]) throws Exception {1427try (FileReader fr = new FileReader(arg[0]);1428FileWriter fw = new FileWriter(arg[1])) {1429PolicyParser pp = new PolicyParser(true);1430pp.read(fr);1431pp.write(fw);1432}1433}1434}143514361437