Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alert - Support for authentication when calling receiver endpoint. #560

Open
wants to merge 27 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c39273f
added support for authentication in the alert (both basic and bearer).
andreee94 Feb 24, 2022
1fa0693
added unit tests for alert authentication
andreee94 Feb 24, 2022
bd88ef3
updated documentation for alert authentication
andreee94 Feb 24, 2022
1c3d61e
fixed yq command in makefile
andreee94 Feb 24, 2022
3de5ef9
added support for authentication in the alert (both basic and bearer).
andreee94 Feb 24, 2022
51ea8a4
added unit tests for alert authentication
andreee94 Feb 24, 2022
9a10f8f
updated documentation for alert authentication
andreee94 Feb 24, 2022
d771c5e
Merge remote-tracking branch 'refs/remotes/origin/feat/alert-authenti…
andreee94 Feb 28, 2022
7613ba3
Improved alert class accordingly to the pull request
andreee94 Feb 28, 2022
3d383a5
Updated alert documentation
andreee94 Feb 28, 2022
7957567
Renamed authorization_prefix to authentication_scheme in the alert_sc…
andreee94 Feb 28, 2022
f96b907
Testing authentication_scheme validation in alert.
andreee94 Feb 28, 2022
be8c718
added support for authentication in the alert (both basic and bearer).
andreee94 Feb 24, 2022
cec1a0f
added unit tests for alert authentication
andreee94 Feb 24, 2022
8050102
updated documentation for alert authentication
andreee94 Feb 24, 2022
c04c902
Improved alert class accordingly to the pull request
andreee94 Feb 28, 2022
d98c6bd
Updated alert documentation
andreee94 Feb 28, 2022
a34506d
Renamed authorization_prefix to authentication_scheme in the alert_sc…
andreee94 Feb 28, 2022
14f58cd
Testing authentication_scheme validation in alert.
andreee94 Feb 28, 2022
dffbd88
Merge remote-tracking branch 'refs/remotes/origin/feat/alert-authenti…
andreee94 Mar 1, 2022
b3a54c0
Code updated to fix pylint suggestions, and other minor changes.
andreee94 Mar 1, 2022
0f26f6d
Embracing the EAFP paradigm.
andreee94 Mar 2, 2022
0a8b73b
Merge branch 'develop' into feat/alert-authentication
andreee94 Mar 2, 2022
b207360
Merge branch 'develop' into feat/alert-authentication
andreee94 Mar 3, 2022
826c78e
Moving the alert webhook authentication documentation in the addition…
andreee94 Mar 5, 2022
f4d02bb
Improved the helm chart to reference existing secrets and config maps…
andreee94 Mar 5, 2022
6aa67ab
Merge remote-tracking branch 'refs/remotes/origin/feat/alert-authenti…
andreee94 Mar 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 37 additions & 35 deletions connaisseur/alert.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from abc import abstractmethod
import json
import logging
import os
Expand Down Expand Up @@ -58,48 +57,49 @@ class AlertReceiverAuthentication:
authentication_scheme: str = None

class AlertReceiverAuthenticationInterface:
def __init__(self, alert_receiver_config: dict, authentication_key: str):
self.authentication_config = alert_receiver_config.get(authentication_key)

if self.authentication_config is None:
raise ConfigurationError(
f"No authentication configuration found ({authentication_key})."
def __init__(self, alert_receiver_config: dict, authentication_config_key: str):
if authentication_config_key is not None:
self.authentication_config = alert_receiver_config.get(
authentication_config_key
)

self.authentication_scheme = self.authentication_config.get(
"authentication_scheme", self.authentication_scheme
)
self._validate_authentication_scheme()
if self.authentication_config is None:
raise ConfigurationError(
"No authentication configuration found for dictionary key:"
f"{authentication_config_key}."
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, you can also try: self.authentication_config = alert_receiver_config[authentication_config_key], and then raise the error in the except: block.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed also other places where EAFP can be applied.


self.authentication_scheme = self.authentication_config.get(
"authentication_scheme", self.authentication_scheme
)
Comment on lines +72 to +74
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the second argument here? self.authentication_scheme would be None at this point, which is the default for dict.get.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it should take the default value set in the classes that inherited the base.

This is a very bad coded concept, but it should work:

class Base:
    def __init__(self):
        self.surname = self.name if self.name is not None else 'Base'
    
class A(Base):
    name = "A"
    def __init__(self):
        super().__init__()

class B(Base):
    name = "B"
    def __init__(self):
        super().__init__()

a = A()
print(a.surname)
        
b = B()
print(b.surname)

Which prints:

A
B

A proper nit-picking review is a great opportunity to improve my coding skills ;)

self._validate_authentication_scheme()

def _validate_authentication_scheme(self) -> None:
if not self.authentication_scheme:
raise ConfigurationError(
"The authentication scheme cannot be null or empty."
)

if " " in self.authentication_scheme:
# check if self.authentication_scheme contains only letters
if not self.authentication_scheme.isalpha():
raise ConfigurationError(
"The authentication scheme cannot contain any space."
"The authentication scheme must contain only letters."
)

@abstractmethod
def get_header(self) -> dict:
pass
return {}

class AlertReceiverNoneAuthentication(AlertReceiverAuthenticationInterface):
"""
Placeholder class for AlertReceiver without authentication.
"""

def __init__(self, alert_receiver_config: dict):
pass

def get_header(self) -> dict:
return {}
super().__init__(alert_receiver_config, None)

class AlertReceiverBasicAuthentication(AlertReceiverAuthenticationInterface):
"""
Class to store authentication information for basic authentication type with username and password.
Class to store authentication information for basic authentication type
with username and password.
"""

username: str
Expand All @@ -124,7 +124,8 @@ def __init__(self, alert_receiver_config: dict):

if self.username is None or self.password is None:
raise ConfigurationError(
f"No username or password found from environmental variables {username_env} and {password_env}."
"No username or password found from environmental variables "
f"{username_env} and {password_env}."
)

def get_header(self) -> dict:
Expand Down Expand Up @@ -169,14 +170,16 @@ def __init__(self, alert_receiver_config: dict):
)
else:
try:
with open(token_file, "r") as token_file:
with open(token_file, "r", encoding="utf-8") as token_file:
self.token = token_file.read()
except FileNotFoundError:
raise ConfigurationError(f"No token file found at {token_file}.")
except FileNotFoundError as err:
raise ConfigurationError(
f"No token file found at {token_file}."
) from err
except Exception as err:
raise ConfigurationError(
f"An error occurred while loading the token file {token_file}: {str(err)}"
)
) from err

def get_header(self) -> dict:
return {"Authorization": f"{self.authentication_scheme} {self.token}"}
Expand All @@ -196,16 +199,15 @@ def __init__(self, alert_receiver_config: dict):
self.__init_authentication_instance(alert_receiver_config)

def __init_authentication_instance(self, alert_receiver_config: dict):
authentication_class = self.__get_authentication_class()
self._authentication_instance = authentication_class(alert_receiver_config)

def __get_authentication_class(self):
if self.authentication_type not in AlertReceiverAuthentication.init_map.keys():
try:
self._authentication_instance = self.init_map[self.authentication_type](
alert_receiver_config
)
except KeyError as err:
raise ConfigurationError(
f"No authentication type found. Valid values are {list(AlertReceiverAuthentication.init_map.keys())}"
) # hopefully this never happens

return self.init_map.get(self.authentication_type)
"No authentication type found. Valid values are "
f"{list(AlertReceiverAuthentication.init_map.keys())}"
) from err # hopefully this never happens

def get_auth_header(self) -> dict:
return self._authentication_instance.get_header()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ def test_alert_init(
{},
pytest.raises(
ConfigurationError,
match=r"The authentication scheme cannot contain any space.",
match=r"The authentication scheme must contain only letters.",
),
),
],
Expand Down