为了账号安全,请及时绑定邮箱和手机立即绑定

Spring Security ACL:我无法更新ACL

Spring Security ACL:我无法更新ACL

繁华开满天机 2021-05-13 18:19:43
我正在尝试学习一些Spring Security ACL控件并将其应用于我的Spring Boot项目。因此,我尝试重用Spring Security参考中的代码片段,我对项目需求做了一些调整。我具有以下组件,以便在启动时用一些初始值填充数据库。@Componentpublic class AppBootstrap {    private Authority adminAuth;    private User admin;    private TimeSheet timeSheetAdmin;    private final JdbcMutableAclService jdbcMutableAclService;    private final PlatformTransactionManager transactionManager;    @Autowired    public AppBootstrap(JdbcMutableAclService jdbcMutableAclService, PlatformTransactionManager transactionManager) {        this.jdbcMutableAclService = jdbcMutableAclService;        this.transactionManager = transactionManager;    }    @Bean    public CommandLineRunner initialAuthorities(AuthorityRepository authorityRepository) {        return args -> {            adminAuth = new Authority(ROLE_ADMIN);            authorityRepository.save(adminAuth);        };    }    @Bean    public CommandLineRunner initialUsers(UserRepository userRepository) {        return args -> {            admin = new User("admin",                    "{bcrypt}$2a$08$lDnHPz7eUkSi6ao14Twuau08mzhWrL4kyZGGU5xfiGALO/Vxd5DOi", "admin",                    "admin", "admin@example.com", true, getDate(2016, JANUARY, 1));            admin.setAuthorities(asList(adminAuth));            userRepository.save(admin);        };    }    @Bean    public CommandLineRunner initialTimeSheets(TimeSheetRepository timeSheetRepository) {        return args -> {            timeSheetAdmin = new TimeSheet(LocalDate.of(2016, MARCH, 1), admin);            timeSheetRepository.save(timeSheetUser);        };    }    @Bean    public CommandLineRunner initialRights() {        return args -> grantPermission(admin, timeSheetAdmin, ADMINISTRATION);    }每次刷新应用程序上下文时都会运行此方法。我可以看到,如果仅运行一种测试方法(或测试类),则该方法将成功运行。这些测试是端到端测试(@RunWith(SpringRunner.class) @SpringBootTest)。另外,@SpringBootApplication独自一人也没问题。但是,如果我一次运行所有测试,@SpringBootTest则以下堆栈跟踪几乎都失败了我有一些问题:当我运行多个测试类时,为什么会发生此错误?如何找到解决方法?有没有更好的方法可以实现相同目的?
查看完整描述

2 回答

?
慕侠2389804

TA贡献1719条经验 获得超6个赞

我遇到过同样的问题。

就我而言,ACL缓存脏了。每次测试后,我必须清除缓存,然后所有测试都以绿色运行,即使同时调用也是如此。

我为此创建了一个TestExcutionListener。只需用它注释您的抽象Test类:


@TestExecutionListeners(

    value = ClearAclCacheTestExecutionListener.class,

    mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS) 

public class AbstractTest{...}

public class ClearAclCacheTestExecutionListener extends AbstractTestExecutionListener {


    @Autowired

    private AclCache aclCache;


    @Override

    public void beforeTestClass(TestContext testContext) {

        testContext.getApplicationContext()

                .getAutowireCapableBeanFactory()

                .autowireBean(this);

    }


    @Override

    public void afterTestMethod(TestContext testContext) throws Exception {

        super.afterTestMethod(testContext);

        aclCache.clearCache();

    }

}


查看完整回答
反对 回复 2021-05-26
?
郎朗坤

TA贡献1921条经验 获得超9个赞

由于这个问题并没有那么受欢迎,因此我尝试了一种不同的方法,该方法似乎非常有用:-)


首先,我创建了一个新的ACLService类,以隔离与JdbcMutableAclService的所有交互。


package com.roberto.security.service;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.security.acls.model.*;

import org.springframework.stereotype.Service;


/**

 * Service class to handle ACL permissions.

 */

@Service

public class ACLService {

    private final MutableAclService mutableAclService;


    @Autowired

    public ACLService(MutableAclService mutableAclService) {

        this.mutableAclService = mutableAclService;

    }


    /**

     * Insert an ACL entry

     * @param oid represents the model object

     * @param recipient represents the principal (user, group of users, etc)

     * @param permission quite explicit name...

     * @return the new ACL database entry

     */

    public MutableAcl addPermission(ObjectIdentity oid, Sid recipient, Permission permission) {

        MutableAcl acl;


        try {

            acl = (MutableAcl) mutableAclService.readAclById(oid);

        } catch (NotFoundException nfe) {

            acl = mutableAclService.createAcl(oid);

        }


        acl.insertAce(acl.getEntries().size(), permission, recipient, true);

        return mutableAclService.updateAcl(acl);

    }   

}

然后,我创建了另一个集成测试,该测试可以正常运行,而没有IllegalStateException。现在,我只需要从我的引导程序类中调用它即可。


package com.roberto.security.service;


import com.roberto.model.TimeSheet;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.security.acls.domain.BasePermission;

import org.springframework.security.acls.domain.ObjectIdentityImpl;

import org.springframework.security.acls.domain.PrincipalSid;

import org.springframework.security.acls.model.*;

import org.springframework.security.test.context.support.WithUserDetails;

import org.springframework.test.annotation.DirtiesContext;

import org.springframework.test.context.junit4.SpringRunner;

import org.springframework.transaction.annotation.Transactional;


import java.util.List;


import static org.junit.Assert.*;

import static org.springframework.test.annotation.DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD;


/**

 * This test handles basic interaction between our codebase

 * Spring Security ACL and the underlying database model

 */

@SpringBootTest

@RunWith(SpringRunner.class)

public class ACLServiceIntegrationTest {


    private Authentication authentication;

    private ObjectIdentity oid ;

    private Sid sid;

    private Permission administration = BasePermission.ADMINISTRATION;


    @Autowired

    private ACLService aclService;


    @Autowired

    private MutableAclService mutableAclService;


    @Autowired

    private PermissionEvaluator permissionEvaluator;


    @Before

    public void setUp() {

        authentication = TestSecurityContextHolder.getContext().getAuthentication();

        sid = new PrincipalSid(((JwtUser) authentication.getPrincipal()).getUsername());

        oid = new ObjectIdentityImpl(TimeSheet.class, 1);

    }


    @Test

    @WithUserDetails("admin")

    public void testBeans() {

        assertNotNull(aclService);

        assertNotNull(mutableAclService);

        assertNotNull(permissionEvaluator);

    }


    @Test

    @Transactional

    @WithUserDetails("admin")

    @DirtiesContext(methodMode = AFTER_METHOD)

    public void addPermissionIntegrationTest() {

        assertFalse(permissionEvaluator.hasPermission(authentication, oid.getIdentifier(), oid.getType(), administration));


        MutableAcl acl = aclService.addPermission(oi, sid, administration);


        assertTrue(permissionEvaluator.hasPermission(authentication, oid.getIdentifier(), oid.getType(), administration));


        assertEquals(TimeSheet.class.toString().split(" ")[1], acl.getObjectIdentity().getType());

        assertTrue(acl.getEntries().stream().anyMatch(e -> e.getSid().equals(sid) && e.getPermission().equals(administration)));

        assertTrue(acl.isGranted(List.of(administration), List.of(sid), true));

    }

}


查看完整回答
反对 回复 2021-05-26
  • 2 回答
  • 0 关注
  • 229 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信