パスワード
アクセス制限サービス
Web は、常に全ての人類に向けられているとは限りません
特定の地域や、会員向けのサービスコンテンツも数多く存在します
こうしたコンテンツは、通常はユーザー名と ID でアクセスを制御しています
指定した URL が無条件でアクセスできるとは限りません
時には、サーバーはパスワードを要求してくる可能性があるのです
これを厳密に制御するにはプロトコルの知識が必要だと思われるかもしれませんが
Java ネットワーク API は、サーバーとの通信は隠蔽してくれます
パスワードは java.net.PasswordAuthentication クラスで表されます
このクラスは、ユーザー名とパスワードをパッケージ化しています
public final class PasswordAuthentication extends Object
このクラスのコンストラクタは次のようになっています
PasswordAuthentication(String userName, char[] password)
userName はユーザー名を、password にはパスワードを指定します
パスワードは基本的に重要な情報であり、他人に盗まれてはいけません
そこで、いつでもデータを完全に上書きできるように char 配列を用いています
このクラスは、ユーザー名を返す PasswordAuthentication.getUserName() と
パスワードを返す PasswordAuthentication.getPassword() があります
public String getUserName()
public char[] getPassword()
getUserName() はユーザー名を、getPassword() はパスワードを返します
このクラスの機能はこれだけです
URL クラスは、データの取得に認証が必要であると判断した場合
設定されている java.net.Authenticator を呼び出す仕組みになっています
このクラスの実装は、要求に応じて PasswordAuthentication を返すのです
public abstract class Authenticator extends Object
このクラスは抽象クラスなのでインスタンス化できません
これはオーセンティケータと呼ばれ、システムに関連付けられます
開発者はこのクラスのサブクラスを作り、コールバックメソッドの
Authenticator.getPasswordAuthentication() をオーバーライドします
protected PasswordAuthentication getPasswordAuthentication()
このメソッドは、オーセンティケータがパスワードを要求された時に呼び出されます
開発者は実装クラスで、必要な情報をユーザーにインプットしてもらうか
あらかじめ用意されている暗号化された鍵ファイルを読み込みます
そして PasswordAuthentication を返せば、システムはこれを利用してアクセスを試みます
Authenticator は Authenticator.setDefault() 静的メソッドを使い
システムに、このクラスの実装クラスをインストールすることができます
public static void setDefault(Authenticator a)
a にはオーセンティケータを指定します
システムは、設定されているオーセンティケータに認証を要求します
import java.net.*;
import java.io.*;
public class Test {
public static void main(String args[]) {
Authenticator auth = new InputPass();
Authenticator.setDefault(auth);
try {
URL url = new URL(args[0]);
FileOutputStream out = new FileOutputStream(args[1]);
InputStream input = url.openStream();
while(true) {
int read = input.read();
if (read == -1) break;
out.write(read);
}
out.close();
}
catch(Exception err) {
System.out.println(err);
}
}
}
class InputPass extends Authenticator {
protected PasswordAuthentication getPasswordAuthentication() {
String user = "" , pass = "";
try {
System.out.print("ユーザー名を入力してください>");
LineNumberReader in = new LineNumberReader(
new InputStreamReader(System.in));
user = in.readLine();
System.out.print("パスワードを入力してください>");
in = new LineNumberReader(
new InputStreamReader(System.in));
pass = in.readLine();
}
catch (IOException err) {
System.out.println(err);
}
return new PasswordAuthentication(user , pass.toCharArray());
}
}
このプログラムは、ダウンロードプログラムの改訂版です
コマンドラインから、対象ファイルの URL と保存するファイル名を指定します
実行すると、次のようになります(本当は、認証情報はそのまま表示されます)
...>java Test http://www.age-soft.co.jp/fc/aut/ test.html
ユーザー名を入力してください>*****
パスワードを入力してください>*****
指定した URL が認証を必要とする場合
システムはオーセンティケータの getPasswordAuthentication() を呼び出します
そして、返されたユーザー名とパスワードを利用してアクセスします
認証を必要としなければ、オーセンティケータは呼び出されませんし
返した認証パスワードが間違っていれば、再度呼び出されます
しかし、いきなりパスワードを入力しろといわれても
どこが要求し、どのように利用されるのかをユーザーは知りたいでしょう
オーセンティケータは、このような情報も保有しています
protected final String getRequestingHost()
protected final InetAddress getRequestingSite()
protected final int getRequestingPort()
protected final String getRequestingProtocol()
protected final String getRequestingPrompt()
protected final String getRequestingScheme()
getRequestHost() はホスト名を getRequestingSite() はアドレスを返します
getRequestingPort() は要求者のポート番号を
getRequestingProtocol() は使用しているプロトコルを返します
String getRequestingPrompt() はプロンプト文字列を返します
これは、要求者が http を用いている場合に入力する文字列です
getRequestingScheme() は要求者が使用している方式を返します
import java.net.*;
import java.io.*;
public class Test {
public static void main(String args[]) {
Authenticator auth = new InputPass();
Authenticator.setDefault(auth);
try {
URL url = new URL(args[0]);
FileOutputStream out = new FileOutputStream(args[1]);
InputStream input = url.openStream();
while(true) {
int read = input.read();
if (read == -1) break;
out.write(read);
}
out.close();
}
catch(Exception err) {
System.out.println(err);
}
}
}
class InputPass extends Authenticator {
protected PasswordAuthentication getPasswordAuthentication() {
String user = "" , pass = "";
try {
System.out.println("リクエスト : " + getRequestingHost());
System.out.println("ポート : " + getRequestingPort());
System.out.println("プロンプト : " + getRequestingPrompt());
System.out.println("プロトコル : " + getRequestingProtocol());
System.out.println("スキーム : " + getRequestingScheme());
System.out.print("ユーザー名を入力してください>");
LineNumberReader in = new LineNumberReader(
new InputStreamReader(System.in));
user = in.readLine();
System.out.print("パスワードを入力してください>");
in = new LineNumberReader(
new InputStreamReader(System.in));
pass = in.readLine();
}
catch (IOException err) {
System.out.println(err);
}
return new PasswordAuthentication(user , pass.toCharArray());
}
}
これは、先ほどのプログラムとほとんど同じものですが
パスワードの入力時に、要求者の情報を標準出力に表示します
...>java Test http://www.age-soft.co.jp/fc/aut/ test.html
リクエスト : www.age-soft.co.jp
ポート : 80
プロンプト : agekunohate-menbers
プロトコル : http
スキーム : basic
ユーザー名を入力してください>...
このような結果になるでしょう