Simple Attribute-Based Access Control With Spring Security

Introduction

Have you ever worked on software where the access rules are based not only on the user’s role but also on the specific entity that role was granted on (i.e. Scoped Roles), something like “Project Manager can add users to HIS PROJECT ONLY”, “Store Agent can access Store Information for HIS STORE ONLY”,  or “Document Owner can modify HIS DOCUMENTS”?

Or, where the access rules are based on context, where the access happens, like time, user-network, or channel (like web-site, mobile-app, some-internal-system, etc.). For example “This resource can be accessed only DURING OFFICE HOURS or ONLY FROM OFFICE NETWORK”?

All of that, and still the logic of these access rules needs to be configurable and flexible to be modified with minimum (or no) software coding or new deployment.

Then, you will probably find Attribute-Based Access Control very useful.

What Is Attribute-Based Access Control (ABAC)

Any access request will have four elements (subject, resource, action, and environment), where:

  • Subject is the entity (mostly a user) that requests access.
  • Resource is the entity to be accessed (e.g. file, database record, Store Information, …).
  • Action is the operation to be carried out on the resource (e.g. read, write, delete, …).
  • Environment is any information regarding the context of the access that might be used in making the access decision (e.g. time, network, …).

ABAC is where each of the elements above is represented by a set of attributes. Each of these attributes has a key and one (or many) value(s). For example, subject could have id, name, and roles attributes.

The ABAC access rules are based on a relationship of elements’ attributes (like subject.id equals resource.ownerId) and/or element’s attribute has/contains specific values (like subject.name equals “Smith”, or subject.roles contains “ADMIN”).

ABAC allows you to define Access Rules with a far finer granularity of access control, relative to other models like Role-Based (RBAC) or Access-Control-List (ACL), without losing any of the capabilities found in other models (e.g. defining rules based only the user-role, as in RBAC).

For more details on ABAC, check NIST Guide to Attribute Based Access Control (ABAC) Definition and Considerations.

For a concise comparison of ABAC and other Access Control models check (quite old, but still informative) NIST: A Survey Of Access Control Models (Draft).

Spring Security Framework and SpEL

The Spring Security Framework enables the developers to inject their Access-Control logic in a centralized component and to be enforced (using 
Expression-Based Access Control) in various execution points of the application, like before/after REST API calls and before/after method calls providing all necessary context (like method parameters or return objects) for the Access-Control logic to work.

On the other hand, SpEL (Spring Expression Language) is an Expression Language similar to Java EL used in JSP and JSF. It used by default in Spring Security when Expression-Based access control is enabled.

In this article, we will use SpEL as the language to define the Access Rules.

The figure below describes the sequence flow for each method call protected by access control:

Simple Attribute-Based Access Control With Spring Security

Inside the AccessDecisionManager the below sequence takes place:

Simple Attribute-Based Access Control With Spring Security

And inside the AfterInvocationManager the below sequence takes place:

Simple Attribute-Based Access Control With Spring Security

As shown in theses diagrams, the access decisions are (eventually) delegated to a component called PermissionEvaluator (colored in blue above), and this is where the ABAC logic will be.

Note: If the diagrams appear to be too small, just drag them into a new tab (or download them).

Key Components

The approach presented in this article is based on the following ideas:

  • Use boolean Spring EL Expressions to define access rules (e.g. subject.project.id == resource.project.id) which will be stored in a central repository (e.g. memory, database, LDAP, file).
  • Define a centralized component that loads the rules, wrap the elements of access context, and evaluate the rules’ expressions to decide whether access is granted or denied.
  • Use the Spring annotations –  @PostAuthorize/@PreAuthorize("hasPermission (...)) – (along with other artifacts mentioned later) to enforce the access rules.

The following are the key components of this approach:

PermissionEvaluator

This is the entry point for ABAC logic to be executed. As mentioned before, all access decisions made by Spring Security framework (Expression-Based Access Control) are delegated to this component, i.e. all annotations  @PreAuthorize("hasPermision(...)"),  @PostAuthorize("hasPermision(...)") are delegated to the component.

The work presented here creates a custom implementation of this component that just delegates the access decision to the PolicyEnforcement component.

public class AbacPermissionEvaluator implements PermissionEvaluator {
    @Autowired
    PolicyEnforcement policy;

    @Override
    public boolean hasPermission(Authentication authentication , Object targetDomainObject, Object permission) {
        //Getting subject
        Object user = authentication.getPrincipal();

        //Getting environment
        Map environment = new HashMap();
        environment.put("time", new Date());

        return policy.check(user, targetDomainObject, permission, environment);
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        return false;
    }
}

ContextAwarePolicyEnforcement

This an optional component that is similar to PermissionEvaluator but can be called at any point in your code, given that the SecurityContext is available and filled with current, authenticated user information.

This component is used when the data needed to make the access decision is not available to @PreAuthorize and @PostAuthorize annotations.

For example, when updating an entity:

  • @PreAuthorize will have access only to the method’s parameters, which are the updated entity’s information, while the access decision needs the information of the existing entity.
  • @PostAuthorize will be called after the update is done, which is too late for an access decision to be taken.
public class ContextAwarePolicyEnforcement {
    @Autowired
    protected PolicyEnforcement policy;

    public void checkPermission(Object resource, String permission) {
        //Getting the subject
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        //Getting the environment
        Map environment = new HashMap();
        environment.put("time", new Date());

        if(!policy.check(auth.getPrincipal(), resource, permission, environment))
        throw new AccessDeniedException("Access is denied");
    }
}

PolicyEnforcement

This is where the actual access decision is taken. It works as follows:

  1. Load all PolicyRules using the PolicyDefinition.
  2. Filter the PolicyRules leaving only the applicable rules (i.e. rules where the target expression evaluates to true) in the current access context.
  3. Evaluates all applicable PolicyRules (i.e., evaluating the condition expression) in the current access context. If any returned true then access is granted; otherwise, access is denied.

The reason that we did not implement the above logic inside the PermissionEvaluator is for decoupling the ABAC logic from the Spring Security and allowing the decision making to be invoked outside the Spring Security Framework (e.g., by calling the PolicyEnforecment directly inside any method’s logic).

public class BasicPolicyEnforcement implements PolicyEnforcement {
    @Autowired
    private PolicyDefinition policyDefinition;

    @Override
    public boolean check(Object subject, Object resource, Object action, Object environment) {
        //Get all policy rules
        List allRules = policyDefinition.getAllPolicyRules();

        //Wrap the context
        SecurityAccessContext cxt = new SecurityAccessContext(subject, resource, action, environment);

        //Filter the rules according to context.
        List matchedRules = filterRules(allRules, cxt);

        //finally, check if any of the rules are satisfied, otherwise return false.
        return checkRules(matchedRules, cxt);
    }

    private List filterRules(List allRules, SecurityAccessContext cxt) {
        List matchedRules = new ArrayList();
        for(PolicyRule rule : allRules) {
            try {
                if(rule.getTarget().getValue(cxt, Boolean.class)) {
                    matchedRules.add(rule);
                }
            } catch(EvaluationException ex) {
                logger.error("An error occurred while evaluating PolicyRule.", ex);
            }
        }
        return matchedRules;
    }

    private boolean checkRules(List matchedRules, SecurityAccessContext cxt) {
        for(PolicyRule rule : matchedRules) {
            try {
                if(rule.getCondition().getValue(cxt, Boolean.class)) {
                    return true;
                }
            } catch(EvaluationException ex) {
                logger.error("An error occurred while evaluating PolicyRule.", ex);
            }
        }
        return false;
    }
}

PolicyDefinition

This interface represents the PolicyRule repository. It has one method, getAllPolicyRules, that loads all available policy rules.

This interface hides the details of how-policy-rules-are-stored from the policy clients. This component could be implemented for (but not limited to) in-memory policy, JSON-file policy, or database policy. The details for each repository format is up to the implementer of this component.

PolicyRule

This is the atomic element of access policy, this is where the ABAC logic is defined to be evaluated when needed.

PolicyRule has the following main properties:

  • target: A SpEL boolean expression where this rule is applicable (i.e. if the expression evaluates to true, then this rule is applicable)
  • condition: A SpEL boolean expression where this rule is satisfied (i.e. if the expression evaluates to true, then access is granted)

Both expressions have access to the four elements of access-request, namely subject, resource, action, and environment.

For the sake of simplicity, the Rules have a positive effect only (i.e., granting access if satisfied) but they can easily be extended to have negative effects also (i.e., denying access if satisfied).

SecurityAccessContext

This is a wrapper class for all the access elements. It has fields for each of Subject, Resource, Action, and Environment.

For each access decision to be taken, an instance of this class is created by PolicyEnforcement and filled with corresponding access elements.

The instances of this class serve as the Root object for evaluating the PolicyRules expressions.

Sample Application

I have made a sample application to illustrate the details of the ABAC using Spring Security.

Overview

The application is a very simple issue tracking system, where there are set of projects and each project has a Project Manager (PM) and a set of Testers and a set of Developers.

It is made up of REST APIs using Spring MVC (no GUI), and the source code can be found here.

For simplicity, all data is stored in memory.

Business Overview

Users

There are 4 types of users: Admins, Project Managers, Testers, and Developers.

For simplicity, users can only have one role.

Projects

Issues are grouped into projects, each project is created and managed through the application.

Each Project can have one Project Manager and many Testers and/or Developers.

For simplicity, users can be assigned to one project only.

Issues and Status

Issues can be created and managed through the application.

There two types of issues: Tasks and Bugs.

Each issue has a status. Issues Status can be any: NEW, ASSIGNED, COMPLETED.

Issues can be assigned to Users, and authorized users can change the Issues status.

Access Rules

Below are sample access rules and their translation to an ABAC SpEL expression:

  • Admin can do all

    • Target: subject.role.name() == ‘ADMIN’
    • Condition: true
  • PM can add new issues to his project only.

    • Target: subject.role.name() == ‘PM’ && action == ‘ISSUES_CREATE’
    • Condition: subject.project.id == resource.project.id
  • Tester can add bugs (and only bugs) to his project

    • Target: subject.role.name() == ‘TESTER’ && action == ‘ISSUES_CREATE’
    • Condition: subject.project.id == resource.project.id && resource.type.name() == ‘BUG’
  • Users can complete issues assigned to them.

    • Target: action == ‘ISSUES_STATUS_CLOSE’
    • Condition: subject.project.id == resource.project.id && subject.name == resource.assignedTo

All access rules are stored in this JSON file.

Challenges and Enhancement

The work presented here, despite its flexibility, does not cover all the concerns that will be faced when using it in real-world applications, below are some of them:

Performance Issues

Loading, filtering, and checking policy rules for each access decision could have a considerable impact on the application’s performance. This could be reduced by the following:

  1. Caching access decisions (i.e. the results of  PolicyEnoforecment#check(..)).
  2. Caching PolicyRules (i.e. the results of  PolicyDefinition#getAllPolicyRules()).
  3. Using compiled SpEL, for more detail check here.

More Elaborate Policy

The access rules presented here are simple (one-level) rules which can be enriched by the following:

  1. Introducing PolicySets that are groups of policy rules and other nested PolicySets. Each PolicySet will have its own condition and target expressions, something like XACML standard.
  2. PolicyRules could have a negative effect.

Policy Rules Validation

The policy rules defined in the article are taken as valid, but in production environments, these rules need to be validated before storing them in the policy repository. For example, expressions should be limited to access only the access context elements (subject, resource, action, and environment).

Policy Repository

In the sample application, I have used an in-memory, and static-JSON-file to store the PolicyRules, but in practice, more complex repositories should be used, like Database, or LDAP.

To enter this work into your JSON file use the new implementation, PolicyDefinition.

Policy Editor

We did not cover how the rules are defined. In real-world applications, there should be a tool (probably with a GUI) to define those rules allowing Admins and maybe SMEs to define and manage these rules with little (or no) programming experience required. 

Related Work

文章来源于互联网:Simple Attribute-Based Access Control With Spring Security

发布者:小站,转转请注明出处:http://blog.gzcity.top/4238.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年5月3日 18:09
下一篇 2022年5月3日 18:09

相关推荐

  • 识别并修复 Web 应用中的 XSS 漏洞

    什么是跨站点脚本? 跨站点脚本 (XSS) 是一个代码注入漏洞,当开发人员在将用户输入插入 HTML 模板之前未对用户输入进行足够好的审查时,就会在处理 HTML 的应用程序中发生该漏洞。它允许攻击者将任意 JavaScript 代码插入模板并在用户的上下文中执行它: 在上图中,开发人员未能清理“姓氏”div 的内容,这导致用户能够通过操纵其姓氏来包含恶意脚…

    2023年6月11日
    9.9K1270
  • Keys to a Great API Security Solution

    So, do you think your APIs are secure? You might want to take another look at your security.  Figure 1 What is API security? APIs are everywhere, and API Security is of the utmost …

    2022年5月3日
    1.1K40
  • How to Improve Your WordPress’ Website Security

    WordPress security has been an important topic ever since the content management system was released back in 2003. As with any highly popular piece of software with a long and rich…

    安全 2022年5月3日
    940570
  • Scalable JWT Token Revokation in Spring Boot

    With stateless JWT Tokens for security, short TTLs (1 min) can be used. These tokens are then refreshed during their time to live. If the server does not get to know when a user ha…

    2022年5月3日
    63760
  • A Simple Blockchain in Java

    I鈥檓 sure we all have heard about cryptocurrency and blockchain and how interrelated they are, which is true too, but they are actually very different and can exist independently. C…

    安全 2022年5月3日
    52240

回复 best binance referral code

您的邮箱地址不会被公开。 必填项已用 * 标注

评论列表(4条)

  • kostenloses binance Konto
    kostenloses binance Konto 2024年10月17日 17:39

    Your point of view caught my eye and was very interesting. Thanks. I have a question for you.

  • Учетная запись в binance

    Thanks for sharing. I read many of your blog posts, cool, your blog is very good.

  • binance register
    binance register 2024年12月3日 09:47

    Thank you for your sharing. I am worried that I lack creative ideas. It is your article that makes me full of hope. Thank you. But, I have a question, can you help me?

  • best binance referral code
    best binance referral code 2025年2月13日 17:49

    Your point of view caught my eye and was very interesting. Thanks. I have a question for you.