JDKでのアクセス権
アクセス権は、システム・リソースへのアクセスを表します。アプレット(またはセキュリティ・マネージャとともに実行するアプリケーション)が、リソースへのアクセスを許可されるためには、アクセスを試みるコードに対し、該当するアクセス権を明示的に与える必要があります。
一般に、アクセス権には名前(「ターゲット名」とも呼ばれる)があり、場合によっては、カンマで区切られた1つ以上のアクションのリストを持つこともあります。たとえば、次のコードでは、/tmp
ディレクトリのabc
という名前のファイルへの読取りアクセスを表すFilePermission
オブジェクトを作成します。
perm = new java.io.FilePermission("/tmp/abc", "read");
ここでは、ターゲット名が/tmp/abc
で、アクション文字列がread
になります。
重要:
前述の文によって、アクセス権オブジェクトが作成されます。アクセス権オブジェクトは、システム・リソースを表しますが、システム・リソースへのアクセスを許可することはありません。アクセス権オブジェクトは、実効性のあるポリシーに基づいて作成され、コードへ割り当てられ(「付与」され)ます。アクセス権オブジェクトが、あるコードに割り当てられると、そのコードはアクセス権オブジェクトで指定されたシステム・リソースへ、指定された方法でアクセスするアクセス権が付与されます。現在のセキュリティ・マネージャが、アクセス判断を行う際に、アクセス権オブジェクトを作成することもあります。この場合、ターゲットのアクセス権オブジェクトは、要求されたアクセスに基づいて作成されます。さらに、ターゲットのアクセス権オブジェクトは、要求を行うコードに付与され、かつ要求を行うコードが保持する、アクセス権オブジェクトに照らしてチェックされます。Javaアプリケーション環境のポリシーは、Policyオブジェクトにより表現されます。"JavaPolicy"
Policy実装では、1つまたは複数のポリシー構成ファイルからポリシーを指定できます。ポリシー・ファイルは、指定したコード・ソースのコードにどのアクセス権を許可するかを指定します。次は、/home/sysadmin
ディレクトリのコードに対して/tmp/abc
ファイルへの読取りアクセスを許可するサンプル・ポリシー・ファイルのエントリです。
grant codeBase "file:/home/sysadmin/" {
permission java.io.FilePermission "/tmp/abc", "read";
};
ポリシー・ファイルの場所、およびポリシー・ファイルにより付与するアクセス権の詳細は、デフォルトのPolicyの実装とポリシー・ファイルの構文を参照してください。
技術的な観点から言うと、リソースへのアクセスを試みる場合は、実行スレッド上のコードに「特権設定」のマークが付けられていないかぎり、実行スレッドが利用するコードはすべて、そのリソースへのアクセス権を保持する必要があります。付録A: 特権ブロックのためのAPIを参照してください。
アクセス権の説明とリスク
次は、組込みのすべてのJDKアクセス権タイプのリストです。各アクセス権タイプのクラスの概要では、各アクセス権を付与した場合のリスクについて説明します。
- java.awt.AWTPermission
- java.io.FilePermission
- java.io.SerializablePermission
- java.lang.RuntimePermission
- java.lang.management.ManagementPermission
- java.lang.reflect.ReflectPermission
- java.net.NetPermission
- java.net.URLPermission
- java.net.SocketPermission
- java.nio.file.LinkPermission
- java.security.AllPermission
- java.security.SecurityPermission
- java.security.UnresolvedPermission
- java.sql.SQLPermission
- java.util.logging.LoggingPermission
- java.util.PropertyPermission
- javax.management.MBeanPermission
- javax.management.MBeanServerPermission
- javax.management.MBeanTrustPermission
- javax.management.remote.SubjectDelegationPermission
- javax.net.ssl.SSLPermission
- javax.security.auth.AuthPermission
- javax.security.auth.PrivateCredentialPermission
- javax.security.auth.kerberos.DelegationPermission
- javax.security.auth.kerberos.ServicePermission
- javax.smartcardio.CardPermission
- javax.sound.sampled.AudioPermission
注意:
FilePermissionパス名の正規化方法における変更に関する重要な情報については、付録A: FilePermissionのパス名の正規化がデフォルトで無効化を参照してください。
メソッドとその呼出しに必要なアクセス権
次の表は、アクセス権を必要とするメソッドのリストであり、どのSecurityManagerメソッドが呼び出され、どのアクセス権がそのSecurityManagerメソッドのデフォルト実装によってチェックされるかを示します。
注意:
これは完全なリストではなく、アクセス権を必要とするその他のメソッドも存在します。SecurityException
をスローするメソッドと必要なアクセス権の詳細は、Java SEおよびJDK API仕様を参照してください。
SecurityManager
メソッドのデフォルトの実装では、SecurityManagerメソッド列の対応するエントリで示されているアクセス権が現在有効なポリシーで与えられている場合だけ、メソッド列で示したメソッドを呼び出すことができます。たとえば、次のような表の行があるとします。
メソッド | 呼び出されるSecurityManagerメソッド | アクセス権 |
---|---|---|
|
checkPermission | java.awt.AWTPermission "accessEventQueue"; |
この表の行では、java.awt.ToolkitクラスのgetSystemEventQueueメソッドへの呼出しは、SecurityManagerメソッドcheckPermissionへの呼出しになることを指定します。これは、呼出しスタック上のコードに次のアクセス権が与えられている場合にのみ成功します。
java.awt.AWTPermission "accessEventQueue";
表の行は次の形式を持ち、アクセス権名中の文字列{foo}
はfoo
の実行時の値で置き換えらます。
メソッド | 呼び出されるSecurityManagerメソッド | アクセス権 |
---|---|---|
|
checkXXX | SomePermission "{foo}"; |
次の例を見てください。
メソッド | 呼び出されるSecurityManagerメソッド | アクセス権 |
---|---|---|
|
checkRead(String) | java.io.FilePermission "{name}", "read"; |
FileInputStream
メソッド(この場合はコンストラクタ)を、次のように引数name
に/test/MyTestFile
を指定して呼び出したとします。
FileInputStream("/test/MyTestFile");
この呼出しは、現在のポリシーで次のアクセス権が設定され、/test/MyTestFile
ファイルへの読取りアクセスが許可されていないと行えません。
java.io.FilePermission "/test/MyTestFile", "read";
より正確には、アクセス権は、このように明示的に設定されているか、次のように、別のアクセス権により暗黙に設定されている必要があります。
java.io.FilePermission "/test/*", "read";
「/test
」ディレクトリに含まれる任意のファイルへの読取りアクセスが許可されています。
中カッコで囲まれた項目が、特定のメソッド引数と同一ではなく、関係のある値を表す場合もあります。次はその例です。
メソッド | 呼び出されるSecurityManagerメソッド | アクセス権 |
---|---|---|
java.net.DatagramSocket public synchronized void receive(DatagramPacket p); |
checkAccept({host}, {port}) | java.net.SocketPermission "{host}:{port}", "accept"; |
ここでは、適切なホストおよびポートの値がreceive
メソッドにより計算されて、checkAccept
に渡されます。
ほとんどの場合、呼び出されるSecurityManagerメソッドの名前のみが一覧表示されます。メソッドは、複数ある同名のメソッドのいずれかであり、引数の型も一覧表示されます。たとえば、checkRead(String)
やcheckRead(FileDescriptor)
などがあります。引数が関係するその他の場合にも、引数は一覧表示されます。
次の表は、パッケージ名順になっています。最初にjava.awt
パッケージ内のクラスのメソッド、次にjava.beans
パッケージ内のクラスのメソッド、という順番です。
表1-6 メソッドおよびそのアクセス権
メソッド | SecurityManagerメソッド | アクセス権 |
---|---|---|
|
checkPermission | このGraphics2Dコンテキストが表示画面上のComponentに描画中であり、かつCompositeがAlphaCompositeクラスのインスタンスではなく、カスタム・オブジェクトの場合、java.awt.AWTPermission "readDisplayPixels" 。注意: setCompositeメソッドは、実際には抽象であるため、セキュリティ・チェックを呼び出すことはできない。こうした条件下では、メソッドの実際の実装ごとに、java.awt.AWTPermission("readDisplayPixels")アクセス権でjava.lang.SecurityManager checkPermissionメソッドを呼び出す必要がある。
|
|
checkPermission | java.awt.AWTPermission "createRobot" |
|
checkPermission | java.awt.AWTPermission "listenToAllAWTEvents" |
|
checkPrintJobAccess |
注意: getPrintJobメソッドは、実際には抽象であるため、セキュリティ・チェックを呼び出すことはできない。このメソッドの実際の各実装部分では、java.lang.SecurityManager checkPrintJobAccessメソッドを呼び出す必要があり、これは、アクセス権 |
|
checkPermission |
注意: getSystemClipboardメソッドは、実際には抽象であるため、セキュリティ・チェックを呼び出すことはできない。このメソッドの実際の各実装部分では、checkPermissionメソッドを呼び出す必要があり、これは、アクセス権 |
|
checkPermission | java.awt.AWTPermission "accessEventQueue" |
|
checkPermission | java.awt.AWTPermission "showWindowWithoutWarningBanner" が設定されていると、ウィンドウが表示されるときに、そのウィンドウがアプレットによって作成されていることを警告するバナーは表示されない。設定されていない場合は、バナーが表示される。
|
|
checkPropertiesAccess | java.util.PropertyPermission "*", "read,write" |
|
checkDelete(String) | java.io.FilePermission "{name}", "delete" |
|
checkRead(FileDescriptor) | java.lang.RuntimePermission "readFileDescriptor" |
(モードは、両方のRandomAccessFileコンストラクタで「r」) |
checkRead(String) | java.io.FilePermission "{name}", "read" |
|
checkWrite(FileDescriptor) | java.lang.RuntimePermission "writeFileDescriptor" |
|
checkWrite(String) | java.io.FilePermission "{name}", "write" |
|
checkPermission | java.io.SerializablePermission "enableSubstitution" |
|
checkPermission | java.io.SerializablePermission "enableSubclassImplementation" |
(モードは「rw」) |
checkRead(String)およびcheckWrite(String) | java.io.FilePermission "{name}", "read,write" |
|
checkPermission | loader がnullで、呼出し側のクラス・ローダーはnullでない場合、java.lang.RuntimePermission("getClassLoader")になる。 |
|
checkPermission | 呼出し側のクラス・ローダーがnullの場合、あるいは呼出し側のクラス・ローダーが、クラス・ローダーが要求されているクラスのクラス・ローダーと同じかその上位クラスの場合は、アクセス権は必要ない。それ以外の場合は、java.lang.RuntimePermission "getClassLoader" が必要。
|
|
checkMemberAccess(this, Member.DECLARED)、およびこのクラスがパッケージ内にある場合はcheckPackageAccess({pkgName}) | 「この」クラスのクラス・ローダーが呼出し側のクラス・ローダーと同一である場合は、デフォルトのcheckMemberAccessはどのようなアクセス権も必要としない。同一でない場合は、java.lang.RuntimePermission "accessDeclaredMembers" が必要。このクラスがパッケージ内にある場合、java.lang.RuntimePermission "accessClassInPackage.{pkgName}" も必要。
|
|
checkMemberAccess(this, Member.PUBLIC)、およびこのクラスがパッケージ内にある場合はcheckPackageAccess({pkgName}) | アクセス・タイプがMember.PUBLICの場合、デフォルトのcheckMemberAccessはどのようなアクセス権も必要としない。このクラスがパッケージ内にある場合、java.lang.RuntimePermission "accessClassInPackage.{pkgName}" が必要。
|
|
checkPermission | java.lang.RuntimePermission "getProtectionDomain" |
|
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
|
checkPermission | 呼出し側のクラス・ローダーがnullの場合、あるいは呼出し側のクラス・ローダーが、クラス・ローダーが要求されているクラスのクラス・ローダーと同じかその上位クラスの場合は、アクセス権は必要ない。それ以外の場合は、java.lang.RuntimePermission "getClassLoader" が必要。
|
|
checkExec | java.io.FilePermission "{command}", "execute" |
|
checkExit(status)。このとき、runFinalizersOnExitに対してstatusは0 | java.lang.RuntimePermission "exitVM.{status}" |
|
checkPermission | java.lang.RuntimePermission "shutdownHooks" |
|
checkLink({libName})。ここで、{libName}はlib、filenameまたはlibname引数 | java.lang.RuntimePermission "loadLibrary.{libName}" |
java.lang.SecurityManagerメソッド |
checkPermission | 表1-7を参照してください。 |
|
checkPropertiesAccess | java.util.PropertyPermission "*", "read,write" |
|
checkPropertyAccess | java.util.PropertyPermission "{key}", "read" |
|
checkPermission | java.lang.RuntimePermission "setIO" |
|
checkPermission | java.util.PropertyPermission "{key}", "write" |
|
checkPermission | java.lang.RuntimePermission "setSecurityManager" |
|
checkPermission | 呼出し側のクラス・ローダーがnullの場合、あるいは呼出し側のクラス・ローダーが、コンテキスト・クラス・ローダーが要求されているスレッドのコンテキスト・クラス・ローダーと同じかその上位クラスの場合は、アクセス権は必要ない。それ以外の場合は、java.lang.RuntimePermission "getClassLoader" が必要。
|
|
checkPermission | java.lang.RuntimePermission "setContextClassLoader" |
|
checkAccess(this) | java.lang.RuntimePermission "modifyThread" |
|
checkAccess({threadGroup}) | java.lang.RuntimePermission "modifyThreadGroup" |
|
checkAccess(this)。現在のスレッドが自分以外のスレッドを停止させようとしている場合は、checkPermissionも呼び出される。 | java.lang.RuntimePermission "modifyThread"。
現在のスレッドが自分以外のスレッドを停止させようとしている場合、 |
|
checkAccess(this)。現在のスレッドが自分以外のスレッドを停止させようとしている場合、またはobjがThreadDeathのインスタンスでない場合は、checkPermissionも呼び出される。 | java.lang.RuntimePermission "modifyThread"。
現在のスレッドが自分以外のスレッドを停止させようとしている場合、またはobjがThreadDeathのインスタンスではない場合は、 |
|
checkAccess({parentThreadGroup}) | java.lang.RuntimePermission "modifyThreadGroup" |
|
ThreadGroupメソッドの場合はcheckAccess(this)、Threadメソッドの場合はcheckAccess(group) | java.lang.RuntimePermission "modifyThreadGroup" |
|
checkAccess(this) | java.lang.RuntimePermission "modifyThreadGroup" が必要。スレッド・グループ内とそのすべてのサブグループ内のスレッドごとにjava.lang.Thread interrupt()メソッドが呼び出されるため、java.lang.RuntimePermission "modifyThread" も必要。Thread interrupt()メソッドを参照。
|
|
checkAccess(this) | java.lang.RuntimePermission "modifyThreadGroup" が必要。java.lang.Thread stop()メソッドは、そのスレッド・グループ内およびそのすべてのサブグループ内のスレッドごとに呼び出されるので、java.lang.RuntimePermission "modifyThread" および場合によってはjava.lang.RuntimePermission "stopThread" も必要。Thread stop()メソッドを参照。
|
|
checkPermission | java.lang.reflect.ReflectPermission "suppressAccessChecks" |
|
checkPermission | java.net.NetPermission "requestPasswordAuthentication" |
|
checkPermission | java.net.NetPermission "setDefaultAuthenticator" |
|
checkMulticast(InetAddress) | java.net.SocketPermission( mcastaddr.getHostAddress(), "accept,connect") |
|
checkMulticast(p.getAddress())またはcheckConnect(p.getAddress().getHostAddress(),p.getPort()) |
|
|
checkMulticast(p.getAddress(), ttl)またはcheckConnect( p.getAddress().getHostAddress(), p.getPort()) |
|
|
checkConnect({host}, -1) | java.net.SocketPermission "{host}", "resolve" |
|
checkListen({port}) | java.net.SocketPermission "localhost:{port}","listen"; |
|
checkAccept({host}, {port}) | java.net.SocketPermission "{host}:{port}", "accept" |
|
checkSetFactory | java.lang.RuntimePermission "setFactory" |
|
checkConnect({host}, {port}) | java.net.SocketPermission "{host}:{port}", "connect" |
|
checkAccept({host}, {port}) | java.net.SocketPermission "{host}:{port}", "accept" |
|
checkPermission | java.net.NetPermission "specifyStreamHandler" |
|
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
|
checkPermission | java.security.SecurityPermission "createAccessControlContext" |
|
checkSecurityAccess("addIdentityCertificate") | java.security.SecurityPermission "addIdentityCertificate" |
|
checkSecurityAccess("removeIdentityCertificate") | java.security.SecurityPermission "removeIdentityCertificate" |
|
checkSecurityAccess("setIdentityInfo") | java.security.SecurityPermission "setIdentityInfo" |
|
checkSecurityAccess("setIdentityPublicKey") | java.security.SecurityPermission "setIdentityPublicKey" |
|
checkSecurityAccess("printIdentity") | java.security.SecurityPermission "printIdentity" |
|
checkSecurityAccess("setSystemScope") | java.security.SecurityPermission "setSystemScope" |
|
checkPermission(this) | このアクセス権オブジェクトはチェックされたアクセス権である。 |
|
checkPermission | java.security.SecurityPermission "getPolicy" |
|
checkPermission | java.security.SecurityPermission "setPolicy" |
|
checkPermission | java.security.SecurityPermission "createPolicy.{type}" |
|
checkSecurityAccess(「clearProviderProperties.」+{name}) | java.security.SecurityPermission "clearProviderProperties.{name}" (name はプロバイダ名)。
|
|
checkSecurityAccess("putProviderProperty."+{name}) | java.security.SecurityPermission "putProviderProperty.{name}" (name はプロバイダ名)。
|
|
checkSecurityAccess("removeProviderProperty."+{name}) | java.security.SecurityPermission "removeProviderProperty.{name}" (name はプロバイダ名)。
|
|
checkCreateClassLoader | java.lang.RuntimePermission "createClassLoader" |
|
checkPermission | java.security.SecurityPermission "getProperty.{key}" |
|
checkSecurityAccess("insertProvider."+provider.getName()) | java.security.SecurityPermission "insertProvider.{name}" |
|
checkSecurityAccess("removeProvider."+name) | java.security.SecurityPermission "removeProvider.{name}" |
|
checkSecurityAccess("setProperty."+key) | java.security.SecurityPermission "setProperty.{key}" |
|
checkSecurityAccess("getSignerPrivateKey") | java.security.SecurityPermission "getSignerPrivateKey" |
|
checkSecurityAccess("setSignerKeypair") | java.security.SecurityPermission "setSignerKeypair" |
|
checkPermission | java.sql.SQLPermission "setLog" |
|
checkPermission | java.sql.SQLPermission "setLog" |
|
checkPermission | java.util.PropertyPermission "user.language","write" |
|
checkRead | java.io.FilePermission "{name}","read" |
|
checkPermission | javax.security.auth.AuthPermission "getSubject" |
|
checkPermission | javax.security.auth.AuthPermission "setReadOnly" |
|
checkPermission | javax.security.auth.AuthPermission "doAs" |
|
checkPermission | javax.security.auth.AuthPermission "doAs" |
|
checkPermission | javax.security.auth.AuthPermission "doAsPrivileged" |
|
checkPermission | javax.security.auth.AuthPermission "doAsPrivileged" |
|
checkPermission | javax.security.auth.AuthPermission "getSubjectFromDomainCombiner" |
|
checkPermission | javax.security.auth.AuthPermission "getSubjectFromDomainCombiner" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginContext.{name}" |
|
checkPermission | javax.security.auth.AuthPermission "getLoginConfiguration" |
|
checkPermission | javax.security.auth.AuthPermission "setLoginConfiguration" |
|
checkPermission | javax.security.auth.AuthPermission "refreshLoginConfiguration" |
|
checkPermission | javax.security.auth.AuthPermission "createLoginConfiguration.{type}" |
java.lang.SecurityManagerメソッドのアクセス権チェック
次の表では、java.lang.SecurityManagerメソッドのデフォルトの実装によってチェックされるアクセス権を示します。
指定された各check
メソッドはSecurityManager
checkPermission
メソッドを指定されたアクセス権で呼び出します(コンテキスト引数を取るcheckConnect
およびcheckRead
メソッドを除く)。これらのメソッドは、AccessControlContext
コンテキストを想定し、コンテキストのcheckPermission
メソッドを指定されたアクセス権で呼び出します。
表1-7 java.lang.SecurityManagerのメソッドおよびアクセス権
メソッド | アクセス権 |
---|---|
|
|
|
|
|
|
注意: このメソッドは非推奨です。かわりにpublic void checkPermission(Permission perm);を使用 |
|
|
|
|
|
|
|
|
|
|
cmdが絶対パスの場合:
それ以外の場合
|
|
|
|
|
|
|
注意: このメソッドは非推奨です。かわりにpublic void checkPermission(Permission perm);を使用 |
|
|
|
注意: このメソッドは非推奨です。かわりにpublic void checkPermission(Permission perm);を使用 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注意: このメソッドは非推奨です。かわりにpublic void checkPermission(Permission perm);を使用 |
|
注意: このメソッドは非推奨です。かわりにpublic void checkPermission(Permission perm);を使用 |
|
|
|
|
|
|
|
JDKがサポートする権限
次の各権限は標準ではありませんが、JDKでサポートされています。ポリシー・ファイルでこれらの権限を付与することが必要な場合があります。
jdk.net.NetworkPermission "setOption.SO_FLOW_SLA";
com.sun.tools.attach.AttachPermission "attachVirtualMachine";
com.sun.jdi.JDIPermission "virtualMachineManager";
com.sun.security.jgss.InquireSecContextPermission "*";
jdk.jfr.FlightRecorderPermission "accessFlightRecorder", "registerEvent";
デフォルトのPolicyの実装とポリシー・ファイルの構文
Javaプログラミング言語のアプリケーション環境のポリシーは、様々なソースを出所とするコードがどのようなアクセス権を使用できるかを指定し、様々なプリンシパルとして実行するもので、Policyオブジェクトによって表されます。具体的には、Policy
クラス(java.security
パッケージ内)内のabstractメソッドの実装を提供するPolicy
サブクラスによって表されます。
Policyオブジェクトが使用するポリシー情報がどこに置かれるかは、Policyの実装によります。Policyのリファレンス実装では、ポリシー情報を静的なポリシー構成ファイルから得ます。
このドキュメントの残りの部分では、Policyのリファレンス実装と、それによって読み取られるポリシー・ファイルで使用する構文について説明します。
デフォルトのPolicyの実装
Policyのリファレンス実装では、1つまたは複数のポリシー構成ファイルからポリシーを指定できます。ポリシー構成ファイルでは、指定されたコード・ソースからのコードに対してどのようなアクセス権を与え、指定されたプリンシパルとして実行するかを指定します。各構成ファイルは、UTF-8方式でエンコードする必要があります。
デフォルトでは、システム全体のポリシー・ファイルが1つと、ユーザー・ポリシー・ファイル(オプション)が1つ存在します。デフォルトでは、常に、プラットフォーム・クラス・ローダーによってロードされるJDKモジュールまたはその祖先で必要なアクセス権が付与されます。
Policyのリファレンス実装は、そのgetPermissionsメソッドがはじめて呼び出されたとき、あるいは、そのrefreshメソッドが呼び出されたときに初期化されます。初期化時には、ポリシー構成ファイル(ポリシー・ファイルの構文を参照)の解析が行われた後、その情報がPolicyオブジェクトに読み込まれます。
ポリシー・ファイルのデフォルトの場所
デフォルトでは、システム全体のポリシー・ファイルが1つと、ユーザー・ポリシー・ファイル(オプション)が1つ存在します。Policyが初期化されると、まずシステム・ポリシーがロードされ、次に、ロードされたシステム・ポリシーにユーザー・ポリシーが追加されます。どちらのポリシーも存在しない場合は、組込みポリシーが使われます。組込みポリシーは、JDKとともにインストールしたjava.policy
ファイルと同じです。
システム・ポリシー・ファイルの場所
デフォルトでは、システム・ポリシー・ファイルは<java-home>/conf/security/java.policy
です。
システムのポリシー・ファイルは、システム全体にわたってコードにアクセス権を与えます。JDKに含まれているjava.policy
ファイルは、すべてのユーザーに動的ポートでの待機を許可し、すべてのコードに、セキュリティにかかわらない特定の標準プロパティ(os.name
プロパティやfile.separator
プロパティなど)の読取りを許可します。
ユーザー・ポリシー・ファイルの場所
デフォルトでは、ユーザー・ポリシー・ファイルは<user-home>/.java.policy
です。
ポリシー・ファイルの場所と形式
ポリシー・ファイルの場所は、セキュリティ・プロパティ・ファイル<java-home>/conf/security/java.security
で指定されています。
ポリシー・ファイルの場所は、次のような形式の名前を持つプロパティの値として指定されています。
policy.url.n
ここで、n
は数値です。次に示す形式の行で、それぞれのプロパティの値を指定します。
policy.url.n=URL
ここで、URL
はURLの指定を表します。たとえば、デフォルトのシステムおよびユーザー・ポリシー・ファイルは、セキュリティ・プロパティ・ファイルに次のように指定されています。:
policy.url.1=file:${java.home}/conf/security/java.policy
policy.url.2=file:${user.home}/.java.policy
(${java.home}
を使用してjava.home
プロパティの値を指定するなど、特別な構文でプロパティの値を指定する方法の詳細は、ポリシー・ファイル内のプロパティの展開を参照。)
URLをいくつも指定して(http://
形式のものを含む)、該当するポリシー・ファイルをすべてロードすることもできます。また、上に示したポリシー・ファイルの指定のうち、2番目のポリシー・ファイルの指定をコメント・アウトするか、あるいは修正すれば、デフォルト・ユーザー・ポリシー・ファイルの読込みを無効にすることができます。
アルゴリズムは、policy.url.1
から処理を開始して、番号を1つずつ増やしながら、URLが見つからなくなるまで処理を続けます。したがって、policy.url.1
とpolicy.url.3
がある場合、policy.url.3
は読み込まれません。
実行時に新しいポリシー・ファイルを指定する
アプリケーションを実行するときに、追加のポリシー・ファイルや別のポリシー・ファイルを指定することもできます。これは、
コマンド行引数を使用して-Djava.security.policy
java.security.policy
プロパティの値を設定することで実行できます。たとえば、次のコマンドを入力した場合(ここで、someURL
はポリシー・ファイルの場所を指定するURL)、指定したポリシー・ファイルが、セキュリティ・プロパティ・ファイルに指定されているすべてのポリシー・ファイルに加えてロードされます。
java -Djava.security.manager
-Djava.security.policy
=someURL SomeApp
次に示すとおり、URLは通常のURLでも、単純に現在のディレクトリのポリシー・ファイルの名前でもかまいません。:
java -Djava.security.manager -Djava.security.policy=mypolicy SomeApp
-Djava.security.manager
オプションによってデフォルト・セキュリティ・マネージャがインストールされるので、このアプリケーションに対してはポリシーのチェックが行われます。アプリケーションSomeAppがセキュリティ・マネージャをインストールする場合は、この引数は必要ありません。
次のコマンドを使用した場合(等号が2つ使用されていることに注意)、指定されたポリシー・ファイルのみが使用され、セキュリティ・プロパティ・ファイルに示されたポリシー・ファイルはすべて無視されます。
java -Djava.security.manager
-Djava.security.policy
==someURL SomeApp
注意:
セキュリティ・プロパティ・ファイル内のpolicy.allowSystemProperty
プロパティがfalseに設定されている場合、-Djava.security.policy
オプションのポリシー・ファイル値は無視されます。デフォルトは、trueです。
Policyの実装の変更
セキュリティ・プロパティ・ファイル(JDKのconf/security
ディレクトリのjava.security
ファイル)を編集すれば、Policyのリファレンス実装を変更できます。
新しいポリシー・クラスを作成し、Policyのリファレンス実装クラスと置き換えることもできます。この場合は、Policy抽象クラスのサブクラスを作成し、getPermissionsメソッド(必要に応じてその他のメソッドも)を実装します。
java.security
で設定できるプロパティの例を次に示します。
policy.provider=PolicyClassName
PolicyClassNameには、目的のPolicy
実装クラスを完全修飾名で指定します。
デフォルトのセキュリティ・プロパティ・ファイルでは、このプロパティは次のように指定されています。
policy.provider=sun.security.provider.PolicyFile
カスタマイズするには、次のように、このプロパティに別のクラスを指定します。
policy.provider=com.mycom.MyPolicy
ポリシー・ファイルの構文
インストールしたJDKのポリシー構成ファイルでは、指定されたコード・ソースからのコードに対し、どのようなアクセス権(システム・リソースへのアクセスの種類)を与え、指定したプリンシパルとして実行するかを指定します。
アプレット(またはセキュリティ・マネージャの下で動作しているアプリケーション)が、ファイルの読み書きなど、セキュリティ保護された操作を行うためには、その操作を行うためのアクセス権が与えられている必要があります。Policyのリファレンス実装では、ポリシー構成ファイルの付与エントリによって、そのアクセス権を与える必要があります。詳細は、以降の説明とJavaセキュリティ・アーキテクチャ仕様を参照してください。(ただし、同じ(URLの)場所にあるファイルと、その場所のサブディレクトリにあるファイルの読取りアクセス権は、常に自動的に与えられます。したがって、そのようなアクセス権については、明示的に指定する必要はありません。)
ポリシー構成ファイルは、エントリのリストで構成されます。1つのkeystoreエントリと、0以上のgrantエントリを持たせることができます。
キーストア・エントリ
キーストアは、秘密キーと、対応する公開キーを認証するX.509証明書チェーンなどのデジタル証明書が格納されたデータベースです。キーストアの作成と管理には、keytool
ユーティリティを使用します。ポリシー構成ファイルで指定されているキーストアは、そのファイルのgrantエントリで指定されている署名者の公開キーを照合するために使用されます。署名者の別名を指定しているgrantエントリがある場合、またはプリンシパルの別名を指定しているgrantエントリがある場合は、ポリシー構成ファイルに必ずkeystoreエントリを置きます。
このとき、ポリシー・ファイル内で有効なkeystore
/keystorePasswordURL
エントリは1つのみです。最初のエントリ以外の後続エントリは無視されます。このエントリは、ファイルのgrantエントリ外部の任意の場所に配置できます。構文は次のとおりです。
keystore "some_keystore_url", "keystore_type", "keystore_provider";
keystorePasswordURL "some_password_url";
各構成要素は次のとおりです。
- some_keystore_url
- キーストアのURLの場所を指定します。
- some_password_url
- キーストア・パスワードのURLの場所を指定します。
- keystore_type
- キーストアのタイプを指定します。
- keystore_provider
- キーストア・プロバイダを指定します。
注意:
-
some_keystore_url
からの入力ストリームはKeyStore.loadメソッドに渡されます。 -
URLとしてNONEが指定されている場合は、nullのストリームがKeyStore.loadメソッドに渡されます。NONEは、キーストアがファイルベースでない場合にURLで指定してください。たとえば、ハードウェア・トークン・デバイスに置かれている場合などです。
-
URLは、ポリシー・ファイルがある場所からの相対位置を表します。たとえば、セキュリティ・プロパティ・ファイルの中でポリシー・ファイルが次のように指定されているとします。
policy.url.1=http://foo.example.com/fum/some.policy
また、このポリシー・ファイルには、次のエントリがあるとします。
keystore ".keystore";
この場合、キーストアは次の場所からロードされます。
http://foo.example.com/fum/.keystore
-
URLに絶対位置を指定することもできます。
キーストアのタイプは、キーストア情報の格納形式とデータ形式を定義するとともに、キーストア内の秘密キーとキーストア自体の整合性を保護するために使われるアルゴリズムを定義します。デフォルトの型は"PKCS12"です。したがって、キーストアのタイプがPKCS12であれば、キーストア・エントリを指定する必要はありません。
付与エントリ
実行されるコードは、常に、特定の「コード・ソース」(CodeSource
型のオブジェクトによって表される)から来ると考えられます。コード・ソースは、コードの出所を表す場所(URL)だけでなく、コードの署名に使われた秘密キーに対応する公開キーを含んだ証明書への参照も含みます。コード・ソース内の証明書は、ユーザーのキーストアからのシンボリックな別名によって参照されます。コードはさらに、特定のプリンシパル(Principal
型のオブジェクトによって表される)またはプリンシパルのグループとして実行されると考えられます。
各付与エントリには、オプションのcodeBase
とsignedBy
、およびプリンシパルの名前と値のペアのあとに、アクセス権を付与するコードを指定する1つ以上の「アクセス権エントリ」が含まれます。付与エントリの基本形式は、次のとおりです。
grant signedBy "signer_names", codeBase "URL",
principal principal_class_name "principal_name",
principal principal_class_name "principal_name",
... {
permission permission_class_name "target_name", "action",
signedBy "signer_names";
permission permission_class_name "target_name", "action",
signedBy "signer_names";
...
};
上の形式でイタリック体になっていない項目は、示されているとおりに指定します。ただし、大文字と小文字は区別されず、また、以降で説明するように、いくつかの項目はオプションです。イタリックで示されている項目は、可変の項目です。
付与エントリは、grant
で始まります。
SignedBy、Principal、およびCodeBaseフィールド
signedBy
、codeBase
、およびprincipal
の値はオプションです。また、これらのフィールドの順序は問われません。
signedBy値
signedBy
の値は、キーストアに格納された証明書の別名を示します。証明書内の公開キーは、コードのデジタル署名の検証に使われます。別名によって指定されたキーストア・エントリ内の公開キーに対応する、秘密キーで署名されたコードに、アクセス権を付与します。
signedBy
の値には、複数の別名をカンマで区切って指定できます。たとえば、"Adam,Eve,Charles"のように指定できます。この場合は、各要素がORではなくANDで結ばれ、「Adam、EveおよびCharlesによって署名された」という意味になります。より厳密には、「Adamによって署名されたコード」とは、「Adamという別名が付けられたエントリを持つキーストアにある公開キー証明書に対応する、秘密キーを使って署名されたJARファイルに含まれている、クラス・ファイル内のコード」という意味です。
signedBy
フィールドはオプションです。省略した場合は、「任意の署名者」という意味になります。コードに署名が付いているかどうか、だれが署名しているかは問われなくなります。
principal値
プリンシパルの値はclass_name
とprincipal_name
のペアを指定します。このペアは、実行中のスレッドのプリンシパル・セット内にある必要があります。プリンシパル・セットは、Subjectによって実行するコードに関連付けられます。
principal_class_name
にワイルドカード値(*)を設定することで、任意のPrincipal
クラスに一致させることができます。さらに、principal_name
にワイルドカード値(*)を設定することで、任意のPrincipal
名に一致させることができます。principal_class_name
またはprincipal_name
に*を設定するときは、*を引用符で囲まないでください。また、ワイルドカードのプリンシパル・クラスを指定する場合は、ワイルドカードのプリンシパル名も指定する必要があります。
プリンシパル・フィールドは省略可能です。省略した場合は、「任意のプリンシパル」という意味になります。
キーストア別名の置換
プリンシパルclass_name
/principal_name
のペアが単一引用符で囲まれた文字列として指定される場合は、キーストアの別名として扱われます。キーストアは別名を経由してX509証明書を調査し、問い合わせます。キーストアがある場合、プリンシパルclass_name
は自動的にjavax.security.auth.x500.X500Principal
として扱われ、principal_name
は自動的に証明書のサブジェクト識別名として扱われます。X509証明書のマッピングが見つからない場合は、grantエントリはすべて無視されます。
codeBase値
codeBase
の値は、コードが置かれる場所を示します。この場所からコードにアクセス権を付与します。codeBase
エントリを省略した場合は、「任意のコード」という意味になり、コードの出所は問われません。
注意:
codeBase
の値はURLであるため、コード・ソースがWindowsシステム上にある場合であっても、ディレクトリのセパレータには、バックスラッシュではなく、必ずスラッシュを使用します。したがって、Windowsシステム上でコードの場所がC:\somepath\api\
の場合、codeBase
ポリシー・エントリは次のように指定します。
grant codeBase "file:/C:/somepath/api/" {
...
};
codeBase
値の正確な意味は、末尾の文字によって異なります。末尾が/
のcodeBase
は、指定されたディレクトリ内のすべてのクラス・ファイル(JARファイルを除く)を示します。末尾が/*
のcodeBase
は、そのディレクトリ内にあるすべてのファイル(クラス・ファイルとJARファイルの両方)を示します。末尾が/-
のcodeBase
は、指定されたディレクトリとその下の全サブディレクトリ内のすべてのファイル(クラス・ファイルとJARファイルの両方)を示します。次の表では、様々なケースを示します。
表1-8 ダウンロードされたコードとポリシー・ファイル間のcodeBase URLの対応
ダウンロードされたコードのcodebase URL | ポリシー・ファイルのcodeBase URL | 一致するかどうか |
---|---|---|
www.example.com/usr/ann/ | www.example.com/usr/ann | はい |
www.example.com/usr/ann/ | www.example.com/usr/ann/ | はい |
www.example.com/usr/ann/ | www.example.com/usr/ann/* | はい |
www.example.com/usr/ann/ | www.example.com/usr/ann/- | はい |
www.example.com/usr/ann/appl.jar | www.example.com/usr/ann/ | いいえ |
www.example.com/usr/ann/appl.jar | www.example.com/usr/ann/- | はい |
www.example.com/usr/ann/appl.jar | www.example.com/usr/ann/* | はい |
www.example.com/usr/ann/appl.jar | www.example.com/usr/- | はい |
www.example.com/usr/ann/appl.jar | www.example.com/usr/* | いいえ |
www.example.com/usr/ann/ | www.example.com/usr/- | はい |
www.example.com/usr/ann/ | www.example.com/usr/* | いいえ |
モジュラ・ランタイム・イメージ(jlink
ツールを参照)を使用している場合は、ポリシー・ファイルでjrt
URLをcodeBase
値として指定することで、イメージ内のアプリケーションとライブラリ・モジュールにアクセス権を付与できます。jrt
URLの詳細は、『JEP 220: Modular Run-Time Images』を参照してください。
次の例では、モジュールcom.greetings
に対してfoo
プロパティの読取りアクセス権を付与します。
grant codeBase "jrt:/com.greetings" {
permission java.util.PropertyPermission "foo", "read";
};
アクセス権エントリ
アクセス権エントリは、単語permission
で始まります。前述のテンプレートにある単語permission_class_name
は、実際にはjava.io.FilePermission
やjava.lang.RuntimePermission
などの特定のアクセス権タイプになります。
java.io.FilePermission
(どのような種類のファイル・アクセスを許可するかを指定)など、多くのアクセス権タイプでは"action"が必須です。java.lang.RuntimePermission
などのカテゴリでは不要なため、必須ではありません。permission_class_nameの後の"target_name
"値で指定されたアクセス権が与えられるか、アクセス権が与えられないかのどちらかになります。
アクセス権エントリのsignedBy
の名前と値のペアは省略可能です。この値が存在する場合は、署名付きアクセス権であることを示します。つまり、そのアクセス権を与えられるようにするためには、アクセス権クラスそれ自体が、指定された別名によって署名されていなければなりません。たとえば、次のような付与エントリがあるとします。
grant {
permission Foo "foobar", signedBy "FooSoft";
};
この場合、このアクセス権タイプFooが与えられるのは、あるJARファイルにアクセス権Foo.class
が置かれていて、そのJARファイルが、別名FooSoftにより指定された証明書内の公開キーに対応する秘密キーによって署名されているときか、Foo.class
がシステム・クラスであるときです(システム・クラスはポリシーによる制限を受けないため)。
アクセス権エントリの各項目は、指定された順序(permission
、permission_class_name、"target_name"、"action"、およびsignedBy
"signer_names")で並んでいる必要があります。各エントリはセミコロンで終わります。
識別子(permission
、signedBy
、codeBase
など)では大文字と小文字は区別されませんが、permission_class_nameと、値として引き渡される文字列については大文字と小文字が区別されます。
注意:
FilePermissionパス名の正規化方法における変更に関する重要な情報については、付録A: FilePermissionのパス名の正規化がデフォルトで無効化を参照してください。
Windowsシステムでのファイル・パスの指定
java.io.FilePermission
を指定する場合、"target_name"はファイル・パスになります。Windowsシステムでは、ファイル・パスをcodebase URLではなく直接文字列で指定する場合は、パス中のバックスラッシュは、次のように2つ重ねて指定する必要があります
grant {
permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read";
};
これは、文字列はトークナイザ(java.io.StreamTokenizer
)によって処理され、トークナイザは「\」をエスケープ文字列と解釈するため(たとえば、「\n」は改行を表す)、バックスラッシュそのものを表すには、バックスラッシュを2つ重ねる必要があるからです。トークナイザは、上記のファイル・パス文字列の処理を終えると、二重のバックスラッシュを単一のバックスラッシュに変換し、最終的には次のようになります。
"C:\users\cathy\foo.bat"
ポリシー・ファイルの例
次のポリシー構成には、次の2つのエントリがあります。
// If the code is signed by "Duke", grant it read/write access to all
// files in /tmp:
grant signedBy "Duke" {
permission java.io.FilePermission "/tmp/*", "read,write";
};
// Grant everyone the following permission:
grant {
permission java.util.PropertyPermission "java.vendor", "read";
};
次のポリシー構成ファイルは、次の条件を満たすコードのみがSecurityクラス内のメソッドを呼び出して、プロバイダの追加または削除を行ったり、Securityプロパティを設定できることを指定します。
- ローカル・ファイル・システムの"
/home/sysadmin/
"ディレクトリにある、署名されたJARファイルからコードがロードされた。 - 署名が、キーストア内の別名
sysadmin
によって参照される公開キーで認証される。
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.*";
};
ポリシー・エントリのいずれか(または両方)を省略可能です。
次は、codeBase
を省略したポリシー構成ファイルです。
grant signedBy "sysadmin" {
permission java.security.SecurityPermission "Security.insertProvider.*";
permission java.security.SecurityPermission "Security.removeProvider.*";
};
このポリシーが有効な場合、"sysadmin
"によって署名されたJARファイルに含まれるコードは、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.*";
};
この例では、コード・ソースを指定する要素がどちらも省略されています。したがって、出所がどこか、署名が付いているか、だれの署名が付いているかに関係なく、どのコードでもプロバイダの追加と削除が行えます。
次は、プリンシパルベースのエントリを表しています。
grant principal javax.security.auth.x500.X500Principal "cn=Alice" {
permission java.io.FilePermission "/home/Alice", "read, write";
};
これにより、X500Principalのアクセス権cn=Alice
として実行するコードは/home/Alice
を読み取ることも書き込むことも可能になります。
次は、ワイルドカード値を含むプリンシパルベースのエントリを表しています。
grant principal javax.security.auth.x500.X500Principal * {
permission java.io.FilePermission "/tmp", "read, write";
};
これにより、X500Principalのアクセス権(識別名に関係なく)として実行するコードは/tmp
を読み取ることも書き込むことも可能になります。
次の例は、codesource情報とprincipal情報を持つgrant文を表しています。
grant codebase "http://www.games.example.com",
signedBy "Duke",
principal javax.security.auth.x500.X500Principal "cn=Alice" {
permission java.io.FilePermission "/tmp/games", "read, write";
};
これにより、"Duke
"によって署名され、"www.games.example.com
"からダウンロードされたコードが"cn=Alice
"によって実行されると、"/tmp/games
"ディレクトリへの読取り権と書出し権が与えられます。
次の例は、キーストアの別名を置き換えるgrant文を示しています。
keystore "http://foo.example.com/blah/.keystore";
grant principal "alice" {
permission java.io.FilePermission "/tmp/games", "read, write";
};
"alice
"は次のように置き換えられます。
javax.security.auth.x500.X500Principal "cn=Alice"
これは、キーストア別名alice
に関連付けられたX.509証明書に、サブジェクトの識別名"cn=Alice
"があることが前提となります。これにより、X500Principalのアクセス権"cn=Alice
"によって実行されるコードに、"/tmp/games
"ディレクトリへの読取り権と書出し権が与えられます。
ポリシー・ファイル内のプロパティの展開
ポリシー・ファイルとセキュリティ・プロパティ・ファイルでは、プロパティの展開が可能です。
プロパティの展開は、シェルでの変数の展開に似ています。ポリシー・ファイルまたはセキュリティ・プロパティ・ファイルに次のような文字列がある場合、
${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
で、プラットフォームがLinuxまたはmacOSである場合、これは次のように変換されます。
permission java.io.FilePermission "/home/cathy/*", "read";
Windowsシステムで、"user.home
"の値がC:\users\cathy
であれば、次のように変換されます。
permission java.io.FilePermission "C:\users\cathy\*", "read";
特殊なケースとして、コード・ベースのプロパティを次のように記述すると、
grant codeBase "file:${my.libraries}/api/"
ファイル・セパレータ文字は自動的に/
文字に変換されます。たとえば、値がmy.libraries
である場合はC:\Users\me\lib
となります。したがって、Windowsシステムでは次のように変換されます。
grant codeBase "file:C:/Users/me/lib/api/"
したがって、コード・ベース文字列では${/}
を使用する必要はありません(使用しないでください)。プロパティの展開は、ポリシー・ファイル内で、二重引用符で囲まれた文字列が使用できる場所であればどこでも行われます。これには、"signer_names"、"URL"、"target_name"、"action"の各フィールドが含まれます。プロパティの展開が許可されるかどうかは、セキュリティ・プロパティ・ファイルの"policy.expandProperties
"プロパティの値によって決まります。このプロパティの値がtrue (デフォルト)の場合は、展開が許可されます。
注意:
ネストされたプロパティは使用できません。次に例を示します。
"${user.${foo}}"
この例では、"foo
"プロパティが"home
"に設定されている場合であっても、エラーになります。これは、プロパティ構文解析プログラムはネストされたプロパティを認識しないためです。プロパティ構文解析プログラムは、最初の${
を見つけると、次に最初の}
を探し、その結果(この場合は${user.$foo}
)をプロパティと解釈しようとします。しかし、そのようなプロパティがない場合はエラーになります。
注意:
付与エントリ、アクセス権エントリまたはキーストア・エントリで展開できないプロパティがある場合、そのエントリは無視されます。たとえば、次のようにシステム・プロパティ"foo
"が定義されていない場合、
grant codeBase "${foo}" {
permission ...;
permission ...;
};
このgrantエントリ内のpermissionはすべて無視されます。また、次のような場合、
grant {
permission Foo "${foo}";
permission Bar "barTarget";
};
"permission Foo...
"エントリだけが無視されます。また、次のように指定されている場合、
keystore "${foo}";
この場合は、keystoreエントリが無視されます。
Windowsシステム、ファイル・パス、およびプロパティの展開
Windowsシステムでのファイル・パス仕様には、実際の1つバックスラッシュごとに、2つのバックスラッシュを含める必要があります。
Windowsシステムでのファイル・パスの指定で説明したように、Windowsシステムでは、ファイル・パスをcodebase URLではなく直接文字列で指定する場合は、パス内の実際の単一のバックスラッシュごとに、次のように2つのバックスラッシュを含める必要があります
grant {
permission java.io.FilePermission "C:\\users\\cathy\\foo.bat", "read";
};
これは、文字列はトークナイザ(java.io.StreamTokenizer
)によって処理され、トークナイザは\
をエスケープ文字列と解釈するため(たとえば、\n
は改行を表す)、バックスラッシュそのものを表すには、バックスラッシュを2つ重ねる必要があるからです。トークナイザは、上記のファイル・パス文字列の処理を終えると、二重のバックスラッシュを単一のバックスラッシュに変換し、最終的には次のようになります。
"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"
ポリシー・ファイルにおける一般的な展開
ポリシー・ファイルでは一般化された形式の展開もサポートされています。たとえば、アクセス権名が次の形式の文字列を含んでいるとします。
${{protocol:protocol_data}}
このような文字列がアクセス権名に含まれる場合、protocolの値によって実行される展開のタイプが決まり、protocol_dataは展開を実行するために使用されます。protocol_dataは空にすることもできます。空の場合、前述の文字列は次のような単純な形式になります。
${{protocol}}
デフォルトのポリシー・ファイルの実装では、次の2つのプロトコルがサポートされます。
-
${{self}}
プロトコル
self
は、${{self}}
文字列全体を1つ以上のプリンシパル・クラスとプリンシパル名のペアに置き換えることを示します。実際に実行される置換えは、permissionを含むgrant節の内容によって決まります。grant節にプリンシパルの情報が含まれていない場合は、permissionは無視されます。プリンシパルベースのgrant節のコンテキストでは、ターゲット名に
${{self}}
を含むpermissionのみが有効です。たとえば、次のgrant節内のBarPermission
は常に無視されます。grant codebase "www.example.com", signedby "duke" { permission BarPermission "... ${{self}} ..."; };
grant句にプリンシパル情報が含まれている場合は、
${{self}}
がそのプリンシパル情報に置き換えられます。たとえば、次のgrant句のBarPermission
内の${{self}}
は、javax.security.auth.x500.X500Principal "cn=Duke"
に置き換えられます。grant principal javax.security.auth.x500.X500Principal "cn=Duke" { permission BarPermission "... ${{self}} ..."; };
grant句内にカンマで区切られたプリンシパルのリストがある場合、
${{self}}
は、そのカンマで区切られたプリンシパルのリストに置き換えられます。grant句内のプリンシパル・クラスとプリンシパル名がどちらもワイルドカードになっている場合、${{self}}
は、現在のAccessControlContext
内のSubject
に関連付けられたすべてのプリンシパルに置き換えられます。次の例は、
self
とキーストア別名の置換の両方を含むシナリオを示しています。keystore "http://foo.example.com/blah/.keystore"; grant principal "duke" { permission BarPermission "... ${{self}} ..."; };
上の例では、最初に
duke
がjavax.security.auth.x500.X500Principal "cn=Duke"
に展開されます。ただし、KeyStore
別名duke
に関連付けられたX.509証明書にサブジェクト識別名cn=Duke
があることが前提となります。次に、${{self}}
が、grant節内で展開されたその同じプリンシパル情報に置き換えられます。javax.security.auth.x500.X500Principal "cn=Duke"
-
${{alias:alias_name}}
プロトコル
alias
は、java.security.KeyStore別名の置換を示します。KeyStoreエントリに指定されたKeyStore
が使用されます。alias_nameは、KeyStore
の別名を表します。${{alias:alias_name}}
は、javax.security.auth.x500.X500Principal "DN"
に置き換えられます。このDNは、alias_nameに属する証明書のサブジェクト識別名を表します。次に例を示します。keystore "http://foo.example.com/blah/.keystore"; grant codebase "www.example.com" { permission BarPermission "... ${{alias:duke}} ..."; };
上の例では、別名dukeに関連付けられているX.509証明書は、
KeyStore
のfoo.example.com/blah/.keystoreから取得されます。dukeの証明書がサブジェクト識別名としてo=dukeOrg, cn=duke
を指定し、${{alias:duke}}
がjavax.security.auth.x500.X500Principal "o=dukeOrg, cn=duke"
で置き換えられるものとします。次のエラー条件に該当する場合、アクセス権エントリは無視されます。
- keystoreエントリが指定されていない
- alias_nameが指定されていない
- alias_nameの証明書を取得できない
- 取得される証明書がX.509証明書ではない
付録A: FilePermissionのパス名の正規化がデフォルトで無効化
正規パスは、リンクやショートカットを含まないパスです。FilePermission
オブジェクトでパス名正規化を実行すると、パフォーマンスに悪影響を与える可能性があります。
JDK 9より前は、2つのFilePermission
オブジェクトが比較されるときに、パス名が正規化されました。これにより、プログラムで、ポリシー・ファイル内でFilePermission
オブジェクトに付与されている名前とは異なる名前を使用してファイルにアクセスできました(そのオブジェクトが同じファイルを指している場合)。正規化では、基にあるファイル・システムにアクセスする必要があったため、非常に低速になる場合がありました。
JDK 9では、パス名正規化はデフォルトでは無効になっています。これは、一方が絶対パスを使用し他方が相対パスを使用する場合、一方がシンボリック・リンクを使用し他方がターゲットを使用する場合、または一方がWindowsロング・ネームを使用し他方がDOS形式の8.3ネームを使用する場合は、2つのFilePermission
オブジェクトが互いに等しくないということです。これは、それらすべてがファイル・システム内の同じファイルを指している場合でも当てはまります。
したがって、パス名がポリシー・ファイルのFilePermission
オブジェクトに付与されている場合、プログラムは同じパス名形式を使用してファイルにアクセスする必要もあります。たとえば、ポリシー・ファイル内のパス名でシンボリック・リンクが使用されている場合、プログラムでもそのシンボリック・リンクを使用する必要があります。ターゲット・パス名でファイルにアクセスすると、アクセス権チェックに失敗します。
互換性レイヤー
相対パスのFilePermission
オブジェクトの付与により(逆に)アプリケーションに絶対パスでのファイルへのアクセスが許可されるように、互換性レイヤーが追加されています。これは、デフォルトのPolicyプロバイダおよび制限付きdoPrivileged呼出しで機能します。
たとえば、相対パス名がa
のファイル上のFilePermission
オブジェクトは、絶対パス名が/pwd/a
(pwd
は現在の作業ディレクトリ)の同一ファイル上のFilePermission
オブジェクトを意味するわけではなくなりました。セキュリティ・マネージャが有効になっている場合は、a
を読み取るFilePermission
オブジェクトをコードに付与すると、そのコードで/pwd/a
も読み取ることができます。
互換性レイヤーは、シンボリック・リンクとターゲット、Windowsロング・ネームとDOS形式8.3ネーム、または同じ名前に正規化できる他の様々な名前形式の間の変換には対応していません。
パス名正規化のカスタマイズ
表1-9のシステム・プロパティは、FilePermission
パス名正規化のカスタマイズに使用できます。java.lang.Systemプロパティの指定方法を参照してください。
表1-9 パス名正規化をカスタマイズするシステム・プロパティ
システム・プロパティ | デフォルト値 | 説明 |
---|---|---|
jdk.io.permissionsUseCanonicalPath |
false |
このシステム・プロパティは、
|
jdk.security.filePermCompat |
false |
このシステム・プロパティは、サードパーティのPolicyの実装をサポートするように互換性レイヤーを拡張するために使用できます。
|