Step 1. Add the JitPack repository to your build file
Add it in your root settings.gradle at the end of repositories:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
Add it in your settings.gradle.kts at the end of repositories:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Add to pom.xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
Add it in your build.sbt at the end of resolvers:
resolvers += "jitpack" at "https://jitpack.io"
Add it in your project.clj at the end of repositories:
:repositories [["jitpack" "https://jitpack.io"]]
Step 2. Add the dependency
dependencies {
implementation 'com.github.lordlothar99:strategy-spring-security-acl:1.5.1-jdk7'
}
dependencies {
implementation("com.github.lordlothar99:strategy-spring-security-acl:1.5.1-jdk7")
}
<dependency>
<groupId>com.github.lordlothar99</groupId>
<artifactId>strategy-spring-security-acl</artifactId>
<version>1.5.1-jdk7</version>
</dependency>
libraryDependencies += "com.github.lordlothar99" % "strategy-spring-security-acl" % "1.5.1-jdk7"
:dependencies [[com.github.lordlothar99/strategy-spring-security-acl "1.5.1-jdk7"]]
Extensible strategy-based Spring Security ACL implementation ; available modules are : PermissionEvaluator, JPA Specification and ElasticSearch Filter
How to install : have a look here : Installation
### Default Spring Security ACL implementation is database-oriented
Spring Security ACL default implementation uses a persistent model in order to evaluate every permission for any object and SID. Aside performance issues due to a huge ternary table in this model (1 row is 3-tuple { sid ; object weak reference ; permission }), developpers would rather use a more programmatic and object-oriented implementation, without any duplication.
Dealing with Access Control List is not a PermissionEvaluator-only concern. Let's take a CRUD-like standard application :
@PreAuthorize("hasPermission(<object>, <permission>)")
, and so would reject unauthorized executions, that's great !@PostAuthorize("hasPermission(<object>, <permission>)")
instead, and therefore try to filter objects after they've been retrieved from underlying layers (often database) ; this leads to two frequent issues:For read-like methods in JPA and ElasticSearch repositories, Strategy-spring-security-acl provides features able to inject ACL restriction criterias directly inside the repositories.
Strategy-security-acl is an extension of Spring Security which will auto-configure thanks to Spring Boot awesome magic
Current bundled features are:
GrantEvaluator
beansJpaSpecification
in your repositories so they would retrieve only authorized objects from database ; thanks to Spring Data JPAFilterBuilder
in your repositories so they would retrieve only authorized objects from ElasticSearch ; thanks to Spring Data ElasticSearch
You need more than existing features ? Create your own !! and share it ;).PermissionEvaluator
## <a name="Installation">Installation</a>
Add Github as a maven repository (yes, you can) :
<repositories>
<repository>
<id>strategy-spring-security-acl-github-repo</id>
<url>https://raw.github.com/lordlothar99/mvn-repo/master/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
### Spring Boot
Configured beans are automatically loaded by Spring Boot's magic, as soon jars are in the path.
Add required dependencies to your pom (latest version is highest tag created on Github : ) :
<dependency>
<groupId>com.github.lothar.security.acl</groupId>
<artifactId>strategy-spring-security-acl-elasticsearch</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>com.github.lothar.security.acl</groupId>
<artifactId>strategy-spring-security-acl-grant</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>com.github.lothar.security.acl</groupId>
<artifactId>strategy-spring-security-acl-jpa</artifactId>
<version>LATEST</version>
</dependency>
Then you need very few Spring config:
import com.github.lothar.security.acl.jpa.repository.AclJpaRepositoryFactoryBean;
...
@EnableJpaRepositories(
value = "<your jpa repositories package here>",
repositoryFactoryBeanClass = AclJpaRepositoryFactoryBean.class
)
import com.github.lothar.security.acl.elasticsearch.repository.AclElasticsearchRepositoryFactoryBean;
...
@EnableElasticsearchRepositories(
value = "<your elastic search repositories package here>",
repositoryFactoryBeanClass = AclElasticsearchRepositoryFactoryBean.class
)
@EnableGlobalMethodSecurity(prePostEnabled = true)
Now, let's say you have a Customer
domain entity in your project, and you need to restrict readable customers, so that only those whose last name is "Smith" can be retrieved.
1. Define your strategy : let's create an CustomerAclStrategy
, which will contain our different ACL features implementations (1 implementation by feature). SimpleAclStrategy
implementation is recommended as a start. In your favorite Configuration
bean, let's define :
@Bean
public SimpleAclStrategy customerStrategy() {
return new SimpleAclStrategy();
}
CustomerGrantEvaluator
bean, and install it inside the CustomerStrategy
. Let's add a new bean into Configuration
: @Bean
public GrantEvaluator smithFamilyGrantEvaluator(CustomerRepository customerRepository,
GrantEvaluatorFeature grantEvaluatorFeature) {
GrantEvaluator smithFamilyGrantEvaluator = new CustomerGrantEvaluator(customerRepository);
customerStrategy.install(grantEvaluatorFeature, smithFamilyGrantEvaluator);
return smithFamilyGrantEvaluator;
}
And create a dedicated CustomerGrantEvaluator
class, it's close to Spring's PermissionEvaluator
API :
import static com.github.lothar.security.acl.jpa.spec.AclJpaSpecifications.idEqualTo;
import org.springframework.security.core.Authentication;
import com.github.lothar.security.acl.sample.domain.Customer;
import com.github.lothar.security.acl.sample.jpa.CustomerRepository;
public class CustomerGrantEvaluator extends AbstractGrantEvaluator<Customer, String> {
private CustomerRepository repository;
public CustomerGrantEvaluator(CustomerRepository repository) {
super();
this.repository = repository;
}
@Override
public boolean isGranted(Permission permission, Authentication authentication,
Customer domainObject) {
return "Smith".equals(domainObject.getLastName());
}
@Override
public boolean isGranted(Permission permission, Authentication authentication, String targetId,
Class<? extends Customer> targetType) {
// thanks to JpaSpecFeature, repository will count only authorized customers !
return repository.count(idEqualTo(targetId)) == 1;
}
}
@PreAuthorize("hasPermission(#customer, 'SAVE')")
...
@PreAuthorize("hasPermission(#customerId, 'com.github.lothar.security.acl.sample.domain.Customer', 'READ')")
Specification
bean, and install it inside the CustomerStrategy
. Let's add this new bean into Configuration
: @Bean
public Specification<Customer> smithFamilySpec(JpaSpecFeature<Customer> jpaSpecFeature) {
Specification<Customer> smithFamilySpec = new Specification<Customer>() {
@Override
public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query,
CriteriaBuilder cb) {
return cb.equal(root.get("lastName"), "Smith");
}
};
customerStrategy.install(jpaSpecFeature, smithFamilySpec);
return smithFamilySpec;
}
FilterBuilder
bean, and install it inside the CustomerStrategy
. Let's add this new bean into Configuration
: @Bean
public TermFilterBuilder smithFamilyFilter(ElasticSearchFeature elasticSearchFeature) {
TermFilterBuilder smithFamilyFilter = termFilter("lastName", "Smith");
customerStrategy.install(elasticSearchFeature, smithFamilyFilter);
return smithFamilyFilter;
}
You just have to put @NoAcl
annotation on this method in order to avoid the ACL JPA Specification to be injected.
It may be useful (for tests purpose for example) to disable all domain objects strategies, and use only one (which may be allowAllStrategy
, so no restriction would be applied). Just add following property in your project's yml/properties file:
strategy-security-acl:
override-strategy: allowAllStrategy
### Struggling with integration ?
Have a look at our samples !!
Projects using JDK 7 can use artifacts version with suffix "jdk7"