5

複数のアプリケーションが CAS SSO サーバーを介して認証する Web アプリケーションに取り組んでいます。ただし、各アプリケーションはそれぞれの役割を維持する必要があり、これらの役割はアプリケーション固有のデータベースに格納されます。したがって、CAS (authc) 用と DB (authz) 用の 2 つのレルムが必要です。

これが私の現在の shiro 設定です。CAS へのリダイレクトは正常に機能していますが、ログインしているユーザー (サブジェクト) に役割/権限が読み込まれていないようです (たとえば、SecurityUtil.isPermitted() が期待どおりに機能していません)。

<bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
        <property name="name" value="jdbcRealm" />
        <property name="dataSource" ref="dataSource" />
        <property name="authenticationQuery"
            value="SELECT password FROM system_user_accounts WHERE username=? and status=10" />
        <property name="userRolesQuery"
            value="SELECT role_code FROM system_roles r, system_user_accounts u, system_user_roles ur WHERE u.user_id=ur.user_id AND r.role_id=ur.role_id AND u.username=?" />
        <property name="permissionsQuery"
            value="SELECT code FROM system_roles r, system_permissions p, system_role_permission rp WHERE r.role_id=rp.role_id AND p.permission_id=rp.permission_id AND r.role_code=?" />

        <property name="permissionsLookupEnabled" value="true"></property>
        <property name="cachingEnabled" value="true" />
        <property name="credentialsMatcher" ref="passwordMatcher" />
    </bean>

    <!-- For CAS -->
    <bean id="casRealm" class="org.apache.shiro.cas.CasRealm">
        <property name="defaultRoles" value="ROLE_USER" />
        <property name="casServerUrlPrefix" value="http://localhost:7080/auth" />
        <property name="casService" value="http://localhost:8080/hawk-hck-web/shiro-cas" />
        <property name="validationProtocol" value="SAML" />
        <property name="cachingEnabled" value="true"></property>
    </bean>
    <bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory" />

<!-- Security Manager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realms">
            <list>
                <ref bean="casRealm" />
                <ref bean="jdbcRealm" />
            </list>
        </property>
        <property name="cacheManager" ref="cacheManager"/>
        <property name="subjectFactory" ref="casSubjectFactory" />
    </bean>

<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
        <property name="failureUrl" value="/error"></property>
    </bean>

<!-- Shiro filter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="http://localhost:7080/auth/login?service=http://localhost:8080/hawk-hck-web/shiro-cas" />
        <property name="successUrl" value="/home/index" />
        <property name="unauthorizedUrl" value="/error" />
        <property name="filters">
            <util:map>
                    <entry key="casFilter" value-ref="casFilter" /> 
            </util:map>
        </property>
        <property name="filterChainDefinitions">
            <value> 
                <!-- !!! Order matters !!! -->
                /shiro-cas = casFilter
                /login = anon
                /logout = logout
                /error = anon
                /static/** = anon
                /** = authc
            </value>
        </property>
    </bean>

レルムを securityManager に登録する方法は正しいはずです。セットアップの良い例が本当に見つかりません。

ここで 2 つの質問があります。

  1. 上記のシナリオを実現するための正しいセットアップ/構成は何ですか?
  2. 異なる/個別のアプリケーション間でユーザーとロールを管理するためのベスト プラクティスは何ですか?
4

3 に答える 3

4

あなたが直面している問題は、CasRealm と JdbcRealm の両方が AuthorizingRealm (Authorizer) と AuthenticatingRealm の両方を拡張しているという事実に関係しています。私が取る最初のステップは、JdbcRealm です。JdbcRealm 実装は、AuthenticationRealm#supports(AuthenticationToken token)メソッド実装を継承します。JdbcRealm を拡張し、すべてのトークン タイプに対して「false」を返すように「supports」メソッドをオーバーライドすると、JdbcRealm は認証目的で使用されなくなります。

@Override
public boolean supports (AuthenticationToken token) {
    return false;
}

CasRealm は別の話です。アクセス許可を確認するときにAuthorizerを実装するレルムを使用しないように Shiro に簡単に指示する方法 (私が知っている) はありません。個人的には、ほとんどのプロトコルのデフォルトの実装で、承認と認証の両方が必要であると想定されていることに不満を感じています。それぞれを 2 つの実装 (AuthenticationCasRealm、AuthorizingCasRealm など) に分割することをお勧めします。

複数のレルムが使用されている場合のアクセス許可のチェックの背後にあるロジックは、ここに記載されています。この動作を参照する特定のテキストは次のとおりです。

ステップ 4: 構成された各レルムがチェックされ、同じオーソライザー インターフェイスが実装されているかどうかが確認されます。その場合、レルム独自のそれぞれの hasRole*、checkRole*、isPermitted*、または checkPermission* メソッドが呼び出されます。

これに基づいて、理論的には、指定された各メソッドとそのオーバーロードされたすべての実装をオーバーライドして、常に「false」を返すことができます。

この問題に対する私の解決策は、各レルムを認証用と承認用の 2 つのコンポーネントに分割するという以前のコメントに基づいています。このようにすると、コードの重複が増えますが、実装に期待する動作が明確になります。

方法は次のとおりです。

  1. org.apache.shiro.realm.AuthenticatingRealm を拡張し、org.apache.shiro.util.Initializable を実装する新しいクラス「AuthenticatingCasRealm」を作成します。

  2. 既存のCasRealm ソースの内容をコピーして、新しい「AuthenticatingCasRealm」クラスに貼り付けます。(既存のコードのコピー アンド ペースト ルートを使用することはしばしば嫌われていることは承知していますが、説明されている状況では、問題を解決する他の方法を私は知りません。)

  3. org.apache.shiro.realm.AuthorizingRealm に実装されていたすべてのメソッドを取り除きます。

  4. Shrio 構成を更新して、新しい AuthenticatingCasRealm 実装を参照します。

これらの変更に基づいて、Shrio 構成に 2 つのカスタム実装が必要になります。「supports」メソッドをオーバーライドする JdbcRealm の 1 つと、Authorization API メソッドを削除する CasRealm の 1 つです。

Shiro の構成を介して Authorizer を明示的に宣言することに基づく追加の方法が 1 つあります。これは、状況により適している可能性があります。

以下は、カスタム ShiroFilter 拡張機能を介したオーソライザーとオーセンティケーターの明示的な宣言です。どちらも起動時に実装され、提供された JNDI 名に登録されました。

public class CustomShiroFilter extends ShiroFilter {

    @Override
    public void init () throws Exception {
        super.init();
        DefaultWebSecurityManager dwsm = (DefaultWebSecurityManager) getSecurityManager();
        dwsm.setAuthorizer((Authorizer)JndiUtil.get("realms/authorizerRealm"));
        dwsm.setAuthenticator((Authenticator)JndiUtil.get("realms/authenticatorRealm"));
    }
}
于 2014-11-04T15:49:03.557 に答える
3

AuthorizingRealmを拡張するレルムは 1 つだけ必要です。それは提供します

  • authc: メソッドdoGetAuthenticationInfo(CAS サーバー)
  • authz: メソッドdoGetAuthorizationInfo(JDBC)

お役に立てれば

于 2013-11-20T15:54:55.837 に答える
0

認証に LDAP レルムを使用shiro.iniし、単純なユース ケースの承認に標準ファイルを使用した同様のケースがありました。

「justin.hughey」の回答を補完するために、ユースケースを機能させるために青写真 (春の可能性もあります) の構成を提供します。

<!-- Bean for Authentication --> 
<bean id="rccadRealm" class="org.mydomain.myproject.security.shiro.ldap.realm.LdapRealm"
        init-method="init">
    <property name="searchBase" value="${realm.searchBase}" />
    <property name="singleUserFilter" value="${realm.singleUserFilter}" />
    <property name="timeout" value="30000" />
    <property name="url" value="${contextFactory.url}" />
    <property name="systemUsername" value="${contextFactory.systemUsername}" />
    <property name="systemPassword" value="${contextFactory.systemPassword}" />
</bean>

<!-- Bean for Authorization --> 
<bean id="iniRealm" class="org.mydomain.myproject.security.realm.AuthzOnlyIniRealm">
    <argument value="file:$[config.base]/etc/shiro.ini"/>
    <property name="authorizationCachingEnabled" value="true" />
</bean>

<bean id="myModularAuthenticator"
    class="org.mydomain.myproject.security.service.MyModularRealmAuthenticator">
    <property name="realms">
        <list>
            <ref component-id="ldapRealm" />
        </list>
    </property>
</bean>

<bean id="mySecurityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
    <property name="authenticator" ref="myModularAuthenticator" />
    <property name="authorizer" ref="iniRealm" />
    <property name="cacheManager" ref="cacheManager" />
</bean>

重要なことは、次のことが必要だったということです。

  • amodularRealmAuthenticatorおよび let 'authenticator' のデフォルト戦略 (レルムが 1 つしかないため)
  • false を返すメソッドをオーバーライドして認証に使用しないようにする特別な AuthzOnlyIniRealm supports

LdapRealm の実装は、 Shiro の単なる拡張ですActiveDirectoryRealm

于 2016-04-12T08:59:24.707 に答える