SGP is a library that brings Activity Based Authorization to Spring Boot apps.
Are you developing a Spring Boot app that needs a flexible, dynamic and highly configurable permission system?
SGP functionality consists of two equally important parts: Gathering permissions and guarding protected resources.
SGP scans the configured app package for ProtectedResources and their Permissions.
Once it finds a Permission it stores it into the JPA Entity that implements the PermissionModel interface.
This process happens at every app startup. This makes for a very nice experience when new features are added that should be protected, they are automatically picked up and ready.
This feature can also be disabled, which can be useful for test purposes.
SGP plugs into your app, adds a spring security AccessDecisionManager and a MethodSecurityMetadataSource and enables global method security (Spring Boot feature).
It checks the spring security provided Authentication instance for sufficient permissions by invoking Authentication#getAuthorities().
SGP doesn't tell you what type of authentication to use or how your DB schema should look like.
It's up to you to provide the other pieces of the app that make use of the permission system. (User and role management, authentication etc.)
Yes, this library uses JPA to manage scanned Permissions at app startup. Meaning, it is advisable to have the EntityManagerFactory Bean to be available and the @EntityScan annotation to be configured correctly.
For gradle:
compile("com.ebf:spring-granular-permissions:3.0.0")For maven:
<dependency>
<groupId>com.ebf</groupId>
<artifactId>spring-granular-permissions</artifactId>
<version>3.0.0</version>
</dependency>Make sure the @EntityScan annotation is present in your DB configuration and points to the package(s) of your DB models.
@Configuration
@EntityScan(basePackageClasses = { BaseModel.class })
public class MyDbConfiguration{
}import javax.persistence.Entity;
import javax.persistence.Id;
import com.ebf.security.repository.PermissionModel;
@Entity
public class Model extends BaseModel implements PermissionModel {
@Id
private String name;
private String otherField;
/* your other entity fields ... */
/* implement the methods from the PermissionModel interface */
@Override
public void setPermission(String permission) {
this.name = permission;
}
@Override
public String getPermission() {
return name;
}
/* your other entity getters and setters ... */
}Configure SGP by annotating any of your configuration classes by the PermissionScan annotation and tell it where to look for the Permission annotations on your protected resources.
import com.ebf.security.annotations.PermissionScan;
@Configuration
@PermissionScan
public class SGPConfiguration {
}By default, the PermissionScan annotation is going to scan for Permissions in the package name that is the same as the class where the annotation is located.
If you wish to change this location, or include other ones, you can use the basePackageNames or basePackageClasses attributes like so:
import com.ebf.security.annotations.PermissionScan;
import my.classpackage.Type;
@Configuration
@PermissionScan(
basePackageNames = { "my.package", "my.other.package" },
basePackageClasses = Type.class
)
public class SGPConfiguration {
}This would scan the following packages for ProtectedResources and Permissions:
my.packagemy.other.packagemy.classpackage
@RestController
@ProtectedResource
public class TestController {
@RequestMapping(path = "/")
@Permission("test:request")
public void testRequest() {
//i will only be executed if the security context contains an authority with the name "test:request"
}
}That's it.
The PermissionScan is also initializing the permissions that were picked up by the scan using the PermissionModelRepository.
Initialization process does the following:
- Creates permission models that were part of the scan and not yet persisted in the repository
- Deletes permissions models that are no longer part of the scan but are persisted in the repository
You can choose to omit this process completely by specifying the strategy attribute on the PermissionScan annotation:
import com.ebf.security.annotations.PermissionScan;
@Configuration
@PermissionScan(strategy = PermissionScan.InitializationStrategy.NONE)
public class SGPConfiguration {
}You can choose when this initialization process should occur in the app startup process:
EARLY
As soon as the
PermissionInitializerBean is ready
ON_READY(default)
When the
ApplicationReadyEventis fired
ON_REFRESH
When the
ContextRefreshedEventis fired
Like with the What does it do? section, this is split in the same two parts:
They are all thrown at startup and will prevent your app from starting:
NoPermissionModelFoundException
When no entity implements the
PermissionModelinterface
MoreThanOnePermissionModelFoundException
When more than one entity is implementing the
PermissionModelinterface
AccessDeniedException
When the
Authenticationinstance doesn't hold sufficient autority
Note:
Spring Boot's autoconfiguration will make the rest resources respond with 403 Unauthorized when AccessDeniedException is thrown.
A very dumb sample app can be found in test code.