I'm new in the Spring's world I'm using Spring Boot 1.2.5 with Spring Security 3.1.2. Due to my project's requirements I need to configure an ACL security model. I have the following java class configuration:
@Configuration
public class ACLConfig {
@Autowired
DataSource dataSource;
@Bean
JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}
@Bean
DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource);
}
@Bean
EhCacheBasedAclCache aclCache() {
EhCacheFactoryBean factoryBean = new EhCacheFactoryBean();
EhCacheManagerFactoryBean cacheManager = new EhCacheManagerFactoryBean();
cacheManager.setAcceptExisting(true);
cacheManager.setCacheManagerName(CacheManager.getInstance().getName());
cacheManager.afterPropertiesSet();
factoryBean.setName("aclCache");
factoryBean.setCacheManager(cacheManager.getObject());
factoryBean.setMaxBytesLocalHeap("16M");
factoryBean.setMaxEntriesLocalHeap(0L);
factoryBean.afterPropertiesSet();
return new EhCacheBasedAclCache(factoryBean.getObject());
}
@Bean
LookupStrategy lookupStrategy() {
return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger());
}
@Bean
AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"),
new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"),
new SimpleGrantedAuthority("ROLE_SUPER_ADMIN"));
}
@Bean
JdbcMutableAclService aclService() {
JdbcMutableAclService service = new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());
service.setClassIdentityQuery("select currval(pg_get_serial_sequence('acl_class', 'id'))");
service.setSidIdentityQuery("select currval(pg_get_serial_sequence('acl_sid', 'id'))");
return service;
}
@Bean
AclEntryVoter aclDeleteVoter()
{
AclEntryVoter voter = new AclEntryVoter(aclService(),"ACL_NOMCITY_DELETE", new Permission[] {BasePermission.DELETE});
voter.setProcessDomainObjectClass(NomCity.class);
return voter;
}
@Bean
AclEntryVoter aclUpdateVoter()
{
return new AclEntryVoter(aclService(),"ACL_NOMCITY_UPDATE", new Permission[]{BasePermission.ADMINISTRATION});
}
@Bean
AclEntryVoter aclReadVoter()
{
return new AclEntryVoter(aclService(),"ACL_NOMCITY_READ", new Permission[]{BasePermission.READ});
}
@Bean
AccessDecisionManager accessDecisionManager (){
List<AccessDecisionVoter<? extends Object>> list = new ArrayList<>();
list.add(aclDeleteVoter());
list.add(aclReadVoter());
list.add(aclUpdateVoter());
return new AffirmativeBased(list);
}
}
I have the following RestController's methods, it use the ACLs defined earlier:
@RequestMapping(value = "/nomCitys",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional
@Secured({"ROLE_ADMIN","ROLE_USER"})
public ResponseEntity<NomCity> create(@Valid @RequestBody NomCity nomCity) throws URISyntaxException {
NomCity result = nomCityRepository.save(nomCity);
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
ObjectIdentity oi = new ObjectIdentityImpl(NomCity.class,result.hashCode());
MutableAcl acl = mutableAclService.createAcl(oi);
acl.insertAce(0, BasePermission.ADMINISTRATION, new GrantedAuthoritySid("ROLE_ADMIN"), true);
acl.insertAce(1, BasePermission.DELETE, new PrincipalSid(user.getUsername()), true);
acl.insertAce(2, BasePermission.READ, new GrantedAuthoritySid("ROLE_USER"), true);
mutableAclService.updateAcl(acl);
return ResponseEntity.created(new URI("/api/nomCitys/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert("nomCity", result.getId().toString()))
.body(result);
}
When I create a new city the following ACL entries are created too:
- The user with ROLE_ADMIN role have Admin permission.
- The user how create the city have Delete permission.
- The user with ROLE_USER role can read the city.
The following method is the delete method:
@RequestMapping(value = "/nomCitys/{id}",
method = RequestMethod.DELETE,
produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional
@Secured("ACL_NOMCITY_DELETE")
public ResponseEntity<Void> delete(@PathVariable Long id) {
nomCityRepository.delete(id);
ObjectIdentity oid = new ObjectIdentityImpl(NomCity.class,id);
mutableAclService.deleteAcl(oid, true);
return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert("nomCity", id.toString())).build();
}
When I create a new city all work fine, the ACL entries are created and stored in the data base, but when I go to remove a city I get a 403, although I'm logging with the user who created the city, reviewing some pages I saw the following xml entry:
<security:global-method-security
secured-annotations="enabled" access-decision-manager ref="customAccessDecisionManager" />
I suppose that it register the AccessDecisionManager but I don't know how do the same using Java Config and I don't if it's the reason of all my problems.