JettyにSecurityを。DIGEST認証。
Security、大事ですね。
社内イントラだから、大丈夫じゃねとか多いと思います。
まぁ、確かにそうかもしれませんが、
性悪説にたつと色々考える必要があります。
ということで、JettyのSecutiryを色々、設定してみたいと思います。
AWSに構築しているので、まずは、ファイアウォールです。
が、
ec2のsecurity groupで入りは、弾けそうですが、
社内やら、自宅やら、E-Mobileやらアクセス元が多数あるので、
後回しにします。iptablesも後回し。
まずが、アプリケーション自体、Jettyの設定をやりたいと思います。
デフォルトのままだと、
http://localhost:8080:/hoge/piyo/
とかで、ディレクトリ丸見えなので、コレ見えなくしたい。
とゆー事で、認証かけます。
Basic、Digest、NTLM、OAuthなどありますが、
×NTLM→Windows認証なので、いらない。
×OAuth→TwitterやFacebookのOAuthの認証実装した事あるけど、Oauth2ならシンプルだけど、トークン面倒。
いかんせんアプリケーション側の変更もそれなりにあるので、ちょっと大変。
となると、Basic認証か、Digest認証の2択ですが、
Basicよりは、Digestだろって事で、Digest認証でいきます。
っとその前に、Flex(Air)でDigest認証いけるのか?
ネットでは、Basic認証のサンプルたくさんあったけど・・。
http://livedocs.adobe.com/flex/3_jp/langref/flash/net/URLRequest.html
「 HTTP 認証 (基本 / ダイジェスト)、Windows 統合認証 (NTLM および Kerberos を含む)、SSL 証明書認証」
大丈夫っぽい。
まず本家のドキュメントみる。http://wiki.eclipse.org/Jetty/Feature/Realms
tomcatと同じです。web.xmlに
web.xml
<!-- security setting --> <security-constraint> <web-resource-collection> <web-resource-name>hogeAuth</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>admin</role-name> <role-name>user</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>DIGEST</auth-method> <realm-name>hogeAuth</realm-name> </login-config> <security-role> <role-name>admin</role-name> </security-role> <security-role> <role-name>user</role-name> </security-role>
エラーが出るとは思うけど、このままでJetty起動してみる。
java.lang.IllegalStateException: No LoginService
出ました。設定せねば。
次、http://wiki.eclipse.org/Jetty/Tutorial/Realms
みると、
全てのアプリケーションに同一の設定をする場合は、jetty.xml
アプリケーション個別に設定する場合は、context.xml
にそれぞれ、LoginServiceの設定が出来ますよっと書いてある。
開発環境では、context.xmlを参照せず、Jettyを起動していて、
本番環境では、context.xmlを設定しています。
開発環境でcontext.xmlを参照して起動する方法がわかってないだけなんですが、
まぁ、複数アプリケーションを動かす予定はないので、jetty.xmlに設定します。
jetty.xml
<!-- =========================================================== --> <!-- Set Realms --> <!-- =========================================================== --> <Call name="addBean"> <Arg> <New class="org.eclipse.jetty.security.HashLoginService"> <Set name="name">hogeAuth</Set> <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set> <Set name="refreshInterval">0</Set> </New> </Arg> </Call>
また、エラーが出るとは思うけど、このままでJetty起動してみる。
java.lang.IllegalStateException: No LoginService
同じエラー。ほぅ・・・。
前に、TomcatからJetty(http://d.hatena.ne.jp/nosa1/20120124/1327397386)
の設定をしましたが、Jettyのデバッグの設定、これやっぱりrun-jetty-runが内包してるJetty
をみてるっぽいです。
だもんで、デバッグの構成の一番下にある「Additional Jetty.xml」に
編集した単体Jettyのjetty.xmlを設定します。もう一回起動。
:FAILED HashLoginService[hogeAuth]: java.io.FileNotFoundException: ・・・省略。 \etc\realm.properties (指定されたパスが見つかりません。)
予想通り。まだ無いからね(実はあります)。
あら??/etcの上のディレクトリが、eclipseのプロジェクト名になってる。
run-jetty-runを使ってますが、これで起動すると、
jetty.homeがデバッグの構成で割り当てたプロジェクトになるっぽい。
困った。jetty.xmlは、単体Jettyのを参照するように出来るけど、
realm.propertiesは、eclipseのワークスペースに入れなきゃいけないなんて。
そうすると、単体Jettyを起動すると、jetty.homeが単体Jettyのディレクトリになるから、
このままだと、単体Jettyのetcにrealm.properties、ワークスペースのetcにもrealm.properties
とrealm.propertiesを2つもつハメになってしまう。
run-jetty-runで、jetty.homeが設定できればいいんですけど。
Tomcatプラグインだと、TomcatHomeが設定出来たんだけどなー。
あまり調べきれていませんが、
起動オプションでjetty.homeを変更する方法は、見つけられませんでした。
また、jetty.xmlにjetty.homeを記述する方法も分かりませんでした。
http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty#Configuring_Connectors
これとか見ると、なんとなく出来そうなんですけどね。
起動したら、そこがHomeって事なんでしょうか・・・。
で、色々設定みてたのですが、やっぱrun-jetty-runにココがhomeだよって教えてあげなきゃいけないわけで。
とりあえずの解決ですが、
デバッグの構成から、引数のタブ、作業ディレクトリーを単体Jettyのディレクトリにしてあげると
ここをjetty.homeと認識するかは不明ですが、単体Jettyの/etcを参照するようです。
起動時にエラーがなくなったので、ブラウザアクセスしてみる。
404!
なんで???ここは401でしょー!
認証の設定外してみる。げっ、404・・・。
これ、デバッグの構成で、「Additional Jetty.xml」に設定すると、その上にあるプロジェクトの設定無視しますね・・・。
(作業ディレクトリをワークスペースに戻して404が出るし)
つーことは、単体Jettyのjetty.xmlにコンテキストの設定しないとってことか。
https://github.com/alexwinston/RunJettyRun
ここ参考に設定しました。
jetty.xml
<!-- =========================================================== --> <!-- Set handler Collection Structure --> <!-- =========================================================== --> <Set name="handler"> <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection"> <Set name="handlers"> <Array type="org.eclipse.jetty.server.Handler"> <!-- ======================================================= --> <!-- Configure a web application with web.xml --> <!-- ======================================================= --> <Item> <New class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/hoge</Set> <Set name="resourceBase">C:\workspace\webapp</Set> </New> </Item> <Item> <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/> </Item> <Item> <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/> </Item> </Array> </Set> </New> </Set>
デバッグも大丈夫。作業ディレクトリを単体Jettyにしても大丈夫。
棚ぼたというかなんというか、jetty.xmlにコンテキストの設定をしてしまったので、
context.xml要らなくなりました。まぁ、勉強になったってことで・・・。
認証の設定戻す→ブラウザアクセス→認証のダイアログでる→401!
次は、realm.propertiesを設定します。
デフォルトだと、realm.propertiesって、既にありました。
サンプルとして持っておきたいので、別で作成します。
realm.properties
admin: MD5:164c88b302622e17050af52c89945d44,admin user: MD5:164c88b302622e17050af52c89945d44,user
ブラウザからアクセスしてみると、認証ポップアップが出る。
ユーザ名とパスワードを入れる。認証通らない・・・。
BASIC認証に変えてみる。認証通る。うーん。
と悩んでたら、サンプルのrealm.propertiesに、
「If DIGEST Authentication is used, the password must be in a recoverable
format, either plain text or OBF:.」
DIGEST認証使う場合は、プレーンテキストかOBF形式使いなさいと書いてある。
ほぅ。設定にプレーンテキストは書きたくないので。OBF使います。
すいません。ところでOBFってなんですか?
http://d.hatena.ne.jp/yukinkster/20110828/1314563738
ここ参考にさせて頂きました。(SSLの時もお世話になりそうです)
本家のドキュメントは、これhttp://wiki.eclipse.org/Jetty/Tutorial/Passwords
が、
8.1.0.RCを使っているからか、ドキュメント通りでは、動きませんでした。
C:\jetty\jetty-distribution-8.1.0.RC1\lib>java -cp jetty-util-8.1.0.RC1.jar org.eclipse.jetty.util.security.Password me password password OBF:1v2j1uum1xtv1zej1zer1xtn1uvk1v1v MD5:5f4dcc3b5aa765d61d8327deb882cf99 CRYPT:me797W335G/ME
ドキュメントと違うのは、httpのjar必要ない。
jetty-util-8.1.0.RC1.jarの中を見てみたら、パッケージ構成がドキュメントと違う。
これでOBFが手に入りました。これをrealm.propertiesに設定します。
で、ブラウザアクセス。認証OK!
さて、アプリケーション側変更します。Flex(AIR)です。
幸いAIRなので、楽チンです。Flexアプリケーションの場合は、ちょっと面倒です。
こことか http://livedocs.adobe.com/flex/3/html/help.html?content=url_requests_2.html
URLRequestDefaultsのAPI http://livedocs.adobe.com/flex/3_jp/langref/flash/net/URLRequestDefaults.html
見ると分かります。
URLRequestDefaults.authenticate = true; URLRequestDefaults.useCache = false; URLRequestDefaults.setLoginCredentialsForHost("www.example.com", "Ada", "love1816$X");
マニュアル通りです。URLVariables忘れずに。
と思ったら、罠がありました。
http://livedocs.adobe.com/flex/3_jp/langref/flash/net/URLRequestDefaults.html#setLoginCredentialsForHost()
「メモ : このメソッドは、ファイルのアップロードまたは RTMP 要求で使用される URLRequest オブジェクトには適用されません。」
うおーぃ。ファイルアップロード使ってるよー。
確かにファイルアップロード、エラリます。
ついでに、
http://www.riaxdnp.jp/?p=908
こんな素敵なご指摘もありますね。
整理すると、
setLoginCredentialsForHost()は、ファイルアップロードでは使えない(適用されない)
↓
URLRequestで何とかする必要がある。
↓
FileReferenceのupload
APIリファレンス(http://livedocs.adobe.com/flex/3_jp/langref/flash/net/FileReference.html#upload())に
「URLRequest オブジェクトの requestHeaders プロパティは無視されるため、カスタム HTTP リクエストヘッダはアップロードまたはダウンロードでサポートされません。」
とあるので、URLRequestHeaderは使えない。
↓
降参?
ネット見てると、MacではNGってのは通説っぽいけど、Winだといけるってありますね。
ヘッダ使えないのに、どうやってるんだろ?
これか、http://unknownplace.org/memo/2007/10/26/#e001
やってるっていうか、やってくれちゃってるんですね。
さーて、どうしよっかなー。
まず、テキスト送信出来るケースは、普通にPOSTしよう。今日はここまで。