クライアントとサーバーのセキュアなソケット接続を表すサンプル・コード
これらのサンプルでは、クライアントとサーバーの間にセキュアなソケット接続を設定する方法を示します。
サンプルのクライアント・プログラムを実行中に、Webサーバーなどの既存のサーバーと通信できます。または、サンプル・サーバー・プログラムClassFileServer
と通信することもできます。サンプルのクライアント・プログラムとサーバー・プログラムは、同じネットワークに接続された別個のマシンで実行することも、1台のマシンで、ただし別のターミナル・ウィンドウから両方を実行することもできます。
amples/sockets/clientディレクトリのサンプルSSLSocketClient*
プログラム(および「HTTPS接続を表すサンプル・コード」で説明するURLReader*
プログラム)は、すべてClassFileServer
サンプル・サーバー・プログラムで実行できます。これを実行する方法の例は、「ClassFileServerを使用したSSLSocketClientWithClientAuthの実行」に示しています。同様の変更をして、URLReader
、SSLSocketClient
またはSSLSocketClientWithTunneling
をClassFileServer
で実行できます。
クライアントとサーバーとの間で通信中に認証エラーが発生する場合(WebサーバーとClassFileServer
のどちらを使用しているか関係なく)、必要な鍵がトラストストア(トラスト鍵データベース)にないためである可能性があります。用語と定義を参照してください。たとえば、ClassFileServer
は、SSLハンドシェーク中に必要なlocalhost
の公開鍵を格納するtestkeys
というキーストアを使用します。testkeys
キーストアはClassFileServer
ソースと同じsamples/sockets/serverディレクトリにあります。参照するトラストストアで、localhost
の対応する公開鍵の証明書をクライアントが見つけられない場合、認証エラーが発生します。SSLソケット・サンプルの構成要件で説明しているように、samplecacerts
トラストストア(localhost
の公開鍵と証明書を格納する)を使用してください。
SSLソケット・サンプルの構成要件
クライアントとサーバーとの間のセキュアなソケット接続を作成するサンプル・プログラムを実行する場合は、適切な証明書ファイル(トラストストア)を利用できるようにしておく必要があります。クライアント・プログラムとサーバー・プログラムの両方で、samples
ディレクトリのsamplecacerts
証明書ファイルを使用してください。この証明書ファイルを使用すると、クライアントがサーバーを認証できるようになります。このファイルには、JDK (cacertsファイルにある)に付属する一般的な証明書発行局(CA)のすべての証明書と、サンプルサーバーClassFileServer
との通信時にクライアントがlocalhost
を認証するために必要なlocalhost
の証明書が含まれています。ClassFileServer
は、samplecacerts
の公開鍵に対応するlocalhost
の公開鍵を含むキーストアを使用します。
クライアントとサーバーの両方でsamplecacerts
ファイルを使用できるようにするには、それをjava-home/lib/security/jssecacerts
ファイルにコピーして名前をcacerts
に変更し、java-home/lib/security/cacerts
ファイルと置き換えます。あるいは、クライアントとサーバーの両方に対してjava
コマンドを実行する場合は、次のオプションをコマンド行に追加します。
-Djavax.net.ssl.trustStore=path_to_samplecacerts_file
samplecacerts
トラスト・ストアのパスワードはchangeit
です。keytool
ユーティリティを使用して、サンプルの独自の証明書を置き換えることができます。
ブラウザを使用して、ClassFileServer
の例で提供されているサンプルのSSLサーバーにアクセスしている場合は、ダイアログ・ボックスが開いて、証明書が認識されないというメッセージが表示されます。これは、サンプル・プログラムで使用する証明書は自己署名付きのもので、テスト用にすぎないためです。現在のセッションで証明書に同意できます。SSLサーバーのテストが終了したあと、ブラウザを終了し、ブラウザの名前空間からテスト用証明書を削除します。
クライアント認証の場合、適切なディレクトリの別のduke
証明書を使用できます。公開鍵および証明書も、samplecacerts
ファイルに格納されています。
SSLSocketClientの実行
SSLSocketClient.java
の例では、SSLSocket
を使用するクライアントを作成し、HTTP要求を送信してHTTPSサーバーから応答を受け取る方法を示します。デフォルトでは、この例はwww.verisign.com
に接続しますが、ClassFileServer
に接続するように簡単に調整できます(ClassFileServerの実行を参照)。このプログラムの出力は、https://www.verisign.com/index.html
のHTMLソースです。
ファイアウォールの内側から、このプログラムを提供されたとおりに実行しないでください。ファイアウォールの内側から実行すると、JSSEはファイアウォールを経由したwww.verisign.com
へのパスを検出できないので、UnknownHostException
を受け取ります。ファイアウォールの外側から実行できる同等のクライアントを作成するには、サンプル・プログラムSSLSocketClientWithTunneling
で示すように、プロキシ・トンネリングを設定します。
注意:
ファイルが指定されるように、GETリクエストを少し変更する必要があります。
使用方法
java SSLSocketClient
SSLSocketClient.java
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
/*
* This example demostrates how to use a SSLSocket as client to
* send a HTTP request and get response from an HTTPS server.
* It assumes that the client is not behind a firewall
*/
public class SSLSocketClient {
public static void main(String[] args) throws Exception {
try {
SSLSocketFactory factory =
(SSLSocketFactory)SSLSocketFactory.getDefault();
SSLSocket socket =
(SSLSocket)factory.createSocket("www.verisign.com", 443);
/*
* send http request
*
* Before any application data is sent or received, the
* SSL socket will do SSL handshaking first to set up
* the security attributes.
*
* SSL handshaking can be initiated by either flushing data
* down the pipe, or by starting the handshaking by hand.
*
* Handshaking is started manually in this example because
* PrintWriter catches all IOExceptions (including
* SSLExceptions), sets an internal error flag, and then
* returns without rethrowing the exception.
*
* Unfortunately, this means any error messages are lost,
* which caused lots of confusion for others using this
* code. The only way to tell there was an error is to call
* PrintWriter.checkError().
*/
socket.startHandshake();
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())));
out.println("GET / HTTP/1.0");
out.println();
out.flush();
/*
* Make sure there were no surprises
*/
if (out.checkError())
System.out.println(
"SSLSocketClient: java.io.PrintWriter error");
/* read response */
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
out.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
SSLSocketClientWithTunnellingの実行
SSLSocketClientWithTunneling.java
の例は、ファイアウォールの外側からセキュアなWebサーバーにアクセスするプロキシ・トンネリングの方法を示します。
プログラムはhttps://www.verisign.com/index.html
のHTMLソース・ファイルを返します。
使用方法
java -Dhttps.proxyHost=webproxy -Dhttps.proxyPort=ProxyPortNumber SSLSocketClientWithTunneling
webproxy
は使用するプロキシ・ホスト名に、ProxyPortNumber
は適切なポート番号に置き換えてください。
システム・プロパティhttps.proxyHost
およびhttps.proxyPort
は、プロキシ・ホストへのソケット接続を作成するために使用され、その後、SSLSocketは、そのソケットの上の階層に配置されます。
SSLSocketClientWithTunneling.java
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
/*
* This example illustrates how to do proxy Tunneling to access a
* secure web server from behind a firewall.
*
* Please set the following Java system properties
* to the appropriate values:
*
* https.proxyHost = <secure proxy server hostname>
* https.proxyPort = <secure proxy server port>
*/
public class SSLSocketClientWithTunneling {
public static void main(String[] args) throws Exception {
new SSLSocketClientWithTunneling().doIt("www.verisign.com", 443);
}
String tunnelHost;
int tunnelPort;
public void doIt(String host, int port) {
try {
/*
* Let's setup the SSLContext first, as there's a lot of
* computations to be done. If the socket were created
* before the SSLContext, the server/proxy might timeout
* waiting for the client to actually send something.
*/
SSLSocketFactory factory =
(SSLSocketFactory)SSLSocketFactory.getDefault();
/*
* Set up a socket to do tunneling through the proxy.
* Start it off as a regular socket, then layer SSL
* over the top of it.
*/
tunnelHost = System.getProperty("https.proxyHost");
tunnelPort = Integer.getInteger("https.proxyPort").intValue();
Socket tunnel = new Socket(tunnelHost, tunnelPort);
doTunnelHandshake(tunnel, host, port);
/*
* Ok, let's overlay the tunnel socket with SSL.
*/
SSLSocket socket =
(SSLSocket)factory.createSocket(tunnel, host, port, true);
/*
* register a callback for handshaking completion event
*/
socket.addHandshakeCompletedListener(
new HandshakeCompletedListener() {
public void handshakeCompleted(
HandshakeCompletedEvent event) {
System.out.println("Handshake finished!");
System.out.println(
"\t CipherSuite:" + event.getCipherSuite());
System.out.println(
"\t SessionId " + event.getSession());
System.out.println(
"\t PeerHost " + event.getSession().getPeerHost());
}
}
);
/*
* send http request
*
* See SSLSocketClient.java for more information about why
* there is a forced handshake here when using PrintWriters.
*/
socket.startHandshake();
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())));
out.println("GET / HTTP/1.0");
out.println();
out.flush();
/*
* Make sure there were no surprises
*/
if (out.checkError())
System.out.println(
"SSLSocketClient: java.io.PrintWriter error");
/* read response */
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
out.close();
socket.close();
tunnel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Tell our tunnel where we want to CONNECT, and look for the
* right reply. Throw IOException if anything goes wrong.
*/
private void doTunnelHandshake(Socket tunnel, String host, int port)
throws IOException
{
OutputStream out = tunnel.getOutputStream();
String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n"
+ "User-Agent: "
+ sun.net.www.protocol.http.HttpURLConnection.userAgent
+ "\r\n\r\n";
byte b[];
try {
/*
* We really do want ASCII7 -- the http protocol doesn't change
* with locale.
*/
b = msg.getBytes("ASCII7");
} catch (UnsupportedEncodingException ignored) {
/*
* If ASCII7 isn't there, something serious is wrong, but
* Paranoia Is Good (tm)
*/
b = msg.getBytes();
}
out.write(b);
out.flush();
/*
* We need to store the reply so we can create a detailed
* error message to the user.
*/
byte reply[] = new byte[200];
int replyLen = 0;
int newlinesSeen = 0;
boolean headerDone = false; /* Done on first newline */
InputStream in = tunnel.getInputStream();
boolean error = false;
while (newlinesSeen < 2) {
int i = in.read();
if (i < 0) {
throw new IOException("Unexpected EOF from proxy");
}
if (i == '\n') {
headerDone = true;
++newlinesSeen;
} else if (i != '\r') {
newlinesSeen = 0;
if (!headerDone && replyLen < reply.length) {
reply[replyLen++] = (byte) i;
}
}
}
/*
* Converting the byte array to a string is slightly wasteful
* in the case where the connection was successful, but it's
* insignificant compared to the network overhead.
*/
String replyStr;
try {
replyStr = new String(reply, 0, replyLen, "ASCII7");
} catch (UnsupportedEncodingException ignored) {
replyStr = new String(reply, 0, replyLen);
}
/* We asked for HTTP/1.0, so we should get that back */
if (!replyStr.startsWith("HTTP/1.0 200")) {
throw new IOException("Unable to tunnel through "
+ tunnelHost + ":" + tunnelPort
+ ". Proxy returns \"" + replyStr + "\"");
}
/* tunneling Handshake was successful! */
}
}
SSLSocketClientWithClientAuthの実行
SSLSocketClientWithClientAuth.java
の例はRunning SSLSocketClientに似ていますが、これは、サーバーから要求された場合にクライアント認証を実行するためにキー・マネージャを設定する方法を示します。このプログラムも、クライアントがファイアウォールの外側にはいないことを前提にしています。SSLSocketClientWithTunnellingの実行の例に従ってプログラムを変更すれば、ファイアウォールの内側から接続することもできます。
このプログラムを実行するには、ホスト、ポート、および要求されたファイル・パスの3つのパラメータを指定する必要があります。前の例を反映させるには、ホストにwww.verisign.com
、ポート番号に443
、要求されたファイル・パスにhttps://www.verisign.com/
を設定することで、このプログラムをクライアント認証なしで実行します。これらのパラメータを使用したときの出力が、Webサイトhttps://www.verisign.com/
のHTMLソースです。
SSLSocketClientWithClientAuth
を実行してクライアント認証を行うには、クライアント認証を要求するサーバーにアクセスする必要があります。このサーバーには、サンプル・プログラムClassFileServer
を使用できます。ClassFileServerによるSSLSocketClientWithClientAuthの実行を参照してください。
使用方法
java SSLSocketClientWithClientAuth host port requestedfilepath
注意:
前述のClassFileServerアプリケーションに接続する場合は、このアプリケーションがduke
ユーザーのクレデンシャルを検出できることを確認してください。サンプル・トラストストアを参照してください。
SSLSocketClientWithClientAuth.java
import java.net.*;
import java.io.*;
import javax.net.ssl.*;
import javax.security.cert.X509Certificate;
import java.security.KeyStore;
/*
* This example shows how to set up a key manager to do client
* authentication if required by server.
*
* This program assumes that the client is not inside a firewall.
* The application can be modified to connect to a server outside
* the firewall by following SSLSocketClientWithTunneling.java.
*/
public class SSLSocketClientWithClientAuth {
public static void main(String[] args) throws Exception {
String host = null;
int port = -1;
String path = null;
for (int i = 0; i < args.length; i++)
System.out.println(args[i]);
if (args.length < 3) {
System.out.println(
"USAGE: java SSLSocketClientWithClientAuth " +
"host port requestedfilepath");
System.exit(-1);
}
try {
host = args[0];
port = Integer.parseInt(args[1]);
path = args[2];
} catch (IllegalArgumentException e) {
System.out.println("USAGE: java SSLSocketClientWithClientAuth " +
"host port requestedfilepath");
System.exit(-1);
}
try {
/*
* Set up a key manager for client authentication
* if asked by the server. Use the implementation's
* default TrustStore and secureRandom routines.
*/
SSLSocketFactory factory = null;
try {
SSLContext ctx;
KeyManagerFactory kmf;
KeyStore ks;
char[] passphrase = "passphrase".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("testkeys"), passphrase);
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), null, null);
factory = ctx.getSocketFactory();
} catch (Exception e) {
throw new IOException(e.getMessage());
}
SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
/*
* send http request
*
* See SSLSocketClient.java for more information about why
* there is a forced handshake here when using PrintWriters.
*/
socket.startHandshake();
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())));
out.println("GET " + path + " HTTP/1.0");
out.println();
out.flush();
/*
* Make sure there were no surprises
*/
if (out.checkError())
System.out.println(
"SSLSocketClient: java.io.PrintWriter error");
/* read response */
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
out.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
ClassFileServerの実行
ClassFileServer.java
およびClassServer.java
で構成されるこの例は、単純なHTTPまたはHTTPS要求(GETメソッドのみがサポートされます)に対応できるミニWebサーバーの実装を示します。デフォルトでは、サーバーはSSL/TLSを使用しません。ただし、コマンド行オプションによってSSL/TLSを有効にできます。要求は次の形式にする必要があります。
GET /<filename>
使用方法
java ClassFileServer port docroot [TLS [true]]
port
: サーバーが常駐するポート。利用できる未使用のポート番号です。たとえば、2001
のような数字を使用できます。docroot
: ローカル・ディレクトリ階層のルート。取得するファイルを含むサーバーのディレクトリを表します。たとえば、Linuxでは、/home/userid/
(userid
は特定のUIDを表す)を使用でき、WindowsシステムではC:\
を使用できます。TLS
: SSL/TLSサービスを有効にするオプション・フラグ。TLS
およびtrue
パラメータを省略した場合は、TLSではない通常のファイルサーバーを認証なしで使用し、何も起こらないことを示します。これは、一方の側(クライアント)がTLSとネゴシエーションを行おうとしても、もう一方の側(サーバー)は行おうとしないため、通信ができないからです。true
: クライアントがそれ自体を認証する必要があることを示すオプション・フラグ。このオプションでは、SSL/TLSサポートを有効にする必要があります。
セキュアなサーバーはlocalhost
の証明書とともに事前インストールされます。サーバーがクライアントとして同じホスト上にある場合は、https://localhost:port/file
形式のURLは、ホスト名検証を渡す必要があります。別のホスト上で実行することを選択した場合は、使用されるhttpsホスト名の新しいホスト証明書を作成する必要があり、そのようにしないと、ホスト名の不一致問題が発生します。(注意: Javaでは、カスタムHostnameVerifier実装を提供することによって、またはブラウザでホスト名の不一致について説明するダイアログ・ボックスを受け入れることによって、HttpsURLConnectionクラスで修正できます。)
TLSバリアント(HTTPS)を使用している場合は、httpsプロトコルを指定してください。
https://hostname:2001/dir1/file1
注意:
ブラウザを使用している場合、アプリケーションがlocalhost
証明書を認識しないというメッセージを示すダイアログ・ポップアップが表示されます。ブラウザに表示される自己署名証明書は、最初は信頼されていないため、このことは正常です。必要に応じて、localhost
証明書をブラウザのトラストストアにインポートできます。
ClassFileServer.java
import java.io.*;
import java.net.*;
import java.security.KeyStore;
import javax.net.*;
import javax.net.ssl.*;
import javax.security.cert.X509Certificate;
/* ClassFileServer.java -- a simple file server that can server
* Http get request in both clear and secure channel
*
* The ClassFileServer implements a ClassServer that
* reads files from the file system. See the
* doc for the "Main" method for how to run this
* server.
*/
public class ClassFileServer extends ClassServer {
private String docroot;
private static int DefaultServerPort = 2001;
/**
* Constructs a ClassFileServer.
*
* @param path the path where the server locates files
*/
public ClassFileServer(ServerSocket ss, String docroot) throws IOException
{
super(ss);
this.docroot = docroot;
}
/**
* Returns an array of bytes containing the bytes for
* the file represented by the argument <b>path</b>.
*
* @return the bytes for the file
* @exception FileNotFoundException if the file corresponding
* to <b>path</b> could not be loaded.
*/
public byte[] getBytes(String path)
throws IOException
{
System.out.println("reading: " + path);
File f = new File(docroot + File.separator + path);
int length = (int)(f.length());
if (length == 0) {
throw new IOException("File length is zero: " + path);
} else {
FileInputStream fin = new FileInputStream(f);
DataInputStream in = new DataInputStream(fin);
byte[] bytecodes = new byte[length];
in.readFully(bytecodes);
return bytecodes;
}
}
/**
* Main method to create the class server that reads
* files. This takes two command line arguments, the
* port on which the server accepts requests and the
* root of the path. To start up the server: <br><br>
*
* <code> java ClassFileServer <port> <path>
* </code><br><br>
*
* <code> new ClassFileServer(port, docroot);
* </code>
*/
public static void main(String args[])
{
System.out.println(
"USAGE: java ClassFileServer port docroot [TLS [true]]");
System.out.println("");
System.out.println(
"If the third argument is TLS, it will start as\n" +
"a TLS/SSL file server, otherwise, it will be\n" +
"an ordinary file server. \n" +
"If the fourth argument is true,it will require\n" +
"client authentication as well.");
int port = DefaultServerPort;
String docroot = "";
if (args.length >= 1) {
port = Integer.parseInt(args[0]);
}
if (args.length >= 2) {
docroot = args[1];
}
String type = "PlainSocket";
if (args.length >= 3) {
type = args[2];
}
try {
ServerSocketFactory ssf =
ClassFileServer.getServerSocketFactory(type);
ServerSocket ss = ssf.createServerSocket(port);
if (args.length >= 4 && args[3].equals("true")) {
((SSLServerSocket)ss).setNeedClientAuth(true);
}
new ClassFileServer(ss, docroot);
} catch (IOException e) {
System.out.println("Unable to start ClassServer: " +
e.getMessage());
e.printStackTrace();
}
}
private static ServerSocketFactory getServerSocketFactory(String type) {
if (type.equals("TLS")) {
SSLServerSocketFactory ssf = null;
try {
// set up key manager to do server authentication
SSLContext ctx;
KeyManagerFactory kmf;
KeyStore ks;
char[] passphrase = "passphrase".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("testkeys"), passphrase);
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), null, null);
ssf = ctx.getServerSocketFactory();
return ssf;
} catch (Exception e) {
e.printStackTrace();
}
} else {
return ServerSocketFactory.getDefault();
}
return null;
}
}
ClassServer.java
import java.io.*;
import java.net.*;
import javax.net.*;
/*
* ClassServer.java -- a simple file server that can serve
* Http get request in both clear and secure channel
*/
public abstract class ClassServer implements Runnable {
private ServerSocket server = null;
/**
* Constructs a ClassServer based on <b>ss</b> and
* obtains a file's bytecodes using the method <b>getBytes</b>.
*
*/
protected ClassServer(ServerSocket ss)
{
server = ss;
newListener();
}
/**
* Returns an array of bytes containing the bytes for
* the file represented by the argument <b>path</b>.
*
* @return the bytes for the file
* @exception FileNotFoundException if the file corresponding
* to <b>path</b> could not be loaded.
* @exception IOException if error occurs reading the class
*/
public abstract byte[] getBytes(String path)
throws IOException, FileNotFoundException;
/**
* The "listen" thread that accepts a connection to the
* server, parses the header to obtain the file name
* and sends back the bytes for the file (or error
* if the file is not found or the response was malformed).
*/
public void run()
{
Socket socket;
// accept a connection
try {
socket = server.accept();
} catch (IOException e) {
System.out.println("Class Server died: " + e.getMessage());
e.printStackTrace();
return;
}
// create a new thread to accept the next connection
newListener();
try {
OutputStream rawOut = socket.getOutputStream();
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
rawOut)));
try {
// get path to class file from header
BufferedReader in =
new BufferedReader(
new InputStreamReader(socket.getInputStream()));
String path = getPath(in);
// retrieve bytecodes
byte[] bytecodes = getBytes(path);
// send bytecodes in response (assumes HTTP/1.0 or later)
try {
out.print("HTTP/1.0 200 OK\r\n");
out.print("Content-Length: " + bytecodes.length +
"\r\n");
out.print("Content-Type: text/html\r\n\r\n");
out.flush();
rawOut.write(bytecodes);
rawOut.flush();
} catch (IOException ie) {
ie.printStackTrace();
return;
}
} catch (Exception e) {
e.printStackTrace();
// write out error response
out.println("HTTP/1.0 400 " + e.getMessage() + "\r\n");
out.println("Content-Type: text/html\r\n\r\n");
out.flush();
}
} catch (IOException ex) {
// eat exception (could log error to log file, but
// write out to stdout for now).
System.out.println("error writing response: " + ex.getMessage());
ex.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
}
}
}
/**
* Create a new thread to listen.
*/
private void newListener()
{
(new Thread(this)).start();
}
/**
* Returns the path to the file obtained from
* parsing the HTML header.
*/
private static String getPath(BufferedReader in)
throws IOException
{
String line = in.readLine();
String path = "";
// extract class from GET line
if (line.startsWith("GET /")) {
line = line.substring(5, line.length()-1).trim();
int index = line.indexOf(' ');
if (index != -1) {
path = line.substring(0, index);
}
}
// eat the rest of header
do {
line = in.readLine();
} while ((line.length() != 0) &&
(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
if (path.length() != 0) {
return path;
} else {
throw new IOException("Malformed Header");
}
}
}
ClassFileServerによるSSLSocketClientWithClientAuthの実行
サンプル・プログラムSSLSocketClientWithClientAuth.java
およびClassFileServer.;ava
を使用して、認証済の通信を設定できます。この通信では、クライアントとサーバーが相互に認証します。サンプルのプログラムは、同じネットワークに接続された別個のマシンで実行することも、1台のマシンで、ただし別のターミナル・ウィンドウまたはコマンド・プロンプト・ウィンドウから両方を実行することもできます。クライアントとサーバーの両方を設定するには、次を実行します。
ClassFileServer
プログラムを1つのマシンまたはターミナル・ウィンドウから実行します。ClassFileServerの実行を参照してください。SSLSocketClientWithClientAuth
プログラムを別のマシンやターミナル・ウィンドウで実行します。SSLSocketClientWithClientAuth
には、次のパラメータが必要です。host
は、ClassFileServer
を実行するために使用するマシンのホスト名です。port
は、ClassFileServer
用に指定したものと同じポートです。requestedfilepath
は、サーバーから取得するファイルのパスを示します。このパラメータには、/filepath
と指定する必要があります。GET文の一部として使用されるので、ファイル・パスにはフォワード・スラッシュが必要です。GET文には、稼動中のオペレーティング・システムの種類にかかわらず、フォワード・スラッシュが必要です。文の構成は次のようになります。"GET " + requestedfilepath + " HTTP/1.0"
注意:
ClassFileServer
が動作しているローカル・マシンに接続するように、他のSSLClient*
アプリケーションのGET
コマンドを変更できます。