アクセス権の例としては、次のコードを使うと /tmp ディレクトリの「abc」というファイルの読み取りアクセス権が得られます。
perm = new java.io.FilePermission("/tmp/abc", "read");新しいアクセス権は、Permission クラス、またはそのサブクラスの 1 つ (java.security.BasicPermission など) からサブクラス化されます。サブクラス化された、BasicPermission 以外のアクセス権は通常、それ自体のパッケージに属します。したがって、FilePermission は java.io パッケージにあります。
すべての新規 Permission クラスに実装する必要のある重要な抽象メソッドが、implies
メソッドです。基本的に、「a implies b」は、アクセス権「a」を与えられている者は、当然アクセス権「b」を与えられるということを意味します。この点は、アクセス制御の決定の際に重要です。
抽象クラス java.security.Permission には、java.security.PermissionCollection という名前の抽象クラスと java.security.Permissions という final クラスが関連します。
java.security.PermissionCollection クラスは、ファイルのアクセス権など 1 つのカテゴリの Permission オブジェクトのコレクション (複製可能なセット) を表し、簡単にグループ化できるようになっています。ファイルのアクセス権などのように、アクセス権を PermissionCollection オブジェクトに任意の順序で追加できる場合は、implies
関数が呼び出されたときに、PermissionCollection オブジェクトが確実に正しいセマンティクスに従うことが重要です。
java.security.Permissions クラスは、Permission オブジェクトのコレクションを表します。つまり、異種のアクセス権のスーパーコレクションです。
アプリケーションには、システムがサポートしているアクセス権の新規のカテゴリを自由に追加できます。アプリケーションに特定のアクセス権を追加する方法については、あとで説明します。
以降では、すべての組み込みアクセス権の構文とセマンティクスについて説明します。
アクセス権の各インスタンスは、通常、コンストラクタに 1 つ以上の文字列パラメータを渡すことによって生成されます。2 つのパラメータを使う一般的なケースでは、通常、1 つ目のパラメータは「ターゲットの名前」 (アクセス権の目的のファイル名など) で、2 つ目のパラメータは動作 (ファイルに対する「読み取り」動作など) です。通常、複数の動作のセットをコンマで区切った文字列の組み合わせで指定できます。
UnresolvedPermission クラスは、こうした「未解決」のアクセス権を保持するために使用されます。同様に、java.security.UnresolvedPermissionCollection クラスには UnresolvedPermission アクセス権のコレクションが保存されます。
アクセス制御の際に、以前は未解決であったものの、現在そのクラスがロードされているアクセス権のタイプがチェックされ、未解決のアクセス権が「解決」されて、適切なアクセス制御が決定されます。つまり、可能であれば、UnresolvedPermission 内の情報に基づいて適切なクラスタイプの新規オブジェクトのインスタンスが生成されます。この新規オブジェクトが UnresolvedPermission に置き換わり、UnresolvedPermission は削除されます。
この時点でも解決されないアクセス権は、セキュリティーポリシーで付与されない無効なアクセス権とみなされます。
file directory (same as directory/) directory/file directory/* (all files in this directory) * (all files in the current directory) directory/- (all files in the file system under this directory) - (all files in the file system under the current directory) "<<ALL FILES>>" (all files in the file system)「<<ALL FILES>>」は特別な文字列で、システム内のすべてのファイルを表します。UNIX システムでは、root ディレクトリの下のすべてのファイルです。MS-DOS システムでは、すべてのドライブのすべてのファイルです。
動作は、read、write、delete、および execute です。ファイルのアクセス権を作成する有効なコード例を次に示します。
import java.io.FilePermission; FilePermission p = new FilePermission("myfile", "read,write"); FilePermission p = new FilePermission("/home/gong/", "read"); FilePermission p = new FilePermission("/tmp/mytmp", "read,delete"); FilePermission p = new FilePermission("/bin/*", "execute"); FilePermission p = new FilePermission("*", "read"); FilePermission p = new FilePermission("/-", "read,execute"); FilePermission p = new FilePermission("-", "read,execute"); FilePermission p = new FilePermission("<<ALL FILES>>", "read");> このクラスの
implies
メソッドは、ファイルシステムを正確に解釈します。たとえば、FilePermission("/-", "read,execute") は、FilePermission("/home/gong/public_html/index.html", "read") を表し、FilePermission("bin/*", "execute") は FilePermission("bin/emacs19.31", "execute") を表します。
注:多くの場合、これらの文字列の形式はプラットフォームにより異なります。たとえば、Windows システムの C ドライブ上の temp ディレクトリの foo というファイルへの読み取りアクセスを表すには、次の表現を使用します。
FilePermission p = new FilePermission("c:\\temp\\foo", "read");文字列はトークナイザ (java.io.StreamTokenizer) によって処理されますが、そこでは「\」を使ったエスケープ文字列 (改行を表す「\n」など) が許されるので、単一のバックスラッシュを表すためには二重のバックスラッシュを使う必要があります。トークナイザが FilePermission のターゲット文字列の処理を終え、二重のバックスラッシュを単一のバックスラッシュに変換すると、結果は次の実際のパスになります
"c:\temp\foo"全プラットフォーム共通のファイル記述言語ができるまでは、文字列はプラットフォームごとに異なる形式で指定する必要があります。また、「*」や「-」のようなメタシンボルを使用して特定のファイル名を表すことはできません。これは、さしあたり許容できる程度の小さな制限事項だと考えます。UNIX システムでは「/-」と「<<ALL FILES>>」は、どちらもファイルシステム全体を指します。(利用可能なファイルシステムであれば、複数のファイルシステムを指すこともできる。) 別のオペレーティングシステム (MS Windows や MacOS など) ではこの 2 つは、別のターゲットを指す可能性があります。
次のように、ターゲットがディレクトリだけで動作が「read」の場合は、
FilePermission p = new FilePermission("/home/gong/", "read");そのディレクトリ内のファイルを一覧表示するためだけのアクセス権が与えられ、ファイルの読み取りは許可されません。ファイルの読み取りを許可するには、次のように明示的なファイル名を指定するか、「*」または「-」を指定します。
FilePermission p = new FilePermission("/home/gong/myfile", "read"); FilePermission p = new FilePermission("/home/gong/*", "read"); FilePermission p = new FilePermission("/home/gong/-", "read");コードは必ず、そのコードと同じ (URL の) 位置、およびそのサブディレクトリの位置からのファイルの読み取りアクセス権を自動的に取得します。そのための明示的なアクセス権は必要ありません。
hostname (a single host) IP address (a single host) localhost (the local machine) "" (equivalent to "localhost") hostname.domain (a single host within the domain) hostname.subdomain.domain *.domain (all hosts in the domain) *.subdomain.domain * (all hosts)つまり、ホストは、DNS 名、数値の IP アドレス、「localhost」 (ローカルマシンの場合)、(「localhost」を指定するのと同じ) のどれかで表現されます。
DNS 名によるホストの指定では、ワイルドカード「*」を 1 つだけ使うことができます。これを使う場合は、「*.sun.com」のようにいちばん左の位置に使います。
N (a single port) N- (all ports numbered N and above) -N (all ports numbered N and below) N1-N2 (all ports between N1 and N2, inclusive)上の形式で、N、N1、N2 は、0 から 65535 (2^16-1) の範囲内の負でない整数です。
ソケットでの動作は、accept、connect、listen、および resolve です (resolve は基本的に DNS の照合)。「resolve」動作は、「accept」、「connect」、および「listen」により暗示されます。つまり、ホストからの入力接続の listen や accept、またはホストへの出力接続の開始が可能なユーザーは、そのリモートホストの名前を照合できるようになるはずということです。
import java.net.SocketPermission; SocketPermission p = new SocketPermission("java.example.com","accept"); p = new SocketPermission("192.0.2.99","accept"); p = new SocketPermission("*.com","connect"); p = new SocketPermission("*.example.com:80","accept"); p = new SocketPermission("*.example.com:-1023","accept"); p = new SocketPermission("*.example.com:1024-","connect"); p = new SocketPermission("java.example.com:8000-9000", "connect,accept"); p = new SocketPermission("localhost:1024-", "accept,connect,listen");SocketPermission("java.example.com:80,8080","accept") と SocketPermission("java.example.com,javasun.example.com","accept") は、有効なソケットアクセス権ではありません。
listen 動作はローカルホストのポートだけに適用され、accept 動作はローカルホストとリモートホストの両方のポートに適用されます。両方の動作が必要です。
BasicPermission の名前は、「exitVM」、「setFactory」、「print.queuePrintJob」など、指定したアクセス権の名前です。命名規約は、階層的なプロパティー命名規約に従います。名前の末尾には「*」や「.*」を付けて、ワイルドカードを指定できます。たとえば、「java.*」や「*」は有効ですが、「*java」や「a*b」は無効です。
動作の文字列 (Permission から継承される) は使用されません。したがって、「名前付き」のアクセス権 (名前を持つが動作リストのないアクセス権。名前付きアクセス権は、ある場合とない場合がある) の基底クラスとして、一般に BasicPermission が使用されます。必要に応じて、サブクラスは BasicPermission の上に重ねて動作を実装できます。
BasicPermission サブクラスには、java.lang.RuntimePermission、java.security.SecurityPermission、java.util.PropertyPermission、java.net.NetPermission などがあります。
このクラスは、BasicPermission の上に重ねて動作を実装する BasicPermission サブクラスの 1 つです。動作は、read と write です。それぞれの意味は、次のように定義されます。「read」アクセス権は、java.lang.System 内の getProperty
メソッドを呼び出してプロパティー値を取得することを許可します。「write」アクセス権は、setProperty
メソッドを呼び出してプロパティー値を設定することを許可します。
createClassLoader getClassLoader setContextClassLoader setSecurityManager createSecurityManager exitVM setFactory setIO modifyThread stopThread modifyThreadGroup getProtectionDomain readFileDescriptor writeFileDescriptor loadLibrary.{library name} accessClassInPackage.{package name} defineClassInPackage.{package name} accessDeclaredMembers.{class name} queuePrintJob
accessClipboard accessEventQueue listenToAllAWTEvents showWindowWithoutWarningBanner
requestPasswordAuthentication setDefaultAuthenticator specifyStreamHandler
suppressAccessChecksこれは、リフレクトされたオブジェクトが使用される位置で実行される、Java プログラミング言語の標準のアクセスチェック (public、default(package) アクセス、protected、private メンバーに対するチェック) を無効にします。
enableSubclassImplementation enableSubstitution
getPolicy setPolicy getProperty.{key} setProperty.{key} insertProvider.{provider name} removeProvider.{provider name} setSystemScope setIdentityPublicKey setIdentityInfo printIdentity addIdentityCertificate removeIdentityCertificate clearProviderProperties.{provider name} putProviderProperty.{provider name} removeProviderProperty.{provider name} getSignerPrivateKey setSignerKeyPair
doAs doAsPrivileged getSubject getSubjectFromDomainCombiner setReadOnly modifyPrincipals modifyPublicCredentials modifyPrivateCredentials refreshCredential destroyCredential createLoginContext.{name} getLoginConfiguration setLoginConfiguration refreshLoginConfiguration
implies
メソッドを定義して、特定のアクセス権クラスとほかのアクセス権クラスとの関係を表す必要があります。たとえば、java.io.FilePermission("/tmp/*", "read") には java.io.FilePermission("/tmp/a.txt", "read") が含まれますが、java.net.NetPermission にはどれも含まれません。
一見しただけではわからない、暗黙の包含関係もあります。たとえば、あるアプレットにファイルシステム全体への書き込みアクセス権を与えるとします。これにより、このアプレットには、JVM 実行時環境を含むシステムのバイナリファイルの書き換えが許可されると考えられます。これは結果的に、そのアプレットにすべてのアクセス権を与えることを意味します。
別の例として、あるアプレットにクラスローダーを生成する実行時アクセス権を与える場合、クラスローダーはクリティカルな操作を実行できるので、結果的に、このアプレットにさらに多くのアクセス権を与えることになります。
「危険」を伴うアクセス権にはこれ以外に、システムプロパティーの設定を許可するもの、パッケージの定義やネイティブコードライブラリのローディングのための実行時アクセス権 (Java のセキュリティー構造はネイティブコードレベルでの悪意のある動作を防ぐように設計されていないため)、および AllPermission があります。
アクセス権の詳細については、Permissions in JDK 7 を参照してください。アクセス権を必要とする Java の組み込みメソッド、および特定のアクセス権の割り当てに伴う危険性について、一覧で説明されています。
新しくアクセス権を作成するには、次の例のような方法をお勧めします。ABC 社のアプリケーション開発者が「TV を見る」ための新しいカスタムのアクセス権を作成するとします。
最初に、抽象クラス java.security.Permission (またはそのサブクラスのひとつ) を継承する新しいクラス com.abc.Permission、および com.abc.Permission を継承する新しいクラス com.abc.TVPermission を作成します。ほかのクラスの implies
メソッドが正しく実装されるように注意してください。ただし、com.abc.TVPermission は中間の com.abc.Permission がなくても、直接 java.security.Permission を継承することはできます。
public class com.abc.Permission extends java.security.Permission public class com.abc.TVPermission extends com.abc.Permission次の図では、サブクラスの関係を示します。
次に、アプリケーションパッケージにそれらの新規クラスをインクルードします。
特定のコードにこの新しいタイプのアクセス権を許可する場合、各ユーザーはポリシーファイルにエントリを追加します。(ポリシーファイルの構文の詳細についてはあとのセクションで説明。) 次に、5 チャンネルを見る (watch) アクセス権を http://www.example.com/ のコードに付与するポリシーファイルの例を示します。
grant codeBase "http://www.example.com/" { permission com.abc.TVPermission "channel-5", "watch"; }アプリケーションのリソース管理コードで、アクセス権を与えるべきかどうかのチェックを行うときは、com.abc.TVPermission オブジェクトをパラメータとして AccessController の
checkPermission
メソッドを呼び出します。
com.abc.TVPermission tvperm = new com.abc.TVPermission("channel-5", "watch"); AccessController.checkPermission(tvperm);新しいアクセス権を追加するときは、新しい (アクセス権) クラスを作成します。セキュリティーマネージャーに新しいメソッドを追加するのではないので注意してください。以前は、新しいタイプのアクセスをチェックするためには SecurityManager クラスに新しいメソッドを追加する必要がありました。
「channel-1:13」や「channel-*」など、より難解な TVPermissions を許可するには、これらの擬似名のセマンティクスの扱いを知っている TVPermissionCollection オブジェクトを実装する必要があるかもしれません。
新しいコードがアクセス制御の組み込みアルゴリズムを実行するためには、AccessController クラスの checkPermission
メソッドを呼び出してアクセス権チェックを起動します。ClassLoader や SecurityManager があるかどうかについては、必ずしも調べる必要はありません。ただし、インストールされているセキュリティーマネージャークラスにそのアルゴリズムを任せる場合は、SecurityManager.checkPermission
メソッドを呼び出します。
ファイルの読み書きなど、アプレット (または SecurityManager の下で実行中のアプリケーション) がセキュリティーの対象である動作を行うためには、そのアプレット (またはアプリケーション) はその動作のためのアクセス権を与えられていることが必要です。唯一の例外として、コードは必ず、同じ CodeSouce、およびその CodeSouce のサブディレクトリからのファイルの読み取りアクセス権を自動的に持ちます。この場合は、明示的なアクセス権は必要ありません。
Policy オブジェクトのインスタンスは、複数存在できますが、「有効な」インスタンスは常に 1 つだけです。現在インストールされている Policy オブジェクトは getPolicy
メソッドの呼び出しにより取得でき、(Policy のリセット権を持つコードによる) setPolicy
メソッドの呼び出しによって変更できます。
Policy オブジェクトが使用するポリシー情報がどこに置かれるかは、Policy の実装によります。たとえば、ポリシーの構成は、単純な ASCII ファイル、Policy クラスの直列化バイナリファイル、データベースのどれかの形で保存できます。Policy のリファレンス実装の 1 つでは、情報を静的なポリシー構成ファイルから取得します。
ポリシー構成ファイルは、エントリのリストで構成されます。1 つの keystore エントリと、0 以上の grant エントリを持たせることができます。
「キーストア」は、非公開鍵と、対応する公開鍵を認証する X.509 証明書チェーンなどのデジタル証明書が格納されたデータベースです。キーストアの作成と管理には、keytool ユーティリティーを使います。ポリシー構成ファイルで指定されているキーストアは、そのファイルの grant エントリで指定されている署名者の公開鍵を照合するために使用されます。署名者の別名を指定している grant エントリがある場合、またはプリンシパルの別名を指定している grant エントリがある場合は、ポリシー構成ファイルには必ず keystore エントリを置きます (次を参照)。
現在、ポリシーファイルで指定できる keystore エントリは 1 つだけで、2 つ目以降の keystore エントリは無視されます。keystore エントリは、ポリシーファイルの grant エントリの外であれば、どこに指定してもかまいません。keystore エントリの構文は次のとおりです。
keystore "some_keystore_url", "keystore_type";ここで、「some_keystore_url」にはキーストアの URL 位置を指定し、「keystore_type」にはキーストアのタイプを指定します。keystore_type の指定は任意で行います。指定しない場合、キーストアのタイプは、セキュリティープロパティーファイルの「keystore.type」プロパティーで指定されたものとみなされます。
URL は、ポリシーファイルがある場所からの相対位置を表します。たとえば、セキュリティープロパティーファイルの中でポリシーファイルが次のように指定されているとします。
policy.url.1=http://foo.bar.example.com/blah/some.policyまた、このポリシーファイルには、次のエントリがあるとします。
keystore ".keystore";この場合、キーストアは次の場所からロードされます。
http://foo.bar.example.com/blah/.keystoreURL に絶対位置を指定することもできます。
キーストアの型は、キーストア情報の格納形式とデータ形式を定義するとともに、キーストア内の非公開鍵とキーストア自体の整合性を保護するために使われるアルゴリズムを定義します。Sun Microsystems がサポートするデフォルトのタイプは、Sun Microsystems に所有権があるキーストアタイプ名「JKS」です。
ポリシーファイルの各 grant エントリは、本質的には 1 つの CodeSource とそのアクセス権から成ります。実際には、CodeSource は 1 つの URL と証明書のセットから成りますが、ポリシーファイルのエントリの内容は URL と署名者名のリストです。システムは、指定された署名者の証明書を決定するためにキーストアを調べたあとで、対応する CodeSource を生成します。
ポリシーファイルの各 grant エントリは、次の形式のどれかです。ここで先頭の「grant」は予約語で、新しいエントリの開始を示し、括弧の中にはオプション項目が示されます。各エントリ内の先頭の「permission」も予約語で、そのエントリ内で新しいアクセス権の記述が開始されることを示します。各 grant エントリは、指定したコードソースとプリンシパルに 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 ... };コンマの直前または直後には、空白文字を入れてもかまいません。アクセス権クラスの名前は、Java の完全修飾形のクラス名 (java.io.FilePermission など) でなければならず、省略 (FilePermission など) はできません。
動作のフィールドは、省略可能なオプションフィールドで、アクセス権クラスが動作を必要としない場合には省略できます。このフィールドを指定する場合は、必ずターゲットフィールドの直後に置きます。
CodeBase URL の正確な意味は、最後の文字に依存します。末尾が「/」の CodeBase は、指定されたディレクトリ内のすべてのクラスファイル (JAR ファイルを除く) を示します。末尾が「/*」の CodeBase は、そのディレクトリ内にあるすべてのファイル (クラスファイルと JAR ファイルの両方) を示します。末尾が「/-」の CodeBase は、指定されたディレクトリとその下の全サブディレクトリ内のすべてのファイル (クラスファイルと JAR ファイルの両方) を示します。
CodeBase フィールド (URL) は、省略可能なオプションフィールドで、省略した場合は「任意のコードベース」が指定されます。
最初の署名者名フィールドは、署名者に関連付けられている 1 組の公開鍵 (キーストアの証明書内にある) に、別のメカニズムを通じてマッピングされた文字列の別名です。これらの鍵は、ある署名付きのクラスが本当にこれらの署名者によって署名されたかどうかを確認するために使用されます。
この署名者フィールドは、複数の署名者の名前をコンマ区切りの文字列で指定できます。たとえば、「Adam,Eve,Charles」は、Adam と Eve と Charles によって署名されることを意味します (各者の関係は OR ではなく AND)。
このフィールドは省略可能なオプションフィールドで、省略した場合は「任意の署名者」、つまり「コードが署名付きかどうかは不問」の指定になります。
Permission エントリ内にある 2 つ目の署名者フィールドは、keystore エントリの別名を表します。この keystore エントリには、そのアクセス権クラスを実装しているバイトコードへの署名に使用される非公開鍵に対応する公開鍵が含まれます。このアクセス権エントリが有効なのは (つまりこのエントリに基づいてアクセス制御権が与えられるのは)、バイトコードの実装が別名によって正しく署名されていることが確認された場合だけです。
プリンシパルの値は class_name と principal_name のペアを指定します。このペアは、実行中のスレッドのプリンシパルセット内にある必要があります。プリンシパルセットは、Subject によって実行するコードに関連付けられます。プリンシパルフィールドは省略可能です。省略した場合は、「任意のプリンシパル」という意味になります。
プリンシパル class_name/principal_name のペアが単一引用符で囲まれた文字列として指定される場合は、キーストアの別名として扱われます。キーストアは別名を経由して X509 証明書を調査し、問い合わせます。キーストアがある場合は、principal_class は自動的に javax.security.auth.x500.X500Principal
として扱われ、principal_name は証明書で名前を識別されたサブジェクトとして自動的に扱われます。X509 証明書のマッピングが見つからない場合は、grant エントリはすべて無視されます。
CodeBase フィールド、SignedBy フィールド、および Principal フィールドの順序は任意です。
Policy ファイル形式の、非公式の BNF 文法の例を次に示します。ここで小文字で始まる語はターミナル語です。
PolicyFile -> PolicyEntry | PolicyEntry; PolicyFile PolicyEntry -> grant {PermissionEntry}; | grant SignerEntry {PermissionEntry} | grant CodebaseEntry {PermissionEntry} | grant PrincipalEntry {PermissionEntry} | grant SignerEntry, CodebaseEntry {PermissionEntry} | grant CodebaseEntry, SignerEntry {PermissionEntry} | grant SignerEntry, PrincipalEntry {PermissionEntry} | grant PrincipalEntry, SignerEntry {PermissionEntry} | grant CodebaseEntry, PrincipalEntry {PermissionEntry} | grant PrincipalEntry, CodebaseEntry {PermissionEntry} | grant SignerEntry, CodebaseEntry, PrincipalEntry {PermissionEntry} | grant CodebaseEntry, SignerEntry, PrincipalEntry {PermissionEntry} | grant SignerEntry, PrincipalEntry, CodebaseEntry {PermissionEntry} | grant CodebaseEntry, PrincipalEntry, SignerEntry {PermissionEntry} | grant PrincipalEntry, CodebaseEntry, SignerEntry {PermissionEntry} | grant PrincipalEntry, SignerEntry, CodebaseEntry {PermissionEntry} | keystore "url" SignerEntry -> signedby (a comma-separated list of strings) CodebaseEntry -> codebase (a string representation of a URL) PrincipalEntry -> OnePrincipal | OnePrincipal, PrincipalEntry OnePrincipal -> principal [ principal_class_name ] "principal_name" (a principal) PermissionEntry -> OnePermission | OnePermission PermissionEntry OnePermission -> permission permission_class_name [ "target_name" ] [, "action_list"] [, SignerEntry];ここで、いくつか例を示します。次のポリシーでは、Roland によって署名されたコードにアクセス権 a.b.Foo を与えます。
grant signedBy "Roland" { permission a.b.Foo; };次の例では、すべてのコード (署名者やコードベースにかかわらず) に FilePermission を与えます。
grant { permission java.io.FilePermission ".tmp", "read"; };次の例では、Li と Roland の両者によって署名されたコードに、2 つのアクセス権を与えます。
grant signedBy "Roland,Li" { permission java.io.FilePermission "/tmp/*", "read"; permission java.util.PropertyPermission "user.*"; };次の例では、Li によって署名され http://www.example.com からロードされたコードに、2 つのアクセス権を与えます。
grant codeBase "http://www.example.com/*", signedBy "Li" { permission java.io.FilePermission "/tmp/*", "read"; permission java.io.SocketPermission "*", "connect"; };次の例では、com.abc.TVPermission を実装したバイトコードが確実に Li によって署名されている場合にだけ、Li と Roland の両者によって署名されたコードに 2 つのアクセス権を与えます。
grant signedBy "Roland,Li" { permission java.io.FilePermission "/tmp/*", "read"; permission com.abc.TVPermission "channel-5", "watch", signedBy "Li"; };2 つ目の署名者フィールドを使う目的は、インストールされた Java Runtime にそのアクセス権クラスが存在しない場合に、不正行為を防ぐことです。たとえば、com.abc.TVPermission クラスのコピーは、リモートの JAR アーカイブの一部としてダウンロードできますが、ユーザーポリシーにそれを参照するエントリが含まれることがあります。アーカイブは短命なので、com.abc.TVPermission クラスが別の Web サイトからふたたびダウンロードされる可能性があります。このときのユーザーポリシー内のアクセス権エントリの存在は、クラスのバイトコードの最初のコピーに対するユーザーの信頼を反映するものであるため、2 つ目のコピーが認証済みであることは重要です。
認証を確実なものにするために、バイトコードの最初のコピー (のハッシュ値) を保存して 2 つ目のコピーと比べる方法ではなく、デジタル署名を使用する理由は、アクセス権クラスの作者が合法的にクラスファイルを更新して新しい設計や実装を反映することがあるからです。
注: ファイルパスの文字列は、プラットフォームごとに異なる形式で指定する必要があります。これは、将来、全プラットフォームに共通するファイル記述言語ができるまでは必要です。上記の各例は、Solaris システム用の文字列で記述されています。Windows システムでは、文字列中で直接ファイルパスを指定する場合は、単一のバックスラッシュは次のように二重のバックスラッシュで表します。
grant signedBy "Roland" { permission java.io.FilePermission "C:\\users\\Cathy\\*", "read"; };文字列はトークナイザ (java.io.StreamTokenizer) によって処理されますが、そこでは「\」を使用したエスケープ文字列 (改行を表す「\n」など) の使用が許されるので、単一のバックスラッシュを表すためには二重のバックスラッシュを使用する必要があります。トークナイザが FilePermission のターゲット文字列の処理を終え、二重のバックスラッシュを単一のバックスラッシュに変換すると、結果は次の実際のパスになります
"C:\users\Cathy\*"最後に、プリンシパルベースの grant エントリの例を示します。
grant principal javax.security.auth.x500.X500Principal "cn=Alice" { permission java.io.FilePermission "/home/Alice", "read, write"; };これにより、X500Principal のアクセス権 cn=Alice として実行するコードは /home/Alice を読み取ることも書き込むことも可能になります。
次の例は、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.bar.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 ディレクトリへの読み取りアクセス権と書き込みアクセス権が与えられます。
プロパティーの展開は、シェルにおける変数の展開に似ています。ポリシーファイルまたはセキュリティープロパティーファイルに次のような文字列がある場合、
この文字列は指定されたシステムプロパティーの値まで展開されます。次に例を示します。
permission java.io.FilePermission "${user.home}", "read";この場合、"${user.home}" は、システムプロパティー user.home の値に展開されます。user.home の値が /home/cathy である場合、上の記述は下の記述と同じになります。
permission java.io.FilePermission "/home/cathy", "read";プラットフォームにより異なるポリシーファイルを使いやすくするために、${/} という特殊な表記 (${file.separator} の簡略形) も使用できます。これは「${file.separator}」へのショートカットで、次のようにしてアクセス権を定義できます。
permission java.io.FilePermission "${user.home}${/}*", "read";Solaris システムで、user.home が /home/cathy であれば、これは次のように変換されます。
permission java.io.FilePermission "/home/cathy/*", "read";Windows システムで、user.home が C:\users\cathy であれば、次のように変換されます。
permission java.io.FilePermission "C:\users\cathy\*", "read";特殊なケースとして、コードベースのプロパティーを次のように記述すると、
grant codeBase "file:/${java.home}/lib/ext/"file.separator 文字は自動的にすべて / に置き換えられます。コードベースが URL であるため、/ に置き換えるのが望ましいといえます。したがって、Windows システムで java.home が C:\j2sdk1.2 に設定されていても、次のように変換されます。
grant codeBase "file:/C:/j2sdk1.2/lib/ext/"したがって、コードベース文字列では ${/} を使う必要はありません。また、使うべきではありません。
プロパティーの展開は、ポリシーファイル内で、二重引用符で囲まれた文字列が使用できる場所であればどこでも行われます。これには、署名者、コードベース、ターゲット名、動作の各フィールドがあります。
プロパティーの展開が許可されるかどうかは、セキュリティープロパティーファイルの policy.expandProperties プロパティーの値によって決まります。このプロパティーの値が true (デフォルト) の場合は、展開が許可されます。
注: 入れ子のプロパティーは使用できません。次に例を示します。
"${user.${foo}}"この例では、foo プロパティーが home に設定されている場合であっても、エラーになります。これは、プロパティー構文解析プログラムは入れ子になったプロパティーを認識しないためです。プロパティー構文解析プログラムは、最初の「${」を見つけたら、次に最初の「}」を探し、結果の「${user.$foo}」をプロパティーと解釈しようと試みます。しかし、そのようなプロパティーがない場合はエラーになります。
注: grant エントリ、アクセス権エントリ、または keystore エントリで展開できないプロパティーがある場合、そのエントリは無視されます。たとえば、次のようにシステムプロパティー foo が定義されていない場合、
grant codeBase "${foo}" { permission ...; permission ...; };この grant エントリ内の permission はすべて無視されます。また、次のような場合、
grant { permission Foo "${foo}"; permission Bar; };permission Foo... エントリだけが無視されます。また、次のように指定されている場合、
keystore "${foo}";この場合は、keystore エントリが無視されます。
注: Windows システムでは、文字列中で直接ファイルパスを指定する場合は、単一のバックスラッシュは次のように二重のバックスラッシュで表します。
"C:\\users\\cathy\\foo.bat"文字列はトークナイザ (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"
デフォルトのポリシーファイルの実装では、次の 2 つのプロトコルがサポートされます。
プロトコル self は、${{self}} 文字列全体を 1 つ以上のプリンシパルクラスとプリンシパル名のペアに置き換えることを示します。実際に実行される置き換えは、permission を含む grant 節の内容によって決まります。
grant 節にプリンシパルの情報が含まれていない場合は、permission は無視されます。プリンシパルベースの grant 節のコンテキストでは、ターゲット名に ${{self}} を含む permission のみが有効です。たとえば、次の grant 節内の BarPermission は常に無視されます。
grant codebase "www.foo.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.bar.example.com/blah/.keystore"; grant principal "duke" { permission BarPermission "... ${{self}} ..."; };上の例では、初めに "duke" が、javax.security.auth.x500.X500Principal "cn=Duke" に展開されます。ただし、キーストアの別名「duke」に関連付けられた X.509 証明書がサブジェクトの識別名「cn=Duke」を持っていることが前提となります。次に、${{self}} が、grant 節内で展開されたその同じプリンシパル情報に置き換えられます。javax.security.auth.x500.X500Principal "cn=Duke"
プロトコル alias は、java.security.KeyStore 別名の置換を示します。KeyStore エントリ に指定された KeyStore
が使用されます。alias_name は、KeyStore
の別名を表します。${{alias:alias_name}} は、javax.security.auth.x500.X500Principal "DN" に置き換えられます。DN は、alias_name に属する証明書のサブジェクトの識別名を表します。たとえば、
keystore "http://foo.bar.example.com/blah/.keystore"; grant codebase "www.foo.example.com" { permission BarPermission "... ${{alias:duke}} ..."; };上の例の別名 duke に関連付けられている X.509 証明書は、
KeyStore
(foo.bar.com/blah/.keystore) から取得されます。duke の証明書がサブジェクト識別名として "o=dukeOrg, cn=duke" を指定し、${{alias:duke}} が javax.security.auth.x500.X500Principal "o=dukeOrg, cn=duke" で置き換えられるものとします。
次のエラー条件に該当する場合、アクセス権エントリは無視されます。
getPermissions
メソッドまたは implies
メソッドを呼び出すことにより行われます。
ワイルドカード「*」の使用が認められているなどの理由により、ProtectionDomain 内のコードソースがポリシー内の複数のエントリのコードソースに一致することがあります。
ポリシー内の適切なアクセス権セットを探すために、次のアルゴリズムが使用されます。
1. match the public keys, if code is signed. 2. if a key is not recognized in the policy, ignore the key if every key is ignored, treat the code as unsigned. 3. if the keys are matched, or no signer was specified { try to match all URLs in the policy for the keys } 4. if the keys are matched (or no signer was specified), and the URLs are matched (or no codebase was specified) { try to match all principals in the policy with the principals associated with the current executing thread. 5. if either key, URL, or principals are not matched, use built-in default permission, which is the original sandbox permission.ポリシーエントリの codeBase URL の正確な意味は、最後の文字に依存します。末尾が「/」の codeBase は、指定されたディレクトリ内のすべてのクラスファイル (JAR ファイルを除く) を示します。末尾が「/*」の codeBase は、そのディレクトリ内にあるすべてのファイル (クラスファイルと JAR ファイルの両方) を示します。末尾が「/-」の codeBase は、指定されたディレクトリとその下の全サブディレクトリ内のすべてのファイル (クラスファイルと JAR ファイルの両方) を示します。
たとえば、ポリシー内に「http://www.example.com/-」がある場合は、その Web サイト上のすべてのコードベースはこのポリシーエントリに一致します。一致するコードベースには、「http://www.example.com/j2se/sdk/」および「http://www.example.com/people/gong/appl.jar」があります。
複数のエントリが一致する場合は、それらのエントリ内のすべてのアクセス権が与えられます。つまり、アクセス権は追加割り当てできます。たとえば、鍵 A で署名されたコードにアクセス権 X が与えられ、鍵 B で署名されたコードにはアクセス権 Y が与えられており、特定のコードベースが指定されていない場合、A と B の両方で署名されたコードにはアクセス権 X と Y の両方が与えられます。同様に、コードベースが「http://www.example.com/-」のコードにアクセス権 X が与えられ、「http://www.example.com/people/*」のコードにアクセス権 Y が与えられており、特定の署名者が指定されていない場合は、「http://www.example.com/people/applet.jar」からのアプレットには X と Y の両方のアクセス権が与えられます。
ここでの URL のマッチングは、純粋に構文上のマッチングです。たとえば、あるポリシーに URL「ftp://ftp.sun.com」を指定するエントリがあるとします。このようなエントリは、Java コードを直接 ftp からダウンロードして実行できる場合にだけ有用です。
ローカルファイルシステムの URL を指定する場合、ファイルの URL を使用できます。たとえば Solaris システムの /home/cathy/temp ディレクトリ内のファイルを指定するには、次のようにします。
"file:/home/cathy/temp/*"Windows システムの C ドライブにある temp ディレクトリ内のファイルを指定するには、次のようにします。
"file:/c:/temp/*"注:コードベースの URL には、プラットフォームにかかわらず、必ず「/」(「\」記号ではなく) を使用してください。
"/home/gong/bin/MyWonderfulJava"
ポリシーファイルは、単純なテキストエディタ、または後述する PolicyTool ユーティリティーを使って作成できます。
デフォルトでは、システム全体のポリシーファイルが 1 つあり、ユーザーポリシーファイルが 1 つあります。
システムポリシーファイルは、デフォルトでは次の場所にあります。
{java.home}/lib/security/java.policy (Solaris) {java.home}\lib\security\java.policy (Windows)ここで java.home は Java 2 SDK がインストールされているディレクトリを示すシステムプロパティーです。
ユーザーポリシーファイルは、デフォルトでは次の場所にあります。
{user.home}/.java.policy (Solaris) {user.home}\.java.policy (Windows)ここで user.home は、ユーザーのホームディレクトリを示すシステムプロパティーです。
Policy が初期化されると、まずシステムポリシーがロードされ、次に、ロードされたシステムポリシーにユーザーポリシーが追加されます。どちらのポリシーも存在しない場合は、組み込みポリシーが使われます。組み込みポリシーは、オリジナルのサンドボックス (sandbox) ポリシーと同じものです。
ポリシーファイルの場所は、セキュリティープロパティーファイルの中で指定されています。セキュリティープロパティーファイルは、次の場所にあります。
{java.home}/lib/security/java.security (Solaris) {java.home}\lib/security\java.security (Windows)ポリシーファイルの場所は、次のような形式の名前を持つプロパティーの値として指定されています。
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「http://」の形式のものも含めて、実際には複数の URL を指定でき、指定したポリシーファイルのすべてがロードされます。また、上に示したポリシーファイルの指定のうち、2 番目のポリシーファイルの指定をコメントアウトするか、あるいは修正すれば、デフォルトユーザーポリシーファイルの読み込みを無効にすることができます。
アルゴリズムは、policy.url.1 から処理を開始して、番号を 1 つずつ増やしながら、URL が見つからなくなるまで処理を続けます。したがって、policy.url.1 と policy.url.3 がある場合、policy.url.3 は読み込まれません。
アプリケーションを実行するときに、追加のポリシーファイルや別のポリシーファイルを指定することもできます。この場合は、-Djava.security.policy コマンド行引数を使って java.security.policy プロパティーの値を設定します。たとえば、次のように指定します。
java -Djava.security.manager -Djava.security.policy=pURL SomeAppここで pURL は、ポリシーファイルの位置を示す URL です。指定されたポリシーファイルは、セキュリティープロパティーファイルで指定されたすべてのポリシーファイルに追加されてロードされます。引数「-Djava.security.manager」により、デフォルトのセキュリティーマネージャーが確実にインストールされるので、「アプレットおよびアプリケーションのセキュリティー管理」の説明にあるように、アプリケーションはポリシーチェックを受けます。アプリケーション SomeApp がセキュリティーマネージャーをインストールする場合は、-Djava.security.manager 引数を指定する必要はありません。
次のように、「==」の付いた形式を使うと、ここで指定されたポリシーファイルだけがロードされ、ほかのポリシーファイルは無視されます。
java -Djava.security.manager -Djava.security.policy==pURL SomeAppアプレットビューアにポリシーファイルを渡す場合も、次のように「-Djava.security.policy」引数を使います。
appletviewer -J-Djava.security.policy=pURL myApplet注: セキュリティープロパティーファイルで policy.allowSystemProperty プロパティーに false が設定されている場合は、-Djava.security.policy のポリシーファイルの値は (java コマンドと appletviewer コマンドのどちらの場合も) 無視されます。デフォルトは true です。
getPermissions
メソッド (および必要に応じてほかのメソッド) を実装していることが条件です。
Policy のリファレンス実装は、「policy.provider」セキュリティープロパティー (セキュリティープロパティーファイル内) の値を、目的の Poliocy 実装クラスの完全修飾形の名前に設定し直すことにより変更できます。セキュリティープロパティーファイルは、次の名前のファイルです。
{java.home}/lib/security/java.security (Solaris) {java.home}\lib\security\java.security (Windows){java.home} は、実行環境がインストールされたディレクトリ (Java 2 SDK 内の jre ディレクトリ、または Java 2 Runtime Environment の最上位ディレクトリ) を参照します。
policy.provider プロパティーは、ポリシークラスの名前を指します。デフォルトは次のとおりです。
policy.provider=sun.security.provider.PolicyFileカスタマイズするには、次のように、このプロパティー値に別のクラスを指定します。
policy.provider=com.mycom.MyPolicyMyPolicy クラスは、java.security.Policy のサブクラスでなければなりません。このような、ポリシークラスのオーバーライドはあくまでも一時的な解決策であり、より包括的なポリシー API が設計されれば不要になります。
RuntimeException のサブクラスである java.security パッケージ内に、現時点で 2 つの例外があります。下位互換性により、現時点ではこれらの例外は変更できません。将来この問題を再検討します。
目次 | 前へ | 次へ |