2012-10-26 11 views
9

Javaセキュリティは、数週間のための私のメインテーマであると、私は次のアーカイブ:JAAS - のJava EE 6でのJavaプログラムによるセキュリティ(@DeclareRolesなし)

  • カスタムバルブAuthentificator(extends AuthenticatorBase
  • JBossのカスタム・ログイン・モジュール(extends UsernamePasswordLoginModule
  • 担保エンドポイント(JAX-RS)

私の主要な問題は、私のエンドポイントは、注釈でのみ動作していること、です、私はそれを使用しない場合、私は認証を得ることができません。詳しくは、メソッドAuthenticatorBase.invoke(org.apache.catalina.authenticatorから)がメソッドRealmBase.hasResourcePermissionを呼び出し、そこでロールがチェックされます。

私は定義済みのロールを使用しないので、チェックは失敗します。

私の質問:

@Path("/secure") 
@Stateless 
public class SecuredRestEndpoint { 

    @Resource 
    SessionContext ctx; 

    @GET 
    public Response performLogging() { 

     // Receive user information 
     Principal callerPrincipal = ctx.getCallerPrincipal(); 
     String userId = callerPrincipal.getName(); 

     if (ctx.isCallerInRole("ADMIN")) { 
      // return 200 if ok 
      return Response.status(Status.OK).entity(userId).build(); 
     } 
    ... 
    } 
} 

いくつかの追加の背景:ちょうどユーザ名が自動転送される認証(X-FORWARD-USERのためのリバースプロキシを使用する必要があるというようなコードを使用する方法はあります)。なぜ私は自分のAuthenticatorクラスとカスタムログインモジュールを使用するのですか(私はパスワード認証情報を持っていません)。しかし、私は問題がアプリケーションサーバー自体からの標準的な認証方法でも発生すると思います。

答えて

2

私はあなたが正しくなっている場合、2つの問題があります。

  1. あなたのコードに@DeclareRolesは表示されません。 web.xmlを使用しても構わない場合は、次を参照してください。http://docs.oracle.com/cd/E19159-01/819-3669/bncbg/index.html

  2. 残りのリソースにはセキュリティ上の脅威がないため、残りのリソースにアクセスするためにユーザー名を使用するだけですが、残りの人が誰を呼んでいるかを知る必要があるのと同じ時間。

    1. これを行う方法は複数あります。ユーザーを特定するには、http要求にユーザーのIDのみを入力する必要があります。JAASセキュリティは過剰です。たとえば、ユーザIDをURI:/user/bob、または/user?id=bobのようなURIパラメータで指定します。

    2. java6の仕様にはロールベースの認証/承認が書かれているので、セキュリティが必須である場合(私が間違っていない場合は、javaeeの標準セキュリティコンポーネントを使用しています)、ロールに対処する必要があります。あなたのコードは、(あなたが確保できるリソースの静的なセットを持っているという意味)は、静的なので。

+0

ありがとうございます。 1.私のコードで '@ DeclareRoles'を使用したくない理由は静的であり、ロールは時間の経過とともに(メンテナンス)変更できるからです。 2.1 RESTコード内にユーザー名だけを持つことは望ましくありません。私が現在の名前を持っていない深い文脈について考えてみると、いつも彼を提供することはできません。私はreqeustヘッダーからパラメータを簡単に読み取ることができますが、それは私の目的ではありません。 2.2私は 'SesseionContext'とユーザ役割でJEEセキュリティを持つのが好きですが、なぜそれはプログラム的ではなく静的でなければならないのですか? –

+0

ちょうど質問のために "ちょうどそれは静的でなければならず、プログラム的ではないのですか?"アプリケーションは一般的に言えば、再デプロイメントなしでセキュリティ保護可能な機能を動的に増やすべきではないため、ロールは静的です。 web.xmlやBeanでロールを指定するかどうかを決めることで、コードのメンテナンスを容易にすることができますが、コードの再デプロイを避けるほうがよいでしょう。 – Xiangyu

+0

良い点とweb.xml内でそれを変更することは大したことではありません(再デプロイメントは必要ありません)。私は間違いなくそれを検討します。私のプロジェクトでは、何かが変更された場合には再デプロイしないことが重要です。なぜなら、コードに触れたくない、あるいはベンダーにいつもそれをさせることを望まないクライアントのためのカスタムコードだからです。それは簡単な設定可能なソリューションを探していた理由です。しかしそれとは別に、私は自分のアプローチをする方法があると思っていました。できるだけ多くの回答を得るために賞金を開いていきます:D –

6

に、私は増加アクセス粒度別にセキュリティロールを追加するためのあなたの条件を理解していません。コードが静的でないモジュラー環境でこの要件を確認できました。この場合、後で展開することで宣言された追加のセキュリティロールをサポートする必要があります。

私は、似たような実装にサポートするセキュリティシステム持っていた、言った:

  • を再デプロイすることなく、役割を削除/(宣言)を追加することは、
  • これらの役割にユーザーを関連付けます。

私がやったことを抽象度の高いレベルで説明し、いくつかの役に立つアイデアを与えることを願っています。

@Singleton 
@LocalBean 
public class MySecurityDataManager { 

    public void declareRole(String roleName) { 
     ... 
    } 

    public void removeRole(String roleName) { 
     ... 
    } 

    /** 
    * Here, I do not know what your incoming user data looks like such as: 
    * do they have groups, attributes? In my case I could determine user's groups 
    * and then assign them to roles based on those. You may have some sort of 
    * other attribute or just plain username to security role association. 
    */ 
    public void associate(Object userAttribute, String roleName) { 
     ... 
    } 

    public void disassociate(Object userAttribute, String roleName) { 
     ... 
    } 

    /** 
    * Here basically you inspect whatever persistence method you chose and examine 
    * your existing associations to build a set of assigned security roles for a 
    * user based on the given attribute(s). 
    */ 
    public Set<String> determineSecurityRoles(Object userAttribute) { 
     ... 
    } 
} 

次にカスタムjavax.security.auth.spi.LoginModuleを実装:

まず第一に、このような何かを@EJBを実装します。私は抽象的な実装があなたのために働くことをコンテナが分かっていない限り、ゼロから実装することをお勧めします。


:また、私はあなたがいない場合、あなたがより良い私が取得していますかを理解するために、次のように慣れる示唆します
public class MyLoginModule implements LoginModule { 

    private MySecurityDataManager srm; 

    @Override 
    public void initialize(Subject subject, CallbackHandler callbackHandler, 
      Map<String, ?> sharedState, Map<String, ?> options) { 
     // make sure to save subject, callbackHandler, etc. 
     try { 
      InitialContext ctx = new InitialContext(); 
      this.srm = (MySecurityDataManager) ctx.lookup("java:global/${your specific module names go here}/MySecurityDataManager"); 
     } catch (NamingException e) { 
      // error logic 
     } 
    } 

    @Override 
    public boolean login() throws LoginException { 
     // authenticate your user, see links above 
    } 

    @Override 
    public boolean commit() throws LoginException { 
     // here is where user roles get assigned to the subject 
     Object userAttribute = yourLogicMethod(); 
     Set<String> roles = srm.determineSecurityRoles(userAttribute); 
     // implement this, it's easy, just make sure to include proper equals() and hashCode(), or just use the Jboss provided implementation. 
     Group rolesGroup = new SimpleGroup("Roles", roles); 
     // assuming you saved the subject 
     this.subject.getPrincipals().add(rolesGroup); 
    } 

    @Override 
    public boolean abort() throws LoginException { 
     // see links above 
    } 

    @Override 
    public boolean logout() throws LoginException { 
     // see links above 
    } 

} 

動的な構成(ロールの宣言、ユーザーの関連付けなど)を可能にするには、UIを構築しますtは同じ@EJB MySecurityDataManagerを使用して、ログインモジュールがセキュリティロールを決定するために使用するセキュリティ設定をCRUDします。

ここでは、これらを適切な方法でパッケージ化することができます。MyLoginModuleMySecurityDataManagerを検索し、コンテナに展開することを確認してください。私はJBossに取り組んでいましたが、あなたはJBossについて言及しました。より堅牢な実装には、LoginModuleのコンフィグレーションの検索文字列が含まれます。これは、実行時にinitialize()メソッドのオプションマップから読み取ることができます。ここでのJBossの設定例を示します:

<security-domain name="mydomain" cache-type="default"> 
    <authentication> 
     <login-module flag="required" 
         code="my.package.MyLoginModule" 
         module="deployment.${your deployment specific info goes here}"> 
      <module-option name="my.package.MySecurityDataManager" 
          value="java:global/${your deployment specific info goes here}/MySecurityDataManager"/> 
     </login-module> 
    </authentication> 
</security-domain> 

この時点では、コンテナ内の他の展開のセキュリティを管理するには、このセキュリティドメインmydomainを使用することができます。ここで

はカップルの使用シナリオです:

  1. は新しい.warファイルを展開し、mydomainセキュリティドメインに割り当てます。 .warには、コード全体にあらかじめ定義されたセキュリティ注釈が付いています。セキュリティ・レルムには最初はないため、ユーザーはログインできません。しかし、デプロイ後は、セキュリティ・ロールが十分に文書化されているため、書いたmydomain構成インタフェースを開き、それらのロールを宣言してからユーザーを割り当てます。今すぐログインすることができます。
  2. 数ヶ月の展開後、ユーザーはもはや戦争の特定の部分にアクセスできなくなります。 .warのその部分に関係するセキュリティロールをmydomainから削除し、誰もそれを使用できなくなります。

最高の部分、特に#2は再配置されません。また、アノテーションで宣言されたデフォルトのセキュリティ設定をオーバーライドする編集XMLはありません(これはあなたのインタフェースがそれより優れていると仮定しています)。

乾杯! もっと詳しく説明しますが、今のところ、少なくとも必要とするかどうかを教えてください。

+0

あなたの答えをありがとう、残念ながら私は休暇中ですので、今は適切に対応できません。 2週間後に私はあなたの答えを試してみます。乾杯! –

+0

お楽しみください!私はあまりにもいいと思う。 – rdcrng

+0

JBossの代わりにJettyを使用していても、それは素晴らしいインスピレーションの源です。 – gouessej

関連する問題