手順は次のとおりです。
- セキュリティキーを生成する
- TomcatでHTTSのサポートを追加
- SpringSecurityにHTTSサポートを追加
- テストする(およびそれなしで)
セキュリティキーを生成する
標準JREパッケージのkeytoolユーティリティは、キーの生成に役立ちます。 JAVA_HOMEがパスに追加されている場合は、コマンドラインからkeytoolを実行します。そうでない場合は、
%JAVA_HOME%/bin
移動し、そこからkeytoolを実行します。 MS Windowsの場合、コマンドは次のようになります。
keytool -genkey -alias ContactManager -keyalg RSA -keystore c:/contactmanager.keystore
alias
-一意のキー識別子
keyalg
生成アルゴリズム。 RSA、DSA、DESの可能な値
keystore
-ファイルパス
開始後、プログラムはパスワードといくつかのパラメータを入力するように求めます。パスワードを覚えておくことが望ましいですが、それでも私たちにとって有用です。残りの値は任意です:誰、何、どこ、国など。 その結果、指定されたディレクトリのディスク上のファイルを取得します。 キーの準備ができました。
Tomcat設定を変更する
ファイル
%CATALINA_HOME%/conf/server.xml
を開き、コメント化された部分を見つけます
<!-- Define a SSL HTTP/1.1 Connector on port 8443 This connector uses the JSSE configuration, when using APR, the connector should be using the OpenSSL style configuration described in the APR documentation --> <!-- <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" /> -->
Connector要素からコメントを削除し、キーの属性をいくつか追加します。
<Connector port="8443" SSLEnabled="true" protocol="HTTP/1.1" maxThreads="150" scheme="https" secure="true" keystoreFile="c:\contactmanager.keystore" keystorePass="password" sslProtocol="TLS" />
keystorePass
生成するときに入力したパスワード。 はい、開いたままです。 この問題を解決する方法はありますが、今のところはこのままにしておきましょう。 実際、すべて実行できます。 おっと...
INFO: Initializing ProtocolHandler ["http-apr-8080"] 28, 2013 11:43:04 AM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["http-apr-8443"] 28, 2013 11:43:04 AM org.apache.coyote.AbstractProtocol init SEVERE: Failed to initialize end point associated with ProtocolHandler ["http-apr-8443"] java.lang.Exception: Connector attribute SSLCertificateFile must be defined when using SSL with APR at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:507) ...
うまくいきませんでした。 Googleは、
protocol="HTTP/1.1"
を
protocol="org.apache.coyote.http11.Http11Protocol"
置き換える必要があると答えてい
protocol="HTTP/1.1"
。 まず、すべてが整いました。
... 28, 2013 11:56:41 AM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["http-apr-8080"] 28, 2013 11:56:41 AM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["http-bio-8443"] 28, 2013 11:56:41 AM org.apache.coyote.AbstractProtocol init INFO: Initializing ProtocolHandler ["ajp-apr-8009"] 28, 2013 11:56:41 AM org.apache.catalina.startup.Catalina load INFO: Initialization processed in 1909 ms ...
アドレスhttps:// localhost:8443にアクセスすると、ブラウザーは証明書の疑わしい点について警告しますが、その警告は無視し、「ご自身の責任で続行」をクリックしてTomcatのルートページを表示します。
Spring Securityを構成する
ここでも、すべてが非常に簡単です。 security.xmlファイルで、
requires-channel="https"
属性をWebサービスの各重要なURLに追加する
requires-channel="https"
ます。 次のようになります。
<intercept-url pattern="/ws/index*" access="hasAnyRole('ROLE_USER','ROLE_ANONYMOUS')" requires-channel="https"/> <intercept-url pattern="/ws/add*" access="hasRole('ROLE_USER')" requires-channel="https"/> <intercept-url pattern="/ws/delete/*" access="hasRole('ROLE_ADMIN') " requires-channel="https"/>
テスト中
また、
/ws/index
リソースを
HTTPS
背後に隠したため、
index_user1()
テストの実行を試みます。 ただし、これは予想されるエラーです。 問題は、どのような種類のエラーで、どのように修正するかです。 JUnitは曲線の答えを誓います
com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input at [Source: java.io.StringReader@1841d1d3; line: 1, column: 1]
しかし、そうではないことは明らかです。 コンソールでログを見ると、そこがもっとおもしろいです。エラーステータスがあります302:
... MockHttpServletResponse: Status = 302 Error message = null Headers = {Location=[https://localhost/ws/index]} Content type = null Body = Forwarded URL = null Redirected URL = https://localhost/ws/index Cookies = []
どうやら、私たちはどういうわけかテストで間違った方法でリクエストを形成します。 MockHttpServletRequestBuilder ビルダーに移動して、そのメソッドのリストを調べ、セキュリティに関連する何かを探します。 うん、そこにある。
/** * Set the secure property of the {@link ServletRequest} indicating use of a * secure channel, such as HTTPS. * * @param secure whether the request is using a secure channel */ public MockHttpServletRequestBuilder secure(boolean secure){ this.secure = secure; return this; }
必要なもののようです。 このメソッドをビルダーの呼び出しチェーンに追加します。
def result = mockMvc.perform(MockMvcRequestBuilders.get("/ws/index") .secure(true) // <--------- HTTPS .with(SecurityRequestPostProcessors.userDetailsService(USER1))) .andDo(MockMvcResultHandlers.print()) .andReturn()
やれやれ! 素晴らしい。 残りのWSテストも同じ方法で変更します。 これで、安全な接続を介して認証データを転送し、RESTサービスを外部に安全にレイアウトできます。 ただし、これはRESTリクエストにのみ適用され、古いフォームベースの認証は保護されておらず、弱点のままです。 この問題を自分で解決することを提案します。
さらに何ができますか? 現在、安全なリソースへのすべてのリクエストに対してユーザー名とパスワードを提供する必要があります。 さらに、ユーザーはseciruty.xmlファイルに厳密に登録されており、突然(なぜ突然ですか?)私たちのサービスが普及するでしょうか? したがって、次のイテレーションでは、ユーザー情報をデータベースに転送し、ユーザーのセッションに関するデータを保存する認証トークンで動作するように認証スキームを変更します。
継続する。