2010年4月12日月曜日

作業ログ : BlazeDS のカスタム LoginCommand がなぜかうまく動かなくて調べた時のログ

BlazeDS のカスタム LoginCommand がなぜかうまく動かなくて調べた時のログ

経緯

GAE/J + BlazeDS 環境の Security 設定を書いているときにハマった時のログ。

とりあえずのゴール

何が分からないのかも分からない状態なので、とりあえずいろいろ調べてみることにしよう。


Integrating Spring Security with BlazeDS and Flex RIAsを読んでみた
Integrating Spring Security with BlazeDS and Flex RIAs

とりあえず、Integrating Spring Security with BlazeDS and Flex RIAsを見て、実際に security 系の機能を利用する側の雰囲気をつかんでみる。
  • この記事は spring-flex が正式にリリースされる前に書かれた Spring Security + BlazeDS + Flex 環境についてのまとめ記事。
  • 環境は以下を前提としている。
    • Spring 2.5.5
    • Spring-Security 2.0.4 (core & tiger)
    • BlazeDS 3.2
    • Flex3
  • この記事は、end-point に対してセキュリティをかける目的は持っておらず、メソッド呼び出しレベルでセキュリティをかけることを目的としている。
  • BlazeDS は user の credential を request から取得し、それを SpingSecurity に渡して SecureContext が作成され、認証され、 ThreadLocal 中の SecureContext に認証情報が格納される。その後、普通に SpringSecurity が普通にメソッドを保護する。→ 実際に接続の受諾や拒否を行う部分を SpringSecurity にやらせてしまうわけですね。
  • BlazeDS の持つサーバ側の session 管理機能を一切使わず、自分で実装しようとしてるのかな?
  • Step1:maven の pom.xml を設定して jar を取得する。
  • Step2:amf のアクセスを org.springframework.web.filter.DelegatingFilterProxy で受けるように web.xml を設定する。
  • Step3:Spring Security の設定をする。
  • Step4:Spring Security に対応した flex.messaging.security.LoginCommand を実装する。
  • Step5:services-config.xml に設定する。
基本的に、GAE/J + BlazeDS 環境の Security 設定 でハマった時と同じ方法ですね。今回の件の問題解決には関係なさそう。


GAE 上でうまくセキュリティが動作しない件の調査

spring-flex を使ってみてもいいけど、っていうか使う予定ではいるけど、現状の問題の原因がわからないままというのもなんなので、もうちょっと調べてみた。
  • ローカル環境にて、セキュリティ関連の動作を追ってみた。とりあえず、printStackTrace() を埋め込んでみました。
以下、ログイン時のカスタムLoginCommandまでの流れ。
java.lang.Exception: This is only a test.
 at security.CustomLoginCommand.doAuthentication(CustomLoginCommand.java:12)
 at flex.messaging.security.LoginManager.login(LoginManager.java:206)
 at flex.messaging.services.AuthenticationService.decodeAndLoginWithCharset(AuthenticationService.java:131)
 at flex.messaging.services.AuthenticationService.serviceCommand(AuthenticationService.java:81)
 at flex.messaging.MessageBroker.routeCommandToService(MessageBroker.java:1605)
 at flex.messaging.endpoints.AbstractEndpoint.serviceMessage(AbstractEndpoint.java:861)
 at flex.messaging.endpoints.amf.MessageBrokerFilter.invoke(MessageBrokerFilter.java:121)
 at flex.messaging.endpoints.amf.LegacyFilter.invoke(LegacyFilter.java:158)
 at flex.messaging.endpoints.amf.SessionFilter.invoke(SessionFilter.java:44)
 at flex.messaging.endpoints.amf.BatchProcessFilter.invoke(BatchProcessFilter.java:67)
 at flex.messaging.endpoints.amf.SerializationFilter.invoke(SerializationFilter.java:146)
 at flex.messaging.endpoints.BaseHTTPEndpoint.service(BaseHTTPEndpoint.java:278)
 at flex.messaging.MessageBrokerServlet.service(MessageBrokerServlet.java:322)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
 at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
 at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:51)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
 at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
 at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
 at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
 at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
 at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
 at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
 at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349)
 at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
 at org.mortbay.jetty.Server.handle(Server.java:326)
 at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
 at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
 at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
 at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
 at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
 at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
 at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)


GAE上での動作についてメモ

  • GAE上では、ログイン後の動作にて、LoginManager.getCurrentPrincipal() が null を返している。ということは、ログイン時の CurrentPrincipal の格納に問題があるのか、取得時に問題があるのかのどちらかと考えられる。
  • ローカル上では、ログイン時には、ログインの認証が成功した後に FlexSession.setUserPrincipal() が呼び出されている。その後普通にセキュリティ制約のあるアクセスしてみたところ、FlexSession.setUserPrincipal() は呼ばれていない。サーバ上でオンメモリで保存されてもシリアライズを介したとしても、この動作は納得。しかし、HttpSessionレベルではどうなっているのだろうか?FlexSessionとSessionの関係ってどうなってるんだろ?
  • FlexSessionは、HttpSession に "__flexSession" という属性名で格納される。
  • GAE の Session をいろいろいじってみたのだが、普通に session に属性を set/get するのは問題なく動作するし、FlexSesson が session に保存されていることも確認したし、HttpFlexSession のインスタンスがシリアライズ/デシリアライズされているらしいことも確認(toString()の@以下の番号が変化することで確認)した。となると、FlexSession か Principal のシリアライズ/デシリアライズが問題?
  • ローカルで普通に FlexSession をシリアライズ/デシリアライズしたら、getUserPrincipal() がnullになりました。ということは、GAEの問題じゃないですね。
  • 調べてみたら、HttpFlexSession#writeObject() メソッドが、例外を握りつぶしていました。例外の内容は、CustomLoginCommand が Serializable でないという内容。Principal が CustomLoginCommand のインナークラスだったので、CustomLoginCommand が Serializable である必要があったんですねぇ。ということで、CustomPrincipal として独自のクラスに切り出して、再度動作確認。
  • GAE上で動作しましたー!

0 件のコメント:

コメントを投稿