Apache+TomcatでのSSL設定(個別ディレクトリ) (復刻)

過去のSerendipityのブログの記事で比較的アクセスの多いものをWordPressに移行しています。

 

懸案の特定のTomcatアプリケーションに関してSSLアクセスのみを許容する設定について
設定方法が判明しました。

現在の私の環境では
/etc/httpd/conf.d
以下の設定ファイルは自動的にhttpd.confにincludeされます。

Include conf.d/*.conf

そこにTomcatへのマッピング設定ファイルを設置しています。
こんな感じ…

[root@ip-10-162-38-78 conf.d]# cat aws.conf
<Location /aws/>
ProxyPass ajp://localhost:8009/aws/
</Location>

実際にはこのconf.d配下の*.confファイルはhttpd.confにincludeされている
だけです。
さらに、conf.dにはSSL設定のための
ssl.conf
がありました。
このssl.conf内に実はVirtual Hostとして443をポートにするサーバが設定されています。

このssl.conf内のVirtual Host設定内にLocationタグを記述すれば、それはhttpdサーバ
全体ではなく、SSLで接続するVirtual Host内だけのマッピングになります。

ssl.conf内の構造:

<VirtualHost>
(内容省略)
<Location /samplegw/>
ProxyPass ajp://localhost:8009/samplegw/
</Location>

</VirtualHost>

これで/samplegw/というアクセスに関してはhttps(443)でアクセスされた場合のみ、マッピング
されるようになりました。

Log4jを試してみる (復刻ページ)

Serendipityブログでアクセスの比較的多いページをこちらに移植しています。
このエントリは2012/11/10のものです。

たいしたアプリはつくっていないので今まで使っていませんでしたが、ロギングはプログラミングの基本ですね。自分用の小さなアプリではファイルアクセスと書き込みをまとめて小さなクラスを作ったりしていましたが、javaを使う限りはLog4jを使うべきでしょう。 

ネットを参考に遊んでみました。サンプルとしてはServletのConstractor部分でInitializeを実施してGetの処理の部分でさらにログを出力。基本的にはデフォルト設定でどのように動作するかを確認してみました。

ServletのConstractor部分への追加

logger=Logger.getLogger(“test”);
BasicConfigurator.configure();
logger.setLevel(Level.WARN);

logger.info(“This is info.”);
logger.warn(“This is warn.”);
logger.error(“This is major.”);

ServletのGet処理部分への追加
logger.warn(“Get is called”);
このサーブレットをTomcatに追加してみました。
まず、Tomcat上でLog4jが動作するために、/usr/share/java/tomcat7にlog4j-1.2.15.jarを配置します。これでログはTomcatのログ/var/log/tomcat7/catalina.outに出力されました。

学習になったのは、サーブレットのConstractorが動作するのがTomcatへのDeployのタイミングではなく、最初にGetを実施したタイミングということ。Tomcatの場合、ServletのConstractor部分でUnixのDaemonのような動作の起動を考えていたのですが、何か工夫が必要のようです。

不思議なのは、このURLにアクセスするとログが2行、あるいは3行出力されること…..一つのリクエストに複数のスレッドが反応しているのでしょうか?何かおかしいですよね。

追記:
問題はTomcatのキャッシュのようです。WARファイルを更新してwebappsのディレクトリに入れると自動的に古いアプリケーションがDestroyされて新しいアプリケーションがDeployされる…..ように見えますが、実際には古いアプリはメモリ上で動作しているみたいですね。だから複数のインスタンスが同時進行となってしまい、ログのメッセージも複数表示されるようです。
Tomcatの再起動を実施して問題は解消しました。

JBoss and Tomcat (復刻ページ)

Serendipityブログで比較的アクセスの多いものを移植しています。
このページは2012/11/06のもの。
さらにコードの部分が正しく表示されていませんでした。

AWSで久しぶりに動き…

といっても自分でWindowsのインスタンスを起動。Linuxと同じくMinimumのものであればAWS新規ユーザは1年間無料とのこと、早速動作させてJbossを動かすところまで行きましたが、Jboss重い重い。Windowsが重いのかも知れませんが、Jbossを動作させていると画面のレスポンスが遅い、遅い。1人でWebからアクセスする限りはその速さは特に問題ありませんが…

さらに気がついたのが、AWSのEC2の課金のIOの数値の上がり方が非常に大きいこと。Linux一台(Apache+Tomcat+Mysql)で一月の数値に今月の5日で到達してしまいました。もしかしたら、Windowsのベースが重いのかも知れませんが、とりあえずJbossは遊ばないときは止めておくことにしました。

Jbossを動かしながら少し学んだこと。JbossはTomcat上で動作していることは知っていましたが、実際どのようにうごいているのか分かりませんでした。ディレクトリの構造は必ずしもこうある必要はないと思いますが、Jbossのアプリケーションの一つとしてTomcatが動いているイメージでした。アプリケーションの階層とは逆のイメージですね。

Jbossのアプリケーションの配置場所は

C:\jboss-epp-5.2\jboss-as\server\default\deploy

という感じですが、この中のjbossweb.sarがwebサーバのアプリケーション、実態はTomcatのようです。jbossweb.sarディレクトリ内はこんなファイル群があります。

context.xml,jasper-jdt.jar,jbossweb.jar, jboss-web-service-jar, jstl.jar, server.xml

server.xmlの中をのぞくと

なんてのが見えます。Tomcatと同じですね。

 

TomcatのJRE Versionと開発環境 (復刻ページ)

復刻ページ:Serendipity版のブログでアクセス頻度の高いページを移植しています。
これは2012/08/23の記事です。
本日のトラブルシュート
PC上の開発環境で作成したログイン画面のプロジェクトをサーバ上に移設したのですが、 動きません。 Apache側からのリンクはうまく動いているようなのですがindex.jspを含めwebapp上に 展開したリソースに全くアクセスできません。
殆どお手上げの時にTomcatのログレベルをDEBUGにして起動時のログを見てみました。 こんなエラーがありました。 

catalina.2012-08-23.log Caused by: java.lang.UnsupportedClassVersionError: test/nozomu/com/HelloWorld : Unsupported major.minor version 51.0 (unable to load class test.nozomu.com.HelloWorld)

結局、開発環境が1.7なのに対して、Tomcat側のJREの環境が1.6であるためのエラーのようです。 開発環境かサーバ側どちらかを修正しなければいけないのですが、開発環境の設定が良く分からなかったので Tomcat側でとりあえず修正

tomcat.conf:
#JAVA_HOME=”/usr/lib/jvm/jre”
JAVA_HOME=”/usr/java/jre1.7.0_05″

一応、サーバにも1.7のJREが入っていたのでこれでOKになりました。
今まで、Eclipse上でサーブレットの開発を行っていなかったのと、PC上で確かAWSのサンプルコードを コンパイルするときにPC側の環境を1.7にしたのが背景でしょう。
でも、開発側の環境設定も確認しておかないといけませんね。

mobiファイル自動転送プロジェクト

先日のmobiファイルをKindle端末へ直接メールする方法ですが、うまく動作するようになりました。入力画面もRadioボタンを使って、新規に作品が追加された場合も一行追加するだけで対応できるようにしました。
今回、Crayon Syntax HighlighterというWordpressのプラグインをインストールしたので、これを使って、コードも綺麗に表示したいと思います。(今まではCodeの表示に苦労していました….)
全体の流れは
htmlのformでGETの実行
JSPでGETの引数解析とJava Toolの起動
Java ToolによってNative Scriptの起動
Native Scriptによってmailxを起動してメール転送 となります。

htmlのフォームはこんな感じです。

ここではKindle上のアカウント名とKindleアカウントに登録しているメールアドレスを入力してもらいます。mobiファイルはRadioボタンによる選択、サブディレクトリはhiddenで指定します。

JSPでは引数のチェックを行って、正しく引数が設定されている場合のみサーブレットを起動します。

 

Javaのツールのコードです。単純にNativeコマンドの実行を行っています。Windowsで動作しているTomcatでは使えませんが、Linux(Unix)上で動作している場合、Unixのツールを簡単に使えるので個人的には重宝しています。
Linuxを単にTomcatを動作させるプラットフォームと考えるよりも、Unixの遺産を使いこなす環境と考えることも個人的には意味があるのではと思います。

Javaのツールのコード

使うスクリプトが増えてきて、引数の多いものを逐次追加しているのはご愛嬌というところで…..

最後にKshで作ったスクリプトになります。

jspのレベルではURLを直接タイプすれば誰でもメールできますが、結局はkindle.comにしかメールできませんし、添付ファイルも指定ディレクトリのものしか添付できませんので、不正に使用されることは無いと考えています。

試験した感想としては自分の通常使うメールクライアントに添付してkindle.comにメールするほうが端末にファイルが転送される時間が短いです。
おそらく、AWSで絞っているのか、sendmailの設定なのかはわかりませんが、私のサーバからAWS内のメールサーバへのメール転送に時間がかかり、さらにその先の転送スピードも遅いように見えます。AWS内でのデータ転送がトラフィックの関係で遅いのか、あるいは、契約上スループットが抑えられているのかは興味深いところです。添付ファイルのサイズが小さいと転送も速いように感じられます。

Web ServiceのSSL化

昨日ちょっと触れました、Web ServiceのSSL化です。
2時間位、ネットの情報とともに格闘したら解決しました。意外に簡単でした。

まず、自分のhtppsの環境を理解する必要があります。Tomcat上のアプリケーションがhttpsで通信される場合、二つの方法があります。ひとつはApache(httpd)でSSLをイネーブルして、Tomcatでは何もしない方法。もうひとつはApacheはいじらず、Tomcat自体のSSLを有効にする方法。Apacheを使用していない環境であれば必然的に後者になります。
このあたりの環境を理解しないでネットの調査をするといらないことに時間を費やしてしまいます。私のように….。私の環境はApacheでSSLです。

Apache側でSSLを実現していますので、私の場合にはTomcatをいじる必要はありませんでした。まず、ベースは他のWebApplicationのSSL化と同じことになります。このあたりは以前、自分のWikiに記載しておきました。
Client側のURLをhttpsに変更してClientを起動します。しかし、以下のようなエラーが出てしまいます。
javax.servlet.ServletException: javax.servlet.jsp.JspException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
実はClient側のJREがこのサイトを正規のものと理解できないので、アクセスできないようです。ですから、ClientのJRE自体にこのサーバの認証データを登録する必要がありました。
先ほどのApacheのSSL化では以下の三つのセキュリティ関連のファイルを作成しました。
server.key(秘密鍵)
server.csr(CSRファイル、公開鍵+証明書申請情報)
server.crt(デジタル証明書)
このうちClient側に設定するファイルはserver.crtです。
このファイルをブラウザーを使用してPCにダウンロードすると、なぜかファイル名が
server.cer
に変化していました。ブラウザー、あるいはWindowsがファイルの意味を理解しているようです。
さて、各JREには以下のようなファイルがあり、そこにサーバの認証情報が格納されるようです。
例:\glassfish3\jdk7\jre\lib\security\cacerts
keytoolというjavaのツールを使ってcertificateを追加します。keytoolはjre\binにありますので、場合によってはPathを張る必要があります。
コマンド:
> keytool -import -alias <別名> -file client.cer -noprompt -trustcacerts -keystore %JAVA_HOME%/jre/lib/security/cacerts

私の実例:
keytool -import -alias nantoka7cert -file server.cer -noprompt -trustcacerts -keystore \glassfish3\jdk7\jre\lib\security\cacerts

いくつかのJREを併用している場合はそれぞれ設定しておいた方が良いかもしれません。
この時点で最初のエラーは出なくなりましたが、私のjRE7の環境ではさらに以下のエラーが出ました。
Exception in thread “main” javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
これはJREからURLの表現に関してセキュリティが厳しくなっているようで、私のssl.confの設定しデフォルトのままだったので起きた問題でした。
ssl.conf内の設定:
以前:
ServerName localhost:443
以後:
ServerName nantoka7.com:443
JRE7の場合、SOAPのclientが指定するURLはこの設定と合致しないといけないようです。上記の場合、www.nantoka7.com ではだめで、nantoka7.comである必要があります。
これで私のFileTransferWebServiceもhttps上で動作するようになりました。
以前、SOAPではパスワードがPlain Textで送られるのが問題…というのを読んだことがあります。httpsを使えばその問題はクリアできますね。

 

 

 

 

FileTransferServer 一応の完成

先日からのWebServiceによるファイル転送プロジェクトですが、とりあえずの完成です。
細かい使い勝手などは今後修正していくにせよ、基本的な動作はとりあえず、満足できるレベルになりました。
前回の懸案事項のパケットサイズと周期の関係も
パケットサイズ: 64KB
周期(delay):500msec
をデフォルトとしました。これらはClient側でのコントロールできるパラメータですので、今後、クライアント側を修正していくなかで改良できると思います。

サーバ側Code:
サーバ側オブジェクト
FileTransferWebService.java
サービスの本体となります。Clientから使用可能なMethodは以下となります。
createFile(String filename)
ファイル名に該当するFileオブジェクトを作成し、コネクションに追加する動作となります。
deleteFile(String filename)
ファイル名に該当するファイルを削除します。
listFileNames(String filename)
サーバ側に存在するファイル名の配列を戻します。
put (String filename, ChunkData packet)
ファイル名に書き込むデータをサーバ側に送ります。戻り値が0の場合はデータが正常に書き込まれたことをあらわします。それ以外の値が帰ってきた場合には、その番号のパケットをサーバ側が求めていることを意味します。

ChunkData.java
ここで、Client側とやり取りするパケットのフォーマットを定義しています。ファイルの送り手側がそのファイルに関する全パケット数と各パケットの番号をセットします。サーバ側で、そのパケットの順序どおりにファイルに書き込むことになります。パケットには該当のファイル名も含まれています。ファイル名によって、後述のコネクションを識別することになります。

Connection.java
WebServiceの場合、一つ一つのリクエストごとにそのリクエストがどのファイルのものかを識別しなければなりません。また、データの書き込み途中のFileオブジェクトも管理する必要があります。それをこのConnectionオブジェクト内のリストで管理します。新規にファイルが作成される場合や、削除、あるいはデータ書き込みがされる場合にはこのリスト内にファイルが存在するかを確認し、もし、存在すればそのFileオブジェクトに対して所望の処置を行い。もし、そのリスト内にFileオブジェクトが存在しなければ新規に作成することになります。
このファイルオブジェクトはファイル名で管理されています。

 サンプルクライアントCode:
対向のホスト名(アドレス)、ユーザ名、パスワードの後に、
list
create
delete
のキーワードによってファイルを転送したり、削除したり、サーバ側の確認ができます。

EC2のサーバにファイル転送を行う場合、二つの方法を使っていました。
Poster(FireFoxのadd-onのPUTクライアント)
SCPによるファイル転送
Posterの場合は大きなファイルの転送を行おうとするとうまく送ることができないことがありました。また、SCPの場合、SSHのパスワード認証をEnableにしなければならず、セキュリティ上好ましくありません。
今回、WebService経由でのファイル転送の手段が増えましたのでサーバにファイルを送る際のオプションが増えて助かります。できればこのサービスをSSL上に移行したいところですが、Certificateのところでうまくうごかないんだろうと思っています。

 

 

Web Serviceによるファイル転送

さて、PCの引越しも終了しましたので以前のWebServiceを使ったファイル転送プロジェクトです。 Goodle, AmazonそしてMicrosoftでも無料のネットワークストレージが提供されていますが、 基本的にこのネットワークストレージにファイル転送する手段はhttpベースと私は理解しています。 httpベースなので、FWでがちがちにポートを絞られている環境でも動作することができます。
同じような仕組みを自分のEC2のサーバで作れないかというのが今回の発端。
Webサービスでサーバからデータを取り出したり、逆にデータを転送する仕組みはつくりましたので、 その延長上の仕組みとして
サーバ側:  File作成  File削除  Fileへのデータの追加
…これはファイルの作成時にFileオブジェクトにデータを書き込む仕組みです。
基本的にはこれだけなのですが、Clientからのリクエストが一回ごとに独立したSoapリクエストになりますので、 File名をキーにしてそのFileオブジェクトなどを保持する仕組みが必要です。
クライアント側:  ローカル側のファイル名とそのファイルのデータをパケットにしてサーバ側に送ります。  ファイルのサイズから事前にトータルパケット数と毎回の送っているパケット番号をデータに組み込みます。
本当は、サーバ側とクライアント側でパケット番号のミスマッチがおきたときの処理なども実装が必要ですが、 そこまではまだ詳しく考えていません。
まあ、とりあえず、この仕組みでファイルの転送を行うと600KB程度のファイルは問題なく遅れるのですが、数MBを 超えるファイルは途中でconnection timeoutでAXISのエラーで転送がとまってしまいました。

調査してみると、サーバ側、クライアント側ともにTimeWaitのソケットが大量に存在しています。 おそらく、ソケットのリソースが枯渇して接続できなくなってしまうのでしょう。 そこで、一回のパケットのサイズを1KB、一回の転送ごとに1秒のsleepをいれたところ、とりあえずは転送が 止まることはなくなりました。
ただし、この設定では9M程度のファイルの転送時間が9000/60/60=2.5と約2時間半もかかります。
どのくらいの値にチューニングするのが良いんでしょうね?
Amazon Cloudアプリの動作をWiresharkで解析してみても勉強になるかもしれません。

 

 

 

Specified JDBC Driver com.mysql.jdbc.Driver class not found

PCの引越しをしていますが、Eclipse上で以前作成したWebApplicationがローカルでDBにアクセスする際にエラーになりました。

一応、Reference Library には
mysql-connector-java-5.1.20-bin.jar
へのパスが張ってあるのですが、Driverのクラスが見つからないようでした。
最終的にはWeb Applibrary(WEB-INF/libへのファイルコピー)にファイルを追加することによって、動作しました。
Hibernate実行時に使用されるライブラリはWeb-INFに存在しないといけないのかも知れません。

 

PCの引っ越しとEclipseの移設

先日のウィルス騒ぎを契機に私のPCのOSをWindows XPからWindows 7にアップグレードすることになりました。ITから代替機が支給され、まず、Win7の代替機にデータを移行して、その後、アップグレードされた旧PCに再度環境を構築することになります。
現時点では代替機のWin7環境で作業しています。
最終的には、再度PCの移行がありますので、あまり、真剣に作業を行っていませんが、今後同様な環境の再構築はあるはずなのでメモしておくのは意味がありそうです。
まず、Eclipse本体自体はディレクトリごと、PCを超えて移動すれば基本的にOKでした。また、各プロジェクトに関してはも、XPでは\Document and Users…というようなディレクトリが\Users…というディレクトリに変わったことくらいで、こちらもWorkspaceのディレクトリごとコピーすることで問題ありませんでした。
比較的戸惑ったのが、Javaのruntime environmentの設定とTomcatなどのサーバ設定。TomcatはEclipse内部のpluginで動作するようですが、JbossとかGlassFishは別途インストールしたアプリケーションをEclipse内部の設定で起動する必要があります。
事前に以前のPC上のJREのインストールが以前のPCと同様に設定できていれば、このあたりもスムーズに移行できるのだと思いますが、私の場合はそのあたりが不完全でしたので、ちょっと手間取りました。
むしろ、Eclipse上のServer設定を一旦削除して、JREの設定を修正しながら、Serverも再作成する方がスムーズな気がしました。また、JREを一旦削除するとTomcatなどのサーバ再度の開発環境からServer用のライブラリがBuild Pathから消えてしまいますので再度設定する必要があります。
このあたりのポイントを若干メモしておくと、
Serverについて
Windows –> Show View —> Others —> Servers    サーバタブが表示される。
Server tabで右クリック–> New –> Server でTomcat, GlassFish, Jbossなどを作成する。
Java Run Time Environemtについて
Windows –> Preference –> Java (Expandして)–>Install JREs
ここでAddやEditでJREの設定を実行します。私の今の環境例です。

さらにServerごとのRuntime Enviromentは
同じく
Windows –> Preference –> Server (Expandして)–>Runtime Environment
ここでそれぞれのサーバに関してはRuntime Environment などの設定をします。
Tomcatの場合には必要であればサーバ自体をEclipse内部にダウンロード、インストールできますし、JbossやGlassFishの場合にはインストールしたディレクトリへのパスを指定します。

Tomcatの例:

Jbossの例:

MySQLの移行ができていないのでDBアクセスあたりはまだ動きません。
MySQLのVersionが開発環境のPCと商用環境のLinuxで異なるのでたぶん、ファイルベースでの移行はできませんので、テーブル形式をコピーしてそのうえでデータを移行するような流れになるとは考えています。