Skip to content

Commit

Permalink
[authentication] named scanner broke auth factory (RedHatProductSecur…
Browse files Browse the repository at this point in the history
…ity#127)

The authentication factory expected a fixed string for the scanners, to
get to the authentication type.

This was broken by the named scanner (e.g.: `zap_anonymous`).

This commit fixes that.

Also, while at it, I tidied a little:
- moved the factory into its own file
- improved the dev documentation for authentication
  • Loading branch information
cedricbu authored Sep 19, 2023
1 parent e91e5fb commit 2d9ee59
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 65 deletions.
15 changes: 9 additions & 6 deletions docs/DEVELOPER-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,23 +63,26 @@ likely either anonymous or error handling)

Example for the ZAP scanner (`scanners.zap`):

```
from scanners import generic_authentication_factory
```python
from scanners.authentication_factory import generic_authentication_factory

@generic_authentication_factory("zap")
@generic_authentication_factory()
def authentication_factory(self):
"""Default action"""
"""Default action, called when no corresponding authenticator were found"""
```

Once done, simply register each authentication type, based on
`scanners.zap.authentication.type` :
`scanners.*.authentication.type` :

```
```python
@authentication_factory.register("http_basic")
def authentication_set_http_basic_auth(self):
"""Configure HTTP Basic authentication"""
```

Then calling the `authentication_factory()` function will automatically redirect the call to the correct authentication function.


### Path helper

Because scanners may need to handle path from the "host" view and the "container" view, and translate from one to another, we have created a `path_translator` module to facilitate this.
Expand Down
57 changes: 0 additions & 57 deletions scanners/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,60 +67,3 @@ def str_to_scanner(name, method):
mod = importlib.import_module(f"scanners.{name}.{name}_{method}")
class_ = getattr(mod, mod.CLASSNAME)
return class_


###########################################################
# AUTHENTICATION HELPERS #
# - authentication factory #
###########################################################


def generic_authentication_factory(scanner_name):
"""Decorator factory for generic authentication.
First create the decorator:
@generic_authentication_factory("zap")
def authentication_factory(self):
[ default action. i.e.: probably raise error]
Then populate it by registering methods:
@authentication_factory.register(None)
def authentication_set_anonymous(self):
[return authentication of type `None`]
"""

def config_authentication_dispatcher(func):
"""This is intended to be a decorator to register authentication functions
The function passed during creation will be called in case no suitable functions are found.
i.e.: it should raise an error.
It is possible to retrieve an authenticator by calling <dispatcher>.dispatch(<version>)
This may be used for testing purpose
"""
registry = {} # "method" -> authenticator()

registry["error"] = func

def register(method):
def inner(func):
registry[method] = func
return func

return inner

def decorator(scanner):
authenticator = scanner.config.get(
f"scanners.{scanner_name}.authentication.type", default=None
)
func = registry.get(authenticator, registry["error"])
return func(scanner)

def dispatch(scanner):
return registry.get(scanner, registry["error"])

decorator.register = register
decorator.registry = registry
decorator.dispatch = dispatch

return decorator

return config_authentication_dispatcher
53 changes: 53 additions & 0 deletions scanners/authentication_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
###########################################################
# AUTHENTICATION HELPERS #
# - authentication factory #
###########################################################


def generic_authentication_factory():
"""Decorator factory for generic authentication.
First create the decorator:
@generic_authentication_factory("zap")
def authentication_factory(self):
[ default action. i.e.: probably raise error]
Then populate it by registering methods:
@authentication_factory.register(None)
def authentication_set_anonymous(self):
[return authentication of type `None`]
"""

def config_authentication_dispatcher(func):
"""This is intended to be a decorator to register authentication functions
The function passed during creation will be called in case no suitable functions are found.
i.e.: it should raise an error.
It is possible to retrieve an authenticator by calling <dispatcher>.dispatch(<version>)
This may be used for testing purpose
"""
registry = {} # "method" -> authenticator()

registry["error"] = func

def register(method):
def inner(func):
registry[method] = func
return func

return inner

def decorator(scanner):
authenticator = scanner.my_conf("authentication.type")
func = registry.get(authenticator, registry["error"])
return func(scanner)

def dispatch(scanner):
return registry.get(scanner, registry["error"])

decorator.register = register
decorator.registry = registry
decorator.dispatch = dispatch

return decorator

return config_authentication_dispatcher
4 changes: 2 additions & 2 deletions scanners/zap/zap.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

import yaml

from scanners import generic_authentication_factory
from scanners import RapidastScanner
from scanners.authentication_factory import generic_authentication_factory
from scanners.downloaders import authenticated_download_with_rtoken


Expand Down Expand Up @@ -549,7 +549,7 @@ def _save_automation_file(self):
# - May modify `self.automation_config` (e.g.: adding jobs, users)
# - May add environment vars
# - MUST return True if it created a user, and False otherwise
@generic_authentication_factory("zap")
@generic_authentication_factory()
def authentication_factory(self):
"""This is the default function, attached to error reporting"""
raise RuntimeError(
Expand Down

0 comments on commit 2d9ee59

Please sign in to comment.