しかし、私がこの変更を行うと、Spring、Tomcat、Servlet APIに固有のいくつかの制限と非互換性が発見されました。伝統と同じように、Sunは問題の80%の解決策を作成し、残りは読者のための練習として残しました。
現在認証されているユーザーの名前を含むjavax.security.Principal
オブジェクトを返します。ユーザーが認証されていない場合、 メソッドはnullを返します。上記文書の
厳格な読みは「...現在の認証済みユーザーの名前」それはが含まれている必要があることをを述べたが、私の当初の目標を満たすために、私は「としてこれを解釈しています。 ..認証されたサブジェクトの名前または識別子 "。これは、com.sun.security.auth.UserPrincipalのドキュメント(「ユーザー名またはアカウント名で識別されるユーザープリンシパル」)とより密接に対応しています。
JAASRealm
とHttpServletRequest
上記制限のため、それは明らかに重要である起因アカウント識別子が(現在のセッションのみ、要求および応答へのアクセスを有する)ServletFilter
介して要求に伝播される場合、それがなければならないこと(最初の質問のオプション1はこの要件を満たし、最初のオプションが表示され、元のユーザー名は必要ない場合のみオプション2を満たします)。私は本当に必要なのはアカウント識別子だと思うので、私はMyLoginModule
に "EmailAddressPrincipal"を手渡し、Subject
を介して "AccountIdentifierPrincipal"を返します(つまり、MyLogin.commit()
は "最初のプリンシパルとしてバッキングコレクションがプリンシパルの順序を保持しなければならないことを意味するAccountIdentifierPrincipalを使用します。 )
を Subject.getPrincipals(によって返されたプリンシパルに対するこのレルム繰り返し処理としては、:
JAASRealm
ドキュメントは、それはあなたが読んでいるどのセクションに依存し、校長の正確な順序について、実際に少し矛盾しています が、このユーザーのプリンシパルとして「ユーザークラス」リストと一致する最初のプリンシパルを識別します。
返された最初のプリンシパルは常に、ユーザー プリンシパルとして扱われます。
基本的に、私が作成するつもりならば何をしているかJAASRealm
模倣は、認証は次のようになります。そのServletFilter
:
final LoginContext loginContext = new LoginContext(MyLoginModule.JAAS_REALM, new DefaultCallbackHandler(username, password));
loginContext.login();
final Subject subject = loginContext.getSubject();
request.getSession().setAttribute("AUTH_USER_PRINCIPAL", subject.getPrincipals(AccountIdentifierPrincipal.class).iterator().next());
request.getSession().setAttribute("AUTH_ROLE_PRINCIPALS", subject.getPrincipals(MyRolePrincipal.class));
残念ながら、これはjavax.security.auth.Subjectのコンストラクタと直接競合していますこれは、プリンシパルのバッキングコレクションとしてjava.util.Setが使用されることを要求します。また、Set.iterator()ドキュメントの状態:
要素は特定の順序で返される(このセットは 保証を提供するいくつかのクラスのインスタンスである場合を除きます)。
Subject
に我々が持っている最古のアクセスは、残念ながらLoginContext
の内部のどこかに呼び出される何か(と思う)であるLoginModule.initialize()
方法、です。これは、Principals
のバッキングコレクションとして使用されるSet
の正確なサブクラスを制御できないことを意味し、したがってその順序を制御することはできません。これがServletFilter
に到着するまでにはSynchronizedSetであるため、元のクラスが何であったか、または並べ替えが発生したかどうかは明らかではありません。
これはすべて、JAASRealm
が期待どおりに動作するために、オプション2がテーブルから外れているか、単一のユーザープリンシパルを使用していることを示しているようです。中間層には、Subject
Principals
の順番を明確に示す任意のインターフェイスはありません。ユーザープリンシパルが予期された順序から戻されたため、JAASRealm
によってユーザープリンシパルが間違った型として解釈される可能性があるセキュリティ上の脆弱性が想定されます。これを防ぐには、commit
の間にSubject
に宣言されたユーザータイプのPrincipal
を1つだけ追加する必要があり、複数のユーザークラス名は避けるべきです。
したがって、オプション2のために、私はJAASRealm
の使用を避けています。上記のすべてのドキュメントによれば、JAASを忠実に遵守していないためです。これにより純粋なServletFilter
のアプローチに戻ります。
ここで、javax.security.auth.Subjectには、複数のユーザープリンシパル、ロール、およびACLグループが必要です。残念ながら、このクラスは部分的にしかシリアライズ可能ではないため、クラスをPrincipal
としてラップして返すことはできません。
SpringのDefaultJaasAuthenticationProviderを満たすために、を実装して、Principal
をロール名にマップする必要がありました。これにより、マッピングの実行方法を完全に制御することができました。
私のServletFilter
ではAuthorityGranter
を使用できませんが(webappはSpringフレームワークに依存しません)、Spring以外のWebアプリケーションのマップロールにも同様のアプローチを採用しています。一時的に、HttpServletRequestWrapperを使用してセッション属性(認証時にセッションに格納されている)からプリンシパルとロールを読み取り、getUserPrincipalとisUserInRoleを上書きしています。最終的にJAASRealmをテストして、この作品を処理できるかどうかを確認しますが、まだまだです。
「SubjectIdentifier」を同じ「Subject」に関連付けられた別の「Principal」として実装することは、JAAS APIによって暗示されるメカニズムであり、それ自体は標準的な情報セキュリティの概念と用語で直接的にモデル化されています。あなたが正常にユーザを認証したら、あなたが使用できるようにしたいすべての関連する 'Principal'でそれらを表す' Subject'を設定します。 –