2013-05-21 2 views
3

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

Это мой текущий конфигуратор shiro. Я получаю перенаправление к CAS, работающему должным образом, но зарегистрированный пользователь (Subject), похоже, не загружает роли/разрешения (например, SecurityUtil.isPermited() не работает должным образом)

<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. Какова наилучшая практика управления пользователями и ролями в разных/отдельных приложениях?
+0

Вы проверили роли? Мы используем очень похожую конфигурацию с casRealm для аутентификации и textRealm и/или activeDirectoryRealm для авторизации. Для разрешений мы используем пользовательскую реализацию RolePermissionResolver. –

+0

В casRealm мы опускаем свойство defaultRoles. –

ответ

2

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

  • authc: метод doGetAuthenticationInfo (CAS сервер)
  • AuthZ: метод doGetAuthorizationInfo (JDBC)

Надеется, что это помогает

+0

Если вы используете вышеуказанный подход, вам нужно только настроить существующие области и не нуждаться в какой-либо пользовательской реализации. –

3

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Вот явное объявление Авторизатора и Аутентификатора через пользовательское расширение 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")); 
    } 
} 
0

У нас был подобный случай, когда мы используем Realm 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> 

ключевых моментов является то, что нам нужно :

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

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

Смежные вопросы