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 ProtectedResource
s and their Permission
s.
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.package
my.other.package
my.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
PermissionInitializer
Bean is ready
ON_READY
(default)
When the
ApplicationReadyEvent
is fired
ON_REFRESH
When the
ContextRefreshedEvent
is 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
PermissionModel
interface
MoreThanOnePermissionModelFoundException
When more than one entity is implementing the
PermissionModel
interface
AccessDeniedException
When the
Authentication
instance 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.