Enfoques arquitectónicos para la autorización en aplicaciones de servidor: marco de control de acceso basado en actividades

Hoy hablaremos de seguridad en aplicaciones web (y, probablemente, no solo). Antes de describir los enfoques y marcos, les contaré algunos antecedentes.



Antecedentes



Durante muchos años de trabajo en TI, tuve que lidiar con proyectos en varios campos. Cada proyecto tenía sus propios requisitos de seguridad. Si en términos de autenticación todo era más o menos igual en términos de requisitos, entonces las formas de implementar el mecanismo de autorización resultaron ser bastante diferentes de un proyecto a otro. Cada vez, la autorización tuvo que escribirse casi desde cero para los objetivos específicos del proyecto, para desarrollar una solución arquitectónica, luego para refinarla con requisitos cambiantes, pruebas, etc. - Todo esto es un proceso común que no se puede evitar en el desarrollo. Con cada implementación del siguiente enfoque arquitectónico de este tipo, existía cada vez más la sensación de que se podía llegar a algún tipo de enfoque general que cubriera los principales propósitos de la autorización y que pudiera reutilizarse en otras aplicaciones.Este artículo considerará un enfoque arquitectónico generalizado para la autorización utilizando el ejemplo delmarco .



Enfoques para crear un marco



Como de costumbre, antes de desarrollar algo nuevo, debe decidir qué problemas se resolverán, cómo el marco será conveniente y útil, y quizás ya haya una solución lista para usar (hablaremos de esto más adelante).



Todo el mundo conoce dos estilos de codificación: imperativo y declarativo. El estilo imperativo describe cómo obtener el resultado, el estilo declarativo describe lo que desea obtener como resultado.



, , . , , (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




El artículo analiza los enfoques arquitectónicos para la autorización, presentados por Easy-ABAC Framework.

Entre las ventajas del marco desarrollado se encuentran:



  1. Estilo de autorización declarativa
  2. Manejo de errores de configuración en tiempo de compilación
  3. Configuración sencilla y directa
  4. Flexibilidad



All Articles