Architectural approaches to authorization in server applications: Activity-Based Access Control Framework

Today we'll talk about security in web (and, probably, not only) applications. Before describing the approaches and frameworks, I will tell you a little background.



Background



For many years of work in IT, I had to deal with projects in various fields. Each project had its own security requirements. If in terms of authentication everything was more or less the same in terms of requirements, then the ways of implementing the authorization mechanism turned out to be quite different from project to project. Each time, authorization had to be written almost from scratch for the specific goals of the project, to develop an architectural solution, then to refine it with changing requirements, test, etc. - all this is a common process that cannot be avoided in development. With each implementation of the next such architectural approach, there was more and more the feeling that you could come up with some kind of general approach that would cover the main purposes of authorization and that could be reused in other applications.This article will consider a generalized architectural approach to authorization using the example of the developedframework .



Approaches to creating a framework



As usual, before developing something new, you need to decide what problems will be solved, how the framework will be convenient and useful, and, perhaps, there is already a ready-made solution (we will talk about this later).



Everyone knows two styles of coding - imperative and declarative. The imperative style describes how to get the result, the declarative style describes what you want to get as a result.



, , . , , (permissions) ..

( ) , . , . ( ), — , .



, , . , , — . : , , — , .





:



  1. — , ..




: ( xml, yaml, properties), java annotations.

, , :



  1. Java annotations java, JVM, runtime, compile time.
  2. , .. .
  3. , .. java.




:



  • , ( , Admin, Viewer, Editor)
  • , (permissions) ( , .. )
  • , ( actions) ( ), .. , ( ) , , ( create, modify, delete). , . action-based , — , , , .




. , . .



, java annotations . — .. . Java Annotation Processing, .



Java Module System, Oracle, JDK 9, .





:



  • , , , , , .. .
  • (actions)
  • , ()
  • ( ) ()
  • () — , ,


Easy-ABAC Framework



.



Spring Boot .

( maven):



<dependency>
  <groupId>com.exadel.security</groupId>
  <artifactId>easy-abac</artifactId>
  <version>1.1</version>
</dependency>


1.1.



, :



@SpringBootApplication
@Import(AbacConfiguration.class)
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}


Project . , .



1.



, :





:





(, , , .. — ).



:



import com.exadel.easyabac.model.core.Action;

public enum ProjectAction implements Action {
    VIEW,
    UPDATE,
    CLOSE,
    DELETE
}


- com.exadel.easyabac.model.core.Action. enum — .

, enum () , — , .



2.



- :



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


.



:



import com.exadel.easyabac.model.annotation.Access;
import com.exadel.easyabac.model.validation.EntityAccessValidator;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Access(identifier = ProjectId.class)
public @interface ProjectAccess {

    ProjectAction[] actions();

    Class<? extends EntityAccessValidator> validator();
}


actions validator , :



Error:(13, 9) java: value() method is missing for @com.example.abac.model.ProjectAccess
Error:(13, 9) java: validator() method is missing for @com.example.abac.model.ProjectAccess


Target:



@Target({ElementType.METHOD, ElementType.TYPE})


, — instance- .



3.



:



import com.exadel.easyabac.model.validation.EntityAccessValidator;
import com.exadel.easyabac.model.validation.ExecutionContext;
import com.example.abac.model.ProjectAction;
import org.springframework.stereotype.Component;

@Component
public class ProjectValidator implements EntityAccessValidator<ProjectAction> {

    @Override
    public void validate(ExecutionContext<ProjectAction> context) {
        // here get current user actions
        // and compare them with context.getRequiredActions()
    }
}


( ):



@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Access(identifier = ProjectId.class)
public @interface ProjectAccess {

    ProjectAction[] value();

    Class<? extends EntityAccessValidator> validator() default ProjectValidator.class;
}


:



@ProjectAccess(value = ProjectAction.VIEW, validator = ProjectValidator.class)


4.



, :



import com.exadel.easyabac.model.annotation.ProtectedResource;
import com.example.abac.Project;
import com.example.abac.model.ProjectAccess;
import com.example.abac.model.ProjectAction;
import com.example.abac.model.ProjectId;
import org.springframework.web.bind.annotation.*;

@RestController
@ProtectedResource
@RequestMapping("/project/{projectId}")
public class ProjectController {

    @GetMapping
    @ProjectAccess(ProjectAction.VIEW)
    public Project getProject(@ProjectId @PathVariable("projectId") Long projectId) {
        Project project = ...; // get project here
        return project;
    }

    @PostMapping
    @ProjectAccess({ProjectAction.VIEW, ProjectAction.UPDATE})
    public Project updateProject(@ProjectId @PathVariable("projectId") Long projectId) {
        Project project = ...; // update project here
        return project;
    }

    @PostMapping("/close")
    @ProjectAccess(ProjectAction.CLOSE)
    public Project updateProject(@ProjectId @PathVariable("projectId") Long projectId) {
        Project project = ...; // close project here
        return project;
    }

    @DeleteMapping
    @ProjectAccess(ProjectAction.DELETE)
    public Project updateProject(@ProjectId @PathVariable("projectId") Long projectId) {
        Project project = ...; // delete project here
        return project;
    }
}


@ProtectedResource , — instance- @Access-based , — .



@PublicResource , , , @ProtectedResource



, , . , ( ).



5.



. . , , — -.



, EntityAccessValidator, validate:



public void validate(ExecutionContext<Action> context);


ExecutionContext - : context.getRequiredActions() Action, .



Action — — . Action(s) : , ...



2 Actions — , — Action — . exception, , AccessDeniedException ExceptionHandler HTTP status 403 — .



.









, - , , - . , , :



: Apache Shiro, JAAS, Spring Security.

Apache Shiro JAAS , , JAAS , Apache Shiro — — , ,

Spring Security — ( ), , compile-time. . , .



Easy-ABAC Framework , , — ...





, . " " .

spring-based . Spring.

.



C



  1. Java
  2. Spring-based




The article discusses architectural approaches to authorization, presented by Easy-ABAC Framework.

Among the advantages of the developed framework are:



  1. Declarative authorization style
  2. Handling configuration errors at compile time
  3. Simple and straightforward configuration
  4. Flexibility



All Articles