JdbcMutableAclService — транзакция должна быть запущена

#java #spring #transactions #spring-security #acl

#java #spring #транзакции #spring-безопасность #acl

Вопрос:

Я пытаюсь внедрить acl spring security в проект. После построения основной части конфигурации и создания соответствующей схемы базы данных я пытаюсь создать несколько ACE и позволить волшебству произойти. Но я сталкиваюсь с этим исключением снова и снова

 java.lang.IllegalArgumentException: Transaction must be running
    org.springframework.util.Assert.isTrue(Assert.java:65)
    org.springframework.security.acls.jdbc.JdbcMutableAclService.createOrRetrieveSidPrimaryKey(JdbcMutableAclService.java:219)
    org.springframework.security.acls.jdbc.JdbcMutableAclService$1.setValues(JdbcMutableAclService.java:136)
    org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:892)
    org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:1)
    org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:586)
    org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:614)
    org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:883)
    org.springframework.security.acls.jdbc.JdbcMutableAclService.createEntries(JdbcMutableAclService.java:123)
    org.springframework.security.acls.jdbc.JdbcMutableAclService.updateAcl(JdbcMutableAclService.java:314)
  

Мои основные части конфигурации

 <bean id="dataSource"
    class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close" >
    <property name="driverClassName" value="${core.db.driverClassName}" />
    <property name="url" value="${core.db.jdbcUrl}" />
    <property name="username" value="${core.db.user}" />
    <property name="password" value="${core.db.password}" />
</bean>

<bean id="aclCache"
    class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
    <constructor-arg>
        <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
            <property name="cacheManager">
                <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
            </property>
            <property name="cacheName" value="aclCache" />
        </bean>
    </constructor-arg>
</bean>

<bean id="auditLogger"
    class="org.springframework.security.acls.domain.ConsoleAuditLogger" />

<bean id="aclAuthorizationStrategy"
    class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
    <constructor-arg name="auths">
        <list>
            <bean
                class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                <constructor-arg value="ACL_ADMIN" />
            </bean>
            <bean
                class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                <constructor-arg value="ACL_ADMIN" />
            </bean>
            <bean
                class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                <constructor-arg value="ACL_ADMIN" />
            </bean>
        </list>
    </constructor-arg>
</bean>

<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
    <constructor-arg name="dataSource" ref="dataSource"/>
    <constructor-arg name="aclCache" ref="aclCache"/>
    <constructor-arg name="aclAuthorizationStrategy" ref="aclAuthorizationStrategy"/>
    <constructor-arg name="auditLogger" ref="auditLogger"/>
</bean>

<bean id="aclService"
    class="org.springframework.security.acls.jdbc.JdbcMutableAclService" >
    <constructor-arg name="dataSource" ref="dataSource" />
    <constructor-arg name="lookupStrategy" ref="lookupStrategy" />
    <constructor-arg name="aclCache" ref="aclCache" />
    <property name="sidIdentityQuery" value="SELECT id FROM acl_sid" />
    <property name="classIdentityQuery" value="SELECT id FROM acl_class" />
</bean>

<bean id="jdbcTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<bean id="txProxyTemplate" abstract="true" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    <property name="transactionManager"><ref local="jdbcTransactionManager"/></property> 
    <property name="target"><ref local="aclService" /></property> 
    <property name="transactionAttributes"> 
        <props> 
            <prop key="create*">PROPAGATION_REQUIRED</prop> 
            <prop key="update*">PROPAGATION_REQUIRED</prop> 
            <prop key="delete*">PROPAGATION_REQUIRED</prop> 
        </props> 
    </property> 
</bean>  
  

Кажется, я чего-то не хватает, потому что транзакция должна быть активной через TransactionProxy.

Доступ к службе в контроллере таким образом

 ...
ObjectIdentity oi = new ObjectIdentityImpl(X.class, vm.hashCode());
Sid sid = new PrincipalSid(userDn);
Permission p = BasePermission.READ;

// Create or update the relevant ACL
MutableAcl acl = null;
try {
    acl = (MutableAcl) aclService.readAclById(oi);
} catch (NotFoundException nfe) {
    acl = aclService.createAcl(oi);
}

// Now grant some permissions via an access control entry (ACE)
acl.insertAce(acl.getEntries().size(), p, sid, true);
aclService.updateAcl(acl);
...
  

Ответ №1:

Попробуйте покрыть вызывающие методы aclService шаблоном транзакции:

 TransactionTemplate tt = new TransactionTemplate(transactionManager);
    tt.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus status) {
            ObjectIdentity oid = new ObjectId
            entityImpl(clazz.getCanonicalName(), securedObject.getId());
                // your aclService operation here: 
                aclService.deleteAcl(oid, true);            
        }
    });
  

Комментарии:

1. 6 лет спустя я столкнулся с той же проблемой и нашел это очень полезным. Просто небольшой комментарий: Транзакция утверждается при создании записей класса или sid для целей синхронизации. Нет необходимости запускать транзакцию для deleteAcl()

Ответ №2:

Упомянутая вами ошибка возникает только тогда, когда sid отсутствует в таблице acl_sid и вставляется Spring ACL автоматически. Попробуйте добавить строки вручную, а затем повторно запустите код. У меня это сработало.

См. http://forum.springsource.org/showthread.php?55490-ACL-Transaction-must-be-running

Ответ №3:

Приведенный выше метод или сервис с аннотацией @Transactional (содержащий метод) может решить проблему.

Комментарии:

1. Это самый простой ответ, хотя я не уверен, насколько хорошей была поддержка этой аннотации в 2011 году, lol