com.exadel.security:abac-model

Activity Based Security Framework

License

License

Categories

Categories

Security
GroupId

GroupId

com.exadel.security
ArtifactId

ArtifactId

abac-model
Last Version

Last Version

1.3
Release Date

Release Date

Type

Type

jar
Description

Description

Activity Based Security Framework

Download abac-model

How to add to project

<!-- https://jarcasting.com/artifacts/com.exadel.security/abac-model/ -->
<dependency>
    <groupId>com.exadel.security</groupId>
    <artifactId>abac-model</artifactId>
    <version>1.3</version>
</dependency>
// https://jarcasting.com/artifacts/com.exadel.security/abac-model/
implementation 'com.exadel.security:abac-model:1.3'
// https://jarcasting.com/artifacts/com.exadel.security/abac-model/
implementation ("com.exadel.security:abac-model:1.3")
'com.exadel.security:abac-model:jar:1.3'
<dependency org="com.exadel.security" name="abac-model" rev="1.3">
  <artifact name="abac-model" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.exadel.security', module='abac-model', version='1.3')
)
libraryDependencies += "com.exadel.security" % "abac-model" % "1.3"
[com.exadel.security/abac-model "1.3"]

Dependencies

compile (1)

Group / Artifact Type Version
org.aspectj : aspectjrt jar 1.9.6

provided (1)

Group / Artifact Type Version
org.springframework : spring-context jar 5.3.2

Project Modules

There are no modules declared in this project.

EASY-ABAC
Activity Based Security Framework for Java™

Maven Central License


Latest news

  • 17/06/2020: version 1.1 is out!

What is Easy-ABAC Framework?

Usually developer teams spend much time and money creating and supporting own complex access-control architectures, which cannot fully match security expectations. Fairly often REST resources remain unprotected. It's quite problematic to detect them. The framework will help to detect and fix that. Application will raise compilation error if any resource remains unprotected.

The aim of the Easy-ABAC Framework is to help you protect your REST resources from unauthorized access. The framework provides a centralized, externalized authorization management system with flexible fine-grained access rights configuration in declarative manner.

When to use?

  • Java spring-based web applications
  • Multi-tenant applications
  • Applications with dynamic access rights
  • Applications with fine-grained access rights

Core features

  • Lightweight library and easy to learn API
  • Declarative authorization
  • Compile-time check of missing authorization of REST resources
  • Compile-time check of proper configuration
  • Built for Spring based applications

How it works

How to build?

mvn clean install 

How to use?

To start working with the Easy-ABAC Framework you need to add the easy-abac-{version}.jar to the classpath/module-path or add it as a maven dependency, like this:

<dependency>
    <groupId>com.exadel.security</groupId>
    <artifactId>easy-abac</artifactId>
    <version>${abac-version}</version>
</dependency>

Framework also requires spring-context dependency for not spring-based projects:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
</dependency>

Import framework configuration using @Import annotation:

@SpringBootApplication
@Import(AbacConfiguration.class)
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

or using @ImportResource annotation:

@SpringBootApplication
@ImportResource("classpath*:abac-config.xml")
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

Components Easy-ABAC components

Core Attributes

  • Action interface - to define possible actions with entity
  • @Access annotation - to define custom annotation to restrict access to entity
  • @Id annotation - to define entity identifier parameter in method
  • EntityAccessValidator interface - to define access validation rules for entity(s)
  • @ProtectedResource and @PublicResource annotations - to turn on / turn of easy-abac validation respectively

Example

Let's consider simple example: you have resource (entity) Project, CRUD operations with them and would like to restrict access to the resource.

1. Define available actions for your resource. For example:

    public enum ProjectAction implements com.exadel.easyabac.model.core.Action {
        VIEW,
        UPDATE,
        CREATE,
        DELETE
    }

Actions are used to differentiate access rights to the resource, each authenticated user may have different set of available actions. Further will be described have to attach these actions to user.

2.: Create your entity's entityId annotation :

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.PARAMETER)
    public @interface ProjectId {
    }

The @ProjectId annotation will help us define entity identifier parameter in controller or service method:

public ResponseEntity get(@ProjectId @PathVariable("projectId") Long projectId) {...}

3.: Define the annotation which protects your REST resource.

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Access(id = ProjectId.class)
    public @interface ProjectAccess {
  
        /* required actions, see Step 1 */
        ProjectAction[] value();
        
        /* Choose your validator */
        Class<? extends EntityAccessValidator> validator() default ProjectValidator.class;
    }

The @ProjectAccess annotation will be used to protect REST methods. Here you should define type of actions created in Step 1 as well as validator.

4.: Implement the EntityAccessValidator interface for this resource, where the authorization logic is implemented:

    public class ProjectValidator implements com.exadel.easyabac.model.validation.EntityAccessValidator<ProjectAction> {
        @Override
        public void validate(ExecutionContext<ProjectAction> context) {
            //your validation logic here
        }
    }

The validator might be defined as simple class as well as Spring component. If your validator throws any exception, the access to the resource is denied. The ExecutionContext have the following attributes you can use for validation and logging:

  • Entity identifier (Project identifier in our case)
  • Set of actions which are required to access the resource.
  • The action class type.
  • The org.aspectj.lang.JoinPoint which contains more details about protected method.

5.: Protect your REST endpoints using your annotations.

    @RequestMapping("/{projectId}")
    @ProtectedResource
    @ProjectAccess(ProjectAction.VIEW)
    public class ProjectController {
        
        @RequestMapping("/get")
        public Project get(@ProjectId @PathVariable("projectId") Long projectId) {
            // your code here
        }    
        
        @ProjectAccess(ProjectAction.UPDATE)
        @RequestMapping("/update")
        public Project update(@ProjectId @PathVariable("projectId") Long projectId) {
            //your code here
        }    

        @ProjectAccess(ProjectAction.DELETE)
        @RequestMapping("/delete")
        public Project delete(@PathVariable("projectId") Long projectId) {
             //your code here
        }
        
        @PublicResource // turns off EASY-ABAC validation
        public Project close() {
            //your code here
        }
    }

@ProtectedResource is a class-level annotation to turn on easy-abac validation. All public instance methods will be protected unless @ProtectedResource is provided on method, to turn off easy-abac validation.

@ProjectAccess(ProjectAction.VIEW) construction says that only users which have ProjectAction.VIEW action will have access right to the Project.

@ProjectAccess can restricted access as globally when used on class level as locally for particular method. When used both on class and method levels then set of actions are added up together. For example, ProjectController.update requires two actions - ProjectAction.VIEW & ProjectAction.UPDATE.

Compile time checks

The easy-abac provides user-friendly compile time checks:

  • This will raise compile-time error as @ProjectId annotation is missing:
        @ProjectAccess(ProjectAction.DELETE)
        @RequestMapping("/delete")
        public Project delete(@PathVariable("projectId") Long projectId) {
             //your code here
        }
  • This will raise compile-time error as @ProjectAccess annotation is missing while @ProjectId provided:
        @RequestMapping("/delete")
        public Project delete(@ProjectId @PathVariable("projectId") Long projectId) {
             //your code here
        }
  • This will raise compile-time error as @ProjectAccess annotation is missing while resource is marked with @ProtectedResource globally:
    @ProtectedResource
    public class ProjectController {
  
        @RequestMapping("/delete")
        public Project delete(@ProjectId @PathVariable("projectId") Long projectId) {
             //your code here
        }
    }
  • This will raise compile-time error as value() is missing while required:
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Access(id = ProjectId.class)
    public @interface ProjectAccess {
  
        /* required actions, see Step 1 */
        ProjectAction[] value();
        
        /* Choose your validator */
        Class<? extends EntityAccessValidator> validator() default ProjectValidator.class;
    }
  • This will raise compile-time error as validator() is missing while required:
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Access(id = ProjectId.class)
    public @interface ProjectAccess {
  
        /* required actions, see Step 1 */
        ProjectAction[] value();
    }

Custom validator implementation

Let's consider example for validator implementation.

@Component
public class GeneralEntityAccessValidator implements EntityAccessValidator<Action> {

    private static final String ERROR_TEMPLATE = "Access to entity[id=%s] denied.";

    @Autowired
    private ActionProvider actionProvider;

    @Autowired
    private DemoAuthorization authorization;

    @Override
    public void validate(ExecutionContext<Action> context) {
        Long entityId = context.getEntityId();
        Set<Action> availableActions = actionProvider.getAvailableActions(entityId, context.getActionType());
        Set<Action> requiredActions = context.getRequiredActions();

        Set<Action> missingActions = SetUtils.difference(requiredActions, availableActions);
        if (CollectionUtils.isEmpty(missingActions)) {
            return;
        }

        AccessResponse response = new AccessResponse(
                authorization.getLoggedUserRole(),
                entityId,
                missingActions,
                context.getJoinPoint().getSignature().toString()
        );
        throw new AccessException(String.format(ERROR_TEMPLATE, entityId), response);
    }
}

ActionProvider is provider of actions is available for current logged in user. Here we calculate difference between actions available for user and required actions. In case when user missing some required actions - AccessException is thrown. Further you're free to handle this exception. For example using ExceptionHandler.

@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

    private static final String ACCESS_DENIED_PAGE = "403.html";

    @ExceptionHandler(AccessException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public String handleAccessDeniedException(AccessException exception, Model model) {
        model.addAttribute(exception.getResponse());
        return ACCESS_DENIED_PAGE;
    }
}

Why actions instead of permissions?

We consider the following concepts:

  • Permissions - static user access rights, which cannot be changed depending on any other facts.
  • Actions - dynamic user access rights, which can be changed depending on any other facts.

Example:

User has ProjectAction.UPDATE, but we need to restrict it depending on some project attributes. For example user should be unable to update projects with status 'closed'. So project action ProjectAction.UPDATE is available only for not 'closed' projects. This can be simply implemented as an action provider, which takes user static actions and then filtering them using some dynamic attributes. This also works for static actions.


You can see the framework in action in easy-abac-demo

Project structure:

Contributing

Contributions are welcomed and greatly appreciated.

After creating your first contributing PR you will be requested to sign our Contributor License Agreement by commenting your PR with a special message.

Report Bugs

Report bugs at https://github.com/exadel-inc/activity-based-security-framework/issues

Contacts

[email protected]

License info

EASY-ABAC is Open Source software released under the Apache 2.0 license.

com.exadel.security

Exadel

Global Leaders in Agile Software Development, Innovation, and Digital Solutions

Versions

Version
1.3
1.1
1.0-RC3
1.0-RC2
1.0-RC1