removed authentication methods and tests for data service

This commit is contained in:
Luis Aleixo 2024-01-31 11:50:12 +01:00
parent d09d6f0ec8
commit 7199143257
6 changed files with 8 additions and 158 deletions

View file

@ -352,16 +352,7 @@ $ oc create secret generic \
The CERN data service collects data from various sources and expose them via a REST API endpoint.
Create secret:
```console
$ read DATA_SERVICE_CLIENT_EMAIL
$ read DATA_SERVICE_CLIENT_PASSWORD
$ oc create secret generic \
--from-literal="DATA_SERVICE_CLIENT_EMAIL=$DATA_SERVICE_CLIENT_EMAIL" \
--from-literal="DATA_SERVICE_CLIENT_PASSWORD=$DATA_SERVICE_CLIENT_PASSWORD" \
data-service-api
```
To enable the service set the environment variable `DATA_SERVICE_ENABLED` as `True`.
## Update configuration

View file

@ -24,8 +24,6 @@ if [[ "$APP_NAME" == "calculator-app" ]]; then
export "EXTRA_PAGES"="$EXTRA_PAGES"
export "DATA_SERVICE_ENABLED"="${DATA_SERVICE_ENABLED:=False}"
export "DATA_SERVICE_CLIENT_EMAIL"="$DATA_SERVICE_CLIENT_EMAIL"
export "DATA_SERVICE_CLIENT_PASSWORD"="$DATA_SERVICE_CLIENT_PASSWORD"
echo "Starting the caimira webservice with: python -m caimira.apps.calculator ${args[@]}"
python -m caimira.apps.calculator "${args[@]}"

View file

@ -285,16 +285,6 @@
name: arve-api
- name: DATA_SERVICE_ENABLED
value: 'False'
- name: DATA_SERVICE_CLIENT_EMAIL
valueFrom:
secretKeyRef:
key: DATA_SERVICE_CLIENT_EMAIL
name: data-service-api
- name: DATA_SERVICE_CLIENT_PASSWORD
valueFrom:
secretKeyRef:
key: DATA_SERVICE_CLIENT_PASSWORD
name: data-service-api
image: '${PROJECT_NAME}/calculator-app'
ports:
- containerPort: 8080

View file

@ -494,12 +494,7 @@ def make_app(
data_service = None
data_service_enabled = os.environ.get("DATA_SERVICE_ENABLED", "False")
is_enabled = data_service_enabled.lower() == "true"
if is_enabled:
credentials = {
"email": os.environ.get("DATA_SERVICE_CLIENT_EMAIL", None),
"password": os.environ.get("DATA_SERVICE_CLIENT_PASSWORD", None),
}
data_service = DataService.create(credentials)
if is_enabled: data_service = DataService.create()
return Application(
urls,

View file

@ -1,8 +1,5 @@
import logging
import typing
from datetime import datetime, timedelta, timezone
import jwt
import requests
from caimira.store.data_registry import DataRegistry
@ -18,78 +15,18 @@ class DataService:
def __init__(
self,
credentials: typing.Dict[str, typing.Optional[str]],
host: str,
):
self._credentials = credentials
self._host = host
@classmethod
def create(cls, credentials: typing.Dict[str, typing.Optional[str]], host: str = "https://caimira-data-api.app.cern.ch"):
def create(cls, host: str = "https://caimira-data-api-qa.app.cern.ch"): # UPDATE QA TO PROD ONCE ALL IS WORKING
"""Factory."""
return cls(credentials, host)
def _is_valid(self, access_token):
"""Return True if the expiration token is still valid."""
try:
decoded = jwt.decode(
access_token, algorithms=["HS256"], options={"verify_signature": False}
)
expiration_timestamp = decoded["exp"]
expiration = datetime.utcfromtimestamp(expiration_timestamp).replace(
tzinfo=timezone.utc
)
now = datetime.now(timezone.utc)
is_valid = now < expiration - timedelta(
seconds=5
) # 5 seconds time delta to avoid timing issues
logger.debug(f"Access token expiration: {expiration_timestamp}. Is valid? {is_valid}")
return is_valid
except jwt.ExpiredSignatureError:
logger.warning("JWT token expired.")
except jwt.InvalidTokenError:
logger.warning("JWT token invalid.")
return False
def _login(self):
logger.debug(f"Access token: {self._access_token}")
if self._access_token and self._is_valid(self._access_token):
return self._access_token
# invalid access_token, fetch it again
client_email = self._credentials["email"]
client_password = self._credentials["password"]
if client_email == None or client_password == None:
# If the credentials are not defined, an exception is raised.
raise Exception("DataService credentials not set")
url = f"{self._host}/login"
headers = {"Content-Type": "application/json"}
json_body = dict(email=client_email, password=client_password)
try:
response = requests.post(url, json=json_body, headers=headers)
response.raise_for_status()
if response.status_code == 200:
self._access_token = response.json()["access_token"]
logger.debug(f"Obtained new access token: {self._access_token}")
return self._access_token
else:
logger.error(
f"Unexpected error on login. Response status code: {response.status_code}, body: f{response.text}"
)
except requests.exceptions.RequestException as e:
logger.exception(e)
return cls(host)
def _fetch(self):
access_token = self._login()
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json",
}
url = f"{self._host}/data"

View file

@ -1,78 +1,20 @@
import time
import unittest
from unittest.mock import Mock, patch
import jwt
from caimira.store.data_service import DataService
class DataServiceTests(unittest.TestCase):
def setUp(self):
# Set up any necessary test data or configurations
self.credentials = {"email": "test@example.com", "password": "password123"}
self.data_service = DataService.create(self.credentials, host="https://dataservice.example.com")
def test_jwt_expiration(self):
is_valid = self.data_service._is_valid(None)
self.assertFalse(is_valid)
now = time.time()
encoded = jwt.encode({"exp": now - 10}, "very secret", algorithm="HS256")
is_valid = self.data_service._is_valid(encoded)
self.assertFalse(is_valid)
encoded = jwt.encode({"exp": now}, "very secret", algorithm="HS256")
is_valid = self.data_service._is_valid(encoded)
self.assertFalse(is_valid)
encoded = jwt.encode({"exp": now + 10}, "very secret", algorithm="HS256")
is_valid = self.data_service._is_valid(encoded)
self.assertTrue(is_valid)
@patch("requests.post")
def test_login_successful(self, mock_post):
# Mock successful login response
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"access_token": "dummy_token"}
mock_post.return_value = mock_response
# Call the login method
access_token = self.data_service._login()
# Assert that the access token is returned correctly
self.assertEqual(access_token, "dummy_token")
# Verify that the fetch method was called with the expected arguments
mock_post.assert_called_once_with(
"https://dataservice.example.com/login",
json=dict(email="test@example.com", password="password123"),
headers={"Content-Type": "application/json"},
)
@patch("requests.post")
def test_login_error(self, mock_post):
# Mock login error response
mock_post.return_value = Mock()
mock_post.return_value.status_code = 500
# Call the login method
access_token = self.data_service._login()
# Assert that the login method returns None in case of an error
self.assertIsNone(access_token)
self.data_service = DataService.create(host="https://dataservice.example.com")
@patch("requests.get")
@patch.object(DataService, "_login")
def test_fetch_successful(self, mock_login, mock_get):
def test_fetch_successful(self, mock_get):
# Mock successful fetch response
mock_get.return_value = Mock()
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {"data": "dummy_data"}
# Call the fetch method with a mock access token
mock_login.return_value = "dummy_token"
data = self.data_service._fetch()
# Assert that the data is returned correctly
@ -82,20 +24,17 @@ class DataServiceTests(unittest.TestCase):
mock_get.assert_called_once_with(
"https://dataservice.example.com/data",
headers={
"Authorization": "Bearer dummy_token",
"Content-Type": "application/json",
},
)
@patch("requests.get")
@patch.object(DataService, "_login")
def test_fetch_error(self, mock_login, mock_get):
def test_fetch_error(self, mock_get):
# Mock fetch error response
mock_get.return_value = Mock()
mock_get.return_value.status_code = 500
# Call the fetch method with a mock access token
mock_login.return_value = "dummy_token"
# Call the fetch method
data = self.data_service._fetch()
# Assert that the fetch method returns None in case of an error