2017-10-25 20 views
1

私はJAAS LoginModuleを実装しました。これはSpring 4とStruts 2.3でうまく機能しています。これと同じLoginModuleは、Tomcat 8.0/8.5のServletFilterを介して呼び出され、Springフレームワーク以外のサーブレットへのリクエストを認証して認証します。JAASログインモジュールのユーザープリンシパル - 別のプリンシパルまたはBeanプロパティとしての追加属性?

LoginModuleは、java.security.acl.Groupの単純な実装を使用し、ユーザとロールを2つの単純な実装java.security.Principalで区切ります。 「シンプル」とは、インターフェイスを満たす最小限の実装を意味します。

"User"実装は、nameプロパティを一意のユーザー名(実際には電子メールアドレス)にマッピングします。電子メールアドレスは一意であるが変更される可能性があるため、アカウントデータベースにはグループ、ロールの割り当て、およびサービス要求のログに使用される一意のアカウント識別子(GUID)が含まれています(ユーザーの匿名化もあります)。私のモデルでは、AccountIdentifierには独自のクラスがあります。基本的に私は2つの固有の識別子を持っていますが、認証のために電子メールアドレスをLoginModuleに入力する必要があるため、Userプリンシパルの基礎となりました。

アカウント識別子は現在LoginModuleSubjectに伝播されていませんが、今はサービスリクエストを記録するために必要です。

私はSubject経由でアカウント識別子を利用可能にすることで前方の二つの方法を参照してください、私はJAASのベストプラクティスである不確か午前:

  1. は「accountIdentifierを含めるように私の現在の「ユーザー」Principal実装を拡張"プロパティはLoginModule.commit()の間に設定されます。
  2. LoginModule.commit()の間にSubjectに追加される別のPrincipalとしてAccountIdentifierを実装してください。

最初のオプションは最も簡単ですが、アカウントから個人識別情報を分離する目的に反しているようです。

「ユーザー」プリンシパル(電子メールアドレスを含むプリンシパル)をサブジェクトに追加する必要がありますか?

+1

「SubjectIdentifier」を同じ「Subject」に関連付けられた別の「Principal」として実装することは、JAAS APIによって暗示されるメカニズムであり、それ自体は標準的な情報セキュリティの概念と用語で直接的にモデル化されています。あなたが正常にユーザを認証したら、あなたが使用できるようにしたいすべての関連する 'Principal'でそれらを表す' Subject'を設定します。 –

答えて

1

コメントからアドバイスを受け、2番目のオプションを実装しました。これはJAASの実装方法に同意します。

しかし、私がこの変更を行うと、Spring、Tomcat、Servlet APIに固有のいくつかの制限と非互換性が発見されました。伝統と同じように、Sunは問題の80%の解決策を作成し、残りは読者のための練習として残しました。

私は、この回答を元の質問に対する包括的な回答に向かって文書化するために使用しています。

Tomcat 8.5 JAAS Realmドキュメントの状態:

JAASRealmを使用するには、開発者はTomcatのCMAで事実上 考えられるあらゆるセキュリティレルムを組み合わせる能力を提供します。その後、

や状態に移行:

JAASに指定されていませんが、あなたはTomcatがどのプリンシパルを伝えることができるように、 javax.security.Principalを拡張し、ユーザーとロールを区別 に別々のクラスを作成する必要があります あなたのログインモジュールから返されるのは、ユーザーとロールです( org.apache.catalina.realm.JAASRealm参照)。どちらにかかわらず、最初に返されたプリンシパルはです。ユーザーのプリンシパルとして扱われるのは常にです。

このドキュメントは "ユーザープリンシパル"をフレーズを使用することに注意してください。だから私はjavax.security.Principal(前述のように)を拡張する独自のクラスとして自分のユーザーと役割を実装していますが、ただちに返されるのは1人のプリンシパルにしか許されないHttpServletRequest.getUserPrincipal()によって強制される(私は推測している)組み込みの制限に直面します。 :

現在認証されているユーザーの名前を含むjavax.security.Principalオブジェクトを返します。ユーザーが認証されていない場合、 メソッドはnullを返します。上記文書の

厳格な読みは「...現在の認証済みユーザーの名前」それはが含まれている必要があることをを述べたが、私の当初の目標を満たすために、私は「としてこれを解釈しています。 ..認証されたサブジェクトの名前または識別子 "。これは、com.sun.security.auth.UserPrincipalのドキュメント(「ユーザー名またはアカウント名で識別されるユーザープリンシパル」)とより密接に対応しています。

JAASRealmHttpServletRequest上記制限のため、それは明らかに重要である起因アカウント識別子が(現在のセッションのみ、要求および応答へのアクセスを有する)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がテーブルから外れているか、単一のユーザープリンシパルを使用していることを示しているようです。中間層には、SubjectPrincipalsの順番を明確に示す任意のインターフェイスはありません。ユーザープリンシパルが予期された順序から戻されたため、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を使用してセッション属性(認証時にセッションに格納されている)からプリンシパルとロールを読み取り、getUserPrincipalisUserInRoleを上書きしています。最終的にJAASRealmをテストして、この作品を処理できるかどうかを確認しますが、まだまだです。

関連する問題