JAAS に関する記事の前編の続きです。JAAS でアノテーションのみを使用できるかどうか、またどのような問題が発生するかを考えてみましょう。このパートでは、どのサーブレット API ツールを使用すればコードをより汎用的にできるかを学びます。そして、読んだ内容を要約しましょう。
継続
JAAS テクノロジーのレビューの最初の部分 (「JAAS - テクノロジーの概要 (パート 1)」を参照) では、JAAS とサーブレット API の主な使用例を検討しました。Tomcat サーブレット コンテナが JAAS アーキテクチャを使用して Web アプリケーションのセキュリティを管理していることがわかりました。「認証メソッド」と「セキュリティ レルム」の知識があれば、Tomcat コンテナ自体が認証メカニズムの必要な実装を提供し、それ自体が CallbackHandler を提供するので、ログイン モジュールでそれをすべて使用しました。覚えておくべき重要な点は、ブラウザが BASIC 認証経由で送信されたログイン データとパスワード データを保存することだけです。したがって、Chrome を使用して新しいスキャンを行うたびに、Ctrl+Shift+N を押して新しいウィンドウを開き、シークレット モードで作業できます。注釈
XML を使用した構成は、長い間時代遅れになってきました。したがって、サーブレット API バージョン 3.0 以降では、web.xml デプロイメント記述子ファイルを使用せずに、アノテーションを使用してサーブレット設定を設定できることが重要です。アノテーションを使用するとセキュリティ管理がどのように変わるかを見てみましょう。また、アノテーションを使用して上記のアプローチを実装することは可能でしょうか? サーブレット API 仕様とそのセクション「アノテーションとプラグ可能性」も、アノテーションを理解するのに役立ちます。このセクションでは、サーブレット宣言をweb.xml
アノテーションで置き換えることができると述べています@WebServlet
。したがって、サーブレットは次のようになります。
@WebServlet(name="app", urlPatterns = "/secret")
public class App extends HttpServlet {
次に、「 13.3 プログラムによるセキュリティ」 の章を見てみましょう。アノテーションを通じてセキュリティ制約を宣言することもできると書かれています。
@WebServlet(name="app", urlPatterns = "/secret")
@ServletSecurity(httpMethodConstraints = {
@HttpMethodConstraint(value = "GET", rolesAllowed = "admin")
})
public class App extends HttpServlet {
今、web.xml
私たちのブロックには 1 つだけ残っています - login-config
。問題は、それを簡単かつ簡単に交換する方法がたまたま存在しないことです。Web アプリケーションのセキュリティ設定と Web サーバーのセキュリティ設定は密接に関係しているため、これをプログラム的に行う場合でも、これを行うための簡単で普遍的な方法はありません。これは、JAAS および Servlet API を使用した認証の問題の 1 つです。ブロックについて言えばlogin-config
、これが認証メカニズムの宣言的な記述であることを理解する価値があります。認証メカニズム。これを置き換える簡単で普遍的な方法はまだありません。処理はweb.xml
サーブレット コンテナの奥深くで行われます。たとえば、Tomcat では、ソースContextConfig.javaを確認できます。したがって、Tomcat サーブレット コンテナーにもいくつかのオプションがあり、それらはすべて異なります。たとえば、Embedded Tomcat サーブレット コンテナを使用する場合 (つまり、コードから Web サーバーを起動する場合)、そのようなオプションについては、「コードによる基本認証を使用する Embedded Tomcat」を参照してください。さらに、Embedde Tomcat を起動する一般的な例は、Heraku PaaS プラットフォーム ガイドの「Create a Java Web Application using Embedded Tomcat」で参照できます。Tomcat が埋め込みモードで使用されていない場合は、Tomcat に対して一般的に使用されるアプローチであるイベント リスナーを使用できます。Tomcat では、これは「LifeCycle Listener コンポーネント」です。同時に、サーブレット コンテナ (この例では Tomcat) には独自のクラス ローダーがある場合があり、単純にクラスを取得して使用することはできないことを理解することが重要です。Tomcat の場合は、「 Class Loader HOW-TO 」を理解する必要があります。Undertow と呼ばれる別のサーブレット コンテナでは、これは「 Servlet Extensions 」を使用して実現できます。ご覧のとおり、より柔軟なメカニズムを提供しているものもあれば、提供していないものもあります。ご覧のとおり、選択肢は 1 つだけではありません。それらはすべて非常に異なります。サーブレットAPIとJAASだけで何とか汎用的なことはできないでしょうか?インターネット上では、サーブレット フィルターを使用してブロックなしで認証を実行するという提案を見つけることができますlogin-config
。最後にこのオプションを検討してみましょう。これにより、JAAS がどのように機能するかを繰り返すことができます。
認証フィルター
web.xml
したがって、私たちの目標は、ファイルを完全に削除することです。これを削除すると、残念ながら Security Constraint を使用できなくなります。それらの処理は、サーブレット フィルターが適用されるよりもはるかに早く発生する可能性があります。これは、フィルターを使用する「多用途性」に対して支払わなければならない料金です。それらの。注釈を削除する必要があり@ServletSecurity
、セキュリティ制約で前述したすべてのチェックをプログラムで実行する必要があります。ご覧のとおり、このオプションは多くの不快な制限も課します。まず、@ServletSecurity
リソースからlogin-config
アノテーションを削除しweb.xml
、. ここで、私たち自身が Basic 認証を実装する必要があります。次に、フィルターを追加しましょう。
@WebFilter("/*")
public class JaasFilter implements javax.servlet.Filter {
ここまでは簡単そうに思えます。初期化メソッドを書いてみましょう。
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String jaas_conf = filterConfig.getServletContext().getRealPath("/WEB-INF/jaas.config");
System.getProperties().setProperty("java.security.auth.login.config",jaas_conf);
}
ご覧のとおり、jaas 構成ファイルを検索するには基本的な JAAS ツールを使用する必要があります。これには大きな欠点があります。複数のアプリケーションがある場合、あるアプリケーションが別のアプリケーションの認証を破ってしまう可能性があります。Jaas Config ファイルの一般的な設定方法については、JAAS ドキュメント「付録 A: java.security セキュリティ プロパティ ファイルの JAAS 設定」で詳しく説明されています。次に、フィルタリング方法自体について説明します。HTTP リクエストを受信することから始めましょう。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
// Если в реквесте уже есть Principal - ничего не делаем
if (req.getUserPrincipal() != null ) {
chain.doFilter(request, response);
}
ここではすべてがシンプルです。プリンシパルが利用可能な場合、認証は成功です。次に、ユーザーが認証に合格しなかった場合のフィルターのアクションを記述する必要があります。彼はまだ認識されていません。前回は、基本認証方式である BASIC について説明しました。なぜなら 今はフィルターを自分たちで書いているので、BASIC 認証が実際にどのように機能するかを理解する必要があります。「 MDN Web ドキュメント: HTTP 認証」を使用できます。また、「HTTP 認証はどのように機能するのか?」基本認証がどのように機能するかの説明から、サーバーが BASIC 認証を実行したいのに、ユーザーがデータを提供していない場合、サーバーは特別なヘッダー「WWW-Authenticate」とエラー コード 401 を送信することは明らかです。このための内部メソッド:
private void requestNewAuthInResponse(ServletResponse response) throws IOException {
HttpServletResponse resp = (HttpServletResponse) response;
String value = "Basic realm=\"JaasLogin\"";
resp.setHeader("WWW-Authenticate", value);
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
次に、このメソッドを使用して、doFilter
次のコード ブロックをメソッドに追加しましょう。
// Получаем security Header. А если его нет - запрашиваем
String secHeader = req.getHeader("authorization");
if (secHeader == null) {
requestNewAuthInResponse(response);
}
if
次に、ヘッダーがすでに送信されたときに実行される の ブランチを追加しましょう。
// Проверяем аутентификацию
else {
String authorization = secHeader.replace("Basic ", "");
Base64.Decoder decoder = java.util.Base64.getDecoder();
authorization = new String(decoder.decode(authorization));
String[] loginData = authorization.split(":");
try {
if (loginData.length == 2) {
req.login(loginData[0], loginData[1]);
chain.doFilter(request, response);
} else {
requestNewAuthInResponse(response);
}
} catch (ServletException e) {
requestNewAuthInResponse(response);
}
}
このコードに認証を追加できます。例:req.isUserInRole("admin")
そこで、フィルターを使用して認証を行いました。一方で、多くのコードと手動処理があります。一方で、汎用性とサーバーの独立性もあります。
GO TO FULL VERSION