Как использовать отдельные области для аутентификации и авторизации с помощью Shiro и CAS?

Я работаю над веб-приложением, в котором несколько приложений аутентифицируются через CAS SSO Server. Однако каждое приложение должно поддерживать свои соответствующие роли, и эти роли хранятся в базе данных, специфичной для приложения. Итак, мне нужно иметь 2 области, одну для CAS (для authc) и другую для DB (для authz).

Это моя текущая конфигурация Широ. Я получаю перенаправление на CAS, работающее правильно, но вошедший в систему пользователь (Subject), похоже, не имеет загруженных в него ролей/разрешений (например, 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. Как лучше всего управлять пользователями и ролями в разных/отдельных приложениях?

person Firdous Amir    schedule 21.05.2013    source источник
comment
Вы проверили роли? Мы используем очень похожую конфигурацию с casRealm для аутентификации и textRealm и/или activeDirectoryRealm для авторизации. Для разрешений мы используем собственную реализацию RolePermissionResolver.   -  person Volker Seibt    schedule 11.12.2013
comment
В casRealm мы опускаем свойство defaultRoles.   -  person Volker Seibt    schedule 11.12.2013


Ответы (3)


Проблема, с которой вы столкнулись, связана с тем, что и CasRealm, и JdbcRealm расширяют как AuthorizingRealm (Authorizer), так и AuthenticatingRealm. Первый шаг, который я бы сделал, это JdbcRealm. Реализация JdbcRealm наследует AuthenticatingRealm#supports(AuthenticationToken token) реализация метода. Если вы расширите JdbcRealm и переопределите метод «supports», чтобы он возвращал «false» для всех типов токенов, JdbcRealm больше не будет использоваться для аутентификации.

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

CasRealm — это отдельная история, нет способа (насколько я знаю) легко сказать Широ не использовать область, которая реализует Авторизатор при проверке разрешений. Меня лично разочаровывает то, что реализация по умолчанию для большинства протоколов предполагает необходимость как авторизации, так и аутентификации. Я бы предпочел, чтобы каждая из них была разделена на две реализации (например, AuthenticationCasRealm, AuthorizingCasRealm).

Логика проверки разрешений при использовании нескольких областей задокументирована здесь. . Конкретный текст, который ссылается на это поведение:

Шаг 4: Каждая настроенная область проверяется, чтобы увидеть, реализует ли она один и тот же интерфейс авторизатора. Если это так, вызывается собственный соответствующий метод области hasRole*, checkRole*, isPermitted* или checkPermission*.

Исходя из этого, вы теоретически можете переопределить каждый из именованных методов и все их перегруженные реализации, чтобы они всегда возвращали «false».

Мое решение этой проблемы основано на моем предыдущем комментарии о разделении каждой области на два компонента: один для аутентификации и один для авторизации. Таким образом, вы получите больше повторяющегося кода, но это явно указывает на то, какое поведение вы ожидаете от своей реализации.

Вот как это сделать:

  1. Создайте новый класс AuthenticationCasRealm, который расширяет org.apache.shiro.realm.AuthenticatingRealm и реализует org.apache.shiro.util.Initializable.

  2. Скопируйте и вставьте содержимое существующего исходный код CasRealm в ваш новый класс "AuthenticatingCasRealm". (Я знаю, что путь копирования и вставки существующего кода часто не одобряется, однако в описанных обстоятельствах я не знаю другого способа решения проблемы.)

  3. Удалите все методы, которые были реализованы для org.apache.shiro.realm.AuthorizingRealm.

  4. Обновите конфигурацию Shrio, чтобы она ссылалась на вашу новую реализацию AuthenticationCasRealm.

Основываясь на этих изменениях, теперь у вас должно быть две настраиваемые реализации в вашей конфигурации Shrio; один из JdbcRealm переопределяет метод «поддерживает» и один из CasRealm удаляет методы API авторизации.

Существует один дополнительный метод, основанный на явном объявлении Авторизатор через конфигурацию Широ, которая может лучше подходить для вашей ситуации.

Вот явное объявление Authorizer и Authenticator через пользовательское расширение 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"));
    }
}
person justin.hughey    schedule 04.11.2014

Вам нужна только одна область, которая расширяет область AuthorizingRealm. Это обеспечит

  • authc: метод doGetAuthenticationInfo (сервер CAS)
  • авторизация: метод doGetAuthorizationInfo (JDBC)

Надеюсь это поможет

person vincenzo iafelice    schedule 20.11.2013
comment
Если вы используете описанный выше подход, вам нужно только настроить существующие области и не нужно никакой пользовательской реализации. - person Volker Seibt; 11.12.2013

У нас был аналогичный случай, когда мы использовали область LDAP для аутентификации и использовали стандартный файл shiro.ini для авторизации для простого варианта использования.

Чтобы дополнить ответ «justin.hughey», я даю конфигурацию плана (также может быть spring), чтобы ваш вариант использования работал:

<!-- 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>

Главное, что нам понадобилось:

  • a modularRealmAuthenticator и пусть стратегия по умолчанию (поскольку существует только одна область) для «аутентификатора»
  • специальный AuthzOnlyIniRealm, который переопределяет метод supports, возвращающий false, чтобы предотвратить его использование для аутентификации.

Наша реализация LdapRealm — это просто расширение Shiro ActiveDirectoryRealm.

person рüффп    schedule 12.04.2016