Plugin to throw AccessDeniedException

Created on 21 January 2025, 3 months ago

Problem/Motivation

Scenario: an attacker is hitting a search endpoint with a slow DDOS attack. It's specifically targeting a Search API view with thousands of different search terms, hundreds of different user agents, and thousands of different IP addresses.

The one thing that is consistent is the structure of the query parameters used -- specific facets, and some specific search terms.

I want to intercept these requests and send them a 403 access denied before any search is attempted.

I want to use ECA so I can update the rules if the attacker varies the pattern, I can easily update the conditions to block.

Steps to reproduce

Proposed resolution

Create an action plugin that throws an AccessDeniedException.

Remaining tasks

Create plugin.

Create mechanism so that ECA does not silently catch the exception, but rethrows it.

User interface changes

API changes

Add a property for action plugins to indicate to ECA that an exception should be rethrown. Similar work was done for queue exceptions, except that was on event plugins -- in this case whether the exception should be caught or not should depend on the action plugin, not the event plugin.

Data model changes

✨ Feature request
Status

Active

Version

2.1

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States freelock Seattle

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @freelock
  • First commit to issue fork.
  • πŸ‡©πŸ‡ͺGermany jurgenhaas Gottmadingen

    I've started the process by building the framework so that action plugins can throw exceptions that ECA won't catch. You can now build the action plugin itself and just override the handleExceptions() method to return TRUE.

    As discussed on Slack, please make the plugin a bit more generic by providing 3 config fields:

    • Exception type: this should be a select list that allows for a number of different exceptions.
    • Response code: this should default to 403 but allow for others.
    • Message: an optional message as part of the exception.
  • πŸ‡©πŸ‡ͺGermany jurgenhaas Gottmadingen

    Updated the title to indicate that this should be able to throw various exceptions like also e.g. NotFoundHttpException as in unpublished_404 β†’

    I'm going to implement this as it is also required in Drupal CMS, see πŸ› Unpublished pages should return a 404, not a 403 Active .

  • Pipeline finished with Failed
    2 months ago
    Total: 561s
    #408001
  • Merge request !466Resolve #3501241 "Plugin to throw" β†’ (Merged) created by jurgenhaas
  • πŸ‡©πŸ‡ͺGermany jurgenhaas Gottmadingen

    I've now implemented the "ThrowException" action plugin with all the HttpExceptions that are available from Symfony. I removed the response code idea as all those exception have hard coded response codes provided.

    A sample model which responds with a 404 instead of a 403 on a node that unpublished for anonymous users:

    langcode: en
    status: true
    dependencies:
      module:
        - eca_base
        - eca_misc
    id: unpublished_404
    modeller: bpmn_io
    label: 'Unpublished 404'
    version: 1.0.0
    weight: 0
    events:
      Event_uncaught_exception:
        plugin: 'kernel:exception_status_code'
        label: 'Uncaught Exception'
        configuration: {  }
        successors:
          -
            id: Activity_06x1ob0
            condition: Flow_is_403
    conditions:
      Flow_is_403:
        plugin: eca_scalar
        configuration:
          negate: false
          case: false
          left: '[event:code]'
          right: '403'
          operator: equal
          type: value
    gateways: {  }
    actions:
      Activity_06x1ob0:
        plugin: eca_throw_exception
        label: Activity_06x1ob0
        configuration:
          exception_type: Symfony\Component\HttpKernel\Exception\NotFoundHttpException
          response_message: ''
        successors: {  }
    
  • Pipeline finished with Success
    2 months ago
    Total: 519s
    #408030
  • πŸ‡©πŸ‡ͺGermany michaellenahan

    I tested the patch, it works as expected.

    Because I'm rather new to this, documenting the steps I took to test the patch.
    Note in particular the `composer create-project` command to install the head of the drupal-cms repo, thank you to phenaproxima for this tip in the #drupal-cms-development channel on drupal slack.

    mkdir eca-3501241  
    cd eca-3501241  
    ddev config  
    ddev start  
    ddev composer create-project drupal/cms:1.x-dev -s dev  
    ddev drush site:install --yes
    ddev launch $(ddev drush uli)
    

    By default, the "Privacy policy" page is unpublished.
    Without the model in place, https://eca-3501241.ddev.site/privacy-policy returns a 404.

    So, now let's import the model from @jurgenhaas comment #6.

    mkdir -p web/tmp
    # Paste the yaml from @jurgenhaas #6 comment
    nvim web/tmp/eca.eca.unpublished_404.yml
    # Import the single configuration file
    ddev drush config:import --partial --source=tmp
    

    That worked. For an anonymous user, https://eca-3501241.ddev.site/privacy-policy now returns a 404.

  • πŸ‡©πŸ‡ͺGermany jurgenhaas Gottmadingen

    Great job, this is one of the most comprehensive review reports I've seen in a while.

    Your observation, that the page responds with an empty page in this case is correct and expected.

  • Pipeline finished with Skipped
    2 months ago
    #409983
  • Pipeline finished with Skipped
    2 months ago
    #409984
  • πŸ‡©πŸ‡ͺGermany jurgenhaas Gottmadingen
  • πŸ‡©πŸ‡ͺGermany jurgenhaas Gottmadingen

    From @michaellenahan 's observation that we currently respond with an empty page I was wondering if that could be improved such that Drupal's regular exception handling for 404 pages kicks in. And that made me realize that we has a couple of other areas that needed immediate treatment. I've created follow-up issues and fixed them as well.

    This now behaves as expected and not with an empty page any longer.

  • πŸ‡©πŸ‡ͺGermany jurgenhaas Gottmadingen
  • Pipeline finished with Failed
    about 2 months ago
    Total: 265s
    #426619
  • Pipeline finished with Success
    about 2 months ago
    Total: 233s
    #426627
  • Pipeline finished with Success
    about 2 months ago
    Total: 217s
    #426633
Production build 0.71.5 2024