diff --git a/docs/DEVELOPER-GUIDE.md b/docs/DEVELOPER-GUIDE.md index 7f60696f..28864857 100644 --- a/docs/DEVELOPER-GUIDE.md +++ b/docs/DEVELOPER-GUIDE.md @@ -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. diff --git a/scanners/__init__.py b/scanners/__init__.py index b0c7810f..7fadb353 100644 --- a/scanners/__init__.py +++ b/scanners/__init__.py @@ -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 .dispatch() - 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 diff --git a/scanners/authentication_factory.py b/scanners/authentication_factory.py new file mode 100644 index 00000000..e635ccf4 --- /dev/null +++ b/scanners/authentication_factory.py @@ -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 .dispatch() + 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 diff --git a/scanners/zap/zap.py b/scanners/zap/zap.py index 682dae29..6afbccf6 100644 --- a/scanners/zap/zap.py +++ b/scanners/zap/zap.py @@ -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 @@ -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(