- ベストアンサー
JAVAで、SSL通信
現在、Javaで、別のサーバから、sslで、htmlファイルを 取得するプログラムを作成しようとしています。 環境と、プログラムは、以下のようになっております。 皆さんお忙しいと思いますが、なにとぞご教授お願いいたします。 【環境】 OS:Solaris8 WAS:WebSphere5.0 コンパイラ:WebSphere5.0に存在するコンパイラ 【プログラム】 import java.net.*; import java.io.*; import javax.net.ssl.*; public class JSSETEST2 { public static void main(String[] args) { try { URL url = new URL("https://www.kamata.com/"); HttpsURLConnection conection = (HttpsURLConnection)url.openConnection(); PrintWriter out = new PrintWriter( conection.getOutputStream() ); out.close(); BufferedReader in = new BufferedReader( new InputStreamReader( conection.getInputStream() ) ); String line; while( (line = in.readLine() ) != null ){ System.out.println( line ); } in.close(); } catch(Exception e) { e.printStackTrace(); } } } 【実行】 java -Djava.protocol.handler.pkgs=com.ibm.net.ssl.internal.www.protocol JSSETest 【結果】 java.lang.ClassCastException: com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnection at JSSETEST2.main(JSSETEST2.java:9)
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
まずは,実際に返ってきているオブジェクトのクラスを調べてみてはどうでしょうか? 例えば9行目を, Object obj = url.openConnection(); System.out.println(obj.getClass().getName()); のようにすれば調べられると思います。 またそもそも com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnection は javax.net.ssl.HttpsURLConnection を継承しているのでしょうか? 上記のコードで, Class cls = obj.getSuperClass(); System.out.println(cls.getName()); を数回繰り返せば確認できると思います。 それから,ClassCastExceptionを避けるための一般的な対処としては, import javax.net.ssl.*; のように*を使うのではなく, import javax.net.ssl.HttpsURLConnection; のように,必要なクラスだけをimportする記述にした方が良いと思います。
その他の回答 (4)
- aton
- ベストアンサー率47% (160/334)
#2のatonです。 >com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnection は継承していないことが分かりました。 >今度は、com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnectionを直接importして、実行するようにしてみます。 とあるのですが,「com...HttpsURLConnectionを直接import」するのではなく,9行目を, HttpURLConnection conection = (HttpURLConnection)url.openConnection(); つまり,HttpsURLConnectionではなく,sの付かない HttpURLConnectionを使っても動作するかもしれません。 #書籍を参考にされたとの事ですが, #もとの書籍にも実はそのように記述されていたのではないでしょうか? 但しこれは, >javax.net.ssl.SSLHandshakeException: unknown certificate >というエラーが発生するようになりました。 という問題とはおそらくかかわりがないので,こうしても上記のエラーは解決しないと思います。この問題は,#3でngsvxさんが書かれているように,証明書期限の問題かもしれませんが,もしかしたら別の問題かもしれません。 例えば,参考URLには,「サーバーの個人証明書が クライアントのトラストストアにないことが原因となっている可能性があります」と書かれています。 #ngsvxさんがアドバイスされているように, #Sunの実装への移行も一つの方法かとは思うのですが, #WebSphereというIBMのAPサーバーを使っているので, #なにか他の部分で支障が出てくる恐れもあります。 #ですから,まずはIBM実装内で問題の解決を試みられた方がいいかもしれません。 #もちろん,WebSphereを使う必要がないのであれば, #APサーバーを含めて変えてしまう手もあると思いますが。
お礼
すばやい回答を、どうもありがとうございます。 >9行目を,HttpURLConnection conection = >(HttpURLConnection)url.openConnection(); >つまり,HttpsURLConnectionではなく,sの付かない >HttpURLConnectionを使っても動作するかもしれません。 上記の様に修正して、動作することを確認いたしました。 参考した書籍では、atonさんのおっしゃられてたとおり、 以下の様な記述でした。 URLConnection conection = url.openConnection(); その他、もろもろアドバイスありがとうございました。
補足
解決いたしました。 atonさん、ngxvさんどうもありがとうございました。 >javax.net.ssl.SSLHandshakeException: unknown certificate 上記のエラーが発生していたのは、サーバの証明書 が、きちんとした手続きをとらずに作成した証明書 (opensslで作成した証明書)だったからです。 また、Sunのコンパイラでは、-Dオプションはいりません が、IBMコンパイラではいるみたいです。-Dオプション を使用しない方法もありましたので、下記に記述します。 【ソース】 import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class TestSSLURL { public static void main(String[] args) throws Exception{ Security.addProvider(new com.ibm.jsse.IBMJSSEProvider()); System.setProperty("java.protocol.handler.pkgs", "com.ibm.net.ssl.internal.www.protocol"); URL url = new URL("https://www.highwaybus.com/"); HttpURLConnection conn= (HttpURLConnection) url.openConnection(); BufferedReader in = new BufferedReader( new InputStreamReader( conn.getInputStream())); String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine); in.close(); } } 尚、上記のソースは、以下のURLのサンプルを 参照させていただきました。 http://www-106.ibm.com/developerworks/websphere/library/techarticles/0403_yu/0403_yu.html?ca=dnp-314
- ngsvx
- ベストアンサー率49% (157/315)
#1です。 昨日、書くのを忘れていたのですが、 -Dオプションを付けるというのは、どこから聞きました? というのは、昨日も書いたようにj2sdk1.4だと-Dは必要ないはずなんですよ。実際、私は動きます。 動かないということは、どこかに何らかの手が加えられているのではないかと思うわけです。 (設定ファイルのようなものかもしれません) 手が加えられているのだとしたら、それに関する注意事項等が、書いてある可能性があると思います。
お礼
お礼が遅くなり申し訳ありません。 別の仕事が入って調査を進めるのが遅くなりました。 今日は、空いているので、頂いたヒントを元に、 調査を進めていきたいと思います。 ※この場をお借りして、#2様に報告が遅くなった ことをお詫びいたします。
補足
回答ありがとうございます。 >-Dオプションを付けるというのは、どこから聞きました? 書籍を参考にいたしました。 書籍:XMLとJavaによるWebアプリケーション開発 第2版 出版社:ピアソン・エデュケーション ページ:585~586 >動かないということは、どこかに何らかの手が >加えられているのではないかと思うわけです。 >(設定ファイルのようなものかもしれません) $JAVA_HOME/jre/lib/security/java.securityファイル のことでしょうか?他の設定ファイルは、まだ見つける ことができません。 やはり、Sunのコンパイラと、IBMのコンパイラでは、 違いがあるように思われます。Sunのjarファイルは、 jsse.jarですが、IBMは、ibmjsse.jarですから・・・ Sunのjsse.jarを使用したほうがよいのでしょうか? すこし検討してみます。
- ngsvx
- ベストアンサー率49% (157/315)
#1です。 例外が発生しました?あれれ? 前回の回答はそっけなかったので、もう少し詳しく記述しておきます。 前回、-Dオプションを外せばいいと思ったのは、次の理由によります。 1.HttpsURLConnectionを使ってコンパイルが通るのは、j2sdk1.4以降である。 2.新しいバージョンの JSSE はj2sdk1.4 に統合されている。(参考URL1) 3.-Dオプションを使うのは、旧バージョンの実装を使用するためで、現在は普通使わない。 4.キャスト例外は、IBMの実装が古いので、javax.ssl.net.HttpsURLConnectionを継承していない ために発生したと思われる。 で、なるべくなら、sun以外の実装は使用しない方がよいと思ったので、 -Dオプションを外せばいいという結論を出したわけです。 しかし、URLのコンストラクタで例外が発生するということは、 やはり、IBMの実装が必要なのかな? 私のJDKではバージョンが違うため、URLクラスのソースを見てもわかりませんでした。 自分なら、URLクラスの例外の原因を追及して、-Dオプションを使わないで実行する 方法をとると思いますが、とりあえず動かすなら、#2さんの方法を行って下さい。 話はかわって、JDKに含まれる証明書のうち、ベリサインのものが今年の1月で期限切れになって います。(参考URL2) ベリサインの証明を必要とするSSL通信をすると「証明書がない」という内容の例外が発生します。 気をつけて下さい。 <参考URL1> http://java.sun.com/j2se/1.4/ja/docs/ja/guide/security/jsse/JSSERefGuide.html#ConfigurationClasses <参考URL2> http://jp.sun.com/supportraining/letter122503.html
- 参考URL:
- http://java.sun.com/j2se/1.4/ja/docs/ja/guide/security/jsse/JSSERefGuide.html#ConfigurationClasses
お礼
回答ありがとうございます。詳しく理由まで書いていただいて、申し訳ないです。Sunのコンパイラと、IBMのコンパイラは、結構違いがあることが分かりました。 この回答を参考にして、調査を進めていきたいと思います。
補足
遅くなりましたが、回答いたします。 Sunの実装をした方がよいとのことですが、 できればIBMコンパイラに付属しているものを 使用したかったので、考えていませんでした。 しかし、実行できないとなると、そちらを 使用したほうがよいのかも知れません。 また、#2様の回答を受けて、ためしてみたところ ClassCastエラーは無くなりましたが、今度は、 javax.net.ssl.SSLHandshakeException: unknown certificate というエラーが発生するようになりました。 このエラーは、ngsvx様がおっしゃている 「証明書がない」というエラーなのでしょうか? <参考URL2>を拝見しましたが、理解に苦しんでいる 状態です。 修正したソースと、実行方法を記述しておきます。 【修正ソース】 import java.net.URL; import java.io.BufferedReader; import java.io.InputStreamReader; import com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnection; public class HttpsTest { public static void main(String[] args) { try { URL url = new URL("https://www.kamata.com/"); HttpsURLConnection conection = (HttpsURLConnection)url.openConnection(); conection.setRequestMethod("GET"); BufferedReader in = new BufferedReader( new InputStreamReader( conection.getInputStream() ) ); String line; while( (line = in.readLine() ) != null ){ System.out.println( line ); } in.close(); } catch(Exception e) { e.printStackTrace(); } } 【実行結果】 java -Djava.protocol.handler.pkgs=com.ibm.net.ssl.internal.www.p rotocol HttpsTest javax.net.ssl.SSLHandshakeException: unknown certificate at com.ibm.jsse.bg.a(Unknown Source) at com.ibm.jsse.bg.startHandshake(Unknown Source) at com.ibm.net.ssl.www.protocol.https.b.n(Unknown Source) at com.ibm.net.ssl.www.protocol.https.p.connect(Unknown Source) at com.ibm.net.ssl.www.protocol.http.bw.getInputStream(Unknown Source) at com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnection.getIn putStream(Unknown Source) at HttpsTest.main(HttpsTest.java:15) 以上です。
- ngsvx
- ベストアンサー率49% (157/315)
このソースでコンパイルエラーにならないということは、 J2SE1.4だと思われます。 実行時の -Dオプションを外して実行して下さい。 java JSSETest <アドバイス> 普通のHTTP通信はやったことがありますか? ないのなら、まずそこから始めて下さい。 いきなり難しいことをすると、トラブルの時に 苦労します。
お礼
お忙しい中、回答ありがとうございました。 ご指摘を頂いた所から、解決していこうと思います。
補足
上記で指摘いただいた箇所で調査いたしましたことを回答いたします。 >J2SE1.4だと思われます。 ご指摘のとおり、「J2SE1.4.1_05」です。 >実行時の -Dオプションを外して実行して下さい。 -Dオプションを外しますと、以下のエラーを受けます。 java.net.MalformedURLException: unknown protocol: https at java.net.URL.<init>(URL.java:586) at java.net.URL.<init>(URL.java:476) at java.net.URL.<init>(URL.java:425) at HttpsTest.main(HttpsTest.java:9) >普通のHTTP通信はやったことがありますか? 上記サンプルを編集して、実行できることを確認いた しました。 HTTP通信ソースは、以下のとおりです。 import java.net.*; import java.io.*; import javax.net.*; public class HttpTest { public static void main(String[] args) { try { URL url = new URL("http://ndcpdws1/"); HttpURLConnection conection = (HttpURLConnection)url.openConnection(); conection.setRequestMethod("GET"); BufferedReader in = new BufferedReader( new InputStreamReader( conection.getInputStream() ) ); String line; while( (line = in.readLine() ) != null ){ System.out.println( line ); } in.close(); } catch(Exception e) { e.printStackTrace(); } } }
お礼
大変参考になるアドバイスありがとうございます。 本日(8/17)は、調査する時間がありませんが、 明日(8/18)、早速試して、結果をお知らせいたします。
補足
回答が遅くなり申し訳ありません。 プログラムに以下のロジックを組み込んで 再度実行してみました。 URL url = new URL("https://ndcpdws1/"); Object obj = url.openConnection(); System.out.println("class_name[" + obj.getClass().getName() + "]"); Class cls = obj.getClass().getSuperclass(); System.out.println("super_class_name1[" + cls.getName() + "]"); Class cls2 = cls.getSuperclass(); System.out.println("super_class_name2[" + cls2.getName() + "]"); Class cls3 = cls2.getSuperclass(); System.out.println("super_class_name3[" + cls3.getName() + "]"); Class cls4 = cls3.getSuperclass(); System.out.println("super_class_name4[" + cls4.getName() + "]"); 【実行結果】 java -Djava.protocol.handler.pkgs=com.ibm.net.ssl.internal.www.protocol HttpsTest class_name[com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnection] super_class_name1[com.ibm.net.ssl.HttpsURLConnection] super_class_name2[java.net.HttpURLConnection] super_class_name3[java.net.URLConnection] super_class_name4[java.lang.Object] 上記のことから、 com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnection は継承していないことが分かりました。 今度は、com.ibm.net.ssl.internal.www.protocol.https.HttpsURLConnectionを直接importして、実行するようにしてみます。