---- 在企业内部网中,本文提出了使用安全策略文件来设置java程序权限的一种简单的方法。由于企业内部网中各台计算机的位置、用途和安全性明确,更适于使用安全策略文件来设置java的权限,软件的安装、设置、升级和迁移都非常的方便,并且,还可以和数字签名配合使用,更重要的是,可以细分每个java程序的权限,使用起来灵活方便。
一. Java中安全策略的概念
---- Java应用程序环境的安全策略,详细说明了对于不同的代码所拥有的不同资源的许可,它由一个Policy对象来表达。为了让applet(或者运行在SecurityManager下的一个应用程序)能够执行受保护的行为,例如读写文件,applet(或Java应用程序)必须获得那项操作的许可,安全策略文件就是用来实现这些许可。
---- Policy对象可能有多个实体,虽然任何时候只能有一个起作用。当前安装的Policy对象,在程序中可以通过调用getPolicy方法得到,也可以通过调用setPolicy方法改变。Policy对象评估整个策略,返回一个适当的Permissions对象,详细说明那些代码可以访问那些资源。
---- 策略文件可以储存在无格式的ASCII文件,或Policy类的二进制文件,或数据库中。本文仅讨论无格式的ASCII文件的形式。
二. Policy文件的格式
---- 为了能够更好地理解下面的内容,建议在阅读时参照\jdk1.2\jre\lib\security\java.policy文件和\jdk1.2\jre\lib\security\java.security文件的内容。
---- 1. Policy文件的语法格式与说明
---- 一个Policy文件实质上是一个记录列表,它可能含有一个“keystore”记录,以及含有零个或多个“grant”记录。其格式如下:
keystore "some_keystore_url",
"keystore_type";
grant [SignedBy "signer_names"]
[, CodeBase "URL"] {
Permission permission_class_name
[ "target_name" ]
[, "action"] [, SignedBy "signer_names"];
Permission ...
};
---- 1.1"keystore"记录
---- 一个keystore是一个私有密钥(private keys)数据库和相应的数字签名,例如X.509证书。Policy文件中可能只有一条keystore记录(也可能不含有该记录),它可以出现在文件中grant记录以外的任何地方。Policy配置文件中指定的keystores用于寻找grant记录中指定的、签名者的公共密钥(public keys),如果任何grant记录指定签名者(signer_names),那么,keystore记录必须出现在policy配置文件中。
---- "some_keystore_url"是指keystore的URL位置,"keystore_type"是指keystore的类型。第二个选项是可选项,如果没有指定,该类型则假定由安全属性文件(java.security)中的"keystore.type"属性来确定。keystore类型定义了keystore信息的存储和数据格式,用于保护keystore中的私有密钥和keystore完整性的算法。Sun Microsystems支持的缺省类型为“JKS”。
---- 1.2"grant"记录
---- 在Policy文件中的每一个grant记录含有一个CodeSource(一个指定的代码)及其permission(许可)。
---- Policy文件中的每一条grant记录遵循下面的格式,以保留字“grant”开头,表示一条新的记录的开始,“Permission”是另一个保留字,在记录中用来标记一个新的许可的开始。每一个grant记录授予一个指定的代码(CodeBase)一套许可(Permissions)。
---- permission_class_name必须是一个合格并存在的类名,例如java.io.FilePermission,不能使用缩写(例如,FilePermission)。
---- target_name用来指定目标类的位置,action用于指定目标类拥有的权限。
---- target_name可以直接指定类名(可以是绝对或相对路径),目录名,也可以是下面的通配符:
directory/* 目录下的所有文件
*当前目录的所有文件
directory/-目录下的所有文件,包括子目录
- 当前目录下的所有文件,包括子目录
《ALL FILES》文件系统中的所有文件
对于java.io.FilePermission,action可以是:
read, write, delete和execute。
对于java.net.SocketPermission,action可以是:
listen,accept,connect,read,write。
---- 1.3 Policy文件中的属性扩展(Property Expansion)
---- 属性扩展与shell中使用的变量扩展类似,它的格式为:
"${some.property}"
实际使用的例子为:
permission java.io.FilePermission
"${user.home}", "read";
"${user.home}"的值为"d:\Project",
因此,下面的语句和上面的语句是一样的:
permission java.io.FilePermission "
d:\Project ", "read";
三. 实例
---- 当初始化Policy时,首先装载系统Policy,然后再增加用户Policy,如果两者都不存在,则使用缺省的Policy,即原始的沙箱模型。
---- 系统Policy文件的缺省位置为:
{java.home}/lib/security/java.policy (Solaris)
{java.home}\lib\security\java.policy (Windows)
用户Policy文件的缺省位置为:
{user.home}/.java.policy (Solaris)
{user.home}\.java.policy (Windows)
---- 其实,在实际使用中,我们可能不会象上面介绍的那么复杂,特别是在不使用数字签名时。这时,我们完全可以借鉴JDK 1.2提供给我们的现成的\jdk1.2\jre\lib\security\java.policy文件,根据我们的需要作相应的修改,本文就针对不使用数字签名情况详细说明安全策略文件的用法。
---- 下面,是一个完整的在Windows 95/98/NT下使用的.java.policy文件。在文件中,分别使用注释的形式说明了每个“permission”记录的用途。
// For LanServerTalk.java and LanClientTalk.java
grant {
//对系统和用户目录“读”的权限
permission java.util.PropertyPermission
"user.dir", "read";
permission java.util.PropertyPermission
"user.home", "read";
permission java.util.PropertyPermission
"java.home", "read";
permission java.util.PropertyPermission
"java.class.path", "read";
permission java.util.PropertyPermission
"user.name", "read";
//对线程和线程组的操作权限
permission java.lang.RuntimePermission
"modifyThread";
permission java.lang.RuntimePermission
"modifyThreadGroup";
//操作Socket端口的各种权限
permission java.net.SocketPermission
"-", "listen";
permission java.net.SocketPermission
"-", "accept";
permission java.net.SocketPermission
"-", "connect";
permission java.net.SocketPermission "-", "read";
permission java.net.SocketPermission "-", "write";
//读写文件的权限
permission java.io.FilePermission "-", "read";
permission java.io.FilePermission "-", "write";
//退出系统的权限,例如System.exit(0)
permission java.lang.RuntimePermission "exitVM";
};
四. java.policy文件的使用
---- 对于windows 95/98/NT,使用.java.policy文件的方法主要有下面两种。
---- 1. 使用缺省目录
---- 我们可以简单地将编辑好的.java.policy文件拷贝到windows 95/98/NT的HOME目录,这时,所有的applet(或Java应用程序)可能都拥有某些相同的权限,使用起来简单,但不灵活(例如:对于java.io.FilePermission ,其目标类的target_name必须使用绝对路径),如果不是在企业内部网中使用,还可能存在一定安全隐患。
---- 2. 在命令行中指定
---- 在命令行,如果我们希望传递一个Policy文件给appletviewer,还可以使用"-J-Djava.security.policy"参数来指定policy的位置:
appletviewer -J-Djava.security.
policy=pURL myApplet
---- pURL为Policy文件的位置。下面,是一个实际的例子,以当前目录的.java.policy文件所指定的安全策略运行当前目录的LanServerTalk.html(文件中装载并运行LanServerTalk.java):
appletviewer -J-Djava.security.policy
=.java.policy LanServerTalk.html
---- 这种方法使用灵活,特别是作为一个软件包在企业内部网中发布时,安装、设置和迁移软件,基本无须修改Policy文件的内容,使用起来相当简单,而且,安全许可的范围控制较精细。
__________________________________________________________________________________
缺省策略实现和策略文件语法
上次修改时间: 1998 年 10 月 30 日
Java 应用程序环境的策略(对不同来源的代码指定权限)由 Policy 对象来表示。更明确地说,就是由 Policy
类(包含在 java.security
包中)的实现抽象方法的 Policy
子类来表示。
Policy 对象所用策略信息的源位置由 Policy 实现决定。缺省 Policy 实现从静态策略配置文件获得自己的信息。本文档的其余部分叙述了缺省 Policy 实现及其所读取的策略文件中必须使用的语法。有关使用 Policy Tool 来创建策略文件(不必知道所需语法)的详细信息,请参阅《策略工具文档》 (for Solaris) (for Windows)。
以下是本文档其余部分的概要:
缺省 Policy 实现
在缺省 Policy 实现中,可在一个或多个策略配置文件中指定策略。配置文件的作用是指定特定代码源的代码所能获得的权限。
可利用简单的文本编辑器或 Policy Tool 实用程序来编写策略文件。
缺省情况下,系统上只有单个全系统策略文件和唯一的(可选)用户策略文件。
首次调用缺省 Policy 对象的
getPermissions
方法或在任何时候调用 Policy 对象refresh
方法时,即对其进行初始化。初始化包括分析策略配置文件(请参阅策略文件语法)及组装 Policy 对象。
缺省策略文件位置
如前所述,系统在缺省情况下具有单个全系统策略文件和唯一的用户策略文件。
系统策略文件的缺省位置为:
java.home/lib/security/java.policy (Solaris) java.home\lib\security\java.policy (Windows)注意: java.home 指的是名为“java.home”的系统属性的值,它指定 JDK 的安装目录。
系统策略文件可用于授予全系统代码权限。与 JDK 一起安装的
java.policy
文件可向标准扩展 (Java standard extensions) 授予全部权限,允许任何用户在无特权要求的端口进行监听,同时允许任何代码读取某些对安全不敏感的“标准”属性(例如“os.name”和“file.separator”属性)。用户策略文件的缺省位置为:
user.home/.java.policy (Solaris) user.home\.java.policy (Windows)注意: user.home 指的是名为“user.home”的系统属性的值,它指定用户的主目录。在 Windows 系统中,假定用户名是 uName,“user.home”属性的缺省值为:
C:\Winnt\Profiles\uName(多用户 Windows NT 系统中) C:\Windows\Profiles\uName(多用户 Windows 95 系统中) C:\Windows(单用户 Windows 95 系统中)初始化 Policy 时,将首先加载系统策略,然后在 Policy 中添加用户策略。如果两种策略均不存在,则采用内置策略。该内置策略与原始的沙箱策略相同。
策略文件的位置在安全属性文件中指定。安全属性文件的位置为:
java.home/lib/security/java.security (Solaris) java.home\lib\security\java.security (Windows)如上所述,java.home 指示 JDK 的安装目录。策略文件的位置被指定为其名称具有以下形式的属性的值:
policy.url.n其中 n 为数字。应采用以下形式的语句行来指定每个属性值:
policy.url.n=URL其中,URL 为 URL 规范。
例如,安全属性文件中将把缺省系统和用户策略文件定义为:
policy.url.1=file:${java.home}/lib/security/java.policy policy.url.2=file:${user.home}/.java.policy有关利用特殊语法(例如利用 ${java.home} 来指定 java.home 属性值)来指定属性值的详细信息,请参阅属性扩展。
实际上,用户可以指定多个 URL(包括“http://”形式的 URL),从而加载所有指定的策略文件。也可注释掉或更改第二个 URL,从而禁止读取缺省用户策略文件。
该算法自 policy.url.1 开始,然后不断递增直到查不到 URL 为止。因此,如果有了 policy.url.1 和 policy.url.3,就不会读取 policy.url.3。
运行时指定其它策略文件
在执行应用程序时也可以指定附加的或不同的策略文件,方法是用“-Djava.security.policy”命令行参数来指定(该命令行参数设置 java.security.policy 属性值)。例如,如果使用
java -Djava.security.manager -Djava.security.policy=someURL SomeApp这里 someURL 是指定策略文件位置的 URL,则除了加载安全属性文件中指定的所有策略文件外,还会加载本方法所指定的策略文件。
注意:
- URL 可以是任何标准 URL,也可以只是当前目录下策略文件的文件名,如下例所示:
java -Djava.security.manager -Djava.security.policy=mypolicy WriteFile- “-Djava.security.manager”参数可确保缺省安全管理器已被安装,这样就容易对应用程序进行策略检查。如果应用程序 SomeApp 安装有安全管理器,则不需要该参数。
如果使用
java -Djava.security.manager -Djava.security.policy==someURL SomeApp(请注意双等号),就会仅使用指定的策略文件,而安全属性文件中指出的策略文件将被忽略。
如果要将策略文件传递给 appletviewer,就应使用参数“-J-Djava.security.policy”,如下所示:
appletviewer -J-Djava.security.policy=someURL myApplet请注意:如果将安全属性文件中的“policy.allowSystemProperty”属性设置为“false”,就会忽略“-Djava.security.policy”策略文件值(对于
java
和appletviewer
命令)。缺省值为“true”。
更改 Policy 实现
可以用其它 policy 类来代替缺省 Policy 实现类,前提是前者属于抽象 Policy 类的子类并可实现
getPermissions
方法(及其它必要的方法)。缺省 Policy 实现的更改可通过编辑安全属性文件来完成,其中安全属性文件指 JDK
lib/security
目录中的java.security
文件。下面给出一种可在
java.security
中设置的属性类型的形式:policy.provider=PolicyClassNamePolicyClassName 必须指定所需 Policy 实现类的完整名称。该属性的缺省安全属性文件项如下所示:
policy.provider=sun.security.provider.PolicyFile要想自定义安全属性文件项,可通过更改属性值来指定另一个类,如下例所示:
policy.provider=com.mycom.MyPolicy
策略文件语法
JDK 的策略配置文件可用于指定来自特定代码源的代码所能获得的权限(何种系统资源访问类型)。
为了使 applet(或在安全管理器下运行的应用程序)能够执行受保护的动作(例如读写文件),必须向 applet(或应用程序)授予进行该动作的权限。在缺省 Policy 实现中,必须由策略配置文件中的 grant 项授予该权限。有关详细信息,请参阅以下内容及 “Java 安全体系结构规范”(唯一的例外是:代码对位于与它自身同一 (URL) 位置并且对那一位置子目录下的文件总是自动拥有读权限,而无需授予明确的权限)。
策略配置文件主要包含授权项列表。其中可能包含“keystore”(密钥仓库)项及零个或多个“grant”(授权)项。
Keystore 项
keystore 是存放私钥及相关数字证书(例如验证对应的公钥的 X.509 证书链)的数据库。keytool 实用程序 (for Solaris) (for Windows) 用于创建和管理密钥仓库。策略配置文件中所指定的 keystore 用于查找在该文件的授权项中所指定的签名人公钥。如果某一授权项指定了签名人别名(请参阅以下内容),则在策略配置文件中必须含有 keystore 项。
目前,在策略文件中只能有一个 keystore 项(第一项后的其它 keystore 项将被忽略),且该项可位于文件授权项以外的任何位置。其语法如下所示:
keystore "some_keystore_url", "keystore_type";其中“some_keystore_url”指定密钥仓库的 URL 位置,而“keystore_type”指定密钥仓库的类型。
URL 是相对于策略文件位置而言。因此,如果在安全属性文件中按以下方式指定策略文件:
policy.url.1=http://foo.bar.com/fum/some.policy而且策略文件中含有以下项:
keystore ".keystore";就会从下列位置加载密钥仓库:
http://foo.bar.com/fum/.keystoreURL 也可以是绝对 URL。
keystore type 定义密钥仓库信息的存储和数据格式,同时也定义用于保护密钥仓库中私钥及密钥仓库自身完整性的算法。Sun Microsystems 所支持的缺省类型是名为“JKS”的专用密钥仓库类型。因此,如果密钥仓库类型属于“JKS”,就无需在 keystore 项中加以指定。
授权项
通常认为执行代码来自于某“代码源”(由 CodeSource 类型的对象表示)。代码源不仅包含代码的源位置 (URL),而且还包括对包含与签写代码的私钥相对应的公钥的证书之引用。代码源中的证书通过用户密钥仓库中的符号别名引用。
每个授权项包括一个或多个“权限项”,前面为可选
codeBase
和signedBy
名字/值对,用于指定要授予权限的代码。授权项的基本格式如下所示:grant signedBy "signer_names", codeBase "URL" { permission permission_class_name "target_name", "action", signedBy "signer_names"; .... permission permission_class_name "target_name", "action", signedBy "signer_names"; };以上所有非斜体的项必须按原样出现(尽管大小写无关紧要且部分为可选项,如下所示)。 斜体项代表变量值。
授权项必须以
grant
开头。SignedBy 和 CodeBase 域
signedBy
和codeBase
名字/值对为可选域,其间的顺序无关紧要。
signedBy
值表示存储在密钥仓库中的证书别名。该证书内的公钥用于验证代码上的数字签名;用户可以向由私钥(私钥对应于该别名所指定的 keystore 项中的公钥)签名的代码授予权限。
signedBy
的值可以是由逗号分隔的多个别名。 例如“Adam,Eve,Charles”,其含义为“Adam,Eve 和 Charles 签名”;它们之间的关系是 AND(与)而非 OR(或)。更确切地说,“Adam 签名的代码”语句的含义是“JAR 文件中有含类文件的代码,这个 JAR 文件已用密钥仓库中别名为 Adam 的项中与公钥所对应的私钥签名”。
signedBy
域可选,这是因为如果省略该域,则表示“任何签名人”。代码是否有签名或由谁签名都没有关系。
codeBase
值表示的是代码源位置;用户可向来自该位置的代码授权。空codeBase
项表示“任何代码”;代码来源于何处没有关系。注意:
codeBase
值是 URL,因此应该始终用正斜杠(而不要用反斜杠)作为目录分隔符,即使代码源实际在 Windows 系统上。这样,如果 Windows 系统上代码的源位置实际上是C:\somepath\api\
,则codeBase
策略项的外观将如下所示:grant codeBase "file:/C:/somepath/api/" { ... }
codeBase
值的准确含义要取决于最后的字符。后面跟着“/”的codeBase
将匹配指定目录下的所有类文件(非 JAR 文件)。后面跟着“/*”的codeBase
将匹配该目录下的所有文件(类文件和 JAR 文件)。后面跟着“/-”的codeBase
将匹配该目录下的所有文件(类文件和 JAR 文件)及该目录下子目录中的所有文件。下表说明了各种不同的情况。
下载代码的 Codebase URL 策略中的 Codebase URL 是否匹配? java.sun.com/people/gong/ java.sun.com/people/gong 是
java.sun.com/people/gong/ java.sun.com/people/gong/ 是
java.sun.com/people/gong/ java.sun.com/people/gong/* 是
java.sun.com/people/gong/ java.sun.com/people/gong/- 是
java.sun.com/people/gong/appl.jar java.sun.com/people/gong/ 否
java.sun.com/people/gong/appl.jar java.sun.com/people/gong/- 是
java.sun.com/people/gong/appl.jar java.sun.com/people/gong/* 是
java.sun.com/people/gong/appl.jar java.sun.com/people/- 是
java.sun.com/people/gong/appl.jar java.sun.com/people/* 否
java.sun.com/people/gong/ java.sun.com/people/- 是
java.sun.com/people/gong/ java.sun.com/people/* 否
权限项
权限项必须以
permission
开头。上述模板中的字permission_class_name
的实际值可以是特定的权限类型(例如java.io.FilePermission
或java.lang.RuntimePermission
)。"action" 对于许多权限类型而言都是必需的,例如
java.io.FilePermission
(指定允许何种类型的文件访问权限)。 对于诸如java.lang.RuntimePermission
等权限类型则为可选项:既可以在 permission_class_name 之后的"target_name"
值中指定权限,也可以不指定权限。权限项的
signedBy
名字/值对为可选项。如果有名字/值对,则表示为已签名权限。意即必须由给定的别名对权限类签名,方可授予权限。例如,假定有以下授权项:grant { permission Foo "foobar", signedBy "FooSoft"; }如果将
Foo.class
权限放到 JAR 文件中,且该 JAR 文件已由与 "FooSoft" 别名所指定的证书中的公钥相对应的私钥签名,或在Foo.class
是系统类(因为系统类不受策略限制)的情况下,即可授予 Foo 权限类型。权限项中出现的项目必须按指定顺序出现(
permission
,permission_class_name,"target_name","action" 和signedBy
"signer_names")。分号表示项终止。大小写对于标识符(
permission
、signedBy
、codeBase
等)来说并不重要,但对于 permission_class_name 或作为值传递过来的字符串而言就很重要了。有关 Windows 系统上文件路径规范的注意事项
请注意:在指定
java.io.FilePermission
时,"target_name" 是文件路径。在 Windows 系统上,无论何时在字符串中(而不是在 codeBase URL 中)直接指定文件路径,路径中都需要两个反斜杠来代表一个实际的反斜杠,如下例所示:grant { permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read"; };原因在于:字符串是由符号处理器 (java.io.StreamTokenizer) 来处理的。符号处理器允许将“\”用作转义字符串(例如,“\n”表示换行),因此需要用两个反斜杠来表示一个反斜杠。符号处理器处理完以上文件路径字符串后,将把双反斜杠转换成单个反斜杠,其最终结果为:
"C:\users\cathy\foo.bat"
策略文件示例
策略配置文件中两项的示例如下所示:
// 如果代码由 "Duke" 签字,则向 /tmp 中的所有文件 // 授予读/写访问权限: grant signedBy "Duke" { permission java.io.FilePermission "/tmp/*", "read,write"; };// 授予所有用户以下权限:
grant { permission java.util.PropertyPermission "java.vendor"; };
另一个示例策略配置文件如下所示。
grant signedBy "sysadmin", codeBase "file:/home/sysadmin/*" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; permission java.security.SecurityPermission "Security.setProperty.*"; };本示例规定:只有满足以下条件的代码才能调用 Security 类中的方法以添加或删除提供者或者设置 Security 属性:
- 代码将从位于本地文件系统上“/home/sysadmin/”目录下的签名 JAR 文件中加载。
- 可以用密钥仓库中别名“sysadmin”所引用的公钥来校验签名。
可以忽略代码源中两个组件的任何一个(或两者)。下面是忽略
codeBase
的示例:grant signedBy "sysadmin" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };如果该策略生效,则来自 JAR 文件(由 "sysadmin" 签名)的代码可以添加/删除提供者,而不管 JAR 文件来源于何处。
下面是没有签名人的示例:
grant codeBase "file:/home/sysadmin/-" { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };这里,来自本地文件系统“/home/sysadmin/”目录下任意位置的代码都可以添加/删除提供者。 该代码不必签名。
下面是既不含
codeBase
也不含signedBy
的示例:grant { permission java.security.SecurityPermission "Security.insertProvider.*"; permission java.security.SecurityPermission "Security.removeProvider.*"; };此处,由于两个代码源组件均被忽略,因此任何代码(不管来自于何处,是否已签名或由何人签名)都可添加/删除提供者。
策略文件中的属性扩展
策略文件和安全属性文件中可以进行属性扩展。
属性扩展类似于扩展 shell 中的变量。也就是说,当类似
${some.property}的字符串出现在策略文件或安全属性文件中时,它将被扩展为系统属性的值。 例如,
permission java.io.FilePermission "${user.home}", "read";将把 "${user.home}" 扩展为使用 "user.home" 系统属性的值。如果该属性的值是 "/home/cathy",则以上示例等价于:
permission java.io.FilePermission "/home/cathy", "read";为了能在与平台无关的策略文件中使用,也可采用特殊记号 "${/}"。该记号是 "${file.separator}" 的简化表示。这种方式允许使用下列字符串:
permission java.io.FilePermission "${user.home}${/}*", "read";如果 "user.home" 属性的值是
/home/cathy
,而且是在 Solaris 系统上,则以上字符串将转换为:permission java.io.FilePermission "/home/cathy/*", "read";如果 "user.home" 值是
C:\users\cathy
,而且是在 Windows 系统上,则以上字符串将转换为:permission java.io.FilePermission "C:\users\cathy\*", "read";同样,作为一种特例,如果扩展 codebase 中的属性,例如
grant codeBase "file:${java.home}/lib/ext/"则任何文件分隔符都将自动转换为“/”。这样,在 Windows 系统上,以上字符串将转换为:
grant codeBase "file:C:/jdk1.2/lib/ext/"即使 "java.home" 被设置为
C:\jdk1.2
。因此,用户就不必也不应该在 codeBase 字符串中使用 ${/}。策略文件中允许使用双引号字符串的地方都可进行属性扩展。其中包括 "signer_names"、"URL"、"target_name" 和 "action" 域。
是否允许属性扩展由安全属性文件中的“policy.expandProperties”属性控制。如果该属性为真(缺省值),则允许扩展。
请注意:不能使用嵌套属性;嵌套属性将无效。 例如,
"${user.${foo}}"是无效的,即使将“foo”属性设置为“home”。原因在于属性解析程序不能识别嵌套属性;解析程序只是简单地搜索第一个“${”,然后继续搜索直到找到第一个“}”为止,同时试图将搜索结果(这里是 "${user.$foo}")解释为属性。如果没有这种属性,则解析程序就会发生解释失败。
也请注意:如果在 grant 项、permission 项或 keystore 项中无法扩展某个属性,则该项将被忽略。例如,如果在没有定义系统属性“foo”的情况下使用语句:
grant codeBase "${foo}" { permission ...; permission ...; };则该 grant 项中的所有权限都将被忽略。如果使用语句:
grant { permission Foo "${foo}"; permission Bar; };则将仅忽略“permission Foo...”项。最后,如果使用语句:
keystore "${foo}";则将忽略 keystore 项。
Windows 系统、文件路径和属性的扩展
如上所述,在 Windows 系统上,当直接在字符串中(而不是在 codeBase URL 中)指定文件路径时,用户需要用两个反斜杠来代表文件路径中一个实际的反斜杠,如下例所示:
grant { permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read"; };原因在于:字符串是由符号处理器 (java.io.StreamTokenizer) 来处理的。符号处理器允许将“\”用作转义字符串(例如,“\n”表示换行),因此需要用两个反斜杠来表示一个反斜杠。符号处理器处理完以上文件路径字符串后,将把双反斜杠转换成单个反斜杠,其最终结果为:
"C:\users\cathy\foo.bat"符号处理器处理完字符串后,即进行字符串中的属性扩展。因此,如果使用字符串:
"${user.home}\\foo.bat"则符号处理器首先处理字符串,即将双反斜杠转换成单个反斜杠,其结果为:
"${user.home}\foo.bat"随即扩展 ${user.home} 属性,其最终结果为:
"C:\users\cathy\foo.bat"以上假定 "user.home" 的值是
C:\users\cathy
。当然,为实现与平台无关,最好在开始指定字符串时不要显式带上斜杠,即可以用 ${/} 属性来代替,如下例所示:"${user.home}${/}foo.bat"
所有评论(0)