(0)目次&概説
(1) サーバー側JavaのFORM認証
(1-1) 認証の種類
(1-2) FORM認証の特徴
(1-3) FORM認証の実装概要
(2) FORM認証の実装手順
(2-1) web.xmlの準備
(2-2) ユーザー情報ファイルの準備
(2-3) ログインページの実装
(2-4) ログインエラーページの実装
(2-5) 疎通チェック
(2-6) (参考)Servletの「j_security_check」とは?
(3) エラーが発生した際の対応
(1) サーバー側JavaのFORM認証
(1-1) 認証の種類
・クライアント証明書認証
それぞれの認証方式の比較を次ぎに示します。
(図1)
認証方式 | 暗号化 | セッションID | HTTP仕様(RFC2617)での存在有無 |
基本認証 | なし (Base64平文) |
なし (ブラウザにて認証情報管理=ブラウザを閉じると終了する) |
あり (httpで定義あり) |
フォーム認証 | なし | あり | なし (それぞれのアプリで要実装) |
ダイジェスト認証 | あり (MD5ハッシュ関数) |
なし (ブラウザにて認証情報管理=ブラウザを閉じると終了する) |
あり (httpで定義あり) |
また各方式の原理/特徴は下記の通りです。
(表2)
認証方式 | 原理/特徴 |
基本認証 | ・利用者がユーザID/パスワードを入力して、サーバー側で認証を行う ・サーバー側でユーザID/パスワードを設定し、それをメール等でユーザに通知 ・Base64でエンコードしているため、Base64でデコードすれば盗聴されるリスクがある ・ほぼ全てのWebサーバ&ブラウザに対応している ・ログアウトの機能がない(認証を削除するためにはブラウザを終了する必要ある) →※セッション管理が出来ない ・平文のテキストでパスワード等が送られるため、セキュリティが弱い →用途としては利用者が限定された内部的なwebサービス等に限定される |
フォーム認証 | ・HTMLで作られたフォーム画面からIDとパスワードを入力して認証を行う方式です。 ・利用者がユーザID/パスワードを入力して、サーバー側で認証を行う ・認証が通るとセッションIDを発行してログイン管理を行う →一般公開されているwebサービスでも使われている方式 ・認証の範囲指定が行えるため、SSOなども可能。 ・問題点として、パスワードが平文で送られる点が挙げられる |
ダイジェスト認証 | ・盗聴防止のため、ユーザー名とパスワードをMD5(ハッシュ関数)で送る |
(図1)基本認証のイメージ図
(1-2) FORM認証の特徴
Form認証の特徴として、ルールの範囲内でログイン画面のレイアウトを自由に配置する事ができます。認証のおおまかな流れは下記の通りです。
(図2)
①リクエスト送付
クライアント⇒サーバへリクエストを送付します。
サーバにて認証が必要かをチェックします。認証不要の場合は要求ページを表示します。
サーバにて認証済みかをチェックします。
(a) 認証済みの場合 → 要求ページを表示
(b) 認証未済みの場合 → ログインページに遷移
クライアントにてログインの実施します。
(b) 失敗の場合 → 再度ログインページに遷移
(1-3) FORM認証の実装概要
(1-3-1) config系ファイルの設定全体像
(図3)
(1-3-2) フォーム実装&画面遷移イメージ
(図4)
(2) FORM認証の実装手順
(2-1) web.xmlの準備
web.xmlの配備場所については次の規則に沿って配備します。
適用範囲 | 配備先 |
全アプリケーション |
$CATALINA_HOME/conf/web.xml (例) |
現在のアプリケーション | [アプリケーションルート]/WEB_INF/web.xml (例) /home/admin/eclipse-workspace/LoginForms/WebContent/WEB-INF |
私の環境においては、現在のアプリケーションにのみ適用するために「WEB-INF」配下に置きました。
■記述内容
web.xmlに記述する要素は大きく3つありります。
<security-constraint> | アクセス制御や許可範囲に関する設定をします。 |
<login-config> | 認証方式や方法の設定をします。 |
<security-role> | 認証を利用できるロールの設定を行います。 |
もう少し記述内容を詳細に書くと、次のようになります。
<security-constraint> | - |
∟<web-resource-collection> | ①アクセス制御の範囲指定 (アプリケーションのルートフォルダ以下のディレクトリ指定を行う) |
∟<web-resource-name> | |
∟<url-pattern> | 範囲をURL指定する。 |
∟<auth-constraint> | ②上記のアクセス制御範囲について、アクセス許可するロール名を指定します。 |
∟<role-name> | ロールの名前を指定します。指定する名前は<security-role>にて定義されている必要があります。 |
<login-config> | - |
∟<auth-method> | 認証の方式 (BASIC/FORM/DIGEST/CLIENT-CERT) |
∟<form-login-config> | フォーム認証の際に記述します。 |
∟<form-login-page> | ログインページの指定 (アプリケーションのルートフォルダ以下の指定を行う) |
∟<form-error-page> | ログインエラーページの指定 (アプリケーションのルートフォルダ以下の指定を行う) |
<security-role> | - |
∟<role-name> | ロールの名前を定義 |
今回、実際に設定した例は下記の通りです。
<web-app> <security-constraint> <web-resource-collection> <web-resource-name>From Auth</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constrait> <role-name>admin-gui</role-name> <role-name>manager-gui</role-name> </auth-constrait> </security-constraint> <login-config> <auth-method>FORM</auth-method> <form-login-config> <form-login-page>/Login.jsp</form-login-page> <form-error-page>/LoginError.jsp</form-error-page> </form-login-config> </login-config> <security-role> <role-name>admin-gui</role-name> </security-role> <security-role> <role-name>manager-gui</role-name> </security-role> </web-app>
ちなみに、ロールを設ける意義は「権限の設定をシンプルにするため」です。
各ユーザーに逐一権限を細かに設定すると煩雑になってしまうため「ロール」という形で権限の定義を設けて、そのロールをユーザーに付与する事によって権限設定を簡素化してミスを防止する事が出来ます。
(図5)
(2-2) ユーザー情報ファイルの準備
「ユーザー情報ファイル」とは「権限」と「ユーザー」の情報を記述します。ユーザ情報ファイルの名前はコンテナの種類により異なり、Tomcatの場合は「tomcat-users.xml」という名前です。記述する内容は<tomcat-users></tomcat-users>の間に次の項目を追記します。
■主な設定内容
①「role」の名前
<role>要素の「rolename」属性を用いてロールの名前を定義します。
<role rolename="manager-gui"/>
②「ユーザー」のパスワード/付与権限
<user>要素を用いてユーザー情報の登録を行っていきます。主な属性は下記です。
構文 | 説明 |
name=”[ユーザ名]” | ユーザ名を記載します |
password=”[パスワード]” | パスワードを記載します |
roles=”[ロール名1], [ロール名2],・・・” |
付与するロール名を記載します。複数ロールを付与する場合はカンマで区切って記載します。 |
下記に具体的な記述例を示します。
<user name="Tatsuya" password="12345" roles="admin-gui, manager-gui" />
■設定例(tomcat-users.xml全体)
上記①②を踏まえた全体の設定例を示します。
<tomcat-users xmlns="http://tomcat.apache.org/xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd" version="1.0"> <role rolename="manager-gui"/> <role rolename="admin-gui"/> <user name="Tatsuya" password="abcde" roles="admin-gui, manager-gui" /> <user name="Rainbow" password="bcdef" roles="admin-gui" /> <user name="Mofutarou" password="cdefg" roles="manager-gui" /> </tomcat-users>
■配備先
配備先は下記の通りです。CATALINA_HOMEの場所が分からない場合はこちらを参考にして頂けたらと思います。
https://rainbow-engine.com/linux-tomcat-install/#title2-4
# デフォルトの配備先 $CATALINA_HOME/conf/ # 私の環境では下記のパスです。 /usr/local/src/apache-tomcat-8.5.42/conf
■配備先#2(2020/1/7追記)
配備先というよりは、上記の内容を追記する「tomcat-users.xml」の先について、私の環境では「tomcat-users.xml」は次の通り3カ所にありました。
#① /home/admin/eclipse-workspace/Servers/Tomcat v8.5 Server at localhost-config/tomcat-users.xml #② /home/admin/eclipse-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp1/conf/tomcat-users.xml #③ /usr/local/src/apache-tomcat-8.5.42/conf/tomcat-users.xml
最初は「/usr/local/src/apache-tomcat-8.5.42/conf/」配下のもののみを編集していましたが、認証時に正しいログインID・パスワードで認証をしても次のようにLoginError.jspに遷移してしまう事象が起きました。
回避のために、上記②③にも同様の内容を追記した所、認証が正常に通過しました。
(正確には②のみでも認証は正常に通りました。各ファイルの意味合いについては要確認)
(2-3) ログインページの実装
次にログインページをJSPで作成していきます。
(例)
<%@ page contentType="text/html; charset=UTF-8" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Login to xxxxxxx portofolio</title> <%-- ヘッダーの帯の画像を挿入 --%> <img src="https://rainbow-engine.com/wp-content/uploads/2017/09/cropped-c8a03ed7.jpg" alt="" width="30%"/> <img src="https://rainbow-engine.com/wp-content/uploads/2017/09/cropped-c8a03ed7.jpg" alt="" width="30%"/> <img src="https://rainbow-engine.com/wp-content/uploads/2017/09/cropped-c8a03ed7.jpg" alt="" width="30%"/> <%-- タイトルを中央寄せで記載 --%> <center> <h3 id="mokuji">Login to xxxxxxx portofolio</h3> </center> </head> <body> <%-- 【ポイント①】 フォーム認証の<form>要素のaction属性は"j_security_check"を指定する --%> <form method="POST" action="j_security_check" name="loginform"> <table border="0"> <tr> <%-- 【ポイント②】 フォーム認証の<input>要素でtext属性の時にname属性は"j_username"を指定する --%> <th align="right">User:</th> <td><input type="text" name="j_username" /></td> </tr> <tr> <%-- 【ポイント③】 フォーム認証の<input>要素でpassword属性の時にname属性は"j_password"を指定する --%> <th align="right">Password:</th> <td><input type="password" name="j_password" /></td> </tr> <tr> <td> <%-- type=”submit”で送信フォームのボタンを作成しています。<form>で送っているのでnameとvalueの値が一組になって送信されます。 --%> <input type="submit" value="Login" /> <input type="reset" value="Discard" /> </td> </tr> </table> </form> </body> </html>
(図6)ログイン画面例
(2-4) ログインエラーページの実装
ログイン画面と同様に、ログイン失敗時の画面もJSPで作成します。
(例)
<%@ page language="java" contentType="text/html; charset=UTF-8" %> <!DOCTYPE html> <html> <head> <meta content="text/html;"> <title>Login Error</title> </head> <img src="https://rainbow-engine.com/wp-content/uploads/2017/09/cropped-c8a03ed7.jpg" alt="" width="30%"/> <img src="https://rainbow-engine.com/wp-content/uploads/2017/09/cropped-c8a03ed7.jpg" alt="" width="30%"/> <img src="https://rainbow-engine.com/wp-content/uploads/2017/09/cropped-c8a03ed7.jpg" alt="" width="30%"/> <br/> <body> Error occured. Please go back to the previous screen. [<a href="JavaScript:history.back();">** Back **</a>] </body> </html>
(図7)ログインエラー画面例
(2-5) 疎通チェック
ここまで出来たら、後は実際にログイン出来るか?をチェックします。今回の例では認証範囲の設定(web.xmlの<url-pattern>の値)にて、アプリケーションルート配下「/*」を指定しているので、アプリケーションルート配下のいずれかの画面をブラウザ(EdgeやChromeやFirefox)から要求(URLを打ち込む)事によって、FORM認証が起動してログイン画面に自動で遷移するはずです。
(図251)
以下、実際にログインを操作した例です。
(操作動画)
(2-6) (参考)Servletの「j_security_check」とは?
<form>タグの「action」属性には通常、遷移先のServletやJSPを指定すると思いますが、今回は「j_security_check」を指定しています。これはServlet APIの一部で、サーブレットコンテナ(Tomcatとか)に組み込まれています。
Tomcatの場合、具体的には「org.apache.catalina.authenticator.FormAuthenticator」クラスにて実装されていますが、我々が使う分にはそこまで意識する必要はなく、おまじない的に「action」には「j_security_check」を指定する、という点だけ抑えておけばOKと思います。
ちなみに、ご自身のアプリケーションには「j_security_check」のURLを持つJSPやHTMLが未設定のため、呼び出そうとしても404エラーになります。
(図8)
404 - Not Found メッセージ:/LoginForms/j_security_check 説明:The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
(3) エラーが発生した際の対応
もしFORM認証に関してエラーが発生した際は、以下の記事にいくつかのパターンの対処を掲載しているので、ご確認頂けたらと思います。