ArchitekturansĂ€tze fĂŒr die Autorisierung in Serveranwendungen: Activity-Based Access Control Framework

Heute werden wir ĂŒber Sicherheit in Webanwendungen (und wahrscheinlich nicht nur) sprechen. Bevor ich die AnsĂ€tze und Rahmenbedingungen beschreibe, möchte ich Ihnen einen kleinen Hintergrund geben.



Hintergrund



WĂ€hrend meiner langjĂ€hrigen Arbeit in der IT musste ich mich mit Projekten in verschiedenen Bereichen befassen. Jedes Projekt hatte seine eigenen Sicherheitsanforderungen. Wenn in Bezug auf die Authentifizierung in Bezug auf die Anforderungen alles mehr oder weniger gleich war, stellte sich heraus, dass die Art und Weise der Implementierung des Autorisierungsmechanismus von Projekt zu Projekt sehr unterschiedlich war. Jedes Mal musste die Autorisierung fĂŒr die spezifischen Ziele des Projekts fast von Grund auf neu geschrieben, eine Architekturlösung entwickelt und dann an sich Ă€ndernde Anforderungen, Tests usw. angepasst werden. - All dies ist ein allgemeiner Prozess, der in der Entwicklung nicht vermieden werden kann. Mit jeder Implementierung des nĂ€chsten solchen Architekturansatzes gab es immer mehr das GefĂŒhl, dass Sie einen allgemeinen Ansatz entwickeln könnten, der die Hauptzwecke der Autorisierung abdeckt und in anderen Anwendungen wiederverwendet werden könnte.In diesem Artikel wird ein verallgemeinerter architektonischer Ansatz fĂŒr die Autorisierung am Beispiel des Entwickelten betrachtetRahmen .



AnsÀtze zur Schaffung eines Frameworks



Wie ĂŒblich mĂŒssen Sie vor der Entwicklung von etwas Neuem entscheiden, welche Probleme gelöst werden sollen, wie das Framework bequem und nĂŒtzlich sein wird, und möglicherweise gibt es bereits eine vorgefertigte Lösung (wir werden spĂ€ter darĂŒber sprechen).



Jeder kennt zwei Arten der Codierung - imperativ und deklarativ. Der imperative Stil beschreibt, wie Sie das Ergebnis erhalten, der deklarative Stil beschreibt, was Sie als Ergebnis erhalten möchten.



, , . , , (permissions) ..

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



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





:



  1. — , ..
  2. —




: ( 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




Der Artikel beschreibt architektonische AutorisierungsansÀtze, die von Easy-ABAC Framework vorgestellt werden.

Zu den Vorteilen des entwickelten Frameworks gehören:



  1. Deklarativer Autorisierungsstil
  2. Behandlung von Konfigurationsfehlern beim Kompilieren
  3. Einfache und unkomplizierte Konfiguration
  4. FlexibilitÀt



All Articles